Files
2024-07-17 01:37:59 -06:00

171 lines
4.0 KiB
Go

package cmd
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"github.com/activecm/rita/v5/config"
"github.com/activecm/rita/v5/database"
"github.com/manifoldco/promptui"
"github.com/spf13/afero"
"github.com/urfave/cli/v2"
)
var ErrTrimmedNameEmpty = errors.New("trimmed name cannot contain wildcards or be empty")
var DeleteCommand = &cli.Command{
Name: "delete",
Usage: "delete a dataset",
UsageText: "delete [NAME]",
Description: "if <dataset name> ends in a wildcard, all datasets with that prefix will be deleted",
Args: false,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "non-interactive",
Aliases: []string{"ni"},
Usage: "does not prompt for confirmation of deletion",
Value: false,
Required: false,
},
ConfigFlag(false),
},
Action: func(cCtx *cli.Context) error {
// check if too many arguments were provided
if cCtx.NArg() > 1 {
return ErrTooManyArguments
}
// check if a database name was provided
if !cCtx.Args().Present() {
return ErrMissingDatabaseName
}
input := cCtx.Args().First()
// trim leading and trailing wildcards
trimmedName, err := TrimWildcards(input)
if err != nil {
return err
}
// set up file system interface
afs := afero.NewOsFs()
// validate the trimmed name
if err := ValidateDatabaseName(trimmedName); err != nil {
return err
}
prompt := true
if cCtx.Bool("non-interactive") {
prompt = false
}
// load config file
cfg, err := config.ReadFileConfig(afs, cCtx.String("config"))
if err != nil {
return err
}
// run the delete command
if err := RunDeleteCmd(cfg, input, trimmedName, prompt); err != nil {
return err
}
// check for updates after running the command
if err := CheckForUpdate(cfg); err != nil {
return err
}
return nil
},
}
func RunDeleteCmd(cfg *config.Config, entry string, trimmedName string, ask bool) error {
// validate the trimmed name
if len(trimmedName) == 0 {
return ErrTrimmedNameEmpty
}
// connect to server
server, err := database.ConnectToServer(context.Background(), cfg)
if err != nil {
return err
}
// set uo prompt for confirmation
prompt := promptui.Prompt{
Label: "Delete Dataset",
IsConfirm: true,
}
wildcardStart := strings.HasPrefix(entry, "*")
wildcardEnd := strings.HasSuffix(entry, "*")
if wildcardStart || wildcardEnd {
fmt.Printf("Deleting databases matching: %s\n", entry)
switch {
case wildcardStart && !wildcardEnd:
fmt.Printf("Deleting databases ending with: %s\n", trimmedName)
case !wildcardStart && wildcardEnd:
fmt.Printf("Deleting databases beginning with: %s\n", trimmedName)
case wildcardStart && wildcardEnd:
fmt.Printf("Deleting databases containing: %s\n", trimmedName)
default:
return errors.New("unable to determine wildcard status for dataset deletion")
}
if ask {
if _, err := prompt.Run(); err != nil {
fmt.Println("Cancelling deletion...")
return err
}
}
numDeleted, err := server.DropMultipleSensorDatabases(trimmedName, wildcardStart, wildcardEnd)
if err != nil {
return err
}
if numDeleted == 0 {
fmt.Println("Found no matching datasets to delete.")
} else {
fmt.Println("Successfully deleted", numDeleted, "datasets")
}
} else {
fmt.Printf("Deleting database: %s\n", entry)
if ask {
if _, err := prompt.Run(); err != nil {
fmt.Println("Cancelling deletion...")
return err
}
}
if err := server.DeleteSensorDB(entry); err != nil {
return err
}
fmt.Println("Successfully deleted dataset if it existed.")
}
return nil
}
// TrimWildcards removes leading and trailing wildcards from a database name
func TrimWildcards(dbName string) (string, error) {
// regex to remove leading and trailing wildcards
re := regexp.MustCompile(`^\*+|\*+$`)
trimmedName := re.ReplaceAllString(dbName, "")
// check if the trimmed name contains any wildcards or is empty
if strings.Contains(trimmedName, "*") || len(trimmedName) == 0 {
return "", ErrTrimmedNameEmpty
}
return trimmedName, nil
}