dev_prune/adapters/
unity.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size};
25use anyhow::{Result, anyhow};
26use std::fs;
27use std::path::Path;
28
29const MANIFEST: &str = "ProjectSettings/ProjectVersion.txt";
31
32const EDITOR_LOCK: &str = "Temp/UnityLockfile";
34
35const CACHE_DIRS: &[&str] = &["Library", "Temp"];
37
38pub struct Unity;
40
41impl PackageManager for Unity {
42 fn name(&self) -> &'static str {
43 "unity"
44 }
45
46 fn detect(&self, path: &Path) -> bool {
47 path.join(MANIFEST).is_file()
48 }
49
50 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
51 CACHE_DIRS
52 .iter()
53 .map(|name| path.join(name))
54 .filter(|dir| dir.is_dir())
55 .map(|dir| BloatDir {
56 name: dir
57 .file_name()
58 .unwrap_or_default()
59 .to_string_lossy()
60 .into_owned(),
61 size_bytes: dir_size(&dir),
62 path: dir,
63 shared_bytes: 0,
64 })
65 .collect()
66 }
67
68 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
74 let manifest = path.join(MANIFEST);
75 let content = fs::read_to_string(&manifest).map_err(|e| {
76 anyhow!("`{MANIFEST}` could not be read ({e}): nothing to re-import the assets from.")
77 })?;
78 if !content.contains("m_EditorVersion:") {
79 return Err(anyhow!(
80 "`{MANIFEST}` has no `m_EditorVersion:` line: refusing to treat the \
81 imported-asset cache as regenerable from it."
82 ));
83 }
84 if path.join(EDITOR_LOCK).exists() {
85 return Err(anyhow!(
86 "`{EDITOR_LOCK}` exists: the Unity editor has this project open, and \
87 the asset database is not deletable under it. Close the editor first."
88 ));
89 }
90 Ok(())
91 }
92
93 fn restore(&self, _path: &Path, _timeout: std::time::Duration) -> Result<()> {
94 println!(
95 "Unity's imported-asset cache regenerates when the editor next opens the \
96 project; expect a full re-import on the first open"
97 );
98 Ok(())
99 }
100
101 fn lockfiles(&self) -> &'static [&'static str] {
102 &[MANIFEST]
103 }
104
105 fn opt_in(&self) -> bool {
106 true
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use std::path::PathBuf;
114 use tempfile::tempdir;
115
116 fn project(dir: &Path) -> PathBuf {
118 fs::create_dir_all(dir.join("ProjectSettings")).unwrap();
119 fs::write(
120 dir.join(MANIFEST),
121 "m_EditorVersion: 2022.3.10f1\nm_EditorVersionWithRevision: 2022.3.10f1 (ff3792e53c62)\n",
122 )
123 .unwrap();
124 dir.to_path_buf()
125 }
126
127 fn claimed(project: &Path) -> Vec<String> {
128 Unity
129 .bloat_dirs(project)
130 .into_iter()
131 .map(|b| b.name)
132 .collect()
133 }
134
135 #[test]
136 fn detects_on_the_project_manifest() {
137 let dir = tempdir().unwrap();
138 assert!(!Unity.detect(dir.path()));
139 project(dir.path());
140 assert!(Unity.detect(dir.path()));
141 }
142
143 #[test]
144 fn the_asset_database_and_scratch_space_are_claimed() {
145 let dir = tempdir().unwrap();
146 let root = project(dir.path());
147 fs::create_dir(root.join("Library")).unwrap();
148 fs::write(root.join("Library").join("ArtifactDB"), "cache").unwrap();
149 fs::create_dir(root.join("Temp")).unwrap();
150
151 assert_eq!(claimed(&root), vec!["Library", "Temp"]);
152 }
153
154 #[test]
155 fn nothing_else_beside_the_manifest_is_claimed() {
156 let dir = tempdir().unwrap();
159 let root = project(dir.path());
160 fs::create_dir(root.join("Assets")).unwrap();
161
162 assert!(claimed(&root).is_empty());
163 }
164
165 #[test]
166 fn a_missing_or_bogus_manifest_is_refused() {
167 let dir = tempdir().unwrap();
168 let policy = EnforcePolicy::default();
169 assert!(Unity.enforce_lockfile(dir.path(), policy).is_err());
170 fs::create_dir_all(dir.path().join("ProjectSettings")).unwrap();
171 fs::write(dir.path().join(MANIFEST), "hello there").unwrap();
172 assert!(Unity.enforce_lockfile(dir.path(), policy).is_err());
173 project(dir.path());
174 assert!(Unity.enforce_lockfile(dir.path(), policy).is_ok());
175 }
176
177 #[test]
178 fn an_open_editor_is_refused() {
179 let dir = tempdir().unwrap();
182 let root = project(dir.path());
183 let policy = EnforcePolicy::default();
184 assert!(Unity.enforce_lockfile(&root, policy).is_ok());
185 fs::create_dir(root.join("Temp")).unwrap();
186 fs::write(root.join(EDITOR_LOCK), "").unwrap();
187 assert!(Unity.enforce_lockfile(&root, policy).is_err());
188 }
189
190 #[test]
191 fn unity_is_opt_in() {
192 assert!(Unity.opt_in());
193 }
194}