dev_prune/adapters/
godot.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size};
24use anyhow::{Result, anyhow};
25use std::fs;
26use std::path::Path;
27
28const MANIFEST: &str = "project.godot";
30
31const CACHE_DIRS: &[&str] = &[".godot", ".import"];
33
34pub struct Godot;
36
37impl PackageManager for Godot {
38 fn name(&self) -> &'static str {
39 "godot"
40 }
41
42 fn detect(&self, path: &Path) -> bool {
43 path.join(MANIFEST).is_file()
44 }
45
46 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
47 CACHE_DIRS
48 .iter()
49 .map(|name| path.join(name))
50 .filter(|dir| dir.is_dir())
51 .map(|dir| BloatDir {
52 name: dir
53 .file_name()
54 .unwrap_or_default()
55 .to_string_lossy()
56 .into_owned(),
57 size_bytes: dir_size(&dir),
58 path: dir,
59 shared_bytes: 0,
60 })
61 .collect()
62 }
63
64 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
71 let manifest = path.join(MANIFEST);
72 let content = fs::read_to_string(&manifest).map_err(|e| {
73 anyhow!("`{MANIFEST}` could not be read ({e}): nothing to re-import the assets from.")
74 })?;
75 if !content.contains("config_version=") {
76 return Err(anyhow!(
77 "`{MANIFEST}` has no `config_version=` line: refusing to treat the imported-\
78 resource cache as regenerable from it."
79 ));
80 }
81 Ok(())
82 }
83
84 fn restore(&self, _path: &Path, _timeout: std::time::Duration) -> Result<()> {
85 println!(
86 "Godot's imported-resource cache regenerates when the editor next opens the \
87 project; `godot --headless --import` does it without the window on 4.x"
88 );
89 Ok(())
90 }
91
92 fn lockfiles(&self) -> &'static [&'static str] {
93 &[MANIFEST]
94 }
95
96 fn opt_in(&self) -> bool {
97 true
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use std::path::PathBuf;
105 use tempfile::tempdir;
106
107 fn project(dir: &Path) -> PathBuf {
109 fs::write(
110 dir.join(MANIFEST),
111 "; Engine configuration file.\nconfig_version=5\n\n[application]\n\nconfig/name=\"Demo\"\n",
112 )
113 .unwrap();
114 dir.to_path_buf()
115 }
116
117 fn claimed(project: &Path) -> Vec<String> {
118 Godot
119 .bloat_dirs(project)
120 .into_iter()
121 .map(|b| b.name)
122 .collect()
123 }
124
125 #[test]
126 fn detects_on_the_project_manifest() {
127 let dir = tempdir().unwrap();
128 assert!(!Godot.detect(dir.path()));
129 project(dir.path());
130 assert!(Godot.detect(dir.path()));
131 }
132
133 #[test]
134 fn both_engine_versions_caches_are_claimed() {
135 let dir = tempdir().unwrap();
138 let root = project(dir.path());
139 fs::create_dir(root.join(".godot")).unwrap();
140 fs::write(root.join(".godot").join("uid_cache.bin"), "cache").unwrap();
141 fs::create_dir(root.join(".import")).unwrap();
142
143 assert_eq!(claimed(&root), vec![".godot", ".import"]);
144 }
145
146 #[test]
147 fn nothing_else_beside_the_manifest_is_claimed() {
148 let dir = tempdir().unwrap();
151 let root = project(dir.path());
152 fs::create_dir(root.join("assets")).unwrap();
153
154 assert!(claimed(&root).is_empty());
155 }
156
157 #[test]
158 fn a_missing_or_bogus_manifest_is_refused() {
159 let dir = tempdir().unwrap();
160 let policy = EnforcePolicy::default();
161 assert!(Godot.enforce_lockfile(dir.path(), policy).is_err());
162 fs::write(dir.path().join(MANIFEST), "hello there").unwrap();
163 assert!(Godot.enforce_lockfile(dir.path(), policy).is_err());
164 project(dir.path());
165 assert!(Godot.enforce_lockfile(dir.path(), policy).is_ok());
166 }
167
168 #[test]
169 fn godot_is_opt_in() {
170 assert!(Godot.opt_in());
171 }
172}