dev_prune/adapters/
cocoapods.rs1use super::{
16 BloatDir, EnforcePolicy, PackageManager, dir_size, refuse_if_manifest_stale,
17 run_command_with_timeout,
18};
19use anyhow::{Result, anyhow};
20use std::fs;
21use std::path::Path;
22
23pub struct CocoaPods;
25
26const LOCK_SENTINEL: &str = "SPEC CHECKSUMS";
30
31impl PackageManager for CocoaPods {
32 fn name(&self) -> &'static str {
33 "cocoapods"
34 }
35
36 fn detect(&self, path: &Path) -> bool {
37 path.join("Podfile").exists()
38 }
39
40 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
41 let pods = path.join("Pods");
42 if !pods.is_dir() {
43 return Vec::new();
44 }
45 vec![BloatDir {
46 name: "Pods".to_string(),
47 path: pods.clone(),
48 size_bytes: dir_size(&pods),
49 shared_bytes: 0,
50 }]
51 }
52
53 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
54 let lock = path.join("Podfile.lock");
55 let content = fs::read_to_string(&lock).map_err(|e| {
56 anyhow!(
57 "`Podfile.lock` could not be read ({e}) — without it `pod install` \
58 resolves afresh instead of restoring the versions being deleted."
59 )
60 })?;
61 if !content.contains(LOCK_SENTINEL) {
62 return Err(anyhow!(
63 "`Podfile.lock` has no `{LOCK_SENTINEL}` section — it is not a complete \
64 CocoaPods lockfile, so `Pods/` cannot be proven rebuildable from it."
65 ));
66 }
67 refuse_if_manifest_stale(&path.join("Podfile"), &lock, "pod install")
68 }
69
70 fn restore(&self, path: &Path, timeout: std::time::Duration) -> Result<()> {
71 run_command_with_timeout("pod", &["install"], path, timeout)
72 }
73
74 fn lockfiles(&self) -> &'static [&'static str] {
75 &["Podfile.lock"]
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use tempfile::tempdir;
83
84 fn complete_lock() -> &'static str {
85 "PODS:\n - Alamofire (5.9.1)\n\nSPEC CHECKSUMS:\n Alamofire: abc\n\nCOCOAPODS: 1.15.2\n"
86 }
87
88 #[test]
89 fn detects_on_the_podfile() {
90 let dir = tempdir().unwrap();
91 assert!(!CocoaPods.detect(dir.path()));
92 fs::write(dir.path().join("Podfile"), "platform :ios").unwrap();
93 assert!(CocoaPods.detect(dir.path()));
94 }
95
96 #[test]
97 fn claims_the_pods_directory() {
98 let dir = tempdir().unwrap();
99 assert!(CocoaPods.bloat_dirs(dir.path()).is_empty());
100 fs::create_dir(dir.path().join("Pods")).unwrap();
101 let dirs = CocoaPods.bloat_dirs(dir.path());
102 assert_eq!(dirs.len(), 1);
103 assert_eq!(dirs[0].name, "Pods");
104 }
105
106 #[test]
107 fn a_missing_or_truncated_lockfile_is_refused() {
108 let dir = tempdir().unwrap();
109 assert!(
110 CocoaPods
111 .enforce_lockfile(dir.path(), EnforcePolicy::default())
112 .is_err()
113 );
114 fs::write(dir.path().join("Podfile.lock"), "PODS:\n").unwrap();
115 assert!(
116 CocoaPods
117 .enforce_lockfile(dir.path(), EnforcePolicy::default())
118 .is_err()
119 );
120 fs::write(dir.path().join("Podfile.lock"), complete_lock()).unwrap();
121 assert!(
122 CocoaPods
123 .enforce_lockfile(dir.path(), EnforcePolicy::default())
124 .is_ok()
125 );
126 }
127}