| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- package main
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "github.com/spf13/cobra"
- )
- var rootCmd = &cobra.Command{
- Use: "dev",
- Short: "Development script runner",
- Long: "A CLI tool for managing and running development scripts",
- RunE: func(cmd *cobra.Command, args []string) error {
- return cmd.Help()
- },
- }
- var runCmd = &cobra.Command{
- Use: "run [script-filters...] [-- script-args...]",
- Short: "Run scripts matching filters (or all if no filters)",
- Long: `Run scripts matching filters. Use -- to pass arguments to scripts.
- Scripts marked with "# REQUIRES: sudo" will automatically run with elevated privileges.
- Examples:
- dev run tools/dev.sh # Run specific script
- dev run tools/dev.sh -- arg1 arg2 # Run with arguments
- dev run --verbose install -- --force # Run with flags
- `,
- ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- if err := ensureRunsDir(); err != nil {
- return nil, cobra.ShellCompDirectiveNoFileComp
- }
- scripts, err := findScripts(nil)
- if err != nil {
- return nil, cobra.ShellCompDirectiveNoFileComp
- }
- var completions []string
- for _, script := range scripts {
- desc := script.Desc
- if script.RequiresSudo {
- desc = desc + " [SUDO]"
- }
- completions = append(completions, fmt.Sprintf("%s\t%s", script.RelPath, desc))
- }
- return completions, cobra.ShellCompDirectiveNoFileComp
- },
- RunE: func(cmd *cobra.Command, args []string) error {
- // Parse arguments manually to handle -- separator
- var filters []string
- var scriptArgs []string
- // Find "run" command position and -- separator in raw args
- cmdPos := -1
- separatorPos := -1
- rawArgs := os.Args
- for i, arg := range rawArgs {
- if arg == "run" {
- cmdPos = i
- break
- }
- }
- if cmdPos >= 0 {
- for i := cmdPos + 1; i < len(rawArgs); i++ {
- if rawArgs[i] == "--" {
- separatorPos = i
- break
- }
- }
- }
- if separatorPos >= 0 {
- // Get everything between 'run' and '--' as filters
- filters = rawArgs[cmdPos+1 : separatorPos]
- // Remove any flags from filters
- for i := 0; i < len(filters); i++ {
- if strings.HasPrefix(filters[i], "-") {
- filters = append(filters[:i], filters[i+1:]...)
- i--
- }
- }
- // Get everything after '--' as script args
- scriptArgs = rawArgs[separatorPos+1:]
- } else {
- // No '--' separator found, consider all non-flag args as filters
- for _, arg := range args {
- if !strings.HasPrefix(arg, "-") {
- filters = append(filters, arg)
- }
- }
- }
- if err := ensureRunsDir(); err != nil {
- return err
- }
- scripts, err := findScripts(filters)
- if err != nil {
- return err
- }
- if len(scripts) == 0 {
- if len(filters) > 0 {
- warn("No scripts match filters: %s", strings.Join(filters, ", "))
- } else {
- warn("No scripts found. Use 'dev new <name>' to create one")
- }
- return nil
- }
- for _, script := range scripts {
- if config.DryRun {
- argsStr := ""
- if len(scriptArgs) > 0 {
- argsStr = fmt.Sprintf(" with args: %s", strings.Join(scriptArgs, " "))
- }
- sudoStr := ""
- if script.RequiresSudo {
- sudoStr = " (with sudo)"
- }
- log("Would run: %s%s%s", script.RelPath, argsStr, sudoStr)
- } else {
- if err := executeScript(script, scriptArgs, config.Verbose); err != nil {
- errorLog("❌ %s failed", script.RelPath)
- if !config.Verbose {
- fmt.Printf(" Check log: %s\n", filepath.Join(config.LogsDir, strings.TrimSuffix(script.Name, filepath.Ext(script.Name))+".log"))
- }
- } else {
- if script.RequiresSudo {
- sudoLog("✅ %s completed (elevated)", script.RelPath)
- } else {
- log("✅ %s completed", script.RelPath)
- }
- }
- }
- }
- return nil
- },
- }
- var listCmd = &cobra.Command{
- Use: "ls",
- Aliases: []string{"list"},
- Short: "List all available scripts",
- RunE: func(cmd *cobra.Command, args []string) error {
- if err := ensureRunsDir(); err != nil {
- return err
- }
- scripts, err := findScripts(nil)
- if err != nil {
- return err
- }
- if len(scripts) == 0 {
- warn("No scripts found in %s", config.RunsDir)
- fmt.Println("Use 'dev new <n>' to create a new script")
- return nil
- }
- fmt.Printf("Available scripts in %s:\n\n", config.RunsDir)
- for _, script := range scripts {
- if script.RequiresSudo {
- fmt.Printf(" %s%s%s - %s %s[SUDO]%s\n",
- Blue, script.RelPath, NC, script.Desc, Purple, NC)
- } else {
- fmt.Printf(" %s%s%s - %s\n",
- Blue, script.RelPath, NC, script.Desc)
- }
- }
- sudoCount := 0
- for _, script := range scripts {
- if script.RequiresSudo {
- sudoCount++
- }
- }
- fmt.Printf("\nTotal: %d scripts", len(scripts))
- if sudoCount > 0 {
- fmt.Printf(" (%d require elevated privileges)", sudoCount)
- }
- fmt.Println()
- return nil
- },
- }
- var newCmd = &cobra.Command{
- Use: "new <name>",
- Short: "Create a new script template",
- Args: cobra.ExactArgs(1),
- RunE: func(cmd *cobra.Command, args []string) error {
- return createNewScript(args[0])
- },
- }
- var pushCmd = &cobra.Command{
- Use: "push",
- Aliases: []string{"u", "ush"},
- Short: "Commit, scan for secrets, and push to git origin",
- RunE: func(cmd *cobra.Command, args []string) error {
- return handlePush()
- },
- }
- var depsCmd = &cobra.Command{
- Use: "deps",
- Short: "Install dependencies",
- RunE: func(cmd *cobra.Command, args []string) error {
- return checkDependencies()
- },
- }
- var completionCmd = &cobra.Command{
- Use: "completion [bash|zsh|fish]",
- Short: "Generate completion script",
- Long: `To load completions:
- Bash:
- $ source <(dev completion bash)
- # To load completions for each session, execute once:
- # Linux:
- $ dev completion bash > /etc/bash_completion.d/dev
- # macOS:
- $ dev completion bash > $(brew --prefix)/etc/bash_completion.d/dev
- Zsh:
- # If shell completion is not already enabled in your environment,
- # you will need to enable it. You can execute the following once:
- $ echo "autoload -U compinit; compinit" >> ~/.zshrc
- # To load completions for each session, execute once:
- $ dev completion zsh > "${fpath[1]}/_dev"
- # You will need to start a new shell for this setup to take effect.
- `,
- DisableFlagsInUseLine: true,
- ValidArgs: []string{"bash", "zsh", "fish"},
- Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
- RunE: func(cmd *cobra.Command, args []string) error {
- switch args[0] {
- case "bash":
- return rootCmd.GenBashCompletion(os.Stdout)
- case "zsh":
- return rootCmd.GenZshCompletion(os.Stdout)
- case "fish":
- return rootCmd.GenFishCompletion(os.Stdout, true)
- }
- return nil
- },
- }
|