1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::dependency::Dependency;
use crate::source::Source;
use crate::sources::dir_source::DirSource;
use git2::build::CheckoutBuilder;
use git2::build::RepoBuilder;
use git2::FetchOptions;
use git2::Oid;
use log::*;
use std::path::Path;

#[derive(Clone, Debug)]
pub struct GitSource {
    pub repo: String,
    pub branch: Option<String>,
    pub rev: Option<String>,
    pub tag: Option<String>,
}

impl Source for GitSource {
    fn install(&self, dependency: &Dependency, path: &Path) -> std::io::Result<()> {
        let destination = crate::smaug::cache_dir().join(dependency.clone().name);
        trace!(
            "Installing git repository {} to {}",
            self.repo,
            destination.display()
        );

        if destination.exists() {
            trace!("Removing directory {}", destination.to_str().unwrap());
            rm_rf::ensure_removed(destination.clone()).unwrap();
        }

        let fetch = FetchOptions::new();
        let checkout = CheckoutBuilder::new();

        let mut builder = RepoBuilder::new();
        builder.fetch_options(fetch);
        builder.with_checkout(checkout);

        debug!("Repository: {}", self.repo);
        if self.branch.is_some() {
            debug!("Branch: {}", self.branch.as_ref().unwrap());
            builder.branch(self.branch.as_ref().unwrap().as_str());
        }

        trace!(
            "Cloning git repository to {}",
            destination.to_str().unwrap()
        );
        let repository = builder.clone(&self.repo, destination.as_path()).unwrap();

        if self.rev.is_some() {
            let revision = self.rev.clone().unwrap();
            debug!("Revision: {}", revision);
            let mut checkout = CheckoutBuilder::new();
            let object = repository
                .find_object(
                    Oid::from_str(revision.as_str()).expect("Could not find the revision"),
                    None,
                )
                .unwrap();
            repository
                .reset(&object, git2::ResetType::Hard, Some(&mut checkout))
                .unwrap();
        }

        if self.tag.is_some() {
            let tag = self.tag.clone().unwrap();
            let mut checkout = CheckoutBuilder::new();

            let rev = repository
                .revparse_single(&tag)
                .expect("Couldn't parse tag");

            repository
                .reset(&rev, git2::ResetType::Hard, Some(&mut checkout))
                .unwrap();
        }

        let cached = repository.path().parent().expect("No parent dir");

        DirSource {
            path: cached.to_path_buf(),
        }
        .install(dependency, path)
    }
}