├── gomup.png ├── dependency.go ├── .gitignore ├── .goreleaser.yaml ├── table.go ├── README.md ├── go.mod ├── LICENSE ├── gomup.go ├── go.sum └── ui.go /gomup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alihanyalcin/gomup/HEAD/gomup.png -------------------------------------------------------------------------------- /dependency.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type dependency struct { 4 | path string 5 | name string 6 | version string 7 | updateVersion string 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # This is an example .goreleaser.yml file with some sensible defaults. 2 | # Make sure to check the documentation at https://goreleaser.com 3 | before: 4 | hooks: 5 | # You may remove this if you don't use go modules. 6 | - go mod tidy 7 | builds: 8 | - env: 9 | - CGO_ENABLED=0 10 | goos: 11 | - linux 12 | - windows 13 | - darwin 14 | archives: 15 | - replacements: 16 | darwin: Darwin 17 | linux: Linux 18 | windows: Windows 19 | 386: i386 20 | amd64: x86_64 21 | checksum: 22 | name_template: 'checksums.txt' 23 | snapshot: 24 | name_template: "{{ incpatch .Version }}-next" 25 | changelog: 26 | sort: asc 27 | filters: 28 | exclude: 29 | - '^docs:' 30 | - '^test:' 31 | -------------------------------------------------------------------------------- /table.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/olekukonko/tablewriter" 7 | ) 8 | 9 | func drawTable(dependencies []dependency) { 10 | var data [][]string 11 | for _, v := range dependencies { 12 | data = append(data, []string{ 13 | v.path, 14 | v.name, 15 | v.version, 16 | v.updateVersion, 17 | }) 18 | } 19 | 20 | table := tablewriter.NewWriter(os.Stdout) 21 | table.SetHeader([]string{"Path", "Name", "Current Version", "Update Version"}) 22 | table.SetAutoMergeCells(true) 23 | table.SetRowLine(true) 24 | 25 | var color = []tablewriter.Colors{ 26 | {tablewriter.Bold, tablewriter.FgMagentaColor}, 27 | {tablewriter.FgCyanColor}, 28 | {tablewriter.Bold}, 29 | {tablewriter.Bold}, 30 | } 31 | 32 | for _, v := range data { 33 | table.Rich(v, color) 34 | } 35 | table.Render() 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gomUP 🆙 2 | 3 | gomUP is a tool to keep track of outdated dependencies and upgrade them to the latest version. Designed for monorepo Go 4 | projects and Go projects that contain multiple modules. 5 | 6 | ![gomUP UI](gomup.png) 7 | 8 | # Install 9 | 10 | Go to the [releases page](https://github.com/alihanyalcin/gomup/releases), and download the binaries for your operating 11 | system (macOS, Linux, and Windows).

12 | Alternatively,
13 | You can install it using `go install`: 14 | 15 | ``` 16 | go install github.com/alihanyalcin/gomup@latest 17 | ``` 18 | 19 | Or, use `homebrew`: 20 | 21 | ``` 22 | brew tap alihanyalcin/gomup 23 | brew install gomup 24 | ``` 25 | 26 | # Usage 27 | 28 | ``` 29 | gomup -p 30 | ``` 31 | 32 | After you hit the enter, **gomUP** starts to walk through your project directory path to find go modules. It may take a 33 | while to collect all modules and dependencies. 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/alihanyalcin/gomup 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/briandowns/spinner v1.18.0 7 | github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1 8 | github.com/olekukonko/tablewriter v0.0.5 9 | github.com/rivo/tview v0.0.0-20220106183741-90d72bc664f5 10 | github.com/urfave/cli/v2 v2.3.0 11 | ) 12 | 13 | require ( 14 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect 15 | github.com/fatih/color v1.7.0 // indirect 16 | github.com/gdamore/encoding v1.0.0 // indirect 17 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 18 | github.com/mattn/go-colorable v0.1.2 // indirect 19 | github.com/mattn/go-isatty v0.0.8 // indirect 20 | github.com/mattn/go-runewidth v0.0.13 // indirect 21 | github.com/rivo/uniseg v0.2.0 // indirect 22 | github.com/russross/blackfriday/v2 v2.0.1 // indirect 23 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect 24 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect 25 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 26 | golang.org/x/text v0.3.6 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alihan Doğuş Yalçın 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gomup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "strings" 10 | "sync" 11 | "time" 12 | 13 | "github.com/briandowns/spinner" 14 | "github.com/urfave/cli/v2" 15 | ) 16 | 17 | const gomod = "go.mod" 18 | 19 | var args = []string{ 20 | "list", 21 | "-u", 22 | "-mod=mod", 23 | "-f", 24 | "'{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}} {{.Version}} {{.Update.Version}}{{end}}'", 25 | "-m", 26 | "all", 27 | } 28 | 29 | func main() { 30 | var ( 31 | path string 32 | list bool 33 | ) 34 | 35 | app := &cli.App{ 36 | Name: "gomUP", 37 | Usage: "go module dependency upgrade tool", 38 | Flags: []cli.Flag{ 39 | &cli.StringFlag{ 40 | Name: "path", 41 | Aliases: []string{"p"}, 42 | Usage: "directory path of go projects", 43 | Required: true, 44 | Destination: &path, 45 | }, 46 | &cli.BoolFlag{ 47 | Name: "list", 48 | Aliases: []string{"l"}, 49 | Usage: "list all dependencies", 50 | Required: false, 51 | Destination: &list, 52 | }, 53 | }, 54 | Action: func(c *cli.Context) error { 55 | err := checkPath(path) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | s := spinner.New(spinner.CharSets[36], 250*time.Millisecond) 61 | s.Prefix = "Starting gomUP " 62 | s.Start() 63 | 64 | dependencies := find(path) 65 | 66 | s.Stop() 67 | 68 | if len(dependencies) == 0 { 69 | fmt.Println("everything up-to-date") 70 | return nil 71 | } 72 | 73 | if list { 74 | drawTable(dependencies) 75 | return nil 76 | } 77 | 78 | startUI(dependencies) 79 | 80 | return nil 81 | }, 82 | UseShortOptionHandling: true, 83 | EnableBashCompletion: true, 84 | } 85 | 86 | err := app.Run(os.Args) 87 | if err != nil { 88 | log.Fatal(err) 89 | } 90 | } 91 | 92 | func checkPath(path string) error { 93 | info, err := os.Stat(path) 94 | if os.IsNotExist(err) { 95 | return err 96 | } 97 | 98 | if !info.IsDir() { 99 | return fmt.Errorf("%s is not a directory", path) 100 | } 101 | 102 | return nil 103 | } 104 | 105 | func find(path string) []dependency { 106 | var wg sync.WaitGroup 107 | var dependencies []dependency 108 | 109 | err := filepath.Walk(path, 110 | func(path string, info os.FileInfo, err error) error { 111 | if err != nil { 112 | return err 113 | } 114 | 115 | if info.Name() == gomod { 116 | wg.Add(1) 117 | go func() { 118 | defer wg.Done() 119 | 120 | modPath := path[:(len(path) - len(gomod))] 121 | dep, err := findDepencencies(modPath) 122 | if err != nil { 123 | return 124 | } 125 | dependencies = append(dependencies, dep...) 126 | }() 127 | } 128 | 129 | return nil 130 | }) 131 | if err != nil { 132 | log.Println(err) 133 | } 134 | 135 | wg.Wait() 136 | 137 | return dependencies 138 | } 139 | 140 | func findDepencencies(path string) ([]dependency, error) { 141 | var dependencies []dependency 142 | 143 | cmd := exec.Command("go", args...) 144 | cmd.Dir = path 145 | list, err := cmd.Output() 146 | if err != nil { 147 | return nil, fmt.Errorf("cannot get %s available minor and patch upgrades. error: %w", path, err) 148 | } 149 | 150 | for _, dep := range strings.Split(string(list), "\n") { 151 | if dep != "''" && dep != "" { 152 | dep = strings.Trim(dep, "'") 153 | d := strings.Split(strings.Trim(dep, "'"), " ") 154 | dependencies = append(dependencies, dependency{ 155 | path: path, 156 | name: d[0], 157 | version: d[1], 158 | updateVersion: d[2], 159 | }) 160 | } 161 | } 162 | 163 | return dependencies, nil 164 | } 165 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= 3 | github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= 4 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= 5 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 6 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= 7 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 8 | github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= 9 | github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= 10 | github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1 h1:QqwPZCwh/k1uYqq6uXSb9TRDhTkfQbO80v8zhnIe5zM= 11 | github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04= 12 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 13 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 14 | github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= 15 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 16 | github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= 17 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 18 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 19 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 20 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 21 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 22 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 23 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 24 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 25 | github.com/rivo/tview v0.0.0-20220106183741-90d72bc664f5 h1:n0qwaaNXgplKv5AeDIzpXnwoLh9ddQzVsAY8d7WiZvs= 26 | github.com/rivo/tview v0.0.0-20220106183741-90d72bc664f5/go.mod h1:WIfMkQNY+oq/mWwtsjOYHIZBuwthioY2srOmljJkTnk= 27 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 28 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 29 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 30 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 31 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= 32 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 33 | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= 34 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 35 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= 38 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 40 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= 41 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 42 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 43 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 44 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 45 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 46 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 47 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 48 | -------------------------------------------------------------------------------- /ui.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | "sort" 7 | 8 | "github.com/gdamore/tcell/v2" 9 | "github.com/rivo/tview" 10 | ) 11 | 12 | type view struct { 13 | app *tview.Application 14 | pages *tview.Pages 15 | table *tview.Table 16 | update *tview.Modal 17 | quit *tview.Modal 18 | info *tview.Modal 19 | dependencies []dependency 20 | } 21 | 22 | func startUI(d []dependency) { 23 | sort.Slice(d, func(i, j int) bool { 24 | return d[i].path < d[j].path 25 | }) 26 | 27 | v := &view{ 28 | app: tview.NewApplication(), 29 | pages: tview.NewPages(), 30 | table: tview.NewTable(), 31 | update: tview.NewModal(), 32 | quit: tview.NewModal(), 33 | info: tview.NewModal(), 34 | dependencies: d, 35 | } 36 | 37 | v.setInfoModal() 38 | v.setUpdateModal() 39 | v.setQuitModal() 40 | v.setTable() 41 | 42 | if err := v.app.SetRoot(v.pages, true).SetFocus(v.table).EnableMouse(true).Run(); err != nil { 43 | panic(err) 44 | } 45 | } 46 | 47 | func (v *view) setInfoModal() { 48 | v.info.AddButtons([]string{"OK"}). 49 | SetDoneFunc(func(buttonIndex int, buttonLabel string) { 50 | v.pages.SendToBack("info") 51 | }) 52 | 53 | v.pages.AddPage("info", v.info, true, true) 54 | v.pages.SendToBack("info") 55 | } 56 | 57 | func (v *view) setUpdateModal() { 58 | v.update.AddButtons([]string{"Yes", "No"}) 59 | 60 | v.pages.AddPage("update", v.update, true, true) 61 | v.pages.SendToBack("update") 62 | } 63 | 64 | func (v *view) setQuitModal() { 65 | v.quit.SetText("Do you want to quit?"). 66 | AddButtons([]string{"Quit", "Cancel"}). 67 | SetDoneFunc(func(buttonIndex int, buttonLabel string) { 68 | if buttonLabel == "Quit" { 69 | v.app.Stop() 70 | } else { 71 | v.pages.SendToBack("quit") 72 | } 73 | }) 74 | 75 | v.pages.AddPage("quit", v.quit, true, true) 76 | v.pages.SendToBack("quit") 77 | } 78 | 79 | func (v *view) setTable() { 80 | v.table.SetBorder(true).SetTitle("gomUP - ESC: quit - ENTER: upgrade").SetTitleAlign(tview.AlignCenter) 81 | 82 | colsHeader := []string{"PATH", "NAME", "CURRENT VERSION", "UPDATE VERSION"} 83 | cols, rows := len(colsHeader), len(v.dependencies)+1 84 | for r := 0; r < rows; r++ { 85 | for c := 0; c < cols; c++ { 86 | color := tcell.ColorWhite 87 | if c == 0 && r != 0 { 88 | color = tcell.ColorAquaMarine 89 | } else if c != 0 && r != 0 { 90 | color = tcell.ColorRed 91 | } 92 | 93 | align := tview.AlignLeft 94 | if r == 0 { 95 | align = tview.AlignCenter 96 | } else if c == 0 { 97 | align = tview.AlignRight 98 | } 99 | 100 | var tableCell *tview.TableCell 101 | if r == 0 { 102 | // Set Headers 103 | tableCell = tview.NewTableCell(colsHeader[c]). 104 | SetTextColor(color). 105 | SetAlign(align). 106 | SetSelectable(false). 107 | SetAttributes(tcell.AttrBold) 108 | } else { 109 | tableCell = tview.NewTableCell(v.getString(r-1, c)). 110 | SetTextColor(color). 111 | SetAlign(align). 112 | SetSelectable(c != 0) 113 | } 114 | 115 | v.table.SetCell(r, c, tableCell) 116 | 117 | if c > 0 && c < 4 { 118 | tableCell.SetExpansion(1) 119 | } 120 | } 121 | } 122 | 123 | v.table.SetBorders(true) 124 | v.table.SetSelectable(true, false) 125 | v.table.Select(1, 0).SetFixed(1, 0). 126 | SetDoneFunc(func(key tcell.Key) { 127 | if key == tcell.KeyEscape { 128 | v.pages.SendToFront("quit") 129 | } 130 | }). 131 | SetSelectedFunc(func(row int, column int) { 132 | dependency := v.dependencies[row-1] 133 | v.pages.SendToFront("update") 134 | v.update.SetText(fmt.Sprintf("Do you want to upgrade %s for %s?", dependency.name, dependency.path)). 135 | SetDoneFunc(func(buttonIndex int, buttonLabel string) { 136 | v.pages.SendToBack("update") 137 | if buttonLabel == "Yes" { 138 | v.upgrade(row, cols) 139 | } 140 | 141 | }) 142 | }) 143 | 144 | v.pages.AddPage("table", v.table, true, true) 145 | } 146 | 147 | func (v *view) upgrade(row, cols int) { 148 | v.pages.SendToFront("info") 149 | 150 | dependency := v.dependencies[row-1] 151 | 152 | cmd := exec.Command("go", "get", dependency.name) 153 | cmd.Dir = dependency.path 154 | _, err := cmd.Output() 155 | if err != nil { 156 | v.info.SetText("Error occured: " + err.Error()) 157 | } else { 158 | v.info.SetText("Success!") 159 | 160 | for c := 1; c < cols; c++ { 161 | v.table.GetCell(row, c).SetTextColor(tcell.ColorAquaMarine).SetSelectable(false) 162 | } 163 | } 164 | } 165 | 166 | func (v *view) getString(row, col int) string { 167 | value := v.dependencies[row] 168 | return []string{value.path, value.name, value.version, value.updateVersion}[col] 169 | } 170 | --------------------------------------------------------------------------------