Replaced git library with calls to git binary
This commit is contained in:
30
src/main.rs
30
src/main.rs
@@ -10,6 +10,7 @@ use strum::{EnumIter, IntoEnumIterator};
|
||||
enum MainMenu {
|
||||
Install,
|
||||
Collect,
|
||||
Pull,
|
||||
Diff,
|
||||
Upload,
|
||||
Quit
|
||||
@@ -18,8 +19,9 @@ enum MainMenu {
|
||||
impl ToString for MainMenu {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
MainMenu::Install => "Pull and install files",
|
||||
MainMenu::Install => "Install files",
|
||||
MainMenu::Collect => "Collect files",
|
||||
MainMenu::Pull => "Pull from git",
|
||||
MainMenu::Diff => "View git diff",
|
||||
MainMenu::Upload => "(Commit) and push to git",
|
||||
MainMenu::Quit => "Exit"
|
||||
@@ -28,14 +30,10 @@ impl ToString for MainMenu {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let repo = match repository::open_repo() {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
println!("Failed to open/clone repo!");
|
||||
println!("{}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !repository::open_repo() {
|
||||
println!("Failed to open/clone repo!");
|
||||
return;
|
||||
}
|
||||
|
||||
if !std::path::Path::new("repo/mod.toml").exists() {
|
||||
println!("'mod.toml' doesn't exist!");
|
||||
@@ -54,17 +52,11 @@ fn main() {
|
||||
'main_loop: loop {
|
||||
let res = prompt::select(Some("What do you want to do?"), MainMenu::iter().collect());
|
||||
match res {
|
||||
MainMenu::Install => {
|
||||
if let Err(err) = repository::pull_repo(&repo) {
|
||||
println!("Failed to pull repo!");
|
||||
println!("{}", err);
|
||||
return;
|
||||
}
|
||||
operations::install(&mods);
|
||||
},
|
||||
MainMenu::Install => operations::install(&mods),
|
||||
MainMenu::Collect => operations::collect(&mods),
|
||||
MainMenu::Diff => { std::process::Command::new("git").arg("diff").current_dir("repo").spawn().unwrap().wait().unwrap(); },
|
||||
MainMenu::Upload => operations::upload(&repo),
|
||||
MainMenu::Pull => repository::pull_repo(),
|
||||
MainMenu::Diff => repository::diff(),
|
||||
MainMenu::Upload => operations::upload(),
|
||||
MainMenu::Quit => break 'main_loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,10 +104,15 @@ pub fn collect(config: &ModToml) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upload(repo: &git2::Repository) {
|
||||
if !crate::repository::is_clean(repo) {
|
||||
pub fn upload() {
|
||||
if !crate::repository::is_clean() {
|
||||
let msg = crate::prompt::input("Commit message");
|
||||
crate::repository::commit_changes(repo, msg);
|
||||
if !crate::repository::commit_changes(&msg) {
|
||||
println!("Failed to commit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !crate::repository::push_repo() {
|
||||
println!("Failed to push to origin");
|
||||
}
|
||||
crate::repository::push_repo(repo).expect("Failed to push to origin");
|
||||
}
|
||||
|
||||
@@ -1,131 +1,90 @@
|
||||
use std::path::Path;
|
||||
use git2::Repository;
|
||||
use std::process::{Command, ExitStatus};
|
||||
use std::io::Result;
|
||||
|
||||
fn generate_callbacks(use_ssh_agent: bool, pb: &mut indicatif::ProgressBar) -> git2::RemoteCallbacks {
|
||||
let mut callbacks = git2::RemoteCallbacks::new();
|
||||
trait HadSuccess {
|
||||
fn success(self) -> bool;
|
||||
}
|
||||
|
||||
if use_ssh_agent {
|
||||
callbacks.credentials(|_, username, _| git2::Cred::ssh_key_from_agent(username.unwrap()));
|
||||
} else {
|
||||
callbacks.credentials(|_, username, _| git2::Cred::ssh_key(
|
||||
username.unwrap(),
|
||||
None,
|
||||
Path::new(&format!("{}/.ssh/id_rsa", std::env::var("HOME").unwrap_or_default())),
|
||||
None
|
||||
));
|
||||
impl HadSuccess for Result<ExitStatus> {
|
||||
fn success(self) -> bool {
|
||||
self.map_or(false, |status| status.success())
|
||||
}
|
||||
}
|
||||
|
||||
callbacks.transfer_progress(|progress| {
|
||||
if progress.total_deltas() == 0 {
|
||||
pb.set_length(progress.total_objects().max(1) as u64);
|
||||
pb.set_position(progress.received_objects() as u64);
|
||||
pb.set_message("Receiving objects");
|
||||
impl HadSuccess for &mut Command {
|
||||
fn success(self) -> bool {
|
||||
self.status().success()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! git {
|
||||
() => { Command::new("git").current_dir(Path::new("repo")) };
|
||||
([], $arg:expr) => { git!().arg($arg) };
|
||||
([], $arg:expr, $($args:expr),+) => { git!([], $($args),+).arg($arg) };
|
||||
([$first:expr $(, $rest:expr)*], $($reversed:expr),*) => { git!([$($rest),*], $first $(, $reversed)*) };
|
||||
($($args:expr),+) => { git!([$($args),+],) };
|
||||
}
|
||||
|
||||
fn check_or_set_config(key: &str, value: &str) -> bool {
|
||||
if let Ok(status) = git!("config", "--local", "--get", key).status() {
|
||||
if status.success() {
|
||||
true
|
||||
} else if status.code().unwrap_or(2) == 1 {
|
||||
git!("config", "--local", key, value).success()
|
||||
} else {
|
||||
pb.set_length(progress.total_deltas().max(1) as u64);
|
||||
pb.set_position(progress.total_objects() as u64);
|
||||
pb.set_message("Resolving deltas");
|
||||
false
|
||||
}
|
||||
true
|
||||
});
|
||||
callbacks.push_transfer_progress(|cur, tot, _| {
|
||||
pb.set_length(tot.max(1) as u64);
|
||||
pb.set_position(cur as u64);
|
||||
});
|
||||
|
||||
callbacks
|
||||
}
|
||||
|
||||
fn _clone_repo(callbacks: git2::RemoteCallbacks) -> Result<Repository, git2::Error> {
|
||||
let mut fo = git2::FetchOptions::new();
|
||||
fo.remote_callbacks(callbacks);
|
||||
|
||||
let mut builder = git2::build::RepoBuilder::new();
|
||||
builder.fetch_options(fo);
|
||||
|
||||
builder.clone(
|
||||
"git@ssh.gitlab.mattv.de:root/dotfiles.git",
|
||||
Path::new("repo")
|
||||
)
|
||||
}
|
||||
|
||||
fn clone_repo() -> Result<Repository, git2::Error> {
|
||||
println!("Cloning repo...");
|
||||
let mut pb = indicatif::ProgressBar::new(1);
|
||||
pb.set_style(indicatif::ProgressStyle::with_template("{spinner} [{wide_bar}] {pos:>7}/{len:7} {msg}").unwrap().progress_chars("#>-"));
|
||||
_clone_repo(generate_callbacks(true, &mut pb))
|
||||
.or_else(|_| _clone_repo(generate_callbacks(false, &mut pb)))
|
||||
}
|
||||
|
||||
fn _pull_repo(repo: &Repository, callbacks: git2::RemoteCallbacks) -> Result<(), git2::Error> {
|
||||
let mut fo = git2::FetchOptions::new();
|
||||
fo.remote_callbacks(callbacks);
|
||||
|
||||
let mut co = git2::build::CheckoutBuilder::new();
|
||||
co.force();
|
||||
|
||||
repo.find_remote("origin").unwrap().fetch(&["main"], Some(&mut fo), None)?;
|
||||
|
||||
let mut commits = vec![];
|
||||
repo.fetchhead_foreach(|name, url, oid, was_merge| if was_merge { commits.push(repo.annotated_commit_from_fetchhead(name, &String::from_utf8_lossy(url), oid)); true} else { true })?;
|
||||
let commits = commits.into_iter().collect::<Result<Vec<_>, git2::Error>>()?;
|
||||
if commits.is_empty() {
|
||||
panic!("Failed to get heads from origin!");
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
repo.merge(commits.iter().collect::<Vec<_>>().as_slice(), None, Some(&mut co))
|
||||
}
|
||||
|
||||
pub fn pull_repo(repo: &Repository) -> Result<(), git2::Error> {
|
||||
fn check_config() -> bool {
|
||||
check_or_set_config("user.name", "Mutzi")
|
||||
&& check_or_set_config("user.email", "root@mattv.de")
|
||||
}
|
||||
|
||||
fn clone_repo() -> bool {
|
||||
println!("Cloning repo...");
|
||||
if !Path::new("repo").exists() { std::fs::create_dir("repo").unwrap(); }
|
||||
git!("clone", "git@ssh.gitlab.mattv.de:root/dotfiles.git", ".").success()
|
||||
&& check_config()
|
||||
}
|
||||
|
||||
pub fn pull_repo() {
|
||||
println!("Pulling repo...");
|
||||
let mut pb = indicatif::ProgressBar::new(1);
|
||||
pb.set_style(indicatif::ProgressStyle::with_template("{spinner} [{wide_bar}] {pos:>7}/{len:7} {msg}").unwrap().progress_chars("#>-"));
|
||||
_pull_repo(repo, generate_callbacks(true, &mut pb))
|
||||
.or_else(|_| _pull_repo(repo, generate_callbacks(false, &mut pb)))
|
||||
git!("pull").success();
|
||||
}
|
||||
|
||||
fn _push_repo(repo: &Repository, callbacks: git2::RemoteCallbacks) -> Result<(), git2::Error> {
|
||||
let mut pu = git2::PushOptions::new();
|
||||
pu.remote_callbacks(callbacks);
|
||||
|
||||
let mut remote = repo.find_remote("origin").unwrap();
|
||||
|
||||
remote.push::<&str>(&["refs/heads/main:refs/heads/main"], Some(&mut pu))
|
||||
}
|
||||
|
||||
pub fn push_repo(repo: &Repository) -> Result<(), git2::Error> {
|
||||
pub fn push_repo() -> bool {
|
||||
println!("Pushing repo...");
|
||||
let mut pb = indicatif::ProgressBar::new(1);
|
||||
pb.set_style(indicatif::ProgressStyle::with_template("{spinner} [{wide_bar}] {bytes}/{total_bytes} {msg}").unwrap().progress_chars("#>-"));
|
||||
_push_repo(repo, generate_callbacks(true, &mut pb))
|
||||
.or_else(|_| _push_repo(repo, generate_callbacks(false, &mut pb)))
|
||||
git!("push").success()
|
||||
}
|
||||
|
||||
pub fn open_repo() -> Result<Repository, String> {
|
||||
Repository::open("repo")
|
||||
.or_else(|_| clone_repo())
|
||||
.map_err(|e| e.message().to_string())
|
||||
pub fn open_repo() -> bool {
|
||||
Path::new("repo/.git").exists() || clone_repo()
|
||||
}
|
||||
|
||||
pub fn is_clean(repo: &Repository) -> bool {
|
||||
let mut so = git2::StatusOptions::new();
|
||||
so.show(git2::StatusShow::IndexAndWorkdir);
|
||||
so.include_untracked(true);
|
||||
so.include_ignored(false);
|
||||
so.include_unmodified(false);
|
||||
|
||||
repo.statuses(Some(&mut so)).map_or(false, |s| s.is_empty())
|
||||
pub fn is_clean() -> bool {
|
||||
if let Ok(output) = git!("status", "--porcelain").output() {
|
||||
if output.status.success() {
|
||||
output.stdout.is_empty()
|
||||
} else {
|
||||
println!("Failed to get status:\n{}", String::from_utf8(output.stderr).unwrap());
|
||||
false
|
||||
}
|
||||
} else {
|
||||
println!("Failed to get status");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_changes(repo: &Repository, msg: String) {
|
||||
let sig = git2::Signature::now("Mutzi", "root@mattv.de").unwrap();
|
||||
|
||||
let mut index = repo.index().unwrap();
|
||||
index.add_all(["*"], git2::IndexAddOption::DEFAULT, None).unwrap();
|
||||
|
||||
let tree_id = index.write_tree().unwrap();
|
||||
let tree = repo.find_tree(tree_id).unwrap();
|
||||
let parent_id = repo.refname_to_id("HEAD").unwrap();
|
||||
let parent = repo.find_commit(parent_id).unwrap();
|
||||
|
||||
repo.commit(Some("HEAD"), &sig, &sig, msg.as_str(), &tree, &[&parent]).unwrap();
|
||||
pub fn commit_changes(msg: &str) -> bool {
|
||||
git!("add", ".").success()
|
||||
&& git!("commit", "-m", msg).success()
|
||||
}
|
||||
|
||||
pub fn diff() {
|
||||
git!("diff").success();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user