Skip to main content

mars_agents/source/
mod.rs

1pub mod git;
2pub mod parse;
3pub mod path;
4
5use std::path::PathBuf;
6
7use crate::error::MarsError;
8use crate::types::{CommitHash, SourceName, SourceUrl};
9
10/// Global source cache under `~/.mars/cache` (or `MARS_CACHE_DIR`).
11#[derive(Debug, Clone)]
12pub struct GlobalCache {
13    pub root: PathBuf,
14}
15
16impl GlobalCache {
17    /// Create a new cache directory, ensuring required subdirs exist.
18    ///
19    /// Resolution order:
20    /// 1. `MARS_CACHE_DIR`
21    /// 2. `dirs::home_dir()/.mars/cache`
22    /// 3. `{current_working_dir}/.mars/cache` fallback
23    pub fn new() -> Result<Self, MarsError> {
24        let root = if let Some(cache_dir) = std::env::var_os("MARS_CACHE_DIR") {
25            PathBuf::from(cache_dir)
26        } else if let Some(home) = dirs::home_dir() {
27            home.join(".mars").join("cache")
28        } else {
29            std::env::current_dir()
30                .unwrap_or_else(|_| PathBuf::from("."))
31                .join(".mars")
32                .join("cache")
33        };
34
35        let cache = Self { root };
36        std::fs::create_dir_all(cache.archives_dir())?;
37        std::fs::create_dir_all(cache.git_dir())?;
38        Ok(cache)
39    }
40
41    pub fn archives_dir(&self) -> PathBuf {
42        self.root.join("archives")
43    }
44
45    pub fn git_dir(&self) -> PathBuf {
46        self.root.join("git")
47    }
48}
49
50/// A resolved source reference — pinned to a specific version/commit.
51#[derive(Debug, Clone)]
52pub struct ResolvedRef {
53    pub source_name: SourceName,
54    pub version: Option<semver::Version>,
55    /// Original tag name (e.g., "v0.5.2")
56    pub version_tag: Option<String>,
57    pub commit: Option<CommitHash>,
58    pub tree_path: PathBuf,
59}
60
61/// Available version from a git remote.
62#[derive(Debug, Clone)]
63pub struct AvailableVersion {
64    pub tag: String,
65    pub version: semver::Version,
66    pub commit_id: String,
67}
68
69/// List available versions from a git remote (for resolution).
70pub fn list_versions(
71    url: &SourceUrl,
72    cache: &GlobalCache,
73) -> Result<Vec<AvailableVersion>, MarsError> {
74    git::list_versions(url.as_ref(), cache)
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn global_cache_creates_directory() {
83        let cache = GlobalCache::new().unwrap();
84        assert!(cache.root.exists());
85        if let Some(from_env) = std::env::var_os("MARS_CACHE_DIR") {
86            assert_eq!(cache.root, PathBuf::from(from_env));
87        } else {
88            assert!(cache.root.ends_with(".mars/cache"));
89        }
90        assert!(cache.archives_dir().exists());
91        assert!(cache.git_dir().exists());
92    }
93
94    #[test]
95    fn global_cache_idempotent() {
96        let cache1 = GlobalCache::new().unwrap();
97        let cache2 = GlobalCache::new().unwrap();
98        assert_eq!(cache1.root, cache2.root);
99        assert!(cache1.root.exists());
100    }
101}