|
|
@@ -116,16 +116,25 @@ func profileFileName(name string) string {
|
|
|
// keeps a .json argument from also resolving to `lala-json.json`.
|
|
|
func resolveProfileTarget(arg string) (path string, name string, isPath bool) {
|
|
|
if !strings.HasSuffix(strings.ToLower(arg), ".json") {
|
|
|
- return filepath.Join(profilesPath(), profileFileName(arg)), arg, false
|
|
|
+ return profileFilePath(arg), arg, false
|
|
|
}
|
|
|
base := filepath.Base(arg)
|
|
|
return arg, strings.TrimSuffix(base, filepath.Ext(base)), true
|
|
|
}
|
|
|
|
|
|
+// profileFilePath is the file a name maps to, in the per-user directory. It is the
|
|
|
+// name form of resolveProfileTarget on its own, for the commands that take no path
|
|
|
+// at all: `delete` and `list` are name-only, so `delete lava.json` names the
|
|
|
+// profile `lava-json` and not a file, and the one that says which file it removed
|
|
|
+// must not be the one that could remove a file outside the per-user directory.
|
|
|
+func profileFilePath(name string) string {
|
|
|
+ return filepath.Join(profilesPath(), profileFileName(name))
|
|
|
+}
|
|
|
+
|
|
|
// Save writes the profile into the per-user directory under its own name, which is
|
|
|
// what every caller that has a name and no path means.
|
|
|
func (p *Profile) Save() error {
|
|
|
- return p.saveTo(filepath.Join(profilesPath(), profileFileName(p.Name)))
|
|
|
+ return p.saveTo(profileFilePath(p.Name))
|
|
|
}
|
|
|
|
|
|
// saveTo writes the profile to one file and creates the directory it is in. It
|
|
|
@@ -207,15 +216,19 @@ func ListProfiles() ([]string, error) {
|
|
|
return names, nil
|
|
|
}
|
|
|
|
|
|
-func DeleteProfile(name string) error {
|
|
|
- path := filepath.Join(profilesPath(), profileFileName(name))
|
|
|
+// DeleteProfile removes the profile of that name from the per-user directory and
|
|
|
+// returns the file it removed, so a command that reports the deletion says which
|
|
|
+// file it was. A name only: nothing here resolves a path, so an argument ending in
|
|
|
+// .json names the profile `lava-json`.
|
|
|
+func DeleteProfile(name string) (string, error) {
|
|
|
+ path := profileFilePath(name)
|
|
|
if err := os.Remove(path); err != nil {
|
|
|
if os.IsNotExist(err) {
|
|
|
- return fmt.Errorf("profile %s not found in %s", name, profilesPath())
|
|
|
+ return "", fmt.Errorf("profile %s not found in %s", name, profilesPath())
|
|
|
}
|
|
|
- return fmt.Errorf("delete profile %s: %w", name, err)
|
|
|
+ return "", fmt.Errorf("delete profile %s: %w", name, err)
|
|
|
}
|
|
|
- return nil
|
|
|
+ return path, nil
|
|
|
}
|
|
|
|
|
|
func sanitizeFilename(name string) string {
|
|
|
@@ -302,6 +315,14 @@ func savedProfileLine(name, path string) string {
|
|
|
return fmt.Sprintf("Saved profile %s to %s\n", name, describeDataDir(path))
|
|
|
}
|
|
|
|
|
|
+// deletedProfileLine is what a delete says it did, in the same words as the save:
|
|
|
+// the name and the file it removed, and the file annotated as the user's when that
|
|
|
+// is where it was. A delete that printed nothing is a command that has run and
|
|
|
+// cannot be told apart from one that removed something else.
|
|
|
+func deletedProfileLine(name, path string) string {
|
|
|
+ return fmt.Sprintf("Deleted profile %s from %s\n", name, describeDataDir(path))
|
|
|
+}
|
|
|
+
|
|
|
func NewProfileSaveCmd() *cobra.Command {
|
|
|
return &cobra.Command{
|
|
|
Use: "save [name|file]",
|
|
|
@@ -531,19 +552,26 @@ func NewProfileListCmd() *cobra.Command {
|
|
|
}
|
|
|
|
|
|
func NewProfileDeleteCmd() *cobra.Command {
|
|
|
- var name string
|
|
|
cmd := &cobra.Command{
|
|
|
ValidArgsFunction: completeProfileNames,
|
|
|
Use: "delete [name]",
|
|
|
Short: "Delete a saved profile",
|
|
|
- Args: cobra.MaximumNArgs(1),
|
|
|
+ Long: "Delete a profile from the per-user profiles/ directory, by name; without a\n" +
|
|
|
+ "name it deletes `default`. A path is not accepted, so an argument ending in\n" +
|
|
|
+ ".json names the profile without the dots rather than a file to remove. It\n" +
|
|
|
+ "reports the file it removed.",
|
|
|
+ Args: cobra.MaximumNArgs(1),
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
- if len(args) == 0 {
|
|
|
- name = "default"
|
|
|
- } else {
|
|
|
+ name := "default"
|
|
|
+ if len(args) > 0 {
|
|
|
name = args[0]
|
|
|
}
|
|
|
- return DeleteProfile(name)
|
|
|
+ path, err := DeleteProfile(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ fmt.Fprint(cmd.OutOrStdout(), deletedProfileLine(name, path))
|
|
|
+ return nil
|
|
|
},
|
|
|
}
|
|
|
return cmd
|