dev_prune/adapters/
defold.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size};
21use anyhow::{Result, anyhow};
22use std::fs;
23use std::path::Path;
24
25const MANIFEST: &str = "game.project";
27
28const CACHE_DIRS: &[&str] = &["build"];
30
31pub struct Defold;
33
34impl PackageManager for Defold {
35 fn name(&self) -> &'static str {
36 "defold"
37 }
38
39 fn detect(&self, path: &Path) -> bool {
40 path.join(MANIFEST).is_file()
41 }
42
43 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
44 CACHE_DIRS
45 .iter()
46 .map(|name| path.join(name))
47 .filter(|dir| dir.is_dir())
48 .map(|dir| BloatDir {
49 name: dir
50 .file_name()
51 .unwrap_or_default()
52 .to_string_lossy()
53 .into_owned(),
54 size_bytes: dir_size(&dir),
55 path: dir,
56 shared_bytes: 0,
57 })
58 .collect()
59 }
60
61 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
66 let manifest = path.join(MANIFEST);
67 let content = fs::read_to_string(&manifest).map_err(|e| {
68 anyhow!("`{MANIFEST}` could not be read ({e}): nothing to rebuild from.")
69 })?;
70 if !content.contains("[project]") {
71 return Err(anyhow!(
72 "`{MANIFEST}` has no `[project]` section: refusing to treat the build \
73 output as regenerable from it."
74 ));
75 }
76 Ok(())
77 }
78
79 fn restore(&self, _path: &Path, _timeout: std::time::Duration) -> Result<()> {
80 println!(
81 "Defold's build output regenerates on the next build, in the editor or \
82 with bob"
83 );
84 Ok(())
85 }
86
87 fn lockfiles(&self) -> &'static [&'static str] {
88 &[MANIFEST]
89 }
90
91 fn opt_in(&self) -> bool {
92 true
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use std::path::PathBuf;
100 use tempfile::tempdir;
101
102 fn project(dir: &Path) -> PathBuf {
104 fs::write(
105 dir.join(MANIFEST),
106 "[project]\ntitle = Demo\nversion = 1.0\n\n[display]\nwidth = 960\n",
107 )
108 .unwrap();
109 dir.to_path_buf()
110 }
111
112 fn claimed(project: &Path) -> Vec<String> {
113 Defold
114 .bloat_dirs(project)
115 .into_iter()
116 .map(|b| b.name)
117 .collect()
118 }
119
120 #[test]
121 fn detects_on_the_project_manifest() {
122 let dir = tempdir().unwrap();
123 assert!(!Defold.detect(dir.path()));
124 project(dir.path());
125 assert!(Defold.detect(dir.path()));
126 }
127
128 #[test]
129 fn the_build_output_is_claimed() {
130 let dir = tempdir().unwrap();
131 let root = project(dir.path());
132 fs::create_dir(root.join("build")).unwrap();
133 fs::write(root.join("build").join("game.arcd"), "output").unwrap();
134
135 assert_eq!(claimed(&root), vec!["build"]);
136 }
137
138 #[test]
139 fn nothing_else_beside_the_manifest_is_claimed() {
140 let dir = tempdir().unwrap();
143 let root = project(dir.path());
144 fs::create_dir(root.join(".internal")).unwrap();
145 fs::create_dir(root.join("assets")).unwrap();
146
147 assert!(claimed(&root).is_empty());
148 }
149
150 #[test]
151 fn a_missing_or_bogus_manifest_is_refused() {
152 let dir = tempdir().unwrap();
153 let policy = EnforcePolicy::default();
154 assert!(Defold.enforce_lockfile(dir.path(), policy).is_err());
155 fs::write(dir.path().join(MANIFEST), "hello there").unwrap();
156 assert!(Defold.enforce_lockfile(dir.path(), policy).is_err());
157 project(dir.path());
158 assert!(Defold.enforce_lockfile(dir.path(), policy).is_ok());
159 }
160
161 #[test]
162 fn defold_is_opt_in() {
163 assert!(Defold.opt_in());
164 }
165}