Skip to main content

stratum/
lib.rs

1use std::path::Path;
2
3// For now include everything as pub mod to get errors in IDE.
4use git_url_parse::GitUrlParseError;
5use thiserror::Error;
6
7mod domain;
8mod repository;
9mod url;
10
11pub use domain::{actor::Actor, commit::Commit};
12pub use repository::{Local, Remote, Repository};
13pub use url::GitUrl;
14
15/// Helper function for opening a local repository given a path P
16pub fn open_repository<P: AsRef<Path>>(p: P) -> Result<Repository<Local>, Error> {
17    Repository::<Local>::new(p)
18}
19
20/// Helper function for cloning a remote repository given a url
21pub fn clone_repository<P: AsRef<Path>>(
22    url: &str,
23    dest: Option<P>,
24) -> Result<Repository<Local>, Error> {
25    Repository::<Remote>::new(url, dest)
26}
27
28#[derive(Debug, Error)]
29pub enum Error {
30    /// An abstraction of git2::Error to raise the error effectively
31    #[error(transparent)]
32    Git(#[from] git2::Error),
33
34    /// An abstraction of git-url-parse::GitUrlParseError
35    #[error(transparent)]
36    GitUrlError(#[from] GitUrlParseError),
37
38    /// If a URL can be parsed but is not a valid GitUrl schem
39    #[error("URL scheme was {0}, cannot clone URL.")]
40    UrlScheme(String),
41
42    /// An error associated with a bad path
43    #[error("{0}")]
44    PathError(String),
45}
46
47/// Common functionality that can be imported into any and all unit tests
48/// throughout the library
49#[cfg(test)]
50mod common {
51    use once_cell::sync::Lazy;
52    use std::{fs, path::Path};
53    use tempfile::TempDir;
54
55    use super::{Local, Repository};
56
57    pub const EXPECTED_MSG: &str = "commit msg";
58    pub const EXPECTED_ACTOR_NAME: &str = "test";
59    pub const EXPECTED_ACTOR_EMAIL: &str = "test@example.com";
60
61    /// Make a repository a very basic histroy
62    fn make_repo(tmpdir: &TempDir) {
63        let repo = git2::Repository::init(tmpdir.path()).expect("Failed to init repo");
64
65        let fp = tmpdir.path().join("file.txt");
66        fs::write(&fp, "Hello World\n").expect("Failed to write to file");
67
68        // Stage file for commit
69        let mut index = repo.index().expect("Failed to get index");
70        index
71            .add_path(Path::new("file.txt"))
72            .expect("Failed to add file to index");
73        index.write().expect("Failed to write index");
74
75        let tree_id = index.write_tree().expect("Failed to write tree");
76        let tree = repo.find_tree(tree_id).expect("Failed to find tree");
77
78        // Define author and committer local to this repo
79        let sig = git2::Signature::now(EXPECTED_ACTOR_NAME, EXPECTED_ACTOR_EMAIL)
80            .expect("Failed to create actor signature");
81
82        repo.commit(Some("HEAD"), &sig, &sig, EXPECTED_MSG, &tree, &[])
83            .expect("Failed to create commit");
84    }
85
86    /// Lazily construct the test data into a temp dir that will last the length of
87    /// a single modules test span.
88    static TEST_DATA_DIR: Lazy<TempDir> = Lazy::new(|| {
89        let dir = TempDir::new().expect("Create temp dir");
90        make_repo(&dir);
91        dir
92    });
93
94    /// The path to the test data directory
95    fn test_data_dir() -> &'static Path {
96        TEST_DATA_DIR.path()
97    }
98
99    /// Init a repository object using the lazily constructed git2 repo
100    pub fn init_repo() -> Repository<Local> {
101        Repository::<Local>::new(test_data_dir()).expect("Failed to init local repository")
102    }
103}