Skip to content

Commit 5378fcf

Browse files
committedJul 5, 2023
🚧
1 parent 443bb88 commit 5378fcf

File tree

2 files changed

+79
-15
lines changed

2 files changed

+79
-15
lines changed
 

‎src/commands/clone.rs

+73-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1-
use std::ffi::OsStr;
1+
use std::path::PathBuf;
22

33
use crossterm::style::{Attribute, Stylize};
4+
use git2::{Cred, RemoteCallbacks, Repository};
45
use miette::{Diagnostic, Result};
56
use tap::Pipe;
67
#[cfg(feature = "profiling")]
78
use tracing::instrument;
89

910
use super::Command;
10-
use crate::{
11-
config::{self, Config},
12-
helpers,
13-
};
11+
use crate::config::{self, Config};
1412

1513
#[derive(thiserror::Error, Diagnostic, Debug)]
1614
enum Error {
17-
#[error("Clone command did not run successfully")]
18-
#[diagnostic(code(clone::command::run))]
19-
CloneExecute(#[from] helpers::RunError),
15+
#[error("Could not create dotfiles directory \"{0}\"")]
16+
#[diagnostic(code(init::dotfiles::create))]
17+
CreatingDir(PathBuf, #[source] std::io::Error),
18+
19+
#[error("Could not clone git repository \"{0}\"")]
20+
#[diagnostic(code(init::git::clone))]
21+
GitClone(PathBuf, #[source] git2::Error),
2022
}
2123

2224
#[derive(Debug)]
@@ -39,6 +41,8 @@ impl Command for Clone {
3941
fn execute(&self, (cli, repo): Self::Args) -> Self::Result {
4042
if !cli.dry_run {
4143
config::create_config_file(cli.dotfiles.as_ref().map(|d| d.0.as_path()), &cli.config.0)?;
44+
45+
std::fs::create_dir_all(&self.config.dotfiles).map_err(|err| Error::CreatingDir(self.config.dotfiles.clone(), err))?;
4246
}
4347

4448
println!(
@@ -49,10 +53,68 @@ impl Command for Clone {
4953
Attribute::Reset
5054
);
5155

52-
helpers::run_command("git", &[OsStr::new("clone"), OsStr::new(&repo), self.config.dotfiles.as_os_str()], false, cli.dry_run)?;
53-
54-
println!("\n{}Cloned repo{}", Attribute::Bold, Attribute::Reset);
56+
if !cli.dry_run {
57+
clone_git_repo(&repo, &self.config.dotfiles).map_err(|err| Error::GitClone(self.config.dotfiles.clone(), err))?;
58+
println!("\n{}Cloned repo{}", Attribute::Bold, Attribute::Reset);
59+
}
5560

5661
().pipe(Ok)
5762
}
5863
}
64+
65+
fn clone_git_repo(repo: &str, dotfiles: &std::path::Path) -> Result<Repository, git2::Error> {
66+
let mut callbacks = RemoteCallbacks::new();
67+
callbacks.credentials(|_url, username_from_url, _allowed_types| Cred::ssh_key_from_agent(username_from_url.unwrap()));
68+
let mut fetch_options = git2::FetchOptions::new();
69+
70+
fetch_options.remote_callbacks(callbacks);
71+
72+
let mut builder = git2::build::RepoBuilder::new();
73+
builder.fetch_options(fetch_options);
74+
75+
builder.clone(repo, dotfiles)?.pipe(Ok)
76+
}
77+
78+
#[cfg(test)]
79+
mod test {
80+
use std::path::Path;
81+
82+
use clap::Parser;
83+
use speculoos::assert_that;
84+
85+
use crate::{cli, commands::Command};
86+
87+
#[test]
88+
fn should_clone_repo() {
89+
let config = crate::config::Config {
90+
dotfiles: Path::new("./target/tmp").to_path_buf(),
91+
..Default::default()
92+
};
93+
94+
let config_file = config.dotfiles.parent().unwrap().join("config.toml");
95+
if config_file.exists() {
96+
std::fs::remove_file(&config_file).unwrap();
97+
}
98+
if config.dotfiles.exists() {
99+
std::fs::remove_dir_all(&config.dotfiles).unwrap();
100+
}
101+
let cli = crate::cli::Cli::parse_from([
102+
"",
103+
"--dotfiles",
104+
&config.dotfiles.to_string_lossy(),
105+
"--config",
106+
&config_file.to_string_lossy(),
107+
"clone",
108+
"git@github.com:volllly/rotz.git",
109+
]);
110+
111+
let clone = super::Clone::new(config.clone());
112+
113+
let cli::Command::Clone { repo } = cli.command.clone() else {
114+
panic!();
115+
};
116+
117+
clone.execute((cli, repo)).unwrap();
118+
assert_that!(Path::new(&config.dotfiles).join(".git")).matches(|p| p.exists() && p.is_dir());
119+
}
120+
}

‎src/commands/init.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl Command for Init {
6464
}
6565
}
6666

67-
fn initialize_git_repo(dotfiles: &PathBuf, options: &RepositoryInitOptions) -> Result<(), git2::Error> {
67+
fn initialize_git_repo(dotfiles: &PathBuf, options: &RepositoryInitOptions) -> Result<Repository, git2::Error> {
6868
let git_repo = Repository::init_opts(dotfiles, options)?;
6969

7070
let sig = git_repo.signature()?;
@@ -74,10 +74,12 @@ fn initialize_git_repo(dotfiles: &PathBuf, options: &RepositoryInitOptions) -> R
7474
index.write_tree()?
7575
};
7676

77-
let tree = git_repo.find_tree(tree_id)?;
78-
git_repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;
77+
{
78+
let tree = git_repo.find_tree(tree_id)?;
79+
git_repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;
80+
}
7981

80-
Ok(())
82+
Ok(git_repo)
8183
}
8284

8385
#[cfg(test)]

0 commit comments

Comments
 (0)