dev_prune/adapters/
yarn.rs1use super::{
7 BloatDir, EnforcePolicy, PackageManager, dir_size, enforce_two_tier, run_command_with_timeout,
8};
9use anyhow::Result;
10use std::path::Path;
11
12pub struct Yarn;
14
15fn is_berry_project(project_dir: &Path) -> bool {
23 if project_dir.join(".yarnrc.yml").exists() || project_dir.join(".yarn").is_dir() {
24 return true;
25 }
26 std::fs::read_to_string(project_dir.join("yarn.lock"))
27 .map(|c| c.lines().take(30).any(|l| l.starts_with("__metadata:")))
28 .unwrap_or(false)
29}
30
31impl PackageManager for Yarn {
32 fn name(&self) -> &'static str {
34 "yarn"
35 }
36
37 fn detect(&self, project_dir: &Path) -> bool {
39 project_dir.join("yarn.lock").exists()
40 }
41
42 fn bloat_dirs(&self, project_dir: &Path) -> Vec<BloatDir> {
44 let node_modules = project_dir.join("node_modules");
45 if node_modules.exists() {
46 let size = dir_size(&node_modules);
47 vec![BloatDir {
48 name: "node_modules".to_string(),
49 path: node_modules,
50 size_bytes: size,
51 shared_bytes: 0,
52 }]
53 } else {
54 vec![]
55 }
56 }
57
58 fn enforce_lockfile(&self, project_dir: &Path, policy: EnforcePolicy) -> Result<()> {
74 if !is_berry_project(project_dir) {
77 return Ok(());
78 }
79 enforce_two_tier(
80 &project_dir.join("yarn.lock"),
81 "yarn",
82 &["install", "--immutable", "--mode", "update-lockfile"],
83 &["install", "--mode", "update-lockfile"],
84 project_dir,
85 policy,
86 )
87 }
88
89 fn restore(&self, project_dir: &Path, timeout: std::time::Duration) -> Result<()> {
93 if is_berry_project(project_dir) {
94 run_command_with_timeout("yarn", &["install", "--immutable"], project_dir, timeout)
95 } else {
96 run_command_with_timeout(
97 "yarn",
98 &["install", "--frozen-lockfile"],
99 project_dir,
100 timeout,
101 )
102 }
103 }
104
105 fn lockfiles(&self) -> &'static [&'static str] {
106 &["yarn.lock"]
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use std::fs;
114 use tempfile::tempdir;
115
116 #[test]
117 fn test_name() {
118 assert_eq!(Yarn.name(), "yarn");
119 }
120
121 #[test]
122 fn test_detect_positive() {
123 let dir = tempdir().unwrap();
124 fs::File::create(dir.path().join("yarn.lock")).unwrap();
125 assert!(Yarn.detect(dir.path()));
126 }
127
128 #[test]
129 fn test_detect_negative() {
130 let dir = tempdir().unwrap();
131 assert!(!Yarn.detect(dir.path()));
132 }
133
134 #[test]
135 fn test_bloat_dirs_present() {
136 let dir = tempdir().unwrap();
137 fs::create_dir(dir.path().join("node_modules")).unwrap();
138 let bloat = Yarn.bloat_dirs(dir.path());
139 assert_eq!(bloat.len(), 1);
140 assert_eq!(bloat[0].path, dir.path().join("node_modules"));
141 }
142
143 #[test]
144 fn test_bloat_dirs_absent() {
145 let dir = tempdir().unwrap();
146 let bloat = Yarn.bloat_dirs(dir.path());
147 assert!(bloat.is_empty());
148 }
149
150 #[test]
151 fn a_classic_lockfile_alone_is_not_berry() {
152 let dir = tempdir().unwrap();
153 fs::write(dir.path().join("yarn.lock"), "# yarn lockfile v1\n").unwrap();
154 assert!(!is_berry_project(dir.path()));
155 }
156
157 #[test]
158 fn a_yarnrc_yml_marks_the_project_as_berry() {
159 let dir = tempdir().unwrap();
160 fs::write(dir.path().join("yarn.lock"), "# yarn lockfile v1\n").unwrap();
161 fs::File::create(dir.path().join(".yarnrc.yml")).unwrap();
162 assert!(is_berry_project(dir.path()));
163 }
164
165 #[test]
166 fn a_dot_yarn_directory_marks_the_project_as_berry() {
167 let dir = tempdir().unwrap();
168 fs::write(dir.path().join("yarn.lock"), "# yarn lockfile v1\n").unwrap();
169 fs::create_dir(dir.path().join(".yarn")).unwrap();
170 assert!(is_berry_project(dir.path()));
171 }
172
173 #[test]
174 fn a_metadata_block_in_the_lockfile_marks_the_project_as_berry() {
175 let dir = tempdir().unwrap();
176 fs::write(dir.path().join("yarn.lock"), "__metadata:\n version: 8\n").unwrap();
177 assert!(is_berry_project(dir.path()));
178 }
179
180 #[test]
185 fn enforce_on_classic_needs_no_yarn_binary() {
186 let dir = tempdir().unwrap();
187 fs::write(
188 dir.path().join("yarn.lock"),
189 "# yarn lockfile v1\n\nleft-pad@^1.3.0:\n version \"1.3.0\"\n",
190 )
191 .unwrap();
192 assert!(
193 Yarn.enforce_lockfile(dir.path(), EnforcePolicy::default())
194 .is_ok()
195 );
196 }
197}