diff --git a/.github/workflows/dylint.yaml b/.github/workflows/dylint.yaml index 81cb92f4..a01e8acb 100644 --- a/.github/workflows/dylint.yaml +++ b/.github/workflows/dylint.yaml @@ -14,6 +14,7 @@ jobs: - uses: actions/checkout@v6 - name: Cache + id: cache uses: actions/cache@v5 timeout-minutes: 2 continue-on-error: true @@ -39,6 +40,20 @@ jobs: shell: bash run: cargo install --locked cargo-dylint dylint-link + # When the primary cache key did not match exactly, the cache was either + # missed entirely or restored from one of the looser `restore-keys` + # entries. The third entry ignores `dylint.toml`, so the restored + # `target/dylint/libraries/libperfectionist.so` may have been built from + # a different `dylint.toml`. `cargo dylint` does not always detect a + # changed `git` `rev`/`tag` and reuses the cached `.so` as-is. Remove + # the dylint build directory in this case so the library rebuilds from + # the in-tree `dylint.toml`. On an exact cache hit the `.so` matches + # the current `dylint.toml` and the rebuild is skipped. + - name: Invalidate stale dylint build artifacts + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + run: rm -rf target/dylint + - name: Run dylint shell: bash env: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94c4ab83..a3c570c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ Write documentation, comments, and other prose for ease of understanding first. ## Code Style -Automated tools enforce formatting (`cargo fmt`) and linting (`cargo clippy`). The following conventions are **not** enforced by those tools and must be followed manually. +Automated tools enforce formatting (`cargo fmt`), linting (`cargo clippy`), and a curated set of project-specific rules via dylint (`cargo dylint --all`, run with `DYLINT=true ./test.sh`). The following conventions must be followed manually unless a subsection notes that a specific dylint rule enforces them. ### Import Organization @@ -54,7 +54,8 @@ use crate::get_size::{GetBlockCount, GetBlockSize}; ### Module Organization -- Use the flat file pattern (`module.rs`) rather than `module/mod.rs` for submodules. +The flat file pattern (`module.rs` rather than `module/mod.rs`) is enforced by the `perfectionist::flat_module_pattern` dylint check. In addition to that requirement, follow these conventions: + - List `pub mod` declarations first, then `pub use` re-exports, then private imports and items. - Use `pub use` to re-export key types at the module level for convenience. diff --git a/dylint.toml b/dylint.toml index 770c0632..d91405ef 100644 --- a/dylint.toml +++ b/dylint.toml @@ -1,4 +1,4 @@ [workspace.metadata.dylint] libraries = [ - { git = "https://github.com/KSXGitHub/perfectionist", tag = "0.0.0-rc.0" }, + { git = "https://github.com/KSXGitHub/perfectionist", tag = "0.0.0-rc.7" }, ] diff --git a/src/app/hdd.rs b/src/app/hdd.rs index 281a84bf..c7df4331 100644 --- a/src/app/hdd.rs +++ b/src/app/hdd.rs @@ -237,8 +237,8 @@ fn is_virtual_block_device(block_dev: &str) -> bool { | "xen-blkfront" | "vbd" | "vmw_pvscsi" - | "hv_storvsc" - ) + | "hv_storvsc", + ), ) } diff --git a/src/app/hdd/test_linux_smoke.rs b/src/app/hdd/test_linux_smoke.rs index f5dad8b3..7712c5ee 100644 --- a/src/app/hdd/test_linux_smoke.rs +++ b/src/app/hdd/test_linux_smoke.rs @@ -14,7 +14,7 @@ fn real_sysfs_vda_does_not_panic() { fn nonexistent_device_is_not_virtual() { assert!( !is_virtual_block_device::("nonexistent_device_xyz"), - "non-existent device should not be detected as virtual" + "non-existent device should not be detected as virtual", ); } diff --git a/src/hardlink/hardlink_list/summary.rs b/src/hardlink/hardlink_list/summary.rs index cacc7f55..b6ca4aaa 100644 --- a/src/hardlink/hardlink_list/summary.rs +++ b/src/hardlink/hardlink_list/summary.rs @@ -90,7 +90,7 @@ where } Ordering::Less => { panic!( - "Impossible! Total of nlink ({links}) is less than detected paths ({paths}). Something must have gone wrong!" + "Impossible! Total of nlink ({links}) is less than detected paths ({paths}). Something must have gone wrong!", ); } } diff --git a/src/man_page.rs b/src/man_page.rs index 11c9eebe..cb6ebdf1 100644 --- a/src/man_page.rs +++ b/src/man_page.rs @@ -275,7 +275,7 @@ fn render_possible_values(out: &mut String, arg: &Arg) { } if matches!( arg.get_action(), - ArgAction::SetTrue | ArgAction::SetFalse | ArgAction::Count + ArgAction::SetTrue | ArgAction::SetFalse | ArgAction::Count, ) { return; } diff --git a/test.sh b/test.sh index 6d5ca49b..c0e8ade8 100755 --- a/test.sh +++ b/test.sh @@ -75,7 +75,8 @@ unit() ( run_if "${FMT:-true}" cargo fmt -- --check # Dylint inspects the source under all feature gates in a single pass, so it is # run once with `--all-features` rather than across every feature combination. -run_if "${DYLINT:-false}" cargo dylint --all -- --all-features --all-targets +run_if "${DYLINT:-false}" env RUSTFLAGS="-D warnings ${RUSTFLAGS:-}" \ + cargo dylint --all -- --all-features --all-targets unit "$@" unit --no-default-features "$@" unit --all-features "$@" diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index d854295f..5c863ff8 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -72,7 +72,7 @@ fn min_ratio_1() { "error: invalid value '1' for '--min-ratio ': greater than or equal to 1" "" "For more information, try '--help'." - } + }, ); assert_eq!(&stdout, &[] as &[u8]); } @@ -101,7 +101,7 @@ fn max_depth_0() { r#"error: invalid value '0' for '--max-depth ': Value is neither "inf" nor a positive integer: number would be zero for non-zero type"# "" "For more information, try '--help'." - } + }, ); assert_eq!(&stdout, &[] as &[u8]); } diff --git a/tests/one_file_system.rs b/tests/one_file_system.rs index e96a06d2..fe764a6f 100644 --- a/tests/one_file_system.rs +++ b/tests/one_file_system.rs @@ -230,7 +230,7 @@ fn cross_device_excludes_mount() { .find_map(|mut entry| entry.next()?.ok()); assert!( poll_result.is_some(), - "FUSE mount at {mount_point:?} not ready after {retries} retries" + "FUSE mount at {mount_point:?} not ready after {retries} retries", ); let build_expected_tree = |device_boundary: DeviceBoundary| -> String {