summaryrefslogtreecommitdiff
path: root/src/bin/git-autosave.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/git-autosave.rs')
-rw-r--r--src/bin/git-autosave.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/bin/git-autosave.rs b/src/bin/git-autosave.rs
new file mode 100644
index 0000000..3df94b6
--- /dev/null
+++ b/src/bin/git-autosave.rs
@@ -0,0 +1,113 @@
+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(())
+}