dev_prune/adapters/
swift.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size};
15use anyhow::{Result, anyhow};
16use std::fs;
17use std::path::Path;
18
19pub struct Swift;
21
22impl PackageManager for Swift {
23 fn name(&self) -> &'static str {
24 "swift"
25 }
26
27 fn detect(&self, path: &Path) -> bool {
28 path.join("Package.swift").exists()
29 }
30
31 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
32 let build = path.join(".build");
33 if !build.is_dir() {
34 return Vec::new();
35 }
36 vec![BloatDir {
37 name: ".build".to_string(),
38 path: build.clone(),
39 size_bytes: dir_size(&build),
40 shared_bytes: 0,
41 }]
42 }
43
44 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
49 let manifest = path.join("Package.swift");
50 let content = fs::read_to_string(&manifest).map_err(|e| {
51 anyhow!("`Package.swift` could not be read ({e}) — nothing to rebuild `.build/` from.")
52 })?;
53 if !content.contains("Package(") {
54 return Err(anyhow!(
55 "`Package.swift` declares no `Package(` — refusing to treat `.build/` as \
56 rebuildable from it."
57 ));
58 }
59 Ok(())
60 }
61
62 fn restore(&self, _path: &Path, _timeout: std::time::Duration) -> Result<()> {
63 println!("SwiftPM .build/ will regenerate on the next `swift build`");
64 Ok(())
65 }
66
67 fn lockfiles(&self) -> &'static [&'static str] {
68 &["Package.resolved"]
69 }
70
71 fn opt_in(&self) -> bool {
72 true
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use tempfile::tempdir;
80
81 #[test]
82 fn detects_on_the_package_manifest() {
83 let dir = tempdir().unwrap();
84 assert!(!Swift.detect(dir.path()));
85 fs::write(
86 dir.path().join("Package.swift"),
87 "// swift-tools-version:5.9",
88 )
89 .unwrap();
90 assert!(Swift.detect(dir.path()));
91 }
92
93 #[test]
94 fn claims_the_build_directory_and_not_the_swiftpm_one() {
95 let dir = tempdir().unwrap();
96 fs::create_dir(dir.path().join(".build")).unwrap();
97 fs::create_dir(dir.path().join(".swiftpm")).unwrap();
98 let names: Vec<String> = Swift
99 .bloat_dirs(dir.path())
100 .into_iter()
101 .map(|b| b.name)
102 .collect();
103 assert_eq!(names, vec![".build"]);
104 }
105
106 #[test]
107 fn a_missing_or_bogus_manifest_is_refused() {
108 let dir = tempdir().unwrap();
109 assert!(
110 Swift
111 .enforce_lockfile(dir.path(), EnforcePolicy::default())
112 .is_err()
113 );
114 fs::write(dir.path().join("Package.swift"), "let x = 1").unwrap();
115 assert!(
116 Swift
117 .enforce_lockfile(dir.path(), EnforcePolicy::default())
118 .is_err()
119 );
120 fs::write(
121 dir.path().join("Package.swift"),
122 "let package = Package(name: \"x\")",
123 )
124 .unwrap();
125 assert!(
126 Swift
127 .enforce_lockfile(dir.path(), EnforcePolicy::default())
128 .is_ok()
129 );
130 }
131
132 #[test]
133 fn swift_is_opt_in() {
134 assert!(Swift.opt_in());
135 }
136}