Fix CI: pin Rust 1.99, newer clippy lints, Windows/macOS test portability, NetBSD libexecinfo for cross
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# The cross image for NetBSD lacks libexecinfo, which Rust's standard library
|
||||||
|
# links on NetBSD. Take it (and libelf, which it needs) from the official
|
||||||
|
# NetBSD 9.2 base set, matching the image's libc, checked against the
|
||||||
|
# release's published SHA512.
|
||||||
|
[target.x86_64-unknown-netbsd]
|
||||||
|
pre-build = [
|
||||||
|
"curl -fsSL -o /tmp/base.tar.xz https://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.2/amd64/binary/sets/base.tar.xz",
|
||||||
|
"echo '961511ec63f4803529aeb057632e2b8cf87e73bfdfed445d7521b607f573245359163b9f6b6a158fa80de7a994cf3727af384ec42ac8d9ccdd59a87197a41b55 /tmp/base.tar.xz' | sha512sum -c",
|
||||||
|
"tar -xJf /tmp/base.tar.xz -C /usr/local/x86_64-unknown-netbsd --strip-components=2 ./usr/lib/libexecinfo.so ./usr/lib/libexecinfo.so.0 ./usr/lib/libexecinfo.so.0.0 ./usr/lib/libelf.so ./usr/lib/libelf.so.2 ./usr/lib/libelf.so.2.0",
|
||||||
|
"rm /tmp/base.tar.xz",
|
||||||
|
]
|
||||||
+4
-3
@@ -1,7 +1,8 @@
|
|||||||
# Development
|
# Development
|
||||||
|
|
||||||
Requires a stable Rust toolchain (`rustup`); the dependencies are pinned in
|
Requires `rustup`: `rust-toolchain.toml` pins the compiler (so local builds
|
||||||
`Cargo.lock`. No C toolchain beyond what Rust itself needs.
|
match CI), and `Cargo.lock` pins the dependencies. No C toolchain beyond what
|
||||||
|
Rust itself needs.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make build # target/release/mapsize
|
make build # target/release/mapsize
|
||||||
@@ -27,7 +28,7 @@ binaries under qemu.
|
|||||||
| Linux | amd64, arm64, 386, arm (v7), riscv64 | `*-unknown-linux-musl` (static) | cargo-zigbuild + zig |
|
| Linux | amd64, arm64, 386, arm (v7), riscv64 | `*-unknown-linux-musl` (static) | cargo-zigbuild + zig |
|
||||||
| Windows | amd64, arm64 | `x86_64-pc-windows-gnu`, `aarch64-pc-windows-gnullvm` | cargo-zigbuild + zig |
|
| Windows | amd64, arm64 | `x86_64-pc-windows-gnu`, `aarch64-pc-windows-gnullvm` | cargo-zigbuild + zig |
|
||||||
| macOS | amd64, arm64 | `*-apple-darwin` | cargo on a Mac (or zigbuild) |
|
| macOS | amd64, arm64 | `*-apple-darwin` | cargo on a Mac (or zigbuild) |
|
||||||
| FreeBSD, NetBSD | amd64 | `x86_64-unknown-{freebsd,netbsd}` | cross + Docker |
|
| FreeBSD, NetBSD | amd64 | `x86_64-unknown-{freebsd,netbsd}` | cross + Docker (`Cross.toml` adds NetBSD's libexecinfo) |
|
||||||
|
|
||||||
Platform differences live in `src/platform.rs` (and `cfg` blocks where the
|
Platform differences live in `src/platform.rs` (and `cfg` blocks where the
|
||||||
terminal code needs them); nothing else switches on the OS.
|
terminal code needs them); nothing else switches on the OS.
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.99.0"
|
||||||
|
components = ["rustfmt", "clippy"]
|
||||||
|
profile = "minimal"
|
||||||
+1
-1
@@ -110,7 +110,7 @@ fn interrupt_cancel() -> Cancel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let c = CANCEL.get_or_init(Cancel::new).clone();
|
let c = CANCEL.get_or_init(Cancel::new).clone();
|
||||||
unsafe { libc::signal(libc::SIGINT, on_sigint as libc::sighandler_t) };
|
unsafe { libc::signal(libc::SIGINT, on_sigint as *const () as libc::sighandler_t) };
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ mod tests {
|
|||||||
assert_eq!(top.len(), 3);
|
assert_eq!(top.len(), 3);
|
||||||
assert_eq!(tr.node(top[0]).size, 99);
|
assert_eq!(tr.node(top[0]).size, 99);
|
||||||
assert_eq!(tr.node(top[2]).size, 97);
|
assert_eq!(tr.node(top[2]).size, 97);
|
||||||
assert_eq!(tr.path_string(top[0]), "/r/d/f");
|
assert_eq!(tr.path_string(top[0]).replace('\\', "/"), "/r/d/f");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+6
-3
@@ -916,15 +916,18 @@ pub(crate) mod tests {
|
|||||||
fn hostile_names_preserved() {
|
fn hostile_names_preserved() {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
let root = TempDir::new("names");
|
let root = TempDir::new("names");
|
||||||
let names: [&[u8]; 6] = [
|
#[allow(unused_mut)]
|
||||||
|
let mut names: Vec<&[u8]> = vec![
|
||||||
"日本語.txt".as_bytes(),
|
"日本語.txt".as_bytes(),
|
||||||
"emoji-🎉.png".as_bytes(),
|
"emoji-🎉.png".as_bytes(),
|
||||||
b"esc\x1b[31mred",
|
b"esc\x1b[31mred",
|
||||||
b"nl\nname",
|
b"nl\nname",
|
||||||
b"sp ace",
|
b"sp ace",
|
||||||
b"bad\xffutf8",
|
|
||||||
];
|
];
|
||||||
for n in names {
|
// APFS rejects names that are not valid UTF-8.
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
names.push(b"bad\xffutf8");
|
||||||
|
for &n in &names {
|
||||||
std::fs::write(root.0.join(std::ffi::OsStr::from_bytes(n)), b"x").unwrap();
|
std::fs::write(root.0.join(std::ffi::OsStr::from_bytes(n)), b"x").unwrap();
|
||||||
}
|
}
|
||||||
let t = run_scan(
|
let t = run_scan(
|
||||||
|
|||||||
+14
-4
@@ -686,8 +686,11 @@ impl JsonTime {
|
|||||||
if self.secs >= 0 {
|
if self.secs >= 0 {
|
||||||
UNIX_EPOCH + Duration::new(self.secs as u64, self.nanos)
|
UNIX_EPOCH + Duration::new(self.secs as u64, self.nanos)
|
||||||
} else {
|
} else {
|
||||||
UNIX_EPOCH - Duration::from_secs(self.secs.unsigned_abs())
|
// Windows cannot represent times before 1601 (such as the zero
|
||||||
+ Duration::from_nanos(self.nanos as u64)
|
// time, year 1); those clamp to the Unix epoch.
|
||||||
|
UNIX_EPOCH
|
||||||
|
.checked_sub(Duration::from_secs(self.secs.unsigned_abs()))
|
||||||
|
.map_or(UNIX_EPOCH, |t| t + Duration::from_nanos(self.nanos as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,7 +900,10 @@ mod tests {
|
|||||||
assert_eq!(d.removed.len(), 1);
|
assert_eq!(d.removed.len(), 1);
|
||||||
assert_eq!(&d.old.node(d.removed[0]).name[..], b"b");
|
assert_eq!(&d.old.node(d.removed[0]).name[..], b"b");
|
||||||
let ch = d.changes(&nw, 10, al);
|
let ch = d.changes(&nw, 10, al);
|
||||||
let paths: HashMap<&str, Status> = ch.iter().map(|c| (c.path.as_str(), c.status)).collect();
|
let paths: HashMap<String, Status> = ch
|
||||||
|
.iter()
|
||||||
|
.map(|c| (c.path.replace('\\', "/"), c.status))
|
||||||
|
.collect();
|
||||||
assert_eq!(paths.get("/srv/a/x.iso"), Some(&Status::Grew), "{ch:?}");
|
assert_eq!(paths.get("/srv/a/x.iso"), Some(&Status::Grew), "{ch:?}");
|
||||||
assert_eq!(paths.get("/srv/b"), Some(&Status::Removed), "{ch:?}");
|
assert_eq!(paths.get("/srv/b"), Some(&Status::Removed), "{ch:?}");
|
||||||
assert_eq!(paths.get("/srv/c"), Some(&Status::Added), "{ch:?}");
|
assert_eq!(paths.get("/srv/c"), Some(&Status::Added), "{ch:?}");
|
||||||
@@ -970,6 +976,7 @@ mod tests {
|
|||||||
Some(JsonTime::default())
|
Some(JsonTime::default())
|
||||||
);
|
);
|
||||||
assert_eq!(JsonTime::default().format(), "0001-01-01T00:00:00Z");
|
assert_eq!(JsonTime::default().format(), "0001-01-01T00:00:00Z");
|
||||||
|
#[cfg(not(windows))]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
JsonTime::from_system(JsonTime::default().to_system()),
|
JsonTime::from_system(JsonTime::default().to_system()),
|
||||||
JsonTime::default()
|
JsonTime::default()
|
||||||
@@ -1010,7 +1017,10 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(t.node(iso).size, 10000);
|
assert_eq!(t.node(iso).size, 10000);
|
||||||
assert_eq!(t.ext_name(t.node(iso)), "iso");
|
assert_eq!(t.ext_name(t.node(iso)), "iso");
|
||||||
assert!(t.path_string(iso).ends_with("/tree/a/x.iso"));
|
assert!(t
|
||||||
|
.path_string(iso)
|
||||||
|
.replace('\\', "/")
|
||||||
|
.ends_with("/tree/a/x.iso"));
|
||||||
// And it survives a save/load round trip unchanged.
|
// And it survives a save/load round trip unchanged.
|
||||||
let again = load(&saved(&t)[..]).unwrap();
|
let again = load(&saved(&t)[..]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
+1
-1
@@ -92,7 +92,7 @@ impl Model {
|
|||||||
.map(|(i, &v)| (Category::from_u8(i as u8), v))
|
.map(|(i, &v)| (Category::from_u8(i as u8), v))
|
||||||
.collect();
|
.collect();
|
||||||
let total: i64 = cats.iter().map(|c| c.1).sum();
|
let total: i64 = cats.iter().map(|c| c.1).sum();
|
||||||
cats.sort_by(|a, b| b.1.cmp(&a.1));
|
cats.sort_by_key(|c| std::cmp::Reverse(c.1));
|
||||||
for &(c, v) in &cats {
|
for &(c, v) in &cats {
|
||||||
if y >= end - 8 {
|
if y >= end - 8 {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -590,6 +590,8 @@ fn nesting_reaches_deep_media() {
|
|||||||
|
|
||||||
// Headless, o shows the selected folder in the map instead of launching a
|
// Headless, o shows the selected folder in the map instead of launching a
|
||||||
// file manager.
|
// file manager.
|
||||||
|
// macOS and Windows always have a file manager, so are never headless.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
#[test]
|
#[test]
|
||||||
fn reveal_headless_zooms_map() {
|
fn reveal_headless_zooms_map() {
|
||||||
std::env::set_var("DISPLAY", "");
|
std::env::set_var("DISPLAY", "");
|
||||||
|
|||||||
+3
-5
@@ -462,11 +462,9 @@ impl TopView {
|
|||||||
val.insert(id, n.size - n.alloc);
|
val.insert(id, n.size - n.alloc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TopMode::Hardlinks => {
|
TopMode::Hardlinks if n.has(FLAG_HARDLINKED) => {
|
||||||
if n.has(FLAG_HARDLINKED) {
|
tk.offer(id, n.size);
|
||||||
tk.offer(id, n.size);
|
val.insert(id, n.size);
|
||||||
val.insert(id, n.size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user