pixi_outdated/
lockfile.rs1use anyhow::{Context, Result};
2use rattler_lock::LockFile;
3use std::path::Path;
4
5pub fn get_platforms_from_lockfile(
7 manifest_path: Option<&str>,
8 environment: Option<&str>,
9) -> Result<Vec<String>> {
10 let lockfile_path = if let Some(manifest) = manifest_path {
12 let manifest_dir = Path::new(manifest)
13 .parent()
14 .context("Failed to get manifest directory")?;
15 manifest_dir.join("pixi.lock")
16 } else {
17 Path::new("pixi.lock").to_path_buf()
18 };
19
20 let lockfile = LockFile::from_path(&lockfile_path)
22 .with_context(|| format!("Failed to read lockfile at {}", lockfile_path.display()))?;
23
24 let env_name = environment.unwrap_or("default");
26
27 let (_name, env) = lockfile
28 .environments()
29 .find(|(name, _env)| *name == env_name)
30 .with_context(|| format!("Environment '{}' not found in lockfile", env_name))?;
31
32 let platforms: Vec<String> = env.platforms().map(|p| p.to_string()).collect();
34
35 if platforms.is_empty() {
36 anyhow::bail!("No platforms found for environment '{}'", env_name);
37 }
38
39 Ok(platforms)
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use std::fs;
46 use tempfile::TempDir;
47
48 fn get_example_manifest_path() -> String {
49 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
51 .expect("CARGO_MANIFEST_DIR should be set during tests");
52 format!("{}/examples/pixi.toml", manifest_dir)
53 }
54
55 #[test]
56 fn test_get_platforms_from_example_project() {
57 let manifest_path = get_example_manifest_path();
59 let result = get_platforms_from_lockfile(Some(&manifest_path), None);
60
61 assert!(result.is_ok());
62 let platforms = result.unwrap();
63
64 assert!(platforms.len() >= 2);
65 assert!(platforms.contains(&"linux-64".to_string()));
66 assert!(platforms.contains(&"osx-arm64".to_string()));
67 }
68
69 #[test]
70 fn test_get_platforms_missing_env() {
71 let manifest_path = get_example_manifest_path();
73 let result = get_platforms_from_lockfile(Some(&manifest_path), Some("nonexistent"));
74
75 assert!(result.is_err());
76 let error_msg = result.unwrap_err().to_string();
77 assert!(
78 error_msg.contains("Environment 'nonexistent' not found"),
79 "Expected error message to contain \"Environment 'nonexistent' not found\", but got: {}",
80 error_msg
81 );
82 }
83
84 #[test]
85 fn test_get_platforms_missing_lockfile() {
86 let temp_dir = TempDir::new().unwrap();
87 let manifest_path = temp_dir.path().join("pixi.toml");
88 fs::write(&manifest_path, "").unwrap();
89
90 let result = get_platforms_from_lockfile(Some(manifest_path.to_str().unwrap()), None);
91
92 assert!(result.is_err());
93 assert!(result
94 .unwrap_err()
95 .to_string()
96 .contains("Failed to read lockfile"));
97 }
98
99 #[test]
100 fn test_get_platforms_invalid_lockfile() {
101 let temp_dir = TempDir::new().unwrap();
102 let manifest_path = temp_dir.path().join("pixi.toml");
103 let lockfile_path = temp_dir.path().join("pixi.lock");
104
105 fs::write(&manifest_path, "").unwrap();
106 fs::write(&lockfile_path, "invalid yaml {[}").unwrap();
107
108 let result = get_platforms_from_lockfile(Some(manifest_path.to_str().unwrap()), None);
109
110 assert!(result.is_err());
111 }
112
113 #[test]
114 fn test_get_platforms_without_manifest_path() {
115 let temp_dir = TempDir::new().unwrap();
117 let example_lock = fs::read_to_string("examples/pixi.lock").unwrap();
118 fs::write(temp_dir.path().join("pixi.lock"), example_lock).unwrap();
119
120 let original_dir = std::env::current_dir().unwrap();
122 std::env::set_current_dir(temp_dir.path()).unwrap();
123
124 let result = get_platforms_from_lockfile(None, None);
126
127 std::env::set_current_dir(original_dir).unwrap();
129
130 assert!(result.is_ok());
131 let platforms = result.unwrap();
132 assert!(platforms.len() >= 2);
133 }
134}