From 708f8d638841121dc116ba72220ba281c803e425 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Wed, 8 Jan 2025 22:32:27 +0100 Subject: [PATCH] feat: add ability to specify custom command --- crates/gitnow/src/commands/root.rs | 6 +++ crates/gitnow/src/components/spinner.rs | 2 +- crates/gitnow/src/config.rs | 36 ++++++++++-------- crates/gitnow/src/custom_command.rs | 49 +++++++++++++++++++++++++ crates/gitnow/src/main.rs | 1 + 5 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 crates/gitnow/src/custom_command.rs diff --git a/crates/gitnow/src/commands/root.rs b/crates/gitnow/src/commands/root.rs index 65e0335..3434dd9 100644 --- a/crates/gitnow/src/commands/root.rs +++ b/crates/gitnow/src/commands/root.rs @@ -4,6 +4,7 @@ use crate::{ app::App, cache::CacheApp, components::inline_command::InlineCommand, + custom_command::CustomCommandApp, fuzzy_matcher::{FuzzyMatcher, FuzzyMatcherApp}, git_clone::GitCloneApp, git_provider::Repository, @@ -118,6 +119,11 @@ impl RootCommand { tracing::info!("repository already exists"); } + self.app + .custom_command() + .execute_post_update_command(&project_path) + .await?; + if shell { self.app.shell().spawn_shell(&repo).await?; } else { diff --git a/crates/gitnow/src/components/spinner.rs b/crates/gitnow/src/components/spinner.rs index eee74f4..383a370 100644 --- a/crates/gitnow/src/components/spinner.rs +++ b/crates/gitnow/src/components/spinner.rs @@ -23,7 +23,7 @@ impl<'a> Spinner<'a> { } } -impl<'a> StatefulWidget for Spinner<'a> { +impl StatefulWidget for Spinner<'_> { type State = SpinnerState; fn render( diff --git a/crates/gitnow/src/config.rs b/crates/gitnow/src/config.rs index cbf9dd9..2664fcb 100644 --- a/crates/gitnow/src/config.rs +++ b/crates/gitnow/src/config.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use anyhow::Context; use serde::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Config { #[serde(default)] pub settings: Settings, @@ -12,16 +12,18 @@ pub struct Config { pub providers: Providers, } -#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)] pub struct Settings { #[serde(default)] pub projects: Projects, #[serde(default)] pub cache: Cache, + + pub post_update_command: Option, } -#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)] pub struct Projects { pub directory: ProjectLocation, } @@ -57,7 +59,7 @@ impl std::ops::Deref for ProjectLocation { } } -#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)] pub struct Cache { #[serde(default)] pub location: CacheLocation, @@ -89,7 +91,7 @@ impl Default for CacheLocation { } } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(untagged)] pub enum CacheDuration { Enabled(bool), @@ -131,7 +133,7 @@ impl Default for CacheDuration { } } -#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)] pub struct Providers { #[serde(default)] pub github: Vec, @@ -139,7 +141,7 @@ pub struct Providers { pub gitea: Vec, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct GitHub { #[serde(default)] pub url: Option, @@ -155,7 +157,7 @@ pub struct GitHub { pub organisations: Vec, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct GitHubUser(String); impl From for String { @@ -170,7 +172,7 @@ impl<'a> From<&'a GitHubUser> for &'a str { } } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct GitHubOrganisation(String); impl From for String { @@ -185,7 +187,7 @@ impl<'a> From<&'a GitHubOrganisation> for &'a str { } } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Gitea { pub url: String, @@ -201,21 +203,21 @@ pub struct Gitea { pub organisations: Vec, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(untagged)] pub enum GiteaAccessToken { Direct(String), Env { env: String }, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(untagged)] pub enum GitHubAccessToken { Direct(String), Env { env: String }, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct GiteaUser(String); impl From for String { @@ -230,7 +232,7 @@ impl<'a> From<&'a GiteaUser> for &'a str { } } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct GiteaOrganisation(String); impl From for String { fn from(value: GiteaOrganisation) -> Self { @@ -361,7 +363,8 @@ mod test { }, projects: Projects { directory: PathBuf::from("git").into() - } + }, + post_update_command: None, } }, config @@ -386,7 +389,8 @@ mod test { }, settings: Settings { cache: Cache::default(), - projects: Projects::default() + projects: Projects::default(), + post_update_command: None, } }, config diff --git a/crates/gitnow/src/custom_command.rs b/crates/gitnow/src/custom_command.rs new file mode 100644 index 0000000..5643786 --- /dev/null +++ b/crates/gitnow/src/custom_command.rs @@ -0,0 +1,49 @@ +use std::path::Path; + +use crate::{app::App, config::Config}; + +pub struct CustomCommand { + config: Config, +} + +impl CustomCommand { + pub fn new(config: Config) -> Self { + Self { config } + } + + pub async fn execute_post_update_command(&self, path: &Path) -> anyhow::Result<()> { + if let Some(post_update_command) = &self.config.settings.post_update_command { + let command_parts = post_update_command.split(' ').collect::>(); + let Some((first, rest)) = command_parts.split_first() else { + return Ok(()); + }; + + let mut cmd = tokio::process::Command::new(first); + cmd.args(rest).current_dir(path); + + tracing::info!( + path = path.display().to_string(), + cmd = post_update_command, + "running custom post update command" + ); + let output = cmd.output().await?; + let stdout = std::str::from_utf8(&output.stdout)?; + tracing::info!( + stdout = stdout, + "finished running custom post update command" + ); + } + + Ok(()) + } +} + +pub trait CustomCommandApp { + fn custom_command(&self) -> CustomCommand; +} + +impl CustomCommandApp for App { + fn custom_command(&self) -> CustomCommand { + CustomCommand::new(self.config.clone()) + } +} diff --git a/crates/gitnow/src/main.rs b/crates/gitnow/src/main.rs index 9a596fd..cd7f057 100644 --- a/crates/gitnow/src/main.rs +++ b/crates/gitnow/src/main.rs @@ -15,6 +15,7 @@ mod cache_codec; mod commands; mod components; mod config; +mod custom_command; mod fuzzy_matcher; mod git_clone; mod git_provider;