Rename SolveCraft to SolidCraft everywhere, with compatibility shims (#389)
* WIP deep rename (not for push) * WIP2 * WIP3 * WIP4 wxs fix * rustfmt * Rename the remaining identifiers in merged crash-report code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
27415e4dd7
commit
296683229d
464 files changed
+3408
-2956
No files matched your search
@@ -6,7 +6,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use solvecraft_geom::Vec2;
|
||||
use solidcraft_geom::Vec2;
|
||||
|
||||
use crate::sketch2d::{Geom2, MAX_DRAWING_BYTES, MAX_ENTITIES, bulge_arc};
|
||||
use crate::{IoError, Result};
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
//! First-launch adoption of a pre-rename settings or data folder. Compatibility shim (see
|
||||
//! docs/compatibility.md): when the current folder doesn't exist yet and the legacy one does,
|
||||
//! the legacy folder is copied over. The legacy folder is never changed or deleted, so an older
|
||||
//! release installed side by side keeps working.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Most files and nesting copied from a legacy folder (it holds preferences, autosaves and
|
||||
/// small caches; anything bigger is not ours).
|
||||
const MAX_ENTRIES: usize = 10_000;
|
||||
const MAX_DEPTH: usize = 8;
|
||||
|
||||
/// Copy `legacy` to `current` if `current` doesn't exist and `legacy` is a folder. Returns
|
||||
/// whether a copy was made. Symbolic links are skipped. A copy that fails part way leaves what
|
||||
/// was copied (the next launch sees `current` and doesn't try again) and reports the error.
|
||||
pub fn adopt_legacy_dir(current: &Path, legacy: &Path) -> std::io::Result<bool> {
|
||||
if current.exists() || !legacy.is_dir() || current == legacy {
|
||||
return Ok(false);
|
||||
}
|
||||
let mut budget = MAX_ENTRIES;
|
||||
copy_tree(legacy, current, 0, &mut budget)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn copy_tree(from: &Path, to: &Path, depth: usize, budget: &mut usize) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(to)?;
|
||||
if depth >= MAX_DEPTH {
|
||||
return Ok(());
|
||||
}
|
||||
for entry in std::fs::read_dir(from)? {
|
||||
let entry = entry?;
|
||||
if *budget == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
*budget -= 1;
|
||||
let kind = entry.file_type()?;
|
||||
let target = to.join(entry.file_name());
|
||||
if kind.is_dir() {
|
||||
copy_tree(&entry.path(), &target, depth + 1, budget)?;
|
||||
} else if kind.is_file() {
|
||||
std::fs::copy(entry.path(), &target)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn scratch(tag: &str) -> std::path::PathBuf {
|
||||
let d = std::env::temp_dir().join(format!("solidcraft-legacy-dir-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
std::fs::create_dir_all(&d).unwrap();
|
||||
d
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copies_legacy_folder_once_and_keeps_it() {
|
||||
let d = scratch("copy");
|
||||
let old = d.join("solvecraft");
|
||||
std::fs::create_dir_all(old.join("recovery")).unwrap();
|
||||
std::fs::write(old.join("graphics.json"), "{\"msaa\":8}").unwrap();
|
||||
std::fs::write(old.join("recovery").join("a.solvecraft"), "x").unwrap();
|
||||
let new = d.join("solidcraft");
|
||||
assert!(adopt_legacy_dir(&new, &old).unwrap());
|
||||
assert_eq!(std::fs::read_to_string(new.join("graphics.json")).unwrap(), "{\"msaa\":8}");
|
||||
assert!(new.join("recovery").join("a.solvecraft").is_file());
|
||||
// The legacy folder is untouched.
|
||||
assert!(old.join("graphics.json").is_file() && old.join("recovery").join("a.solvecraft").is_file());
|
||||
// Once the current folder exists, nothing is copied again.
|
||||
std::fs::write(old.join("later.json"), "{}").unwrap();
|
||||
assert!(!adopt_legacy_dir(&new, &old).unwrap());
|
||||
assert!(!new.join("later.json").exists());
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nothing_to_adopt() {
|
||||
let d = scratch("none");
|
||||
let new = d.join("solidcraft");
|
||||
assert!(!adopt_legacy_dir(&new, &d.join("missing")).unwrap());
|
||||
assert!(!new.exists());
|
||||
// An existing current folder is never overwritten.
|
||||
let old = d.join("solvecraft");
|
||||
std::fs::create_dir_all(&old).unwrap();
|
||||
std::fs::write(old.join("p.json"), "old").unwrap();
|
||||
std::fs::create_dir_all(&new).unwrap();
|
||||
std::fs::write(new.join("p.json"), "new").unwrap();
|
||||
assert!(!adopt_legacy_dir(&new, &old).unwrap());
|
||||
assert_eq!(std::fs::read_to_string(new.join("p.json")).unwrap(), "new");
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
}
|
||||
+51
-35
@@ -1,4 +1,4 @@
|
||||
//! File formats. Designs are saved as JSON (`.solvecraft`): the parametric document only, the
|
||||
//! File formats. Designs are saved as JSON (`.solidcraft`): the parametric document only, the
|
||||
//! model is recomputed on load. Bodies export as STL (binary or ASCII), OBJ, STEP and 3MF; STEP
|
||||
//! files import as a base feature (see [`step_import_feature`]), 3MF and STL files as mesh bodies
|
||||
//! (see [`mesh_import_feature`]).
|
||||
@@ -6,6 +6,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod dxf;
|
||||
mod legacy_dir;
|
||||
pub mod safe_write;
|
||||
mod sketch2d;
|
||||
mod svg;
|
||||
@@ -13,6 +14,7 @@ mod threemf;
|
||||
pub mod vfs;
|
||||
|
||||
pub use dxf::{read_dxf, write_dxf};
|
||||
pub use legacy_dir::adopt_legacy_dir;
|
||||
pub use safe_write::{backup_path, write_atomic};
|
||||
pub use sketch2d::{Geom2, MAX_DRAWING_BYTES};
|
||||
pub use svg::read_svg;
|
||||
@@ -20,26 +22,36 @@ mod obj;
|
||||
pub use obj::read_obj;
|
||||
pub use threemf::{MAX_3MF_BYTES, MeshObject, model_xml, read_3mf, weld, write_3mf};
|
||||
|
||||
use solvecraft_doc::{Document, ModelState};
|
||||
use solvecraft_geom::{Mesh, Vec3};
|
||||
use solidcraft_doc::{Document, ModelState};
|
||||
use solidcraft_geom::{Mesh, Vec3};
|
||||
|
||||
/// Design file extension.
|
||||
pub const DESIGN_EXT: &str = "solvecraft";
|
||||
pub const DESIGN_EXT: &str = "solidcraft";
|
||||
/// The design extension of earlier releases. Compatibility shim (docs/compatibility.md): such
|
||||
/// files still open everywhere a design opens; new designs are saved as [`DESIGN_EXT`].
|
||||
pub const LEGACY_DESIGN_EXT: &str = "solvecraft";
|
||||
/// Every extension a design file may have, current first.
|
||||
pub const DESIGN_EXTS: [&str; 2] = [DESIGN_EXT, LEGACY_DESIGN_EXT];
|
||||
|
||||
/// Is this a design file name (`.solidcraft`, or the legacy extension), any case?
|
||||
pub fn is_design_path(path: &str) -> bool {
|
||||
std::path::Path::new(path).extension().and_then(|e| e.to_str()).is_some_and(|e| DESIGN_EXTS.iter().any(|x| e.eq_ignore_ascii_case(x)))
|
||||
}
|
||||
/// Largest design file we read.
|
||||
pub const MAX_DESIGN_BYTES: usize = 256 << 20;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum IoError {
|
||||
#[error("unsupported format `{0}` (use stl, obj, step, 3mf or solvecraft)")]
|
||||
#[error("unsupported format `{0}` (use stl, obj, step, 3mf or solidcraft)")]
|
||||
Format(String),
|
||||
#[error("nothing to export: the design has no bodies")]
|
||||
Empty,
|
||||
#[error("{0}")]
|
||||
Invalid(String),
|
||||
#[error(transparent)]
|
||||
Kernel(#[from] solvecraft_kernel::KernelError),
|
||||
Kernel(#[from] solidcraft_kernel::KernelError),
|
||||
#[error(transparent)]
|
||||
Doc(#[from] solvecraft_doc::DocError),
|
||||
Doc(#[from] solidcraft_doc::DocError),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, IoError>;
|
||||
@@ -65,7 +77,7 @@ pub fn is_iges_path(path: &str) -> bool {
|
||||
pub struct StepFeature {
|
||||
/// Timeline name: the root product's name, else the file name.
|
||||
pub name: String,
|
||||
pub kind: solvecraft_doc::FeatureKind,
|
||||
pub kind: solidcraft_doc::FeatureKind,
|
||||
/// Body names from the file (solid names, else product names).
|
||||
pub body_names: Vec<String>,
|
||||
pub warnings: Vec<String>,
|
||||
@@ -81,8 +93,8 @@ pub fn step_import_feature(bytes: &[u8], file: &str) -> Result<StepFeature> {
|
||||
// (the feature keeps that STEP text).
|
||||
let text = String::from_utf8_lossy(bytes).into_owned();
|
||||
let (text, iges_warnings) =
|
||||
if is_iges_path(file) { solvecraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) };
|
||||
let imp = solvecraft_kernel::step_import_shared(&text)?;
|
||||
if is_iges_path(file) { solidcraft_kernel::iges_to_step(&text).map_err(IoError::Invalid)? } else { (text, Vec::new()) };
|
||||
let imp = solidcraft_kernel::step_import_shared(&text)?;
|
||||
let stem = std::path::Path::new(file)
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
@@ -99,7 +111,7 @@ pub fn step_import_feature(bytes: &[u8], file: &str) -> Result<StepFeature> {
|
||||
Ok(StepFeature {
|
||||
name,
|
||||
body_names: imp.bodies.iter().map(|b| b.name.clone()).collect(),
|
||||
kind: solvecraft_doc::FeatureKind::Import { file: file_name, step: text, components: imp.tree.clone() },
|
||||
kind: solidcraft_doc::FeatureKind::Import { file: file_name, step: text, components: imp.tree.clone() },
|
||||
warnings: iges_warnings.into_iter().chain(imp.warnings.iter().cloned()).collect(),
|
||||
})
|
||||
}
|
||||
@@ -113,7 +125,7 @@ pub fn is_mesh_path(path: &str) -> bool {
|
||||
pub struct MeshFeature {
|
||||
/// Timeline name: the only mesh's name, else the file name.
|
||||
pub name: String,
|
||||
pub kind: solvecraft_doc::FeatureKind,
|
||||
pub kind: solidcraft_doc::FeatureKind,
|
||||
pub body_names: Vec<String>,
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
@@ -143,8 +155,8 @@ pub fn mesh_import_feature(bytes: &[u8], file: &str) -> Result<MeshFeature> {
|
||||
// Check every mesh now, so the command fails rather than the timeline.
|
||||
let mut meshes = Vec::with_capacity(objects.len());
|
||||
for o in &objects {
|
||||
solvecraft_kernel::mesh_body(&o.positions, &o.triangles).map_err(|e| IoError::Invalid(format!("mesh `{}`: {e}", o.name)))?;
|
||||
meshes.push(solvecraft_doc::MeshData {
|
||||
solidcraft_kernel::mesh_body(&o.positions, &o.triangles).map_err(|e| IoError::Invalid(format!("mesh `{}`: {e}", o.name)))?;
|
||||
meshes.push(solidcraft_doc::MeshData {
|
||||
name: o.name.clone(),
|
||||
positions: o.positions.iter().flat_map(|p| [p.x, p.y, p.z]).collect(),
|
||||
triangles: o.triangles.iter().flatten().copied().collect(),
|
||||
@@ -159,7 +171,7 @@ pub fn mesh_import_feature(bytes: &[u8], file: &str) -> Result<MeshFeature> {
|
||||
Ok(MeshFeature {
|
||||
name,
|
||||
body_names: objects.iter().map(|o| o.name.clone()).collect(),
|
||||
kind: solvecraft_doc::FeatureKind::MeshImport { file: file_name, meshes },
|
||||
kind: solidcraft_doc::FeatureKind::MeshImport { file: file_name, meshes },
|
||||
warnings,
|
||||
})
|
||||
}
|
||||
@@ -187,14 +199,14 @@ impl Format {
|
||||
"step" | "stp" => Format::Step,
|
||||
"igs" | "iges" => Format::Iges,
|
||||
"3mf" => Format::ThreeMf,
|
||||
"solvecraft" | "json" => Format::Design,
|
||||
"solidcraft" | "solvecraft" | "json" => Format::Design,
|
||||
_ => return Err(IoError::Format(ext)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Fine export mesh for a body (chord tolerance 2e-4 of its size).
|
||||
pub fn export_mesh(b: &solvecraft_kernel::Body) -> Result<Mesh> {
|
||||
pub fn export_mesh(b: &solidcraft_kernel::Body) -> Result<Mesh> {
|
||||
Ok(b.tessellate((b.size() * 2e-4).max(1e-3))?)
|
||||
}
|
||||
|
||||
@@ -263,7 +275,7 @@ pub fn obj(meshes: &[(String, Mesh)]) -> String {
|
||||
|
||||
/// Export the given bodies of a model (all when `bodies` is empty) in a format.
|
||||
pub fn export(state: &ModelState, bodies: &[String], format: Format, name: &str) -> Result<Vec<u8>> {
|
||||
let sel: Vec<&solvecraft_doc::ModelBody> = state.bodies.iter().filter(|b| bodies.is_empty() || bodies.contains(&b.name)).collect();
|
||||
let sel: Vec<&solidcraft_doc::ModelBody> = state.bodies.iter().filter(|b| bodies.is_empty() || bodies.contains(&b.name)).collect();
|
||||
if sel.is_empty() {
|
||||
return Err(IoError::Empty);
|
||||
}
|
||||
@@ -277,16 +289,16 @@ pub fn export(state: &ModelState, bodies: &[String], format: Format, name: &str)
|
||||
}
|
||||
}
|
||||
Format::Step => {
|
||||
let bs: Vec<solvecraft_kernel::ExportBody> =
|
||||
sel.iter().map(|b| solvecraft_kernel::ExportBody { name: b.name.clone(), body: &b.body, color: b.body.color() }).collect();
|
||||
let header = solvecraft_kernel::StepHeader { file_name: format!("{name}.step"), ..Default::default() };
|
||||
solvecraft_kernel::step_export_bodies(&bs, &header)?.into_bytes()
|
||||
let bs: Vec<solidcraft_kernel::ExportBody> =
|
||||
sel.iter().map(|b| solidcraft_kernel::ExportBody { name: b.name.clone(), body: &b.body, color: b.body.color() }).collect();
|
||||
let header = solidcraft_kernel::StepHeader { file_name: format!("{name}.step"), ..Default::default() };
|
||||
solidcraft_kernel::step_export_bodies(&bs, &header)?.into_bytes()
|
||||
}
|
||||
Format::Iges => {
|
||||
let bs: Vec<solvecraft_kernel::ExportBody> =
|
||||
sel.iter().map(|b| solvecraft_kernel::ExportBody { name: b.name.clone(), body: &b.body, color: b.body.color() }).collect();
|
||||
let header = solvecraft_kernel::StepHeader { file_name: format!("{name}.igs"), ..Default::default() };
|
||||
solvecraft_kernel::iges_export_bodies(&bs, &header)?.into_bytes()
|
||||
let bs: Vec<solidcraft_kernel::ExportBody> =
|
||||
sel.iter().map(|b| solidcraft_kernel::ExportBody { name: b.name.clone(), body: &b.body, color: b.body.color() }).collect();
|
||||
let header = solidcraft_kernel::StepHeader { file_name: format!("{name}.igs"), ..Default::default() };
|
||||
solidcraft_kernel::iges_export_bodies(&bs, &header)?.into_bytes()
|
||||
}
|
||||
Format::ThreeMf => {
|
||||
let objs: Vec<MeshObject> = sel
|
||||
@@ -311,7 +323,7 @@ pub fn export(state: &ModelState, bodies: &[String], format: Format, name: &str)
|
||||
.collect::<Result<_>>()?;
|
||||
write_3mf(&objs)?
|
||||
}
|
||||
Format::Design => return Err(IoError::Format("solvecraft (save the document instead)".into())),
|
||||
Format::Design => return Err(IoError::Format("solidcraft (save the document instead)".into())),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -319,7 +331,7 @@ pub fn export(state: &ModelState, bodies: &[String], format: Format, name: &str)
|
||||
/// the component's own frame (`local` is the model before placing occurrences), and an
|
||||
/// assembly occurrence per component occurrence.
|
||||
pub fn step_assembly(doc: &Document, local: &ModelState, name: &str) -> Result<Vec<u8>> {
|
||||
use solvecraft_kernel::{ExportBody, ExportProduct};
|
||||
use solidcraft_kernel::{ExportBody, ExportProduct};
|
||||
let mut index: std::collections::HashMap<u64, usize> = std::collections::HashMap::new();
|
||||
index.insert(0, 0);
|
||||
let mut products = vec![ExportProduct { name: doc.name.clone(), bodies: Vec::new(), children: Vec::new() }];
|
||||
@@ -338,8 +350,8 @@ pub fn step_assembly(doc: &Document, local: &ModelState, name: &str) -> Result<V
|
||||
p.children.push((child, o.transform, o.name.clone()));
|
||||
}
|
||||
}
|
||||
let header = solvecraft_kernel::StepHeader { file_name: format!("{name}.step"), ..Default::default() };
|
||||
Ok(solvecraft_kernel::step_export_products(&products, 0, &header)?.into_bytes())
|
||||
let header = solidcraft_kernel::StepHeader { file_name: format!("{name}.step"), ..Default::default() };
|
||||
Ok(solidcraft_kernel::step_export_products(&products, 0, &header)?.into_bytes())
|
||||
}
|
||||
|
||||
/// Read a design file's bytes.
|
||||
@@ -425,8 +437,8 @@ pub const MAX_STL_TRIANGLES: usize = 20_000_000;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solvecraft_doc::{FeatureKind, Model, Operation, point_expr};
|
||||
use solvecraft_geom::Vec3;
|
||||
use solidcraft_doc::{FeatureKind, Model, Operation, point_expr};
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
fn model() -> (Document, Model) {
|
||||
let mut doc = Document::new("t");
|
||||
@@ -472,11 +484,11 @@ mod tests {
|
||||
|
||||
fn mesh_volume(bytes: &[u8]) -> f64 {
|
||||
let f = mesh_import_feature(bytes, "x.stl").unwrap();
|
||||
let solvecraft_doc::FeatureKind::MeshImport { meshes, .. } = f.kind else { panic!() };
|
||||
let solidcraft_doc::FeatureKind::MeshImport { meshes, .. } = f.kind else { panic!() };
|
||||
let m = &meshes[0];
|
||||
let pos: Vec<Vec3> = m.positions.chunks(3).map(|c| Vec3::new(c[0], c[1], c[2])).collect();
|
||||
let tris: Vec<[u32; 3]> = m.triangles.chunks(3).map(|c| [c[0], c[1], c[2]]).collect();
|
||||
solvecraft_kernel::measure(&solvecraft_kernel::mesh_body(&pos, &tris).unwrap()).unwrap().volume
|
||||
solidcraft_kernel::measure(&solidcraft_kernel::mesh_body(&pos, &tris).unwrap()).unwrap().volume
|
||||
}
|
||||
|
||||
/// STL quirks: a binary header starting with "solid", a zero triangle count, garbage
|
||||
@@ -542,6 +554,10 @@ mod tests {
|
||||
assert!(step_import_feature(b"ISO-10303-21;", "x.step").is_err());
|
||||
assert!(step_import_feature(&[0xff, 0xfe, 0x00], "x.step").is_err());
|
||||
assert!(Format::from_name("a.dwg").is_err());
|
||||
// Compatibility shim: the legacy design extension is still a design.
|
||||
assert_eq!(Format::from_name("old.solvecraft").unwrap(), Format::Design);
|
||||
assert_eq!(Format::from_name("new.solidcraft").unwrap(), Format::Design);
|
||||
assert!(is_design_path("/d/old.SOLVECRAFT") && is_design_path("new.solidcraft") && !is_design_path("a.step"));
|
||||
assert!(read_stl(&[0u8; 10]).is_err());
|
||||
let mut fake = vec![0u8; 84];
|
||||
fake[80..84].copy_from_slice(&u32::MAX.to_le_bytes());
|
||||
@@ -624,7 +640,7 @@ mod tests {
|
||||
assert_eq!(a.name, b.name);
|
||||
assert!(b.body.is_mesh() && b.body.is_closed_mesh(), "{} is not watertight", b.name);
|
||||
let v_stl = stl_volume(&export(&st, std::slice::from_ref(&a.name), Format::StlBinary, "t").unwrap());
|
||||
let v = solvecraft_kernel::measure(&b.body).unwrap().volume;
|
||||
let v = solidcraft_kernel::measure(&b.body).unwrap().volume;
|
||||
assert!((v - v_stl).abs() <= 1e-6 * v_stl.abs(), "{}: {v} vs {v_stl}", a.name);
|
||||
}
|
||||
// Mesh bodies export again (3MF, STL, OBJ) but not as STEP.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! are split into fans. Texture coordinates, normals and materials are ignored. The file is
|
||||
//! untrusted: counts are capped and bad lines become warnings.
|
||||
|
||||
use solvecraft_geom::Vec3;
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
use crate::threemf::MeshObject;
|
||||
use crate::{IoError, Result};
|
||||
|
||||
@@ -114,7 +114,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn dir(tag: &str) -> PathBuf {
|
||||
let d = std::env::temp_dir().join(format!("solvecraft-safe-write-{tag}-{}", std::process::id()));
|
||||
let d = std::env::temp_dir().join(format!("solidcraft-safe-write-{tag}-{}", std::process::id()));
|
||||
let _ = fs::remove_dir_all(&d);
|
||||
fs::create_dir_all(&d).unwrap();
|
||||
d
|
||||
@@ -123,7 +123,7 @@ mod tests {
|
||||
#[test]
|
||||
fn replaces_and_keeps_a_backup() {
|
||||
let d = dir("bak");
|
||||
let p = d.join("a.solvecraft");
|
||||
let p = d.join("a.solidcraft");
|
||||
write_atomic(&p, b"one", true).unwrap();
|
||||
assert!(!backup_path(&p).exists(), "nothing to back up the first time");
|
||||
write_atomic(&p, b"two", true).unwrap();
|
||||
@@ -139,7 +139,7 @@ mod tests {
|
||||
#[test]
|
||||
fn a_save_stopped_part_way_keeps_the_old_file() {
|
||||
let d = dir("stop");
|
||||
let p = d.join("a.solvecraft");
|
||||
let p = d.join("a.solidcraft");
|
||||
write_atomic(&p, b"old", true).unwrap();
|
||||
for stop in [Step::TempWritten, Step::BackupWritten, Step::Replaced] {
|
||||
write_steps(&p, b"new content", true, Some(stop)).unwrap();
|
||||
@@ -160,7 +160,7 @@ mod tests {
|
||||
#[test]
|
||||
fn a_failed_write_leaves_the_target() {
|
||||
let d = dir("fail");
|
||||
let p = d.join("missing-dir").join("a.solvecraft");
|
||||
let p = d.join("missing-dir").join("a.solidcraft");
|
||||
assert!(write_atomic(&p, b"x", true).is_err());
|
||||
assert!(!p.exists());
|
||||
let _ = fs::remove_dir_all(&d);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! 2D drawing exchange for sketches: DXF (ASCII, read and write) and SVG (read). Readers produce
|
||||
//! plain 2D geometry in millimetres; the engine turns it into sketch curves.
|
||||
|
||||
use solvecraft_geom::Vec2;
|
||||
use solidcraft_geom::Vec2;
|
||||
|
||||
/// One imported 2D entity (millimetres, y up).
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use quick_xml::Reader;
|
||||
use quick_xml::events::{BytesStart, Event};
|
||||
use solvecraft_geom::Vec2;
|
||||
use solidcraft_geom::Vec2;
|
||||
|
||||
use crate::sketch2d::{Geom2, MAX_DRAWING_BYTES, MAX_ENTITIES};
|
||||
use crate::{IoError, Result};
|
||||
|
||||
@@ -12,7 +12,7 @@ use std::io::{Cursor, Read, Write};
|
||||
|
||||
use quick_xml::Reader;
|
||||
use quick_xml::events::{BytesStart, Event};
|
||||
use solvecraft_geom::Vec3;
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
use crate::{IoError, Result};
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ pub fn read_to_string(path: &str, max: usize) -> Result<String> {
|
||||
mod tests {
|
||||
#[test]
|
||||
fn files_round_trip() {
|
||||
let dir = std::env::temp_dir().join(format!("solvecraft-vfs-{}", std::process::id()));
|
||||
let dir = std::env::temp_dir().join(format!("solidcraft-vfs-{}", std::process::id()));
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let p = dir.join("a.txt").to_string_lossy().to_string();
|
||||
assert!(!super::exists(&p));
|
||||
@@ -140,7 +140,7 @@ mod tests {
|
||||
assert!(e.to_string().contains("not a regular file"), "{e}");
|
||||
assert!(super::read_to_string("/dev/zero", 1024).is_err());
|
||||
|
||||
let dir = std::env::temp_dir().join(format!("solvecraft-vfs-fifo-{}", std::process::id()));
|
||||
let dir = std::env::temp_dir().join(format!("solidcraft-vfs-fifo-{}", std::process::id()));
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let fifo = dir.join("p");
|
||||
let made = std::process::Command::new("mkfifo").arg(&fifo).status().map(|s| s.success()).unwrap_or(false);
|
||||
|
||||
Reference in new issue
Block a user