dev_prune/adapters/
yarn.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size, enforce_two_tier, run_command};
7use anyhow::Result;
8use std::path::Path;
9
10pub struct Yarn;
12
13impl PackageManager for Yarn {
14 fn name(&self) -> &'static str {
16 "yarn"
17 }
18
19 fn detect(&self, project_dir: &Path) -> bool {
21 project_dir.join("yarn.lock").exists()
22 }
23
24 fn bloat_dirs(&self, project_dir: &Path) -> Vec<BloatDir> {
26 let node_modules = project_dir.join("node_modules");
27 if node_modules.exists() {
28 let size = dir_size(&node_modules);
29 vec![BloatDir {
30 name: "node_modules".to_string(),
31 path: node_modules,
32 size_bytes: size,
33 }]
34 } else {
35 vec![]
36 }
37 }
38
39 fn enforce_lockfile(&self, project_dir: &Path, policy: EnforcePolicy) -> Result<()> {
52 let lockfile = project_dir.join("yarn.lock");
53 let berry = enforce_two_tier(
54 &lockfile,
55 "yarn",
56 &["install", "--immutable", "--mode", "update-lockfile"],
57 &["install", "--mode", "update-lockfile"],
58 project_dir,
59 policy,
60 );
61 if berry.is_err() && !lockfile.exists() {
62 anyhow::bail!(
63 "`yarn install --mode update-lockfile` failed and there is no \
64 `yarn.lock` to fall back on. Cannot prove `node_modules` is \
65 rebuildable — run `yarn install` and commit the lockfile first."
66 );
67 }
68 Ok(())
69 }
70
71 fn restore(&self, project_dir: &Path) -> Result<()> {
73 run_command("yarn", &["install", "--immutable"], project_dir)
74 }
75
76 fn lockfiles(&self) -> &'static [&'static str] {
77 &["yarn.lock"]
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use std::fs;
85 use tempfile::tempdir;
86
87 #[test]
88 fn test_name() {
89 assert_eq!(Yarn.name(), "yarn");
90 }
91
92 #[test]
93 fn test_detect_positive() {
94 let dir = tempdir().unwrap();
95 fs::File::create(dir.path().join("yarn.lock")).unwrap();
96 assert!(Yarn.detect(dir.path()));
97 }
98
99 #[test]
100 fn test_detect_negative() {
101 let dir = tempdir().unwrap();
102 assert!(!Yarn.detect(dir.path()));
103 }
104
105 #[test]
106 fn test_bloat_dirs_present() {
107 let dir = tempdir().unwrap();
108 fs::create_dir(dir.path().join("node_modules")).unwrap();
109 let bloat = Yarn.bloat_dirs(dir.path());
110 assert_eq!(bloat.len(), 1);
111 assert_eq!(bloat[0].path, dir.path().join("node_modules"));
112 }
113
114 #[test]
115 fn test_bloat_dirs_absent() {
116 let dir = tempdir().unwrap();
117 let bloat = Yarn.bloat_dirs(dir.path());
118 assert!(bloat.is_empty());
119 }
120}