From 1a810aaa44edd643802afc0d39ddfd9360df6385 Mon Sep 17 00:00:00 2001 From: Peter Simonsson Date: Thu, 8 Feb 2024 17:55:21 +0100 Subject: [PATCH] Add a clone repository command Add a command to clone a git repository in the the first search path and create a session for the cloned repository. --- README.md | 22 +++++++++---------- src/cli.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 43 +++++++++++++++++++++--------------- 3 files changed, 98 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 498216e..d0a625a 100644 --- a/README.md +++ b/README.md @@ -67,21 +67,21 @@ Using this command you can automatically generate missing worktree windows for t Use `tms --help` ``` -Scan for all git folders in specified directories, select one and open it as a new tmux session +Scan for all git folders in specified directorires, select one and open it as a new tmux session Usage: tms [COMMAND] Commands: - config Configure the defaults for search paths and excluded directories - start Initialize tmux with the default sessions - switch Display other sessions with a fuzzy finder and a preview window - windows Display the current session's windows with a fuzzy finder and a preview window - kill Kill the current tmux session and jump to another - sessions Show running tmux sessions with asterisk on the current session - rename Rename the active session and the working directory - refresh Creates new worktree windows for the selected session - help Print this message or the help of the given subcommand(s) - + config Configure the defaults for search paths and excluded directories + start Initialize tmux with the default sessions + switch Display other sessions with a fuzzy finder and a preview window + windows Display the current session's windows with a fuzzy finder and a preview window + kill Kill the current tmux session and jump to another + sessions Show running tmux sessions with asterisk on the current session + rename Rename the active session and the working directory + refresh Creates new worktree windows for the selected session + clone-repo Clone repository into the first search path and create a new session for it + help Print this message or the help of the given subcommand(s) Options: -h, --help Print help diff --git a/src/cli.rs b/src/cli.rs index 4a910c0..584c5fd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,7 +4,8 @@ use crate::{ configs::SearchDirectory, configs::{Config, SessionSortOrderConfig}, dirty_paths::DirtyUtf8Path, - execute_command, execute_tmux_command, get_single_selection, TmsError, + execute_command, execute_tmux_command, get_single_selection, session_exists, set_up_tmux_env, + switch_to_session, TmsError, }; use clap::{Args, Parser, Subcommand}; use error_stack::{Result, ResultExt}; @@ -38,6 +39,8 @@ pub enum CliCommand { Rename(RenameCommand), /// Creates new worktree windows for the selected session Refresh(RefreshCommand), + /// Clone repository into the first search path and create a new session for it + CloneRepo(CloneRepoCommand), } #[derive(Debug, Args)] @@ -99,6 +102,12 @@ pub struct RefreshCommand { name: Option, } +#[derive(Debug, Args)] +pub struct CloneRepoCommand { + /// Git repository to clone + repository: String, +} + impl Cli { pub(crate) fn handle_sub_commands(&self) -> Result { // Get the configuration from the config file @@ -147,6 +156,12 @@ impl Cli { refresh_command(args)?; Ok(SubCommandGiven::Yes) } + + Some(CliCommand::CloneRepo(args)) => { + clone_repo_command(args, config)?; + Ok(SubCommandGiven::Yes) + } + None => Ok(SubCommandGiven::No(config.into())), } } @@ -561,6 +576,52 @@ fn refresh_command(args: &RefreshCommand) -> Result<(), TmsError> { Ok(()) } +fn clone_repo_command(args: &CloneRepoCommand, config: Config) -> Result<(), TmsError> { + let search_dirs = config + .search_dirs + .ok_or(TmsError::ConfigError) + .attach_printable("No search path configured")?; + let mut path = search_dirs + .first() + .ok_or(TmsError::ConfigError) + .attach_printable("No search path configured")? + .path + .clone(); + + let (_, repo_name) = args + .repository + .rsplit_once('/') + .expect("Repository path contains '/'"); + let repo_name = repo_name.trim_end_matches(".git"); + path.push(repo_name); + + let repo = Repository::clone(&args.repository, &path).change_context(TmsError::GitError)?; + + let mut session_name = repo_name.to_string(); + + if session_exists(&session_name) { + session_name = format!( + "{}/{}", + path.parent() + .unwrap() + .file_name() + .expect("The file name doesn't end in `..`") + .to_string()?, + session_name + ); + } + + execute_tmux_command(&format!( + "tmux new-session -ds {} -c {}", + session_name, + path.display() + )); + set_up_tmux_env(&repo, &session_name)?; + switch_to_session(&session_name); + + Ok(()) +} + pub enum SubCommandGiven { Yes, No(Box), diff --git a/src/main.rs b/src/main.rs index bebd9bf..381b680 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,34 +110,41 @@ fn main() -> Result<(), TmsError> { repo_name }; - // Get the tmux sessions - let sessions = String::from_utf8(execute_tmux_command("tmux list-sessions -F #S").stdout) - .expect("The tmux command static string should always be valid utf-8"); - let mut sessions = sessions.lines(); - - // If the session already exists switch to it, else create the new session and then switch - let session_previously_existed = sessions.any(|line| { - // tmux will return the output with extra ' and \n characters - line.to_owned().retain(|char| char != '\'' && char != '\n'); - line == repo_short_name - }); - if !session_previously_existed { + if !session_exists(&repo_short_name) { execute_tmux_command(&format!( "tmux new-session -ds {repo_short_name } -c {path}", )); set_up_tmux_env(found_repo, &repo_short_name)?; } + switch_to_session(&repo_short_name); + + Ok(()) +} + +pub(crate) fn switch_to_session(repo_short_name: &str) { if !is_in_tmux_session() { execute_tmux_command(&format!("tmux attach -t {repo_short_name}")); - return Ok(()); + } else { + let result = execute_tmux_command(&format!("tmux switch-client -t {repo_short_name}")); + if !result.status.success() { + execute_tmux_command(&format!("tmux attach -t {repo_short_name}")); + } } +} - let result = execute_tmux_command(&format!("tmux switch-client -t {repo_short_name}")); - if !result.status.success() { - execute_tmux_command(&format!("tmux attach -t {repo_short_name}")); - } - Ok(()) +pub(crate) fn session_exists(repo_short_name: &str) -> bool { + // Get the tmux sessions + let sessions = String::from_utf8(execute_tmux_command("tmux list-sessions -F #S").stdout) + .expect("The tmux command static string should always be valid utf-8"); + let mut sessions = sessions.lines(); + + // If the session already exists switch to it, else create the new session and then switch + sessions.any(|line| { + // tmux will return the output with extra ' and \n characters + line.to_owned().retain(|char| char != '\'' && char != '\n'); + line == repo_short_name + }) } pub(crate) fn set_up_tmux_env(repo: &Repository, repo_name: &str) -> Result<(), TmsError> {