diff --git a/foreman-builder/cmd/create.go b/foreman-builder/cmd/create.go index 8732318..429f2bb 100644 --- a/foreman-builder/cmd/create.go +++ b/foreman-builder/cmd/create.go @@ -13,19 +13,6 @@ import ( "github.com/spf13/cobra" ) -type opts struct { - choices []string - cursor int - selected map[int]struct{} -} - -func initialOpts() opts { - return opts{ - choices: []string{"bash", "zsh"}, - selected: make(map[int]struct{}), - } -} - var createCmd = &cobra.Command{ Use: "create", Short: "Create a new container environment", @@ -34,6 +21,8 @@ var createCmd = &cobra.Command{ }, } +var containerType = "orb" + func runCreate() { currentUser, err := user.Current() if err != nil { @@ -50,64 +39,90 @@ func runCreate() { containerName = "foreman" } - // p := tea.NewProgram(initialOpts()) - // finalOpts, err := p.Run() - // if err != nil { - // fmt.Printf("Alas, there's been an error: %v", err) - // os.Exit(1) - // } - // m := finalOpts.(opts) + home, err := os.UserHomeDir() + if err != nil { + foremanbuilder.Logger.Fatalf("Failed to get home directory: %v", err) + } - // currently will not do anything - // selectedShell := m.choices[m.cursor] + containerNameExists, err := foremanbuilder.GetLineInFile(filepath.Join(home, ".foreman-builder/containers"), containerName, "") + if err != nil { + if err.Error() != "not_found" { + fmt.Println("An Error has occured searching dotfile") + os.Exit(1) + } + } + foremanbuilder.Logger.Debug("container name: %s \n", containerName) + foremanbuilder.Logger.Debug("container name EXISTS: %s \n", containerNameExists) + if containerNameExists != "" { + fmt.Println("Container name must be unique") + os.Exit(1) + } - // fmt.Println("Selected Shell", selectedShell) + err = foremanbuilder.AppendToFile(filepath.Join(home, ".foreman-builder/containers"), fmt.Sprintf("%s::%s", containerName, containerType)) + if err != nil { + foremanbuilder.Logger.Error("Failed to write container to container file") + } foremanbuilder.Logger.Info("Starting environment creation") + if containerType == "orb" { + orbOpts := foremanbuilder.OrbOptions{ + Username: username, + ContainerName: containerName, + } + err := createOrbstackContainer(orbOpts) + if err != nil { + // better error message to show? + fmt.Println("An error has occured during container creation") + os.Exit(1) + } + } + +} + +func createOrbstackContainer(opts foremanbuilder.OrbOptions) error { config, err := foremanbuilder.GetYmlValues("./config.yml") if err != nil { foremanbuilder.Logger.Info("No config file found, skipping") } data := foremanbuilder.OrbstackConfigData{ - Username: username, + Username: opts.Username, Packages: config.Packages, } // check for errors by doing ssh @orb cat /var/log/cloud-init-output.log - home, err := os.UserHomeDir() if err != nil { - foremanbuilder.Logger.Fatalf("Failed to get home directory: %v", err) + foremanbuilder.Logger.Errorf("Failed to get home directory: %v", err) + return err } - confsDir := filepath.Join(home, ".foreman-builder", "confs") if err := os.MkdirAll(confsDir, 0755); err != nil { - foremanbuilder.Logger.Fatalf("Failed to create confs directory: %v", err) + foremanbuilder.Logger.Errorf("Failed to create confs directory: %v", err) + return err } pathName := filepath.Join(confsDir, fmt.Sprintf("orbstack-foreman-%s.yml", data.Username)) - fmt.Println("using", pathName) + foremanbuilder.Logger.Info("using", pathName) err = foremanbuilder.GenerateContainerConfig(data, pathName) if err != nil { - foremanbuilder.Logger.Fatal(err) + foremanbuilder.Logger.Errorf("failed to generate container config, err : %v\n", err) + return err } // run command to create container - orbArgs := []string{"create", "-a", "amd64", "-c", pathName, "rocky:9", containerName} - fmt.Println("running: orb", strings.Join(orbArgs, " ")) + orbArgs := []string{"create", "-a", "amd64", "-c", pathName, "rocky:9", opts.ContainerName} + foremanbuilder.Logger.Info("running: orb", strings.Join(orbArgs, " ")) cmd := exec.Command("orb", orbArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - foremanbuilder.Logger.Fatalf("Error creating container: %s", err) + foremanbuilder.Logger.Errorf("Error creating container: %s", err) + return err } fmt.Println("Container has been created!") - err = foremanbuilder.AppendToFile(filepath.Join(home, ".foreman-builder/containers"), containerName) - if err != nil { - foremanbuilder.Logger.Error("Failed to write container to container file") - } + return nil } diff --git a/foreman-builder/cmd/delete.go b/foreman-builder/cmd/delete.go index 4e11e39..96782c5 100644 --- a/foreman-builder/cmd/delete.go +++ b/foreman-builder/cmd/delete.go @@ -6,6 +6,7 @@ import ( "os/exec" "path/filepath" "slices" + "strings" foremanbuilder "github.com/aidenfine/foreman-builder/foreman-builder" "github.com/spf13/cobra" @@ -21,7 +22,7 @@ var deleteCmd = &cobra.Command{ os.Exit(1) } containerName := args[0] - runDelete(containerName) + runDelete(fmt.Sprint(strings.Split(containerName, "::")[0])) }, } @@ -35,7 +36,9 @@ func runDelete(containerName string) { } dotFolderPath := filepath.Join(home, ".foreman-builder") containersPath := filepath.Join(dotFolderPath, "containers") - containers, err := foremanbuilder.GetAllLines(containersPath) + containers, err := foremanbuilder.GetAllLines(containersPath, "::") + foremanbuilder.Logger.Debugf("containers: %v\n", containers) + foremanbuilder.Logger.Debugf("containerName: %s \n", containerName) if !slices.Contains(containers, containerName) { foremanbuilder.Logger.Fatalf("%s was not created with foreman-builder, foreman-builder will not delete it", containerName) @@ -44,8 +47,16 @@ func runDelete(containerName string) { } containerInfo, err := foremanbuilder.ContainerInfo(containerName) if err != nil { - foremanbuilder.Logger.Fatalf("Failed to get container info: %v", err) - os.Exit(1) + if strings.Contains(err.Error(), fmt.Sprintf("machine not found: '%s'", containerName)) { + foremanbuilder.Logger.Debugf("Container does not exist in orbstack anymore just delete the line") + foremanbuilder.DeleteLineInFile(containersPath, containerName) + fmt.Printf("%s has been deleted\n", containerName) + os.Exit(1) + } else { + foremanbuilder.Logger.Fatalf("Failed to get container info: %v", err) + os.Exit(1) + } + } if containerInfo.State == "running" { var input string @@ -57,11 +68,13 @@ func runDelete(containerName string) { os.Exit(1) } // stop container - exec.Command("orbctl", "stop", containerName) + exec.Command("orbctl", "stop", containerName).Run() } - exec.Command("orbctl", "delete", containerName, "-f") + fmt.Printf("Deleting...\n") + exec.Command("orbctl", "delete", containerName, "-f").Run() // delete container in dotfile foremanbuilder.DeleteLineInFile(containersPath, containerName) + fmt.Printf("%s has been deleted\n", containerName) } diff --git a/foreman-builder/cmd/list.go b/foreman-builder/cmd/list.go index 747ea94..562a8f9 100644 --- a/foreman-builder/cmd/list.go +++ b/foreman-builder/cmd/list.go @@ -26,7 +26,7 @@ func runList() { } dotFolderPath := filepath.Join(home, ".foreman-builder") containersPath := filepath.Join(dotFolderPath, "containers") - containers, err := foremanbuilder.GetAllLines(containersPath) + containers, err := foremanbuilder.GetAllLines(containersPath, "::") if err != nil { fmt.Printf("Error getting all containers %v\n", err) } diff --git a/foreman-builder/cmd/sync.go b/foreman-builder/cmd/sync.go index 528176f..5a3f453 100644 --- a/foreman-builder/cmd/sync.go +++ b/foreman-builder/cmd/sync.go @@ -34,7 +34,7 @@ func SyncContainers() { } dotFolderPath := filepath.Join(home, ".foreman-builder") containersPath := filepath.Join(dotFolderPath, "containers") - foremanContainers, err := foremanbuilder.GetAllLines(containersPath) + foremanContainers, err := foremanbuilder.GetAllLines(containersPath, "::") if err != nil { fmt.Printf("Error getting all containers %v\n", err) foremanbuilder.Logger.Errorf("Error has occurred getting all containers %v\n", err) @@ -43,6 +43,7 @@ func SyncContainers() { for i := 0; i < len(foremanContainers)-1; i++ { if !slices.Contains(orbContainers, foremanContainers[i]) { // mark for deletion + foremanbuilder.Logger.Debugf("During sync... deleting %s\n", foremanContainers[i]) err = foremanbuilder.DeleteLineInFile(containersPath, foremanContainers[i]) if err != nil { fmt.Printf("Error deleting container from dotfile %v \n", err) diff --git a/foreman-builder/cmd/tui.go b/foreman-builder/cmd/tui.go deleted file mode 100644 index 99ddbb2..0000000 --- a/foreman-builder/cmd/tui.go +++ /dev/null @@ -1,85 +0,0 @@ -package cmd - -import ( - "fmt" - - tea "github.com/charmbracelet/bubbletea" -) - -func (m opts) Init() tea.Cmd { - // Just return `nil`, which means "no I/O right now, please." - return nil -} - -func (m opts) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - - // Is it a key press? - case tea.KeyMsg: - - // Cool, what was the actual key pressed? - switch msg.String() { - - // These keys should exit the program. - case "ctrl+c", "q": - return m, tea.Quit - - // The "up" and "k" keys move the cursor up - case "up", "k": - if m.cursor > 0 { - m.cursor-- - } - - // The "down" and "j" keys move the cursor down - case "down", "j": - if m.cursor < len(m.choices)-1 { - m.cursor++ - } - - // The "enter" key and the spacebar (a literal space) toggle - // the selected state for the item that the cursor is pointing at. - case "enter", " ": - _, ok := m.selected[m.cursor] - if ok { - delete(m.selected, m.cursor) - } else { - m.selected[m.cursor] = struct{}{} - } - return m, tea.Quit - } - } - - // Return the updated model to the Bubble Tea runtime for processing. - // Note that we're not returning a command. - return m, nil -} - -func (m opts) View() string { - // The header - s := "What shell would you like to use?\n\n" - - // Iterate over our choices - for i, choice := range m.choices { - - // Is the cursor pointing at this choice? - cursor := " " // no cursor - if m.cursor == i { - cursor = ">" // cursor! - } - - // Is this choice selected? - checked := " " // not selected - if _, ok := m.selected[i]; ok { - checked = "x" // selected! - } - - // Render the row - s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice) - } - - // The footer - s += "\nPress q to quit.\n" - - // Send the UI for rendering - return s -} diff --git a/foreman-builder/dotfolder.go b/foreman-builder/dotfolder.go index e27124c..533d4b8 100644 --- a/foreman-builder/dotfolder.go +++ b/foreman-builder/dotfolder.go @@ -2,6 +2,7 @@ package foremanbuilder import ( "errors" + "fmt" "os" "strings" ) @@ -45,7 +46,7 @@ func DeleteLineInFile(path, name string) error { if strings.TrimSpace(line) == "" { continue } - if line != name { + if strings.Split(line, "::")[0] != name { kept = append(kept, line) } } @@ -59,12 +60,55 @@ func DeleteLineInFile(path, name string) error { return os.Rename(tempFile, path) } - -func GetAllLines(path string) ([]string, error) { +func GetAllLines(path, splitBy string) ([]string, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } - return strings.Split(string(data), "\n"), nil + lines := strings.Split(string(data), "\n") + + if splitBy == "" { + return lines, nil + } + + var splitLines []string + for _, line := range lines { + parts := strings.SplitN(line, splitBy, 2) + splitLines = append(splitLines, parts[0]) + } + + return splitLines, nil +} + +// Can also be used to check if line exists in file, due to return error "not found" if line does not exist +// using containerType == "" will just check for the containerName itself and not care what `-` +// example: We want to find a container named container1 +func GetLineInFile(path, line, containerType string) (string, error) { + data, err := os.ReadFile(path) + if err != nil { + return "", err + } + var lines []string + for s := range strings.SplitSeq(string(data), "\n") { + lines = append(lines, s) + } + // if containerType == "" we can just ignore container postfix + for _, fileLine := range lines { + if strings.TrimSpace(fileLine) == "" { + continue + } + filePrefix := strings.SplitN(fileLine, "::", 2)[0] + searchPrefix := strings.SplitN(line, "::", 2)[0] + if containerType != "" { + containerMatch := fmt.Sprintf("%s::%s", searchPrefix, containerType) + if containerMatch == fileLine { + return fileLine, nil + } + } + if filePrefix == searchPrefix { + return fileLine, nil + } + } + return "", errors.New("not_found") } diff --git a/foreman-builder/dotfolder_test.go b/foreman-builder/dotfolder_test.go index 212eb49..8dbdfd1 100644 --- a/foreman-builder/dotfolder_test.go +++ b/foreman-builder/dotfolder_test.go @@ -1,6 +1,7 @@ package foremanbuilder_test import ( + "fmt" "os" "path/filepath" "testing" @@ -84,3 +85,40 @@ func TestDeleteLineInFile(t *testing.T) { t.Fatalf("expected %q, got %q", expected, string(content)) } } + +func TestGetAllLinesInFile(t *testing.T) { + tmpDir := t.TempDir() + filePath := filepath.Join(tmpDir, "delete.txt") + lines := "container-1::orb\ncontainer2::lima\ncontainer-1-3::3182321ujd12" + err := os.WriteFile(filePath, []byte(lines), 0644) + if err != nil { + t.Fatal(err) + } + // test no split + noSplit, err := foremanbuilder.GetAllLines(filePath, "") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(noSplit) != 3 { + t.Errorf("Expected 3 got %d", len(noSplit)) + } + if noSplit[0] != "container-1::orb" { + t.Errorf("Expected container1-orb got %s", noSplit[0]) + } + + split, err := foremanbuilder.GetAllLines(filePath, "::") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(split) != 3 { + t.Errorf("Expected 3 got %d", len(split)) + } + fmt.Printf("string 1: %s", split[0]) + if split[0] != "container-1" { + t.Errorf("Expected container1-orb got %s", split[0]) + } + if split[2] != "container-1-3" { + t.Errorf("Expected container-1-3 got %s", split[2]) + } + +} diff --git a/foreman-builder/orbstack.go b/foreman-builder/orbstack.go index d06a132..99cb634 100644 --- a/foreman-builder/orbstack.go +++ b/foreman-builder/orbstack.go @@ -2,6 +2,7 @@ package foremanbuilder import ( "encoding/json" + "fmt" "os/exec" ) @@ -21,6 +22,11 @@ type ContainerInfoStruct struct { State string `json:"state"` } +type OrbOptions struct { + ContainerName string `json:"containerName"` + Username string `json:"username"` +} + var execCommand = exec.Command func IsOrbStackRunning() bool { @@ -53,6 +59,9 @@ func ContainerInfo(containerName string) (ContainerInfoStruct, error) { cmd := execCommand("orbctl", "info", containerName, "--format", "json") output, err := cmd.Output() if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + return ContainerInfoStruct{}, fmt.Errorf("%s", exitErr.Stderr) + } return ContainerInfoStruct{}, err } diff --git a/go.mod b/go.mod index 6080fb9..fc0c03c 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/aidenfine/foreman-builder go 1.25.5 -require github.com/charmbracelet/bubbletea v1.3.10 - require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/pretty v0.2.0 // indirect @@ -14,27 +12,6 @@ require ( ) require ( - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/colorprofile v0.4.1 // indirect - github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/x/ansi v0.11.6 // indirect - github.com/charmbracelet/x/cellbuf v0.0.15 // indirect - github.com/charmbracelet/x/term v0.2.2 // indirect - github.com/clipperhouse/displaywidth v0.9.0 // indirect - github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.5.0 // indirect - github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/lucasb-eyer/go-colorful v1.3.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect - github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect - github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/termenv v0.16.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/cobra v1.10.2 - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.3.8 // indirect gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index d1a4de4..42d40ad 100644 --- a/go.sum +++ b/go.sum @@ -1,28 +1,6 @@ -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= -github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= -github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= -github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk= -github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= -github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= -github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI= -github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q= -github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= -github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= -github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA= -github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U= -github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= -github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= @@ -31,24 +9,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= -github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= -github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= @@ -56,8 +18,6 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -65,14 +25,6 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=