Repository: pier-cli/pier (language: rust)

Issue:
Pier copy/cp subcommand
## Example usage
`pier copy <original> <new>`
with the alias:
`pier cp <original> <new>`

### Warnings
The subcommand should not allow you to write over an existing script, but we could perhaps add a `-f` / `--force` flag. This is something that could be useful for the add command as well.


Discussion / hints:

Fix patch:
diff --git a/src/cli.rs b/src/cli.rs
index f113328..c00bb21 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -77,6 +77,12 @@ pub enum CliSubcommand {
         #[structopt(short = "t", long = "tag")]
         tags: Option<Vec<String>>,
     },
+    // Copy existing alias to the new one
+    #[structopt(alias = "cp")]
+    Copy {
+        from_alias: String,
+        to_alias: String,
+    }
 }
 
 #[derive(StructOpt, Debug)]
diff --git a/src/lib.rs b/src/lib.rs
index 6df93e9..c616e0a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -175,6 +175,34 @@ impl Pier {
         Ok(())
     }
 
+/// Copy an alias a script that matches the alias
+    pub fn copy_script(
+        &mut self,
+        from_alias: &str,
+        new_alias: &str
+    ) -> Result<()> {
+        ensure!(!&self.config.scripts.contains_key(&new_alias.to_string()),
+            AliasAlreadyExists {
+                alias: new_alias
+            }
+        );
+
+        // TODO: refactor the line below.
+        let script = self
+            .config
+            .scripts
+            .get(&from_alias.to_string())
+            .context(AliasNotFound {
+                alias: &from_alias.to_string(),
+            })?.clone();
+
+        println!("Copy from alias {} to new alias {}", &from_alias.to_string(), &new_alias.to_string());
+
+        self.config.scripts.insert(new_alias.to_string(), script);
+
+        Ok(())
+    }
+
     /// Prints a terminal table of the scripts in current config file that matches tags.
     pub fn list_scripts(
         &self,
diff --git a/src/main.rs b/src/main.rs
index e0cbc42..fae9c33 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -88,6 +88,11 @@ fn handle_subcommands(cli: Cli) -> Result<Option<process::ExitStatus>> {
                 let exit_code = pier.run_script(&alias, args)?;
                 return Ok(Some(exit_code));
             }
+            CliSubcommand::Copy { from_alias, to_alias } => {
+                let mut pier = Pier::from(cli.opts.path, cli.opts.verbose)?;
+                pier.copy_script(&from_alias, &to_alias)?;
+                pier.write()?;
+            }
         };
     } else {
         let alias = &cli.alias.expect("Alias is required unless subcommand.");


Test patch:
diff --git a/tests/cli.rs b/tests/cli.rs
index be2aa57..fcb271f 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -8,12 +8,12 @@ use std::process::Command;
 const CONFIG_1: &'static str = r#"
 [scripts.test_cmd_1]
 alias = 'test_cmd_1'
-command = 'echo test_1' 
+command = 'echo test_1'
 tags = ['info', 'echo', 'grp_1']
 
 [scripts.test_cmd_2]
 alias = 'test_cmd_2'
-command = 'echo test_2' 
+command = 'echo test_2'
 tags = ['debug', 'echo']
 
 [scripts.test_success]
@@ -191,6 +191,20 @@ pier_test!(cli => test_add_script, cfg => CONFIG_1,
     );
 });
 
+// Tests copying a script
+pier_test!(cli => test_copy_script, cfg => CONFIG_1,
+    | cfg: ChildPath, mut cmd: Command | {
+        cmd.args(&["copy", "test_cmd_1", "test_cmd_4"]);
+        cmd.assert().success();
+
+        cfg.assert(contains(trim!(r#"
+            [scripts.test_cmd_4]
+            alias = 'test_cmd_1'
+            command = 'echo test_1'
+        "#)).trim()
+        );
+    });
+
 // Tests removing a script
 pier_test!(cli => test_remove_script, cfg => CONFIG_1,
 | cfg: ChildPath, mut cmd: Command | {