dev_prune/adapters/
mix_build.rs1use super::{BloatDir, EnforcePolicy, PackageManager, dir_size};
19use anyhow::{Result, anyhow};
20use std::path::Path;
21
22pub struct MixBuild;
24
25impl PackageManager for MixBuild {
26 fn name(&self) -> &'static str {
27 "mix_build"
28 }
29
30 fn detect(&self, path: &Path) -> bool {
31 path.join("mix.exs").exists()
32 }
33
34 fn bloat_dirs(&self, path: &Path) -> Vec<BloatDir> {
35 let build = path.join("_build");
36 if !build.is_dir() {
37 return Vec::new();
38 }
39 vec![BloatDir {
40 name: "_build".to_string(),
41 path: build.clone(),
42 size_bytes: dir_size(&build),
43 shared_bytes: 0,
44 }]
45 }
46
47 fn enforce_lockfile(&self, path: &Path, _policy: EnforcePolicy) -> Result<()> {
52 if !path.join("mix.exs").exists() {
53 return Err(anyhow!("no `mix.exs` — nothing to rebuild `_build/` from."));
54 }
55 if !path.join("mix.lock").exists() {
56 return Err(anyhow!(
57 "`mix.lock` is missing — recompiling `_build/` needs the dependency \
58 versions it pins, and without it `mix deps.get` resolves afresh."
59 ));
60 }
61 Ok(())
62 }
63
64 fn restore(&self, _path: &Path, _timeout: std::time::Duration) -> Result<()> {
65 println!("Mix _build/ will regenerate on the next `mix compile`");
66 Ok(())
67 }
68
69 fn lockfiles(&self) -> &'static [&'static str] {
70 &["mix.lock"]
71 }
72
73 fn opt_in(&self) -> bool {
74 true
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use std::fs;
82 use tempfile::tempdir;
83
84 #[test]
85 fn detects_on_the_mix_manifest() {
86 let dir = tempdir().unwrap();
87 assert!(!MixBuild.detect(dir.path()));
88 fs::write(dir.path().join("mix.exs"), "defmodule X.MixProject do end").unwrap();
89 assert!(MixBuild.detect(dir.path()));
90 }
91
92 #[test]
93 fn claims_the_build_tree_and_never_deps() {
94 let dir = tempdir().unwrap();
95 fs::create_dir(dir.path().join("deps")).unwrap();
96 fs::create_dir(dir.path().join("_build")).unwrap();
97 let names: Vec<String> = MixBuild
98 .bloat_dirs(dir.path())
99 .into_iter()
100 .map(|b| b.name)
101 .collect();
102 assert_eq!(names, vec!["_build"]);
103 }
104
105 #[test]
106 fn a_missing_manifest_or_lockfile_is_refused() {
107 let dir = tempdir().unwrap();
108 assert!(
109 MixBuild
110 .enforce_lockfile(dir.path(), EnforcePolicy::default())
111 .is_err()
112 );
113 fs::write(dir.path().join("mix.exs"), "").unwrap();
114 assert!(
115 MixBuild
116 .enforce_lockfile(dir.path(), EnforcePolicy::default())
117 .is_err()
118 );
119 fs::write(dir.path().join("mix.lock"), "%{}\n").unwrap();
120 assert!(
121 MixBuild
122 .enforce_lockfile(dir.path(), EnforcePolicy::default())
123 .is_ok()
124 );
125 }
126
127 #[test]
128 fn the_build_tree_is_opt_in() {
129 assert!(MixBuild.opt_in());
130 assert!(!crate::adapters::mix::Mix.opt_in());
131 }
132}