use std::path::Path;
use auth_git2::{GitAuthenticator, Prompter};
use git_autosave::{Config, commit_autosave, push_autosaves};
use git2::{RemoteCallbacks, Repository};
use inquire::{InquireError, PasswordDisplayMode};
#[derive(Default, Debug, Clone, PartialEq, Eq)]
struct Inquirer(Config);
fn config_value(git_config: &git2::Config, name: &str) -> Option<String> {
git_config
.get_entry(name)
.ok()
.and_then(|entry| entry.value().map(|entry| entry.to_string()))
}
fn prompt_secret(message: &str) -> Result<String, InquireError> {
inquire::Password::new(message)
.without_confirmation()
.with_display_mode(PasswordDisplayMode::Masked)
.prompt()
}
impl Prompter for Inquirer {
fn prompt_username_password(
&mut self,
url: &str,
git_config: &git2::Config,
) -> Option<(String, String)> {
let username = self
.0
.username_for_url(url)
.cloned()
.or_else(|| config_value(git_config, "autosave.username"));
let password = self
.0
.password_for_url(url)
.cloned()
.or_else(|| config_value(git_config, "autosave.password"));
if let Some(username) = username
&& let Some(password) = password
{
return Some((username, password));
}
println!("Authenticating to {url}");
let username = inquire::prompt_text("Username:").ok()?;
let password = prompt_secret("Password:").ok()?;
Some((username, password))
}
fn prompt_password(
&mut self,
username: &str,
url: &str,
git_config: &git2::Config,
) -> Option<String> {
let password = self
.0
.password_for_url(url)
.cloned()
.or_else(|| config_value(git_config, "autosave.password"));
if let Some(password) = password {
return Some(password);
}
println!("Authenticating to {url}");
prompt_secret(&format!("Password for {username}:")).ok()
}
fn prompt_ssh_key_passphrase(
&mut self,
private_key_path: &Path,
git_config: &git2::Config,
) -> Option<String> {
let password = self
.0
.passphrase_for_key(private_key_path)
.cloned()
.or_else(|| config_value(git_config, "autosave.password"));
if let Some(password) = password {
return Some(password);
}
prompt_secret(&format!(
"Passphrase for {}:",
private_key_path.to_string_lossy()
))
.ok()
}
}
fn main() -> Result<(), anyhow::Error> {
let repository = Repository::discover(".")?;
let gitconfig = repository.config()?;
let mut config = git_autosave::load_config()?;
if std::env::args().any(|arg| arg == "--init") {
git_autosave::init(&repository, Some(&mut config))?;
git_autosave::save_config(&config)?;
}
let auth = GitAuthenticator::new().set_prompter(Inquirer(config));
let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(auth.credentials(&gitconfig));
commit_autosave(&repository)?;
push_autosaves(&repository, callbacks)?;
Ok(())
}
|