1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// src/filtering/lockfile.rs
use std::path::Path;
// List of common lockfile names (case-insensitive check)
const LOCKFILE_NAMES: &[&str] = &[
// --- Web Development (JavaScript/TypeScript) ---
"package-lock.json", // npm v5+
"yarn.lock", // Yarn v1 (and often checked for v2+ PnP)
"pnpm-lock.yaml", // pnpm
"npm-shrinkwrap.json", // Older npm, or for library publishing
"bun.lockb", // Bun (binary format)
"deno.lock", // Deno
// --- PHP ---
"composer.lock", // Composer
// --- Ruby ---
"Gemfile.lock", // Bundler (Note: Capital 'G')
// --- Python ---
"poetry.lock", // Poetry
"Pipfile.lock", // Pipenv (Note: Capital 'P')
"pdm.lock", // PDM
"uv.lock", // uv
"conda-lock.yml", // conda-lock tool (used with Conda)
".req.lock", // A convention sometimes used with pip-tools
// --- Go ---
"go.sum", // Go Modules (checksums, acts like a lock)
"Gopkg.lock", // dep (older Go package manager)
"glide.lock", // Glide (older Go package manager)
// --- Java ---
"gradle.lockfile", // Gradle (when locking is enabled, root file)
// Individual Gradle configuration lockfiles might exist too, e.g., `gradle/dependency-locks/compileClasspath.lockfile`
// Maven doesn't have a standard single lockfile, relies on plugins or conventions
// --- .NET (C#/F#/VB.NET) ---
"packages.lock.json", // NuGet (when locking is enabled)
"paket.lock", // Paket package manager
"project.assets.json", // NuGet internal build artifact, sometimes checked in, contains resolved graph
// --- Swift / Objective-C (Apple Ecosystem) ---
"Package.resolved", // Swift Package Manager (SPM)
"Podfile.lock", // CocoaPods
"Cartfile.resolved", // Carthage
// --- Elixir ---
"mix.lock", // Mix
// --- Erlang ---
"rebar.lock", // Rebar3
// --- Dart / Flutter ---
"pubspec.lock", // Pub
// --- Haskell ---
"stack.yaml.lock", // Stack
"cabal.project.freeze", // Cabal (newer versions)
// --- Rust ---
"Cargo.lock", // Cargo (Note: Capital 'C')
// --- Nix / NixOS ---
"flake.lock", // Nix Flakes
// --- Perl ---
"cpanfile.snapshot", // Carton / cpanm --installdeps .
"META.json", // Can contain resolved dependencies, though more a manifest
"MYMETA.json", // Similar to META.json
// --- R ---
"renv.lock", // renv package manager
"packrat/packrat.lock", // packrat package manager
// --- Julia ---
"Manifest.toml", // Julia Pkg manager (Project.toml is the manifest)
// --- Infrastructure as Code ---
".terraform.lock.hcl", // Terraform provider lock file
// --- Crystal ---
"shard.lock", // Shards package manager
// --- C/C++ ---
"conan.lock", // Conan package manager lockfile
// vcpkg uses baselines in vcpkg.json, not a separate lockfile typically
// --- Lua ---
"luarocks.lock", // LuaRocks (if locking feature is used, might vary)
// --- Elm ---
"elm-stuff/exact-dependencies.json", // Elm (internal, but effectively the lock)
// --- BuckleScript / ReScript ---
// Often uses Node.js ecosystem tools (npm/yarn/pnpm), covered above
// --- Bazel ---
// Bazel often relies on WORKSPACE pinning or bzlmod lockfiles (`MODULE.bazel.lock` potentially)
"MODULE.bazel.lock", // Bazel bzlmod lockfile (experimental/newer)
// Add even more niche or specific tool lockfiles if encountered
];
/// Checks if a path corresponds to a common lockfile name.
pub(crate) fn is_lockfile(path: &Path) -> bool {
path.file_name()
.and_then(|name| name.to_str())
.map(|name_str| {
let lower_name = name_str.to_lowercase();
LOCKFILE_NAMES
.iter()
.any(|&lockfile| lower_name == lockfile)
})
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_is_lockfile_matches() {
assert!(is_lockfile(&PathBuf::from("path/to/Cargo.lock")));
assert!(is_lockfile(&PathBuf::from("package-lock.json")));
assert!(is_lockfile(&PathBuf::from("Yarn.lock"))); // Case insensitive
assert!(is_lockfile(&PathBuf::from("PNPM-LOCK.YAML"))); // Case insensitive
assert!(is_lockfile(&PathBuf::from("go.sum")));
}
#[test]
fn test_is_lockfile_no_match() {
assert!(!is_lockfile(&PathBuf::from("src/main.rs")));
assert!(!is_lockfile(&PathBuf::from("Cargo.toml")));
assert!(!is_lockfile(&PathBuf::from("lockfile.txt")));
assert!(!is_lockfile(&PathBuf::from("noextension")));
assert!(!is_lockfile(&PathBuf::from("path/to/"))); // Directory path
}
#[test]
fn test_is_lockfile_root() {
assert!(is_lockfile(&PathBuf::from("Cargo.lock")));
}
}