mirror of
https://github.com/qwjyh/xdbm
synced 2025-04-18 18:55:51 +09:00
new(sync): implement sync subcommand (WIP)
TODO - update CHANGELOG - refactor sync func
This commit is contained in:
parent
47b3a5e69d
commit
9316290d28
6 changed files with 137 additions and 19 deletions
|
@ -63,6 +63,12 @@ pub(crate) enum Commands {
|
|||
Sync {
|
||||
/// Remote name to sync.
|
||||
remote_name: Option<String>,
|
||||
/// Whether to use ssh-agent
|
||||
#[arg(long)]
|
||||
use_sshagent: bool,
|
||||
/// Manually specify ssh key
|
||||
#[arg(long)]
|
||||
ssh_key: Option<PathBuf>,
|
||||
},
|
||||
|
||||
/// Check config files validity.
|
||||
|
|
|
@ -40,9 +40,7 @@ fn clone_repo(
|
|||
}
|
||||
};
|
||||
Cred::ssh_key(
|
||||
username_from_url
|
||||
.context("No username found from the url")
|
||||
.unwrap(),
|
||||
username_from_url.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
None,
|
||||
key as &Path,
|
||||
passwd.as_deref(),
|
||||
|
@ -51,9 +49,7 @@ fn clone_repo(
|
|||
// use ssh agent
|
||||
info!("Using ssh agent to access the repository");
|
||||
Cred::ssh_key_from_agent(
|
||||
username_from_url
|
||||
.context("No username found from the url")
|
||||
.unwrap(),
|
||||
username_from_url.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
)
|
||||
} else {
|
||||
error!("no ssh_key and use_sshagent");
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use git2::Repository;
|
||||
use git2::{Cred, PushOptions, RemoteCallbacks, Repository};
|
||||
|
||||
pub(crate) fn cmd_sync(config_dir: &PathBuf, remote_name: Option<String>) -> Result<()> {
|
||||
pub(crate) fn cmd_sync(
|
||||
config_dir: &PathBuf,
|
||||
remote_name: Option<String>,
|
||||
use_sshagent: bool,
|
||||
ssh_key: Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
warn!("Experimental");
|
||||
let repo = Repository::open(config_dir)?;
|
||||
let remote_name = match remote_name {
|
||||
|
@ -16,7 +21,74 @@ pub(crate) fn cmd_sync(config_dir: &PathBuf, remote_name: Option<String>) -> Res
|
|||
remotes.get(0).unwrap().to_string()
|
||||
}
|
||||
};
|
||||
|
||||
// using credentials
|
||||
let mut callbacks = RemoteCallbacks::new();
|
||||
callbacks
|
||||
.credentials(|_url, username_from_url, _allowed_types| {
|
||||
if let Some(key) = &ssh_key {
|
||||
info!("Using provided ssh key to access the repository");
|
||||
let passwd = match inquire::Password::new("SSH passphrase").prompt() {
|
||||
std::result::Result::Ok(s) => Some(s),
|
||||
Err(err) => {
|
||||
error!("Failed to get ssh passphrase: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
Cred::ssh_key(
|
||||
username_from_url
|
||||
.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
None,
|
||||
key as &Path,
|
||||
passwd.as_deref(),
|
||||
)
|
||||
} else if use_sshagent {
|
||||
// use ssh agent
|
||||
info!("Using ssh agent to access the repository");
|
||||
Cred::ssh_key_from_agent(
|
||||
username_from_url
|
||||
.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
)
|
||||
} else {
|
||||
error!("no ssh_key and use_sshagent");
|
||||
panic!("This option must be unreachable.")
|
||||
}
|
||||
})
|
||||
.push_transfer_progress(|current, total, bytes| {
|
||||
trace!("{current},\t{total},\t{bytes}");
|
||||
});
|
||||
callbacks.push_update_reference(|reference_name, status_msg| {
|
||||
debug!("remote reference_name {reference_name}");
|
||||
match status_msg {
|
||||
None => {
|
||||
info!("successfully pushed");
|
||||
eprintln!("successfully pushed to {}", reference_name);
|
||||
Ok(())
|
||||
}
|
||||
Some(status) => {
|
||||
error!("failed to push: {}", status);
|
||||
Err(git2::Error::from_str(&format!(
|
||||
"failed to push to {}: {}",
|
||||
reference_name, status
|
||||
)))
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut push_options = PushOptions::new();
|
||||
push_options.remote_callbacks(callbacks);
|
||||
let mut remote = repo.find_remote(&remote_name)?;
|
||||
remote.push(&[] as &[&str], None)?;
|
||||
trace!("remote: {:?}", remote.name());
|
||||
if remote.refspecs().len() != 1 {
|
||||
warn!("multiple refspecs found");
|
||||
}
|
||||
trace!("refspec: {:?}", remote.get_refspec(0).unwrap().str());
|
||||
trace!("refspec: {:?}", remote.get_refspec(0).unwrap().direction());
|
||||
trace!("refspec: {:?}", repo.head().unwrap().name());
|
||||
trace!("head is branch: {:?}", repo.head().unwrap().is_branch());
|
||||
trace!("head is remote: {:?}", repo.head().unwrap().is_remote());
|
||||
remote.push(
|
||||
&[repo.head().unwrap().name().unwrap()] as &[&str],
|
||||
Some(&mut push_options),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
40
src/git.rs
Normal file
40
src/git.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use git2::{Cred, RemoteCallbacks};
|
||||
use inquire::Password;
|
||||
|
||||
pub(crate) fn get_credential<'a>(
|
||||
use_sshagent: bool,
|
||||
ssh_key: Option<PathBuf>,
|
||||
) -> RemoteCallbacks<'a> {
|
||||
// using credentials
|
||||
let mut callbacks = RemoteCallbacks::new();
|
||||
callbacks.credentials(move |_url, username_from_url, _allowed_types| {
|
||||
if let Some(key) = &ssh_key {
|
||||
info!("Using provided ssh key to access the repository");
|
||||
let passwd = match Password::new("SSH passphrase").prompt() {
|
||||
std::result::Result::Ok(s) => Some(s),
|
||||
Err(err) => {
|
||||
error!("Failed to get ssh passphrase: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
Cred::ssh_key(
|
||||
username_from_url.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
None,
|
||||
key as &Path,
|
||||
passwd.as_deref(),
|
||||
)
|
||||
} else if use_sshagent {
|
||||
// use ssh agent
|
||||
info!("Using ssh agent to access the repository");
|
||||
Cred::ssh_key_from_agent(
|
||||
username_from_url.ok_or(git2::Error::from_str("No username found from the url"))?,
|
||||
)
|
||||
} else {
|
||||
error!("no ssh_key and use_sshagent");
|
||||
panic!("This option must be unreachable.")
|
||||
}
|
||||
});
|
||||
callbacks
|
||||
}
|
|
@ -35,6 +35,7 @@ mod cmd_status;
|
|||
mod cmd_storage;
|
||||
mod cmd_sync;
|
||||
mod devices;
|
||||
mod git;
|
||||
mod inquire_filepath_completer;
|
||||
mod storages;
|
||||
mod util;
|
||||
|
@ -91,7 +92,11 @@ fn main() -> Result<()> {
|
|||
Commands::Path {} => {
|
||||
println!("{}", &config_dir.display());
|
||||
}
|
||||
Commands::Sync { remote_name } => cmd_sync::cmd_sync(&config_dir, remote_name)?,
|
||||
Commands::Sync {
|
||||
remote_name,
|
||||
use_sshagent,
|
||||
ssh_key,
|
||||
} => cmd_sync::cmd_sync(&config_dir, remote_name, use_sshagent, ssh_key)?,
|
||||
Commands::Status {
|
||||
path,
|
||||
storage,
|
||||
|
|
15
tests/cli.rs
15
tests/cli.rs
|
@ -313,15 +313,14 @@ mod integrated_test {
|
|||
assert!(config_dir_2.join("backups").join("second.yml").exists());
|
||||
|
||||
// sync
|
||||
std::process::Command::new("git")
|
||||
.arg("push")
|
||||
.current_dir(&config_dir_2)
|
||||
Command::cargo_bin("xdbm")?
|
||||
.arg("-c")
|
||||
.arg(config_dir_2.path())
|
||||
.arg("sync")
|
||||
.arg("-vvvv")
|
||||
.assert()
|
||||
.success();
|
||||
// let repo_2 = Repository::open(config_dir_2)?;
|
||||
// // return Err(anyhow!("{:?}", repo_2.remotes()?.iter().collect::<Vec<_>>()));
|
||||
// let mut repo_2_remote = repo_2.find_remote(repo_2.remotes()?.get(0).unwrap())?;
|
||||
// repo_2_remote.push(&[] as &[&str], None)?;
|
||||
.success()
|
||||
.stderr(predicate::str::contains("successfully pushed"));
|
||||
std::process::Command::new("git")
|
||||
.arg("pull")
|
||||
.current_dir(&config_dir_1)
|
||||
|
|
Loading…
Add table
Reference in a new issue