feat: update go.mod
commit
afb1ad6256
|
@ -0,0 +1,2 @@
|
|||
github.com/make-go-great/color-go
|
||||
github.com/urfave/cli/v2
|
|
@ -0,0 +1,17 @@
|
|||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Window
|
||||
*.exe
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# Go
|
||||
coverage.out
|
||||
|
||||
# GoReleaser
|
||||
dist
|
|
@ -0,0 +1,74 @@
|
|||
run:
|
||||
tests: false
|
||||
skip-dirs:
|
||||
- ".*test.*"
|
||||
- ".*mock.*"
|
||||
- ".*generated.*"
|
||||
- ".*example.*"
|
||||
skip-files:
|
||||
- ".*Mock.*"
|
||||
- ".*_mock.*"
|
||||
- ".*_generated.*"
|
||||
go: "1.18"
|
||||
|
||||
output:
|
||||
sort-results: true
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- deadcode
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- varcheck
|
||||
- errname
|
||||
- errorlint
|
||||
- execinquery
|
||||
- goerr113
|
||||
- gofumpt
|
||||
- gosec
|
||||
- ifshort
|
||||
- importas
|
||||
- makezero
|
||||
- nilnil
|
||||
- prealloc
|
||||
- unconvert
|
||||
fast: true
|
||||
|
||||
linters-settings:
|
||||
gosec:
|
||||
excludes:
|
||||
- G402
|
||||
- G501
|
||||
- G505
|
||||
exclude-generated: true
|
||||
govet:
|
||||
check-shadowing: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- assign
|
||||
- atomic
|
||||
- bools
|
||||
- buildtag
|
||||
- composites
|
||||
- copylocks
|
||||
- fieldalignment
|
||||
- httpresponse
|
||||
- loopclosure
|
||||
- lostcancel
|
||||
- nilfunc
|
||||
- printf
|
||||
- unmarshal
|
||||
- unreachable
|
||||
- unusedresult
|
||||
staticcheck:
|
||||
go: "1.18"
|
||||
checks: ["all", "-SA1019"]
|
||||
|
||||
issues:
|
||||
new: true
|
||||
fix: true
|
|
@ -0,0 +1,5 @@
|
|||
# update-go-mod
|
||||
|
||||
## Thanks
|
||||
|
||||
- [Managing dependencies](https://go.dev/doc/modules/managing-dependencies)
|
|
@ -0,0 +1,8 @@
|
|||
package main
|
||||
|
||||
import "github.com/haunt98/update-go-mod/internal/cli"
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Run()
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
module github.com/haunt98/update-go-mod
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/make-go-great/color-go v0.4.1
|
||||
github.com/urfave/cli/v2 v2.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/make-go-great/color-go v0.4.1 h1:4HIat5r1oQneu5BSDUjHKN/9x4Ay2qEEkswdOgk/VRY=
|
||||
github.com/make-go-great/color-go v0.4.1/go.mod h1:G5G8IJ3PUo+vSQ+UvnfaswF8O/piVIhFJKv1mQjBGpI=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE=
|
||||
github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
@ -0,0 +1,33 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type action struct {
|
||||
flags struct {
|
||||
depsFile string
|
||||
verbose bool
|
||||
dryRun bool
|
||||
}
|
||||
}
|
||||
|
||||
func (a *action) RunHelp(c *cli.Context) error {
|
||||
return cli.ShowAppHelp(c)
|
||||
}
|
||||
|
||||
func (a *action) getFlags(c *cli.Context) {
|
||||
a.flags.verbose = c.Bool(flagVerbose)
|
||||
a.flags.depsFile = c.String(flagDepsFile)
|
||||
a.flags.dryRun = c.Bool(flagDryRun)
|
||||
|
||||
a.log("flags %+v", a.flags)
|
||||
}
|
||||
|
||||
func (a *action) log(format string, v ...interface{}) {
|
||||
if a.flags.verbose {
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/make-go-great/color-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var ErrInvalidModuleVersion = errors.New("invalid module version")
|
||||
|
||||
// See https://pkg.go.dev/cmd/go#hdr-List_packages_or_modules
|
||||
type Module struct {
|
||||
Update *Module
|
||||
Path string
|
||||
Version string
|
||||
}
|
||||
|
||||
func (a *action) Run(c *cli.Context) error {
|
||||
a.getFlags(c)
|
||||
|
||||
// Get all imported modules
|
||||
goListAllArgs := []string{"list", "-m", "-json", "all"}
|
||||
goOutput, err := exec.CommandContext(c.Context, "go", goListAllArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goListAllArgs, " "), err)
|
||||
}
|
||||
|
||||
// goAllOutput is like {...}\n{...}\n{...}
|
||||
// Missing [] and , for json
|
||||
goOutputStr := strings.ReplaceAll(strings.TrimSpace(string(goOutput)), "\n", "")
|
||||
goOutputStr = strings.ReplaceAll(goOutputStr, "}{", "},{")
|
||||
goOutputStr = "[" + goOutputStr + "]"
|
||||
|
||||
importedModules := make([]Module, 0, 100)
|
||||
if err := json.Unmarshal([]byte(goOutputStr), &importedModules); err != nil {
|
||||
return fmt.Errorf("failed to json unmarshal: %w", err)
|
||||
}
|
||||
a.log("go output: %s", string(goOutput))
|
||||
|
||||
mapImportedModules := make(map[string]struct{})
|
||||
for _, importedModule := range importedModules {
|
||||
mapImportedModules[importedModule.Path] = struct{}{}
|
||||
}
|
||||
a.log("imported modules: %+v\n", importedModules)
|
||||
|
||||
// Read pkg from file
|
||||
depsFileBytes, err := os.ReadFile(a.flags.depsFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
color.PrintAppWarning(name, fmt.Sprintf("deps file [%s] not found", a.flags.depsFile))
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to read file %s: %w", a.flags.depsFile, err)
|
||||
}
|
||||
|
||||
depsFileStr := strings.TrimSpace(string(depsFileBytes))
|
||||
lines := strings.Split(depsFileStr, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
a.log("line: %s", line)
|
||||
|
||||
// Check if line is imported module, otherwise skip
|
||||
if _, ok := mapImportedModules[line]; !ok {
|
||||
a.log("%s is not imported module", line)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get module latest version
|
||||
goListArgs := []string{"list", "-m", "-u", "-json", line}
|
||||
goOutput, err = exec.CommandContext(c.Context, "go", goListArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goListArgs, " "), err)
|
||||
}
|
||||
a.log("go output: %s", string(goOutput))
|
||||
|
||||
module := Module{}
|
||||
if err := json.Unmarshal(goOutput, &module); err != nil {
|
||||
return fmt.Errorf("failed to json unmarshal: %w", err)
|
||||
}
|
||||
a.log("module: %+v", module)
|
||||
|
||||
if module.Update == nil {
|
||||
color.PrintAppOK(name, fmt.Sprintf("You already have latest [%s] version [%s]", module.Path, module.Version))
|
||||
continue
|
||||
}
|
||||
|
||||
// Upgrade module
|
||||
if a.flags.dryRun {
|
||||
color.PrintAppOK(name, fmt.Sprintf("Will upgrade [%s] version [%s] to [%s]", module.Path, module.Version, module.Update.Version))
|
||||
continue
|
||||
}
|
||||
|
||||
goGetArgs := []string{"get", "-d", line + "@" + module.Update.Version}
|
||||
goOutput, err = exec.CommandContext(c.Context, "go", goGetArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goGetArgs, " "), err)
|
||||
}
|
||||
a.log("go output: %s", string(goOutput))
|
||||
|
||||
color.PrintAppOK(name, fmt.Sprintf("Upgraded [%s] version [%s] to [%s] success", module.Path, module.Version, module.Update.Version))
|
||||
}
|
||||
|
||||
goModArgs := []string{"mod", "tidy"}
|
||||
goOutput, err = exec.CommandContext(c.Context, "go", goModArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goModArgs, " "), err)
|
||||
}
|
||||
a.log("go output: %s", string(goOutput))
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/make-go-great/color-go"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
name = "update-go-mod"
|
||||
usage = "excatly like the name says"
|
||||
|
||||
flagVerbose = "verbose"
|
||||
flagDepsFile = "deps-file"
|
||||
flagDryRun = "dry-run"
|
||||
|
||||
commandRun = "run"
|
||||
|
||||
usageCommandRun = "run the program"
|
||||
usageFlagVerbose = "show what is going on"
|
||||
usageDepsFile = "show what deps need to upgrade"
|
||||
usageDryRun = "demo what would be done"
|
||||
|
||||
defaultDepsFile = ".deps"
|
||||
)
|
||||
|
||||
var aliasFlagVerbose = []string{"v"}
|
||||
|
||||
type App struct {
|
||||
cliApp *cli.App
|
||||
}
|
||||
|
||||
func NewApp() *App {
|
||||
a := &action{}
|
||||
|
||||
cliApp := &cli.App{
|
||||
Name: name,
|
||||
Usage: usage,
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: commandRun,
|
||||
Usage: usageCommandRun,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: flagVerbose,
|
||||
Aliases: aliasFlagVerbose,
|
||||
Usage: usageFlagVerbose,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flagDepsFile,
|
||||
Usage: usageDepsFile,
|
||||
Value: defaultDepsFile,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: flagDryRun,
|
||||
Usage: usageDryRun,
|
||||
},
|
||||
},
|
||||
Action: a.Run,
|
||||
},
|
||||
},
|
||||
Action: a.RunHelp,
|
||||
}
|
||||
|
||||
return &App{
|
||||
cliApp: cliApp,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Run() {
|
||||
if err := a.cliApp.Run(os.Args); err != nil {
|
||||
color.PrintAppError(name, err.Error())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue