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

Issue:
pier rename/mv subcommand
## Example usage
`pier rename <original> <new>`
with the alias:
`pier mv <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 45372b0..5a2da1b 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -20,6 +20,10 @@ pub enum CliSubcommand {
         /// Set which tags the script belongs to.
         #[structopt(short = "t", long = "tag")]
         tags: Option<Vec<String>>,
+
+        /// Allows to overwrite the existing script
+        #[structopt(short = "f", long = "force")]
+        force: bool,
     },
     /// alias: rm - Remove a script matching alias.
     #[structopt(alias = "rm")]
@@ -76,11 +80,24 @@ pub enum CliSubcommand {
         #[structopt(short = "t", long = "tag")]
         tags: Option<Vec<String>>,
     },
-    // Copy existing alias to the new one
+    /// alias: cp - Copy existing alias to the new one
     #[structopt(alias = "cp")]
     Copy {
+        /// The alias of the script that will be copied.
+        from_alias: String,
+        /// The new alias of the copy of the script.
+        to_alias: String,
+    },
+    /// alias: mv, rename - Move/rename existing alias to the new one
+    #[structopt(aliases = &["mv", "rename"])]
+    Move {
+        /// The alias of the script that will be moved.
         from_alias: String,
+        /// The new alias of the script.
         to_alias: String,
+        /// Allows to overwrite the existing script
+        #[structopt(short = "f", long = "force")]
+        force: bool,
     },
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index db251cb..6616387 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -53,7 +53,7 @@ impl Pier {
             description: Some(String::from("This is an example command.")),
             reference: None,
             tags: None,
-        });
+        }, false);
 
         self.write()?;
 
@@ -136,13 +136,16 @@ impl Pier {
     }
 
     /// Adds a script that matches the alias
-    pub fn add_script(&mut self, script: Script) -> Result<()> {
-        ensure!(
-            !&self.config.scripts.contains_key(&script.alias),
-            AliasAlreadyExists {
-                alias: script.alias
-            }
-        );
+    pub fn add_script(&mut self, script: Script, force: bool) -> Result<()> {
+        if !force {
+            ensure!(
+                !&self.config.scripts.contains_key(&script.alias),
+                AliasAlreadyExists {
+                    alias: script.alias
+                }
+            );
+        }
+
         println!("Added {}", &script.alias);
 
         self.config.scripts.insert(script.alias.to_string(), script);
@@ -205,6 +208,35 @@ impl Pier {
         Ok(())
     }
 
+    /// Move a script that matches the alias to another alias
+    pub fn move_script(&mut self, from_alias: &str, new_alias: &str, force: bool) -> Result<()> {
+        if !force {
+            ensure!(
+                !&self.config.scripts.contains_key(&new_alias.to_string()),
+                AliasAlreadyExists { alias: new_alias }
+            );
+        }
+
+        let script = self
+            .config
+            .scripts
+            .remove(&from_alias.to_string())
+            .context(AliasNotFound {
+                alias: &from_alias.to_string(),
+            })?
+            .clone();
+
+        println!(
+            "Move 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,
@@ -271,7 +303,7 @@ impl Pier {
                         script_tags.join(", "),
                         "",
                         script.display_command(cmd_full, width)
-                        
+
                     ]);
 
                     continue;
diff --git a/src/main.rs b/src/main.rs
index 75a672e..7845c13 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -36,6 +36,7 @@ fn handle_subcommands(cli: Cli) -> Result<Option<process::ExitStatus>> {
                 alias,
                 description,
                 tags,
+                force,
             } => {
                 let mut pier = Pier::from(cli.opts.path, cli.opts.verbose)?;
                 pier.add_script(Script {
@@ -47,7 +48,7 @@ fn handle_subcommands(cli: Cli) -> Result<Option<process::ExitStatus>> {
                     },
                     tags,
                     reference: None,
-                })?;
+                }, force)?;
                 pier.write()?;
             }
 
@@ -96,6 +97,15 @@ fn handle_subcommands(cli: Cli) -> Result<Option<process::ExitStatus>> {
                 pier.copy_script(&from_alias, &to_alias)?;
                 pier.write()?;
             }
+            CliSubcommand::Move {
+                from_alias,
+                to_alias,
+                force,
+            } => {
+                let mut pier = Pier::from(cli.opts.path, cli.opts.verbose)?;
+                pier.move_script(&from_alias, &to_alias, force)?;
+                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 6827cb8..d10a5c2 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -191,6 +191,21 @@ pier_test!(cli => test_add_script, cfg => CONFIG_1,
     );
 });
 
+// Tests adding a script with forcing
+pier_test!(cli => test_add_script_force_script, cfg => CONFIG_1,
+| cfg: ChildPath, mut cmd: Command | {
+    cmd.args(&["add", r#"echo test_3"#, "-a", "test_cmd_1", "-d", "Test Description.", "-f"]);
+    cmd.assert().success();
+
+    cfg.assert(contains(trim!(r#"
+        [scripts.test_cmd_1]
+        alias = 'test_cmd_1'
+        command = 'echo test_3'
+        description = 'Test Description.'
+    "#)).trim()
+    );
+});
+
 // Tests copying a script
 pier_test!(cli => test_copy_script, cfg => CONFIG_1,
 | cfg: ChildPath, mut cmd: Command | {
@@ -205,6 +220,46 @@ pier_test!(cli => test_copy_script, cfg => CONFIG_1,
     );
 });
 
+// Tests moving a script
+pier_test!(cli => test_move_script, cfg => CONFIG_1,
+| cfg: ChildPath, mut cmd: Command | {
+    cmd.args(&["move", "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()
+    );
+    cfg.assert(contains(trim!(r#"
+            [scripts.test_cmd_1]
+            alias = 'test_cmd_1'
+            command = 'echo test_1'
+        "#)).trim().not()
+    );
+});
+
+// Tests moving a script with forcing
+pier_test!(cli => test_move_with_force_script, cfg => CONFIG_1,
+| cfg: ChildPath, mut cmd: Command | {
+    cmd.args(&["move", "test_cmd_1", "test_cmd_2", "-f"]);
+    cmd.assert().success();
+
+    cfg.assert(contains(trim!(r#"
+            [scripts.test_cmd_2]
+            alias = 'test_cmd_1'
+            command = 'echo test_1'
+        "#)).trim()
+    );
+    cfg.assert(contains(trim!(r#"
+            [scripts.test_cmd_1]
+            alias = 'test_cmd_1'
+            command = 'echo test_1'
+        "#)).trim().not()
+    );
+});
+
 // Tests removing a script
 pier_test!(cli => test_remove_script, cfg => CONFIG_1,
 | cfg: ChildPath, mut cmd: Command | {
diff --git a/tests/error_handling.rs b/tests/error_handling.rs
index f0c2db8..06f17ae 100644
--- a/tests/error_handling.rs
+++ b/tests/error_handling.rs
@@ -34,7 +34,19 @@ command = 'echo test_1'
     reference: None,
     tags: None
     };
-    err_eq!(lib.add_script(script), AliasAlreadyExists);
+    err_eq!(lib.add_script(script, false), AliasAlreadyExists);
+});
+
+pier_test!(lib => test_error_alias_already_exists_on_move, cfg => r#"
+[scripts.test_cmd_1]
+alias = 'test_cmd_1'
+command = 'echo test_1'
+
+[scripts.test_cmd_2]
+alias = 'test_cmd_2'
+command = 'echo test_2'
+"#, | _cfg: ChildPath, mut lib: Pier | {
+    err_eq!(lib.move_script("test_cmd_1", "test_cmd_2",  false), AliasAlreadyExists);
 });
 
 // Tests that it returns the error ConfigRead if the file cannot be read.