git_meta/
lib.rs

1//! # Git-meta
2//!
3//! Git-meta is a collection of functionality for gathering information about git repos and commits
4
5//! You can open an existing repo with `GitRepo::open(path)`
6//! (Branch and commits provided for example. Provide `None` to use current checked out values)
7//!
8//! ```ignore
9//! use std::path::PathBuf;
10//! use git_meta::GitRepo;
11//! GitRepo::open(
12//!         PathBuf::from("/path/to/repo"),
13//!         Some("main".to_string()),
14//!         Some("b24fe6112e97eb9ee0cc1fd5aaa520bf8814f6c3".to_string()))
15//!     .expect("Unable to clone repo");
16//! ```
17//!
18//! You can create a new repo for cloning with `GitRepo::new(url)`
19//!
20//! ```ignore
21//! use std::path::PathBuf;
22//! use git_meta::{GitCredentials, GitRepo};
23//! use mktemp::Temp;
24//! let temp_dir = Temp::new_dir().expect("Unable to create test clone dir");
25//!
26//! let creds = GitCredentials::SshKey {
27//!     username: "git".to_string(),
28//!     public_key: None,
29//!     private_key: PathBuf::from("/path/to/private/key"),
30//!     passphrase: None,
31//! };
32//!
33//! GitRepo::new("https://github.com/tjtelan/git-meta-rs")
34//!     .expect("Unable to create GitRepo")
35//!     .with_credentials(Some(creds))
36//!     .to_clone()
37//!     .git_clone_shallow(temp_dir.as_path())
38//!     .expect("Unable to clone repo");
39//! ```
40//!
41//! *Note:* Shallow cloning requires `git` CLI to be installed
42
43use chrono::prelude::*;
44use color_eyre::eyre::Report;
45use git2::Repository;
46use hex::ToHex;
47
48#[doc(hidden)]
49pub mod clone;
50#[doc(hidden)]
51pub mod info;
52#[doc(hidden)]
53pub mod types;
54
55#[doc(hidden)]
56pub mod repo;
57
58//// Can I use this as an empty trait for trait objects
59//pub trait GitInfo {}
60//
61
62// Re-export our types in the root
63#[doc(inline)]
64pub use crate::types::*;
65
66impl GitCommitMeta {
67    /// Trait bound for `id` is to convert the output from:
68    /// `git2::Commit.id().as_bytes()` into a `String`
69    pub fn new<I: ToHex + AsRef<[u8]>>(id: I) -> GitCommitMeta {
70        GitCommitMeta {
71            id: hex::encode(id),
72            message: None,
73            timestamp: None,
74        }
75    }
76
77    /// `time` is intended to convert output from:
78    /// `git2::Commit.time().seconds()` into `Datetime<Utc>`
79    pub fn with_timestamp(mut self, time: i64) -> Self {
80        let naive_datetime = NaiveDateTime::from_timestamp(time, 0);
81        let datetime: DateTime<Utc> = DateTime::from_utc(naive_datetime, Utc);
82
83        self.timestamp = Some(datetime);
84        self
85    }
86
87    /// Set the commit message
88    pub fn with_message(mut self, msg: Option<String>) -> Self {
89        self.message = msg;
90        self
91    }
92}
93
94impl TryFrom<Repository> for GitRepo {
95    type Error = Report;
96
97    fn try_from(repo: Repository) -> Result<Self, Self::Error> {
98        GitRepo::open(repo.path().to_path_buf(), None, None)
99    }
100}
101
102impl From<&GitRepoInfo> for GitRepo {
103    /// Convert from `&GitRepoInfo` to `GitRepo`.
104    fn from(repo: &GitRepoInfo) -> Self {
105        Self {
106            url: repo.url.clone(),
107            head: repo.head.clone(),
108            credentials: repo.credentials.clone(),
109            branch: repo.branch.clone(),
110            path: repo.path.clone(),
111        }
112    }
113}
114
115impl From<&GitRepoCloneRequest> for GitRepo {
116    /// Convert from `&GitRepoCloneRequest` to `GitRepo`.
117    fn from(repo: &GitRepoCloneRequest) -> Self {
118        Self {
119            url: repo.url.clone(),
120            head: repo.head.clone(),
121            credentials: repo.credentials.clone(),
122            branch: repo.branch.clone(),
123            path: repo.path.clone(),
124        }
125    }
126}
127
128impl From<GitRepo> for GitRepoCloneRequest {
129    /// Convert from `GitRepo` to `GitRepoCloneRequest`.
130    fn from(repo: GitRepo) -> Self {
131        Self {
132            url: repo.url.clone(),
133            head: repo.head.clone(),
134            credentials: repo.credentials.clone(),
135            branch: repo.branch.clone(),
136            path: repo.path,
137        }
138    }
139}
140
141impl From<&GitRepo> for GitRepoCloneRequest {
142    /// Convert from `GitRepo` to `GitRepoCloneRequest`.
143    fn from(repo: &GitRepo) -> Self {
144        Self {
145            url: repo.url.clone(),
146            head: repo.head.clone(),
147            credentials: repo.credentials.clone(),
148            branch: repo.branch.clone(),
149            path: repo.path.clone(),
150        }
151    }
152}
153
154impl From<&GitRepo> for GitRepoInfo {
155    /// Convert from `GitRepo` to `GitRepoCloneRequest`.
156    fn from(repo: &GitRepo) -> Self {
157        Self {
158            url: repo.url.clone(),
159            head: repo.head.clone(),
160            credentials: repo.credentials.clone(),
161            branch: repo.branch.clone(),
162            path: repo.path.clone(),
163        }
164    }
165}
166impl From<&GitRepoInfo> for GitRepoCloneRequest {
167    /// Convert from `&GitRepoInfo` to `GitRepoCloneRequest`.
168    fn from(repo: &GitRepoInfo) -> Self {
169        Self {
170            url: repo.url.clone(),
171            head: repo.head.clone(),
172            credentials: repo.credentials.clone(),
173            branch: repo.branch.clone(),
174            path: repo.path.clone(),
175        }
176    }
177}
178
179impl From<&GitRepoCloneRequest> for GitRepoInfo {
180    /// Convert from `&GitRepoCloneRequest` to `GitRepoInfo`.
181    fn from(repo: &GitRepoCloneRequest) -> Self {
182        Self {
183            url: repo.url.clone(),
184            head: repo.head.clone(),
185            credentials: repo.credentials.clone(),
186            branch: repo.branch.clone(),
187            path: repo.path.clone(),
188        }
189    }
190}