From 3d51e909ded49c4d70acd07c6810d01ebc736336 Mon Sep 17 00:00:00 2001 From: Naoki Ikeguchi Date: Tue, 22 Nov 2022 21:41:00 +0900 Subject: [PATCH 1/2] feat: Open an application after cloning --- src/application.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++ src/cmd/clone.rs | 28 ++++++++++++++++------ src/config.rs | 3 +++ src/main.rs | 1 + 4 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 src/application.rs diff --git a/src/application.rs b/src/application.rs new file mode 100644 index 0000000..92daa66 --- /dev/null +++ b/src/application.rs @@ -0,0 +1,59 @@ +use std::collections::HashMap; +use std::ops::Deref; +use std::path::Path; +use std::process::Command; + +use anyhow::{anyhow, Result}; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Application { + cmd: String, + args: Vec, +} + +impl Application { + pub fn open

(&self, path: P) -> Result<()> + where + P: AsRef, + { + let _ = Command::new(&self.cmd) + .args( + self.args + .iter() + .map(|arg| match arg.as_str() { + "%p" => path.as_ref().to_string_lossy().to_string(), + _ => arg.to_string(), + }) + .collect::>(), + ) + .spawn()?; + + Ok(()) + } +} + +#[derive(Debug, Default, Deserialize)] +pub struct Applications { + #[serde(flatten)] + map: HashMap, +} + +impl Applications { + pub fn open

(&self, name: &str, path: P) -> Result<()> + where + P: AsRef, + { + self.get(name) + .ok_or_else(|| anyhow!("Application entry does not exists."))? + .open(path) + } +} + +impl Deref for Applications { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.map + } +} diff --git a/src/cmd/clone.rs b/src/cmd/clone.rs index 3da443d..3b4cf1f 100644 --- a/src/cmd/clone.rs +++ b/src/cmd/clone.rs @@ -23,6 +23,10 @@ pub struct Cmd { /// Change directory after cloned a repository (Shell extension required). #[clap(long)] cd: bool, + + /// Opens the directory after cloned a repository. + #[clap(long)] + open: Option, } impl Cmd { @@ -41,18 +45,13 @@ impl Cmd { }); let url = Url::from_str(&self.repo)?; - let path = Path::resolve(&root, &url); + let path = PathBuf::from(Path::resolve(&root, &url)); let profile = config .rules .resolve(&url) .and_then(|r| config.profiles.resolve(&r.profile)); - let repo = Repository::clone(&url.to_string(), PathBuf::from(&path))?; - if let Some((name, p)) = profile { - p.apply(&mut repo.config()?)?; - - info!("Attached profile [{}] successfully.", style(name).bold()); - } + let repo = Repository::clone(&url.to_string(), &path)?; tx.send(())?; progress.await?; @@ -62,6 +61,21 @@ impl Cmd { repo.workdir().unwrap().to_string_lossy(), ); + if let Some((name, p)) = profile { + p.apply(&mut repo.config()?)?; + + info!("Attached profile [{}] successfully.", style(name).bold()); + } + + if let Some(app) = self.open { + config.applications.open(&app, &path)?; + + info!( + "Opened the repository in [{}] successfully.", + style(&app).bold(), + ); + } + Ok(()) } } diff --git a/src/config.rs b/src/config.rs index 8594321..de22edb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,6 +3,7 @@ use std::fs::read_to_string; use anyhow::Result; use serde::Deserialize; +use crate::application::Applications; use crate::profile::Profiles; use crate::root::Root; use crate::rule::Rules; @@ -12,6 +13,8 @@ pub struct Config { #[serde(default)] pub profiles: Profiles, #[serde(default)] + pub applications: Applications, + #[serde(default)] pub rules: Rules, } diff --git a/src/main.rs b/src/main.rs index 9aab097..486fdf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod application; mod cmd; mod config; mod console; From 2b7e2295d981cc16d7b07664b89831ac835d75e4 Mon Sep 17 00:00:00 2001 From: Naoki Ikeguchi Date: Tue, 22 Nov 2022 21:45:07 +0900 Subject: [PATCH 2/2] feat: Add `ghr open` command --- README.md | 1 + src/cmd/delete.rs | 2 +- src/cmd/mod.rs | 4 ++++ src/cmd/open.rs | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/cmd/open.rs diff --git a/README.md b/README.md index 0e815c5..fb11f91 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Commands: clone Clones a Git repository to local delete Deletes a repository from local init Initialises a Git repository in local + open Opens a repository in an application path Prints the path to root, owner, or a repository profile Manages profiles to use in repositories shell Writes a shell script to extend ghr features diff --git a/src/cmd/delete.rs b/src/cmd/delete.rs index 9ae96a3..8537a0a 100644 --- a/src/cmd/delete.rs +++ b/src/cmd/delete.rs @@ -16,7 +16,7 @@ use crate::url::Url; #[derive(Debug, Parser)] pub struct Cmd { - /// URL or pattern of the repository to clone. + /// URL or pattern of the repository to delete. repo: String, } diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index a76a029..4e1ea59 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -2,6 +2,7 @@ mod cd; mod clone; mod delete; mod init; +mod open; mod path; mod profile; mod shell; @@ -19,6 +20,8 @@ pub enum Action { Delete(delete::Cmd), /// Initialises a Git repository in local. Init(init::Cmd), + /// Opens a repository in an application. + Open(open::Cmd), /// Prints the path to root, owner, or a repository. Path(path::Cmd), /// Manages profiles to use in repositories. @@ -41,6 +44,7 @@ impl Cli { Clone(cmd) => cmd.run().await, Delete(cmd) => cmd.run().await, Init(cmd) => cmd.run(), + Open(cmd) => cmd.run(), Path(cmd) => cmd.run(), Profile(cmd) => cmd.run(), Shell(cmd) => cmd.run(), diff --git a/src/cmd/open.rs b/src/cmd/open.rs new file mode 100644 index 0000000..16f86ea --- /dev/null +++ b/src/cmd/open.rs @@ -0,0 +1,33 @@ +use std::path::PathBuf; +use std::str::FromStr; + +use anyhow::Result; +use clap::Parser; + +use crate::config::Config; +use crate::path::Path; +use crate::root::Root; +use crate::url::Url; + +#[derive(Debug, Parser)] +pub struct Cmd { + /// URL or pattern of the repository to open application in. + repo: String, + + /// Name of the application entry. + application: String, +} + +impl Cmd { + pub fn run(self) -> Result<()> { + let root = Root::find()?; + let config = Config::load_from(&root)?; + + let url = Url::from_str(&self.repo)?; + let path = PathBuf::from(Path::resolve(&root, &url)); + + config.applications.open(&self.application, path)?; + + Ok(()) + } +}