mirror of
https://github.com/storytold/craft-anything.git
synced 2026-11-05 20:47:45 +01:00
Leave a pin's old program copies out of the copy (#56)
A pin leaves out a program's old running copies (name.running-N.exe) when the program they copy is beside them.
This commit is contained in:
@@ -230,7 +230,9 @@ impl Plan {
|
||||
/// Every (file, where it goes under `to`) the copy makes, in order.
|
||||
fn files(&self, ws: &Workspace, to: &Path) -> Result<Vec<Planned>, ToolError> {
|
||||
let (mut own, mut dependencies) = (Vec::new(), Vec::new());
|
||||
let skip = |p: &Path| workspace::rebuilt(p) || ws.is_own_record(p) || p.file_name().and_then(|n| n.to_str()).is_some_and(|n| NEVER_COPIED.contains(&n));
|
||||
let skip = |p: &Path| {
|
||||
workspace::rebuilt(p) || ws.is_own_record(p) || p.file_name().and_then(|n| n.to_str()).is_some_and(|n| NEVER_COPIED.contains(&n)) || stray_copy(p)
|
||||
};
|
||||
walk(&self.app, to, &skip, 0, &mut own)?;
|
||||
for k in &self.keep {
|
||||
let (from, whole) = match k {
|
||||
@@ -239,12 +241,19 @@ impl Plan {
|
||||
};
|
||||
let rel = from.strip_prefix(&self.app).map_err(|_| ToolError::internal("a kept folder isn't inside the app"))?;
|
||||
if whole {
|
||||
walk(from, &to.join(rel), &|p| p.file_name().and_then(|n| n.to_str()).is_some_and(|n| NEVER_COPIED.contains(&n)), 0, &mut dependencies)?;
|
||||
walk(
|
||||
from,
|
||||
&to.join(rel),
|
||||
&|p| p.file_name().and_then(|n| n.to_str()).is_some_and(|n| NEVER_COPIED.contains(&n)) || stray_copy(p),
|
||||
0,
|
||||
&mut dependencies,
|
||||
)?;
|
||||
} else {
|
||||
for e in std::fs::read_dir(from).map_err(|e| ToolError::io(from.display(), e))?.flatten() {
|
||||
if let Ok(m) = e.metadata()
|
||||
&& m.is_file()
|
||||
&& !compiler_leftover(&e.path())
|
||||
&& !stray_copy(&e.path())
|
||||
{
|
||||
own.push((e.path(), to.join(rel).join(e.file_name()), m.len()));
|
||||
}
|
||||
@@ -270,6 +279,25 @@ fn compiler_leftover(p: &Path) -> bool {
|
||||
kind || p.file_name().and_then(|n| n.to_str()).is_some_and(|n| n.starts_with(".cargo-"))
|
||||
}
|
||||
|
||||
/// An old copy of a program, left behind when a build replaced one that was running
|
||||
/// (`snake.running-144900.exe`): a pin copies the program, not each copy of it. It only counts as
|
||||
/// one when the program it copies is still beside it, so a helper that happens to be named like
|
||||
/// one stays.
|
||||
fn stray_copy(p: &Path) -> bool {
|
||||
let Some(name) = p.file_name().and_then(|n| n.to_str()) else { return false };
|
||||
let Some((base, rest)) = name.rsplit_once(".running-") else { return false };
|
||||
let (digits, ext) = rest.split_once('.').map_or((rest, None), |(d, e)| (d, Some(e)));
|
||||
if base.is_empty() || digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
|
||||
return false;
|
||||
}
|
||||
let original = match ext {
|
||||
Some(e) => format!("{base}.{e}"),
|
||||
None => base.to_string(),
|
||||
};
|
||||
let original = p.with_file_name(original);
|
||||
original.is_file() && crate::outputs::is_program(&original)
|
||||
}
|
||||
|
||||
/// How deep a copy goes.
|
||||
const WALK_DEPTH: usize = 64;
|
||||
|
||||
@@ -552,6 +580,34 @@ mod tests {
|
||||
assert!(!ws.root.join(PINNED).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_pin_leaves_out_old_copies_of_its_program_but_keeps_helpers() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let ws = built(d.path());
|
||||
let release = ws.app_dir().join("target/release");
|
||||
let before = estimate(&ws, None).unwrap();
|
||||
let program = |name: &str, body: &[u8]| {
|
||||
let p = release.join(exe(name));
|
||||
std::fs::write(&p, body).unwrap();
|
||||
mark_program(&p);
|
||||
};
|
||||
// What a build leaves when it replaces a program that was running, and two files that only
|
||||
// look like one: a helper with nothing beside it, and a copy whose program is gone.
|
||||
program("snake.running-144900", &[0u8; 4096]);
|
||||
program("snake-tool.running-1", b"helper");
|
||||
program("ghost.running-7", b"gone");
|
||||
let after = estimate(&ws, None).unwrap();
|
||||
assert_eq!(after.files, before.files + 2, "the old copy isn't counted, the two others are");
|
||||
assert_eq!(after.bytes, before.bytes + 6 + 4, "and its size isn't either");
|
||||
let pin = create(&ws, PinMode::Frozen, None, None, &mut |_, _| true).unwrap();
|
||||
assert_eq!(pin.bytes, after.bytes);
|
||||
let copy = pin.app_dir(&ws).join("target/release");
|
||||
assert!(copy.join(exe("snake")).is_file());
|
||||
assert!(!copy.join(exe("snake.running-144900")).exists(), "the old copy of the program is left out");
|
||||
assert!(copy.join(exe("snake-tool.running-1")).is_file(), "a helper with nothing it copies beside it stays");
|
||||
assert!(copy.join(exe("ghost.running-7")).is_file(), "a copy whose program is gone is all there is to run");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_light_pin_shares_media_and_survives_a_rebuild_replacing_or_deleting_them() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
|
||||
+1
-1
@@ -829,7 +829,7 @@ to the project next. Pins are the engine's (tools), kept in the project's `pinne
|
||||
- [x] Pins leave out what a compiler keeps beside a program that nothing needs to run it (`.pdb`
|
||||
debug symbols, `.lib`, `.d`, lock files): measured on real Rust projects, that took a
|
||||
291 MB pin to 49 MB, far more than sharing could
|
||||
- [ ] Leave out a project's old program copies (`*.running-*.exe`, 22 MB each in one project), which
|
||||
- [x] Leave out a project's old program copies (`*.running-*.exe`, 22 MB each in one project), which
|
||||
a pin can't tell from the program's helpers by their name alone
|
||||
- [ ] Say when a light pin ended up copying what it meant to share (a drive without hard links)
|
||||
- [ ] Pins of one project sharing with each other, so a third frozen copy of the same assets
|
||||
|
||||
Reference in New Issue
Block a user