profile

package
v0.17.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: GPL-3.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AddProfileCmd = &cobra.Command{
	Use:   "add <path|url>",
	Short: "Add profile(s) from a local file or URL",
	Long: `Add one or more profiles from a local file, a git repository URL, or a raw file URL.

Local path: the file is validated and registered directly. A repo config
(raid.yaml) is also accepted and registered as a single-repo profile named
after the raid.yaml's ` + "`name`" + ` field — handy for projects that ship
only a raid.yaml without a wrapping profile.

Git URL (git@ prefix, .git suffix, or any HTTP URL that responds to git ls-remote):
  raid shallow-clones the repo and imports *.raid.yaml, *.raid.yml, and profile.json
  files found at the root.

Raw file URL (HTTP/HTTPS URL ending in .yaml, .yml, or .json):
  the file is downloaded, validated, and registered.

Profiles from URLs are saved to ~/<name>.raid.yaml before registration.`,
	Args: cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		return runAddProfileE(cmd, args[0])
	},
}
View Source
var Command = &cobra.Command{
	Use:     "profile",
	Aliases: []string{"p"},
	Short:   "Manage raid profiles",
	Args:    cobra.RangeArgs(0, 1),
	RunE: func(cmd *cobra.Command, args []string) error {
		out := cmd.OutOrStdout()
		json := jsonMode(cmd)

		if len(args) == 0 {
			profile := pro.Get()
			if profile.IsZero() {
				if json {
					return emitJSON(cmd, activeResult{Action: "active"})
				}
				fmt.Fprintln(out, "No active profile found. Use 'raid profile <name>' to set one.")
				return nil
			}
			if json {
				return emitJSON(cmd, activeResult{Action: "active", Name: profile.Name, Path: profile.Path})
			}
			fmt.Fprintln(out, profile.Name)
			return nil
		}

		name := args[0]
		err := raid.WithMutationLock(func() error {
			return pro.Set(name)
		})
		if err != nil {
			return errs.Wrap(err)
		}
		switched := pro.Get()
		if json {
			return emitJSON(cmd, activeResult{Action: "switched", Name: switched.Name, Path: switched.Path})
		}
		fmt.Fprintf(out, "Profile '%s' is now active.\n", name)
		return nil
	},
}
View Source
var CreateProfileCmd = &cobra.Command{
	Use:   "create",
	Short: "Interactively create a new profile",
	Args:  cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runCreateWizardE(cmd, os.Stdin)
	},
}

CreateProfileCmd is the interactive wizard for creating a new profile.

View Source
var ListProfileCmd = &cobra.Command{
	Use:   "list",
	Short: "List profiles",
	RunE: func(cmd *cobra.Command, args []string) error {
		profiles := pro.ListAll()

		sort.Slice(profiles, func(i, j int) bool { return profiles[i].Name < profiles[j].Name })
		activeProfile := pro.Get()

		jsonOutput, _ := cmd.Root().PersistentFlags().GetBool("json")
		if jsonOutput {
			out := make([]profileEntry, 0, len(profiles))
			for _, p := range profiles {
				out = append(out, profileEntry{
					Name:   p.Name,
					Path:   p.Path,
					Active: p.Name == activeProfile.Name,
				})
			}
			enc := json.NewEncoder(cmd.OutOrStdout())
			enc.SetIndent("", "  ")
			return enc.Encode(out)
		}

		if len(profiles) == 0 {
			fmt.Fprintln(cmd.OutOrStdout(), "No profiles found.")
			return nil
		}

		fmt.Fprintln(cmd.OutOrStdout(), "Available profiles:")
		for _, profile := range profiles {
			activeIndicator := ""
			if profile.Name == activeProfile.Name {
				activeIndicator = " (active)"
			}
			fmt.Fprintf(cmd.OutOrStdout(), "\t%s%s\t%s\n", profile.Name, activeIndicator, profile.Path)
		}
		return nil
	},
}
View Source
var RemoveProfileCmd = &cobra.Command{
	Use:        "remove <name>",
	Short:      "Remove profile(s)",
	SuggestFor: []string{"delete"},
	Args:       cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		var removed []string
		var failures []removeResultErr

		// hardErr captures the first non-"not found" failure from pro.Remove
		// (e.g. a config write error). Those represent real failures we must
		// surface; bucketing them with "not found" would hide them behind a
		// PROFILE_NOT_FOUND envelope and a possibly-zero exit on mixed runs.
		var hardErr error
		lockErr := raid.WithMutationLock(func() error {
			for _, name := range args {
				err := pro.Remove(name)
				if err == nil {
					removed = append(removed, name)
					continue
				}
				if rErr, ok := errs.AsError(err); ok && rErr.Code() == errs.CodeProfileNotFound {
					failures = append(failures, removeResultErr{Name: name, Reason: err.Error()})
					continue
				}

				if hardErr == nil {
					hardErr = err
				}
				return nil
			}
			return nil
		})
		if lockErr != nil {
			return errs.Wrap(lockErr)
		}
		if hardErr != nil {
			return errs.Wrap(hardErr)
		}

		// Build the structured-error sentinel (used in both text and JSON
		// modes) so a "every requested profile was missing" run exits with
		// a PROFILE_NOT_FOUND code regardless of output format.
		var allMissingErr error
		if len(removed) == 0 && len(failures) > 0 {
			if len(failures) == 1 {
				allMissingErr = errs.ProfileNotFound(failures[0].Name)
			} else {
				allMissingErr = errs.ProfileNotFound(failures[0].Name + " (and " + fmt.Sprintf("%d", len(failures)-1) + " more)")
			}
		}

		if jsonMode(cmd) {
			if err := emitJSON(cmd, removeResult{Removed: removed, Errors: failures}); err != nil {
				return err
			}

			return allMissingErr
		}

		out := cmd.OutOrStdout()
		for _, name := range removed {
			fmt.Fprintf(out, "Profile '%s' has been removed.\n", name)
		}
		for _, f := range failures {
			fmt.Fprintf(out, "Profile '%s' not found. Use 'raid profile list' to see available profiles.\n", f.Name)
		}
		return allMissingErr
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL