diff --git a/cmd/main.go b/cmd/main.go index 4cf9c0f..f47a218 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,5 +1,5 @@ /* -Copyright © 2024 NAME HERE +Copyright © 2024 Xiao Cui */ package main diff --git a/go.mod b/go.mod index 4fc54bb..d07b602 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/ebitengine/purego v0.6.0-alpha.5 // indirect github.com/fatih/color v1.17.0 // indirect github.com/google/uuid v1.5.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -55,7 +56,7 @@ require ( github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/cobra v1.8.1 - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.5 golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 ) diff --git a/go.sum b/go.sum index ce2d709..5496c43 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,7 @@ github.com/DataDog/sketches-go v1.4.5/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= @@ -30,6 +31,7 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -64,9 +66,11 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= diff --git a/pkg/commands/root/root.go b/pkg/commands/root/root.go index 4c01c59..665f3a0 100644 --- a/pkg/commands/root/root.go +++ b/pkg/commands/root/root.go @@ -1,5 +1,5 @@ /* -Copyright © 2024 NAME HERE +Copyright © 2024 Xiao Cui */ package root @@ -10,9 +10,11 @@ import ( "mycli/pkg/commands/install" "mycli/pkg/iostreams" "mycli/pkg/utils" - "os" + "path/filepath" + "strings" + "github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2/terminal" "github.com/spf13/cobra" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" @@ -70,17 +72,91 @@ func Run() exitCode { iostream := iostreams.System() stderr := iostream.ErrOut ctx := context.Background() + + utils.PrintWelcomeMessage(iostream) rootCmd, err := NewRootCmd(iostream) tracer.Start( tracer.WithService("mycli"), tracer.WithEnv("development"), tracer.WithServiceVersion("1.0.0"), + tracer.WithLogStartup(false), tracer.WithDebugMode(false), tracer.WithAgentAddr("localhost:8126"), ) defer tracer.Stop() + // Get all available commands + var options []string + for _, cmd := range rootCmd.Commands() { + options = append(options, cmd.Use) + } + + // Prompt user to select a command + var selectedOption string + prompt := &survey.Select{ + Message: "Choose a command to run:", + Options: options, + } + survey.AskOne(prompt, &selectedOption) + + // Confirm if user wants to run the install command + var confirm bool + confirmPrompt := &survey.Confirm{ + Message: fmt.Sprintf("Do you want to run the '%s' command?", selectedOption), + } + survey.AskOne(confirmPrompt, &confirm) + + if !confirm { + fmt.Println("Operation cancelled by user.") + return exitOK + } + + var configPath string + if selectedOption == "install" { + // Prompt for config file path + configPrompt := &survey.Input{ + Message: "Enter the path to the config file:", + Default: "config.yaml", + } + survey.AskOne(configPrompt, &configPath) + configPath = os.ExpandEnv(configPath) + // Replace ~ with home directory + if strings.HasPrefix(configPath, "~") { + home, err := os.UserHomeDir() + if err == nil { + configPath = filepath.Join(home, configPath[1:]) + } + } + + // Get the absolute path + absPath, err := filepath.Abs(configPath) + if err == nil { + configPath = absPath + } + fmt.Println(configPath) + // Validate the file path + if _, err := os.Stat(configPath); os.IsNotExist(err) { + fmt.Fprintf(stderr, "Error: Config file does not exist at path: %s\n", configPath) + return exitError + } + } + + // Set the args for the root command + if selectedOption == "install" { + rootCmd.SetArgs([]string{selectedOption, "--config", configPath}) + var selectedCmd *cobra.Command + for _, cmd := range rootCmd.Commands() { + if cmd.Use == selectedOption { + selectedCmd = cmd + break + } + selectedCmd.SetArgs([]string{selectedOption, "--config", configPath}) + } + } else { + rootCmd.SetArgs([]string{selectedOption}) + } + if err != nil { fmt.Fprintf(stderr, "failed to create root command: %s\n", err) return exitError diff --git a/pkg/utils/util.go b/pkg/utils/util.go index 8a68b80..ae1955f 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -2,10 +2,13 @@ package utils import ( "fmt" + "math/rand" + "mycli/pkg/iostreams" "os" "os/exec" "os/user" "strings" + "time" "gopkg.in/yaml.v2" ) @@ -49,3 +52,51 @@ func LoadToolsConfig(filename string) (*ToolConfig, error) { } return &config, nil } + +func getRandomASCIILogo() string { + logos := []string{ + ` + __ ___ ________ ____ + / |/ /_ __/ ____/ / / _/ + / /|_/ / / / / / / / / / + / / / / /_/ / /___/ /____/ / +/_/ /_/\__, /\____/_____/___/ + /____/ +`, + ` + ________ _________ ___ +|\\ __ \\ |\\___ ___\\ |\\ \\ +\\ \\ \\|\\ \\ ____ \\|___ \\ \\_| \\ \\ \\ + \\ \\ __ \\|\\ __\\ \\ \\ \\ \\ \\ \\ + \\ \\ \\ \\ \\ \\ \\__/__ \\ \\ \\ \\ \\ \\____ + \\ \\__\\ \\__\\ \\______\\ \\ \\__\\ \\ \\_______\\ + \\|__|\\|__|\\|______| \\|__| \\|_______| +`, + } + return logos[rand.Intn(len(logos))] +} + +func PrintWelcomeMessage(iostream *iostreams.IOStreams) { + cs := iostream.ColorScheme() + out := iostream.Out + + asciiLogo := getRandomASCIILogo() + + fmt.Fprintln(out, "") + fmt.Fprintln(out, cs.Blue("Welcome to MyCLI!")) + fmt.Fprintln(out, cs.Blue(asciiLogo)) + fmt.Fprintln(out, cs.Green("Your personal machine bootstrapping tool")) + fmt.Fprintln(out, "") + fmt.Fprintf(out, "Version: %s\n", cs.Yellow("1.0.0")) + fmt.Fprintf(out, "Current time: %s\n", cs.Yellow(time.Now().Format("2006-01-02 15:04:05"))) + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Available commands:") + fmt.Fprintln(out, " - install: Install software tools") + fmt.Fprintln(out, " - config: Configure your system") + fmt.Fprintln(out, " - update: Update MyCLI") + fmt.Fprintln(out, "") + fmt.Fprintln(out, cs.Yellow("Tip: Use 'mycli --help' to see all available commands and options.")) + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Let's get started with setting up your machine...") + fmt.Fprintln(out, "") +}