feat: add ability to specify custom command #56

Merged
kjuulh merged 2 commits from feat/add-ability-to-specify-custom-command into main 2025-01-08 22:45:34 +01:00
5 changed files with 97 additions and 17 deletions

View File

@ -4,6 +4,7 @@ use crate::{
app::App, app::App,
cache::CacheApp, cache::CacheApp,
components::inline_command::InlineCommand, components::inline_command::InlineCommand,
custom_command::CustomCommandApp,
fuzzy_matcher::{FuzzyMatcher, FuzzyMatcherApp}, fuzzy_matcher::{FuzzyMatcher, FuzzyMatcherApp},
git_clone::GitCloneApp, git_clone::GitCloneApp,
git_provider::Repository, git_provider::Repository,
@ -118,6 +119,11 @@ impl RootCommand {
tracing::info!("repository already exists"); tracing::info!("repository already exists");
} }
self.app
.custom_command()
.execute_post_update_command(&project_path)
.await?;
if shell { if shell {
self.app.shell().spawn_shell(&repo).await?; self.app.shell().spawn_shell(&repo).await?;
} else { } else {

View File

@ -23,7 +23,7 @@ impl<'a> Spinner<'a> {
} }
} }
impl<'a> StatefulWidget for Spinner<'a> { impl StatefulWidget for Spinner<'_> {
type State = SpinnerState; type State = SpinnerState;
fn render( fn render(

View File

@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use anyhow::Context; use anyhow::Context;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Config { pub struct Config {
#[serde(default)] #[serde(default)]
pub settings: Settings, pub settings: Settings,
@ -12,16 +12,34 @@ pub struct Config {
pub providers: Providers, pub providers: Providers,
} }
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Settings { pub struct Settings {
#[serde(default)] #[serde(default)]
pub projects: Projects, pub projects: Projects,
#[serde(default)] #[serde(default)]
pub cache: Cache, pub cache: Cache,
pub post_update_command: Option<PostUpdateCommand>,
} }
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum PostUpdateCommand {
Single(String),
Multiple(Vec<String>),
}
impl PostUpdateCommand {
pub fn get_commands(&self) -> Vec<String> {
match self.clone() {
PostUpdateCommand::Single(item) => vec![item],
PostUpdateCommand::Multiple(items) => items,
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Projects { pub struct Projects {
pub directory: ProjectLocation, pub directory: ProjectLocation,
} }
@ -57,7 +75,7 @@ impl std::ops::Deref for ProjectLocation {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Cache { pub struct Cache {
#[serde(default)] #[serde(default)]
pub location: CacheLocation, pub location: CacheLocation,
@ -89,7 +107,7 @@ impl Default for CacheLocation {
} }
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)] #[serde(untagged)]
pub enum CacheDuration { pub enum CacheDuration {
Enabled(bool), Enabled(bool),
@ -131,7 +149,7 @@ impl Default for CacheDuration {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Providers { pub struct Providers {
#[serde(default)] #[serde(default)]
pub github: Vec<GitHub>, pub github: Vec<GitHub>,
@ -139,7 +157,7 @@ pub struct Providers {
pub gitea: Vec<Gitea>, pub gitea: Vec<Gitea>,
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHub { pub struct GitHub {
#[serde(default)] #[serde(default)]
pub url: Option<String>, pub url: Option<String>,
@ -155,7 +173,7 @@ pub struct GitHub {
pub organisations: Vec<GitHubOrganisation>, pub organisations: Vec<GitHubOrganisation>,
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHubUser(String); pub struct GitHubUser(String);
impl From<GitHubUser> for String { impl From<GitHubUser> for String {
@ -170,7 +188,7 @@ impl<'a> From<&'a GitHubUser> for &'a str {
} }
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHubOrganisation(String); pub struct GitHubOrganisation(String);
impl From<GitHubOrganisation> for String { impl From<GitHubOrganisation> for String {
@ -185,7 +203,7 @@ impl<'a> From<&'a GitHubOrganisation> for &'a str {
} }
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Gitea { pub struct Gitea {
pub url: String, pub url: String,
@ -201,21 +219,21 @@ pub struct Gitea {
pub organisations: Vec<GiteaOrganisation>, pub organisations: Vec<GiteaOrganisation>,
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)] #[serde(untagged)]
pub enum GiteaAccessToken { pub enum GiteaAccessToken {
Direct(String), Direct(String),
Env { env: String }, Env { env: String },
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)] #[serde(untagged)]
pub enum GitHubAccessToken { pub enum GitHubAccessToken {
Direct(String), Direct(String),
Env { env: String }, Env { env: String },
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GiteaUser(String); pub struct GiteaUser(String);
impl From<GiteaUser> for String { impl From<GiteaUser> for String {
@ -230,7 +248,7 @@ impl<'a> From<&'a GiteaUser> for &'a str {
} }
} }
#[derive(Debug, Serialize, Deserialize, PartialEq)] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GiteaOrganisation(String); pub struct GiteaOrganisation(String);
impl From<GiteaOrganisation> for String { impl From<GiteaOrganisation> for String {
fn from(value: GiteaOrganisation) -> Self { fn from(value: GiteaOrganisation) -> Self {
@ -361,7 +379,8 @@ mod test {
}, },
projects: Projects { projects: Projects {
directory: PathBuf::from("git").into() directory: PathBuf::from("git").into()
} },
post_update_command: None,
} }
}, },
config config
@ -386,7 +405,8 @@ mod test {
}, },
settings: Settings { settings: Settings {
cache: Cache::default(), cache: Cache::default(),
projects: Projects::default() projects: Projects::default(),
post_update_command: None,
} }
}, },
config config

View File

@ -0,0 +1,53 @@
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 {
for command in post_update_command.get_commands() {
let command_parts = command.split(' ').collect::<Vec<_>>();
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);
eprintln!("running command: {}", command);
tracing::info!(
path = path.display().to_string(),
cmd = 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())
}
}

View File

@ -15,6 +15,7 @@ mod cache_codec;
mod commands; mod commands;
mod components; mod components;
mod config; mod config;
mod custom_command;
mod fuzzy_matcher; mod fuzzy_matcher;
mod git_clone; mod git_clone;
mod git_provider; mod git_provider;