storkit: merge 414_story_loc_command_filters_out_known_huge_files
This commit is contained in:
@@ -20,6 +20,23 @@ const SKIP_DIRS: &[&str] = &[
|
|||||||
/// Path components that indicate a worktree path that should be skipped.
|
/// Path components that indicate a worktree path that should be skipped.
|
||||||
const SKIP_PATH_COMPONENTS: &[&str] = &[".storkit/worktrees"];
|
const SKIP_PATH_COMPONENTS: &[&str] = &[".storkit/worktrees"];
|
||||||
|
|
||||||
|
/// Known-huge or machine-generated files that are excluded from the loc count
|
||||||
|
/// even when they have a recognised source extension (e.g. `.json`, `.yaml`).
|
||||||
|
/// Add entries here to extend the exclusion list.
|
||||||
|
const EXCLUDED_FILENAMES: &[&str] = &[
|
||||||
|
"package-lock.json",
|
||||||
|
"yarn.lock",
|
||||||
|
"pnpm-lock.yaml",
|
||||||
|
"bun.lockb",
|
||||||
|
"Cargo.lock",
|
||||||
|
"composer.lock",
|
||||||
|
"Gemfile.lock",
|
||||||
|
"poetry.lock",
|
||||||
|
"go.sum",
|
||||||
|
"go.work.sum",
|
||||||
|
"flake.lock",
|
||||||
|
];
|
||||||
|
|
||||||
pub(super) fn handle_loc(ctx: &CommandContext) -> Option<String> {
|
pub(super) fn handle_loc(ctx: &CommandContext) -> Option<String> {
|
||||||
let top_n = if ctx.args.is_empty() {
|
let top_n = if ctx.args.is_empty() {
|
||||||
DEFAULT_TOP_N
|
DEFAULT_TOP_N
|
||||||
@@ -64,6 +81,11 @@ pub(super) fn handle_loc(ctx: &CommandContext) -> Option<String> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
// Skip known-huge or machine-generated files (lockfiles, etc.).
|
||||||
|
let filename = path.file_name().and_then(|f| f.to_str()).unwrap_or("");
|
||||||
|
if EXCLUDED_FILENAMES.contains(&filename) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
// Skip binary/generated files without a recognisable text extension.
|
// Skip binary/generated files without a recognisable text extension.
|
||||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
||||||
if !is_source_extension(ext) {
|
if !is_source_extension(ext) {
|
||||||
@@ -264,6 +286,88 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn loc_excludes_lockfiles_from_results() {
|
||||||
|
use std::io::Write as _;
|
||||||
|
let dir = tempfile::tempdir().expect("tempdir");
|
||||||
|
// Write a package-lock.json with many lines — it must NOT appear in output.
|
||||||
|
let lockfile = dir.path().join("package-lock.json");
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(&lockfile).unwrap();
|
||||||
|
for _ in 0..500 {
|
||||||
|
writeln!(f, " \"line\": true,").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write a real source file so the output is non-empty.
|
||||||
|
let source = dir.path().join("main.rs");
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(&source).unwrap();
|
||||||
|
for i in 0..20 {
|
||||||
|
writeln!(f, "fn line_{i}() {{}}").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let agents = Arc::new(AgentPool::new_test(3000));
|
||||||
|
let ambient_rooms = Arc::new(Mutex::new(HashSet::new()));
|
||||||
|
let ctx = make_ctx(&agents, &ambient_rooms, dir.path(), "50");
|
||||||
|
let output = handle_loc(&ctx).unwrap();
|
||||||
|
assert!(
|
||||||
|
!output.contains("package-lock.json"),
|
||||||
|
"package-lock.json must be excluded from loc output: {output}"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
output.contains("main.rs"),
|
||||||
|
"main.rs should appear in loc output: {output}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn loc_excludes_cargo_lock_from_results() {
|
||||||
|
use std::io::Write as _;
|
||||||
|
let dir = tempfile::tempdir().expect("tempdir");
|
||||||
|
// Cargo.lock has no recognised source extension so it would be skipped
|
||||||
|
// anyway — but we still verify EXCLUDED_FILENAMES contains it.
|
||||||
|
assert!(
|
||||||
|
EXCLUDED_FILENAMES.contains(&"Cargo.lock"),
|
||||||
|
"EXCLUDED_FILENAMES must contain Cargo.lock"
|
||||||
|
);
|
||||||
|
// Write a Cargo.lock with many lines and verify it is excluded.
|
||||||
|
let lockfile = dir.path().join("Cargo.lock");
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(&lockfile).unwrap();
|
||||||
|
for _ in 0..500 {
|
||||||
|
writeln!(f, "name = \"foo\"").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let source = dir.path().join("lib.rs");
|
||||||
|
{
|
||||||
|
let mut f = std::fs::File::create(&source).unwrap();
|
||||||
|
for i in 0..10 {
|
||||||
|
std::io::Write::write_all(&mut f, format!("fn f{i}() {{}}\n").as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let agents = Arc::new(AgentPool::new_test(3000));
|
||||||
|
let ambient_rooms = Arc::new(Mutex::new(HashSet::new()));
|
||||||
|
let ctx = make_ctx(&agents, &ambient_rooms, dir.path(), "50");
|
||||||
|
let output = handle_loc(&ctx).unwrap();
|
||||||
|
assert!(
|
||||||
|
!output.contains("Cargo.lock"),
|
||||||
|
"Cargo.lock must be excluded from loc output: {output}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn excluded_filenames_constant_is_defined() {
|
||||||
|
// The constant must contain the examples from the story.
|
||||||
|
assert!(
|
||||||
|
EXCLUDED_FILENAMES.contains(&"package-lock.json"),
|
||||||
|
"EXCLUDED_FILENAMES must contain package-lock.json"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
EXCLUDED_FILENAMES.contains(&"Cargo.lock"),
|
||||||
|
"EXCLUDED_FILENAMES must contain Cargo.lock"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn loc_works_via_full_dispatch() {
|
fn loc_works_via_full_dispatch() {
|
||||||
// Verifies the command is reachable through the same dispatch path used
|
// Verifies the command is reachable through the same dispatch path used
|
||||||
|
|||||||
Reference in New Issue
Block a user