delete added, more details below (#3)
- readme updates - delete command added - commands now saved in a map vs fields - login and run now ensure config has been run to prevent errors Reviewed-on: #3 Co-authored-by: jake <jake.young.dev@gmail.com> Co-committed-by: jake <jake.young.dev@gmail.com>
This commit is contained in:
parent
a9c6400761
commit
f8a9528e0f
@ -10,7 +10,7 @@ go install code.jakeyoungdev.com/jake/mctl@main #it is recommended to use a tagg
|
|||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
### Configuring mctl
|
### Configuring mctl
|
||||||
mctl requires a one-time setup via the 'config' command, password is entered securely from the terminal
|
mctl requires a one-time setup via the 'config' command before interacting with any servers, password is entered securely from the terminal
|
||||||
```bash
|
```bash
|
||||||
mctl config -s <serveraddress> -p <rconport>
|
mctl config -s <serveraddress> -p <rconport>
|
||||||
```
|
```
|
||||||
@ -65,6 +65,12 @@ mctl run test jake
|
|||||||
#will run: tp jake 0 0 0 on remote server
|
#will run: tp jake 0 0 0 on remote server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Delete saved command
|
||||||
|
Commands can be deleted with:
|
||||||
|
```bash
|
||||||
|
mctl delete <name>
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
### Commands
|
### Commands
|
||||||
|Command|Description|
|
|Command|Description|
|
||||||
@ -73,6 +79,7 @@ mctl run test jake
|
|||||||
|login|makes connection request to the server using saved configuration and enters command loop|
|
|login|makes connection request to the server using saved configuration and enters command loop|
|
||||||
|save \<name>|saves specific command for reuse|
|
|save \<name>|saves specific command for reuse|
|
||||||
|view \<name>|displays saved command|
|
|view \<name>|displays saved command|
|
||||||
|
|delete \<name>|deletes saved command|
|
||||||
|run \<name> args...|runs saved command filling placeholders with supplied args|
|
|run \<name> args...|runs saved command filling placeholders with supplied args|
|
||||||
|
|
||||||
### Flags
|
### Flags
|
||||||
|
@ -86,6 +86,11 @@ func initConfig() {
|
|||||||
_, err := rand.Read(uu)
|
_, err := rand.Read(uu)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
|
//create custom command map
|
||||||
|
cmdMap := make(map[string]any, 0)
|
||||||
|
|
||||||
|
//write config
|
||||||
|
viper.Set("customcmd", cmdMap)
|
||||||
viper.Set("device", string(uu))
|
viper.Set("device", string(uu))
|
||||||
viper.SafeWriteConfig()
|
viper.SafeWriteConfig()
|
||||||
}
|
}
|
||||||
|
42
cmd/delete.go
Normal file
42
cmd/delete.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2025 Jake jake.young.dev@gmail.com
|
||||||
|
*/
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// deleteCmd represents the delete command
|
||||||
|
var deleteCmd = &cobra.Command{
|
||||||
|
Use: "delete <name>",
|
||||||
|
Example: "mctl delete newcmd",
|
||||||
|
Short: "Delete a saved command",
|
||||||
|
Long: `Deletes a command stored using the save command`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
var cm map[string]any
|
||||||
|
cmdMap := viper.Get("customcmd")
|
||||||
|
if cmdMap == nil {
|
||||||
|
cm = make(map[string]any, 0)
|
||||||
|
} else {
|
||||||
|
cm = cmdMap.(map[string]any)
|
||||||
|
}
|
||||||
|
delete(cm, args[0])
|
||||||
|
viper.Set("customcmd", cmdMap)
|
||||||
|
viper.WriteConfig()
|
||||||
|
},
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("name argument is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(deleteCmd)
|
||||||
|
}
|
@ -5,6 +5,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ import (
|
|||||||
var loginCmd = &cobra.Command{
|
var loginCmd = &cobra.Command{
|
||||||
Use: "login",
|
Use: "login",
|
||||||
Example: "mctl login",
|
Example: "mctl login",
|
||||||
|
SilenceUsage: true,
|
||||||
Short: "Login to server and send commands",
|
Short: "Login to server and send commands",
|
||||||
Long: `Login to server using saved config and enter command loop
|
Long: `Login to server using saved config and enter command loop
|
||||||
sending commands to server and printing the response.`,
|
sending commands to server and printing the response.`,
|
||||||
@ -54,6 +56,13 @@ var loginCmd = &cobra.Command{
|
|||||||
|
|
||||||
fmt.Printf("Disconnected from %s\n", server)
|
fmt.Printf("Disconnected from %s\n", server)
|
||||||
},
|
},
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
//ensure config command has been run
|
||||||
|
if viper.Get("server") == "" || viper.Get("password") == "" || viper.Get("port") == 0 {
|
||||||
|
return errors.New("the 'config' command must be run before you can interact with servers")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -28,6 +28,5 @@ func Execute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
//dont show completion subcommand in help message, makes the syntax confusing
|
|
||||||
rootCmd.Root().CompletionOptions.DisableDefaultCmd = true
|
|
||||||
}
|
}
|
||||||
|
31
cmd/run.go
31
cmd/run.go
@ -17,12 +17,26 @@ import (
|
|||||||
var runCmd = &cobra.Command{
|
var runCmd = &cobra.Command{
|
||||||
Use: "run <name> args...",
|
Use: "run <name> args...",
|
||||||
Example: "mctl run savedcmd 63 jake",
|
Example: "mctl run savedcmd 63 jake",
|
||||||
|
SilenceUsage: true,
|
||||||
Short: "Runs a previously saved command with supplied arguments on remote server",
|
Short: "Runs a previously saved command with supplied arguments on remote server",
|
||||||
Long: `Loads a saved command, injects the supplied arguments into the command, and sends the command to the remove server
|
Long: `Loads a saved command, injects the supplied arguments into the command, and sends the command to the remove server
|
||||||
printing the response`,
|
printing the response`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
//grab saved command
|
//check for command map
|
||||||
cmdName := viper.Get(fmt.Sprintf("customCmd-%s", args[0])).(string)
|
var cm map[string]any
|
||||||
|
cmdMap := viper.Get("customcmd")
|
||||||
|
if cmdMap == nil {
|
||||||
|
cm = make(map[string]any, 0)
|
||||||
|
} else {
|
||||||
|
cm = cmdMap.(map[string]any)
|
||||||
|
}
|
||||||
|
//is this an existing command
|
||||||
|
cmdRun, ok := cm[args[0]]
|
||||||
|
if !ok {
|
||||||
|
fmt.Printf("command %s not found", args[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//convert arguments to interface
|
//convert arguments to interface
|
||||||
var nargs []any
|
var nargs []any
|
||||||
for _, a := range args[1:] {
|
for _, a := range args[1:] {
|
||||||
@ -30,7 +44,7 @@ var runCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//inject arguments
|
//inject arguments
|
||||||
fixed := fmt.Sprintf(cmdName, nargs...)
|
fixed := fmt.Sprintf(cmdRun.(string), nargs...)
|
||||||
fmt.Printf("Running saved command %s\n", fixed)
|
fmt.Printf("Running saved command %s\n", fixed)
|
||||||
|
|
||||||
//create client and send command
|
//create client and send command
|
||||||
@ -44,13 +58,20 @@ var runCmd = &cobra.Command{
|
|||||||
fmt.Println(res)
|
fmt.Println(res)
|
||||||
},
|
},
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
//ensure configuration has been setup
|
||||||
|
if viper.Get("server") == "" || viper.Get("password") == "" || viper.Get("port") == 0 {
|
||||||
|
return errors.New("the 'config' command must be run before you can interact with servers")
|
||||||
|
}
|
||||||
|
|
||||||
//ensure we have a command name
|
//ensure we have a command name
|
||||||
al := len(args)
|
al := len(args)
|
||||||
if al == 0 {
|
if al == 0 {
|
||||||
return errors.New("name argument is required")
|
return errors.New("name argument is required")
|
||||||
}
|
}
|
||||||
cmdCheck := viper.Get(fmt.Sprintf("customCmd-%s", args[0]))
|
|
||||||
count := strings.Count(cmdCheck.(string), "%s")
|
cmdMap := viper.Get("customcmd").(map[string]any)
|
||||||
|
count := strings.Count(cmdMap[args[0]].(string), "%s")
|
||||||
|
|
||||||
//make sure enough arguments are sent to fill command placeholders
|
//make sure enough arguments are sent to fill command placeholders
|
||||||
if al < count+1 {
|
if al < count+1 {
|
||||||
return fmt.Errorf("not enough arguments to populate command. Supplied: %d, Needed: %d", al-1, count)
|
return fmt.Errorf("not enough arguments to populate command. Supplied: %d, Needed: %d", al-1, count)
|
||||||
|
11
cmd/save.go
11
cmd/save.go
@ -27,10 +27,17 @@ var saveCmd = &cobra.Command{
|
|||||||
if sc.Scan() {
|
if sc.Scan() {
|
||||||
txt := sc.Text()
|
txt := sc.Text()
|
||||||
if txt != "" {
|
if txt != "" {
|
||||||
viper.Set(fmt.Sprintf("customCmd-%s", args[0]), txt)
|
var cmdMap map[string]any
|
||||||
|
cm := viper.Get("customcmd")
|
||||||
|
if cmdMap == nil {
|
||||||
|
cmdMap = make(map[string]any, 0)
|
||||||
|
} else {
|
||||||
|
cmdMap = cm.(map[string]any)
|
||||||
|
}
|
||||||
|
cmdMap[args[0]] = txt
|
||||||
|
viper.Set("customcmd", cmdMap)
|
||||||
viper.WriteConfig()
|
viper.WriteConfig()
|
||||||
fmt.Println("\nSaved!")
|
fmt.Println("\nSaved!")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
16
cmd/view.go
16
cmd/view.go
@ -18,7 +18,21 @@ var viewCmd = &cobra.Command{
|
|||||||
Short: "View saved commands",
|
Short: "View saved commands",
|
||||||
Long: `Load command using the supplied name and displays it in the terminal`,
|
Long: `Load command using the supplied name and displays it in the terminal`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Printf("\nCommand: %s\n", viper.Get(args[0]))
|
var cm map[string]any
|
||||||
|
cmdMap := viper.Get("customcmd")
|
||||||
|
if cmdMap == nil {
|
||||||
|
fmt.Println("no custom commands found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cm = cmdMap.(map[string]any)
|
||||||
|
custom, ok := cm[args[0]]
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("command not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Command: %s", custom.(string))
|
||||||
},
|
},
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user