kdeets_lib/
setup.rs

1use crate::Error;
2
3use clap::{Parser, ValueEnum};
4use clap_verbosity::Verbosity;
5use disksize::DiskSize;
6use output::SetupTestOutputBuilder;
7use tame_index::{KrateName, index::FileLock};
8
9mod disksize;
10mod output;
11
12#[derive(Debug, Parser, Default, ValueEnum, Clone)]
13enum SelectVersion {
14    #[default]
15    Latest,
16    Highest,
17    HighestNormal,
18    Earliest,
19    None,
20}
21
22#[derive(Parser, Debug, Default)]
23#[clap(author, version, about, long_about = None)]
24pub struct Setup {
25    #[clap(flatten)]
26    logging: Verbosity,
27    /// Do not replace the existing registry if it exists
28    #[clap(default_value = "false", short = 'r', long)]
29    no_replace: bool,
30    #[clap(
31        short,
32        long,
33        help = "Add dependencies based on specific version\n",
34        default_value = "latest"
35    )]
36    dependencies: SelectVersion,
37    /// The location for the local registry
38    #[clap(short, long, default_value = "tests/local_registry")]
39    location: String,
40    /// The name of the crate
41    crate_: String,
42}
43
44impl Setup {
45    pub fn run(&self) -> Result<String, Error> {
46        log::info!(
47            "Setting up local registry and adding crate: {}",
48            self.crate_
49        );
50        let lock = FileLock::unlocked();
51
52        let combo_index = crate::get_remote_combo_index()?;
53        let crate_name = KrateName::crates_io(&self.crate_)?;
54
55        let index_crate = combo_index.krate(crate_name, true, &lock)?;
56
57        let Some(index_crate) = index_crate else {
58            return Err(Error::CrateNotFoundOnIndex);
59        };
60
61        let registry = if self.location.is_empty() {
62            "tests/local_registry"
63        } else {
64            &self.location
65        };
66        log::debug!("Creating registry at {registry}");
67        let mut output = SetupTestOutputBuilder::new(index_crate.clone(), registry);
68
69        output.initialise_local_registry(self.no_replace)?;
70
71        output.insert_crate(&index_crate)?;
72
73        match self.dependencies {
74            SelectVersion::Latest => {
75                log::debug!("Adding dependencies for most recent version");
76                output.add_dependency_crates(
77                    index_crate.most_recent_version().dependencies(),
78                    &combo_index,
79                )?;
80            }
81            SelectVersion::Earliest => {
82                log::debug!("Adding dependencies for earliest version");
83                output.add_dependency_crates(
84                    index_crate.earliest_version().dependencies(),
85                    &combo_index,
86                )?;
87            }
88            SelectVersion::Highest => {
89                log::debug!("Adding dependencies for highest version");
90                output.add_dependency_crates(
91                    index_crate.highest_version().dependencies(),
92                    &combo_index,
93                )?;
94            }
95            SelectVersion::HighestNormal => {
96                log::debug!("Attempting to add dependencies for highest normal version");
97                let opt_index_version = index_crate.highest_normal_version();
98                if let Some(index_version) = opt_index_version {
99                    output.add_dependency_crates(index_version.dependencies(), &combo_index)?;
100                } else {
101                    log::warn!("No normal version found for crate: {}", self.crate_);
102                };
103            }
104            SelectVersion::None => (),
105        };
106        log::debug!("Finalizing registry");
107        let final_output = output.finalize()?;
108        log::debug!("Registry setup complete");
109        Ok(final_output.to_string())
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use std::path::Path;
116
117    use super::*;
118    const TEST_CRATE_NAME: &str = "forestry";
119    // const TEST_CRATE_NAME: &str = "some_crate";
120    const TEST_NON_EXISTENT_CRATE_NAME: &str = "nonexistent_crate_12345";
121
122    #[test]
123    fn test_setup_run_default_directory() {
124        let _log = simple_logger::init_with_level(log::Level::Debug);
125
126        let setup = Setup {
127            crate_: String::from(TEST_CRATE_NAME),
128            dependencies: SelectVersion::Latest,
129            ..Default::default()
130        };
131        let result = setup.run();
132        log::debug!("Result: {result:?}");
133        assert!(result.is_ok());
134        assert!(Path::new("tests/local_registry").exists());
135    }
136
137    #[test]
138    fn test_setup_run_with_latest_dependencies() {
139        let _log = simple_logger::init_with_level(log::Level::Debug);
140        let temp_dir = tempfile::tempdir().unwrap();
141        let location = temp_dir.path().to_str().unwrap();
142
143        let setup = Setup {
144            crate_: String::from(TEST_CRATE_NAME),
145            dependencies: SelectVersion::Latest,
146            location: location.to_string(),
147            ..Default::default()
148        };
149        let result = setup.run();
150        log::debug!("Result: {result:?}");
151        assert!(result.is_ok());
152        assert!(Path::new(location).exists());
153    }
154
155    #[test]
156    fn test_setup_run_with_earliest_dependencies() {
157        let _log = simple_logger::init_with_level(log::Level::Debug);
158        let temp_dir = tempfile::tempdir().unwrap();
159        let location = temp_dir.path().to_str().unwrap();
160        let setup = Setup {
161            crate_: String::from(TEST_CRATE_NAME),
162            dependencies: SelectVersion::Earliest,
163            location: location.to_string(),
164            ..Default::default()
165        };
166        let result = setup.run();
167        log::debug!("Result: {result:?}");
168        assert!(result.is_ok());
169    }
170
171    #[test]
172    fn test_setup_run_with_highest_normal_dependencies() {
173        let _log = simple_logger::init_with_level(log::Level::Debug);
174        let temp_dir = tempfile::tempdir().unwrap();
175        let location = temp_dir.path().to_str().unwrap();
176        let setup = Setup {
177            crate_: String::from(TEST_CRATE_NAME),
178            dependencies: SelectVersion::HighestNormal,
179            location: location.to_string(),
180            ..Default::default()
181        };
182        let result = setup.run();
183        log::debug!("Result: {result:?}");
184        assert!(result.is_ok());
185    }
186
187    #[test]
188    fn test_setup_run_with_highest_dependencies() {
189        let _log = simple_logger::init_with_level(log::Level::Debug);
190        let temp_dir = tempfile::tempdir().unwrap();
191        let location = temp_dir.path().to_str().unwrap();
192        let setup = Setup {
193            crate_: String::from(TEST_CRATE_NAME),
194            dependencies: SelectVersion::Highest,
195            location: location.to_string(),
196            ..Default::default()
197        };
198        let result = setup.run();
199        log::debug!("Result: {result:?}");
200        assert!(result.is_ok());
201    }
202
203    #[test]
204    fn test_setup_run_with_no_dependencies() {
205        let _log = simple_logger::init_with_level(log::Level::Debug);
206        let temp_dir = tempfile::tempdir().unwrap();
207        let location = temp_dir.path().to_str().unwrap();
208        let setup = Setup {
209            crate_: String::from(TEST_CRATE_NAME),
210            dependencies: SelectVersion::None,
211            location: location.to_string(),
212            ..Default::default()
213        };
214        let result = setup.run();
215        log::debug!("Result: {result:?}");
216        assert!(result.is_ok());
217    }
218
219    #[test]
220    fn test_setup_run_nonexistent_crate() {
221        let _log = simple_logger::init_with_level(log::Level::Debug);
222        let temp_dir = tempfile::tempdir().unwrap();
223        let location = temp_dir.path().to_str().unwrap();
224        let setup = Setup {
225            crate_: String::from(TEST_NON_EXISTENT_CRATE_NAME),
226            dependencies: SelectVersion::Latest,
227            location: location.to_string(),
228            ..Default::default()
229        };
230        let result = setup.run();
231        log::debug!("Result: {result:?}");
232        assert!(matches!(result, Err(Error::CrateNotFoundOnIndex)));
233    }
234
235    #[test]
236    fn test_setup_run_with_no_replace_flag_not_set() {
237        let _log = simple_logger::init_with_level(log::Level::Debug);
238        let temp_dir = tempfile::tempdir().unwrap();
239        let location = temp_dir.path().to_str().unwrap();
240        let setup = Setup {
241            crate_: String::from(TEST_CRATE_NAME),
242            dependencies: SelectVersion::Latest,
243            no_replace: false,
244            location: location.to_string(),
245            ..Default::default()
246        };
247
248        // First run should succeed
249        let result1 = setup.run();
250        log::debug!("Result1: {result1:?}");
251        assert!(result1.is_ok());
252
253        // Second run with no_replace should still succeed
254        let result2 = setup.run();
255        log::debug!("Result2: {result2:?}");
256        assert!(result2.is_ok());
257    }
258
259    #[test]
260    fn test_setup_run_with_no_replace_flag_set() {
261        let _log = simple_logger::init_with_level(log::Level::Debug);
262        let temp_dir = tempfile::tempdir().unwrap();
263        let location = temp_dir.path().to_str().unwrap();
264        let setup = Setup {
265            crate_: String::from(TEST_CRATE_NAME),
266            dependencies: SelectVersion::Latest,
267            no_replace: true,
268            location: location.to_string(),
269            ..Default::default()
270        };
271
272        // First run should succeed
273        let result1 = setup.run();
274        log::debug!("Result1: {result1:?}");
275        assert!(result1.is_ok());
276
277        // Second run with no_replace should not succeed
278        let result2 = setup.run();
279        log::debug!("Result2: {result2:?}");
280        assert!(result2.is_err());
281    }
282}