Skip to content

Commit

Permalink
Merge pull request #77 from nao1215/controll-goroutine-num
Browse files Browse the repository at this point in the history
Fix Issue #76: Limit the number of goroutines
  • Loading branch information
nao1215 authored Mar 5, 2023
2 parents a66e985 + dfe4707 commit 301eef4
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 108 deletions.
51 changes: 37 additions & 14 deletions cmd/check.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
package cmd

import (
"context"
"fmt"
"runtime"
"strings"
"sync"

"github.com/nao1215/gup/internal/goutil"
"github.com/nao1215/gup/internal/print"
"github.com/spf13/cobra"
"golang.org/x/sync/semaphore"
)

var checkCmd = &cobra.Command{
Use: "check",
Short: "Check the latest version of the binary installed by 'go install'",
Long: `Check the latest version of the binary installed by 'go install'
func newCheckCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "check",
Short: "Check the latest version of the binary installed by 'go install'",
Long: `Check the latest version of the binary installed by 'go install'
check subcommand checks if the binary is the latest version
and displays the name of the binary that needs to be updated.
However, do not update`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(check(cmd, args))
},
}
Run: func(cmd *cobra.Command, args []string) {
OsExit(check(cmd, args))
},
}

cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")

func init() {
rootCmd.AddCommand(checkCmd)
return cmd
}

func check(cmd *cobra.Command, args []string) int {
Expand All @@ -33,6 +38,12 @@ func check(cmd *cobra.Command, args []string) int {
return 1
}

cpus, err := cmd.Flags().GetInt("jobs")
if err != nil {
print.Err(fmt.Errorf("%s: %w", "can not parse command line argument (--jobs)", err))
return 1
}

pkgs, err := getPackageInfo()
if err != nil {
print.Err(err)
Expand All @@ -44,18 +55,29 @@ func check(cmd *cobra.Command, args []string) int {
print.Err("unable to check package: no package information")
return 1
}
return doCheck(pkgs)
return doCheck(pkgs, cpus)
}

func doCheck(pkgs []goutil.Package) int {
func doCheck(pkgs []goutil.Package, cpus int) int {
result := 0
countFmt := "[%" + pkgDigit(pkgs) + "d/%" + pkgDigit(pkgs) + "d]"
var mu sync.Mutex
needUpdatePkgs := []goutil.Package{}

print.Info("check binary under $GOPATH/bin or $GOBIN")
ch := make(chan updateResult)
checker := func(p goutil.Package, result chan updateResult) {
weighted := semaphore.NewWeighted(int64(cpus))
checker := func(ctx context.Context, p goutil.Package, result chan updateResult) {
if err := weighted.Acquire(ctx, 1); err != nil {
r := updateResult{
pkg: p,
err: err,
}
result <- r
return
}
defer weighted.Release(1)

var err error
if p.ModulePath == "" {
err = fmt.Errorf(" %s is not installed by 'go install' (or permission incorrect)", p.Name)
Expand All @@ -81,8 +103,9 @@ func doCheck(pkgs []goutil.Package) int {
}

// check all package
ctx := context.Background()
for _, v := range pkgs {
go checker(v, ch)
go checker(ctx, v, ch)
}

// print result
Expand Down
8 changes: 6 additions & 2 deletions cmd/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ func Test_check(t *testing.T) {
print.Stdout = pw
print.Stderr = pw

if got := check(tt.args.cmd, tt.args.args); got != tt.want {
cmd := &cobra.Command{}
cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
if got := check(cmd, tt.args.args); got != tt.want {
t.Errorf("check() = %v, want %v", got, tt.want)
}
pw.Close()
Expand Down Expand Up @@ -194,7 +196,9 @@ func Test_check_gobin_is_empty(t *testing.T) {
print.Stdout = pw
print.Stderr = pw

if got := check(tt.args.cmd, tt.args.args); got != tt.want {
cmd := &cobra.Command{}
cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
if got := check(cmd, tt.args.args); got != tt.want {
t.Errorf("check() = %v, want %v", got, tt.want)
}
pw.Close()
Expand Down
20 changes: 9 additions & 11 deletions cmd/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import (
"github.com/spf13/cobra"
)

var completionCmd = &cobra.Command{
Use: "completion",
Short: "Create shell completion files (bash, fish, zsh) for the gup",
Long: `Create shell completion files (bash, fish, zsh) for the gup command
func newCompletionCmd() *cobra.Command {
return &cobra.Command{
Use: "completion",
Short: "Create shell completion files (bash, fish, zsh) for the gup",
Long: `Create shell completion files (bash, fish, zsh) for the gup command
if it is not already on the system`,
Run: func(cmd *cobra.Command, args []string) {
completion.DeployShellCompletionFileIfNeeded(rootCmd)
},
}

func init() {
rootCmd.AddCommand(completionCmd)
Run: func(cmd *cobra.Command, args []string) {
completion.DeployShellCompletionFileIfNeeded(rootCmd)
},
}
}
24 changes: 12 additions & 12 deletions cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ import (
"github.com/spf13/cobra"
)

var exportCmd = &cobra.Command{
Use: "export",
Short: "Export the binary names under $GOPATH/bin and their path info. to gup.conf.",
Long: `Export the binary names under $GOPATH/bin and their path info. to gup.conf.
func newExportCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "export",
Short: "Export the binary names under $GOPATH/bin and their path info. to gup.conf.",
Long: `Export the binary names under $GOPATH/bin and their path info. to gup.conf.
Use the export subcommand if you want to install the same golang
binaries across multiple systems. By default, this sub-command
exports the file to $XDG_CONFIG_HOME/.config/gup/gup.conf (e.g. $HOME/.config/gup/gup.conf.)
After you have placed gup.conf in the same path hierarchy on
another system, you execute import subcommand. gup start the
installation according to the contents of gup.conf.`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(export(cmd, args))
},
}
Run: func(cmd *cobra.Command, args []string) {
OsExit(export(cmd, args))
},
}
cmd.Flags().BoolP("output", "o", false, "print command path information at STDOUT")

func init() {
exportCmd.Flags().BoolP("output", "o", false, "print command path information at STDOUT")
rootCmd.AddCommand(exportCmd)
return cmd
}

func export(cmd *cobra.Command, args []string) int {
Expand Down
39 changes: 24 additions & 15 deletions cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,36 @@ package cmd

import (
"fmt"
"runtime"

"github.com/nao1215/gup/internal/config"
"github.com/nao1215/gup/internal/file"
"github.com/nao1215/gup/internal/print"
"github.com/spf13/cobra"
)

var importCmd = &cobra.Command{
Use: "import",
Short: "Install command according to gup.conf.",
Long: `Install command according to gup.conf.
func newImportCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "import",
Short: "Install command according to gup.conf.",
Long: `Install command according to gup.conf.
Use the export subcommand if you want to install the same golang
binaries across multiple systems. After you create gup.conf by
import subcommand in another environment, you save conf-file in
$XDG_CONFIG_HOME/.config/gup/gup.conf (e.g. $HOME/.config/gup/gup.conf.)
Finally, you execute the export subcommand in this state.`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(runImport(cmd, args))
},
}
Run: func(cmd *cobra.Command, args []string) {
OsExit(runImport(cmd, args))
},
}

cmd.Flags().BoolP("dry-run", "n", false, "perform the trial update with no changes")
cmd.Flags().BoolP("notify", "N", false, "enable desktop notifications")
cmd.Flags().StringP("input", "i", config.FilePath(), "specify gup.conf file path to import")
cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")

func init() {
importCmd.Flags().BoolP("dry-run", "n", false, "perform the trial update with no changes")
importCmd.Flags().BoolP("notify", "N", false, "enable desktop notifications")
importCmd.Flags().StringP("input", "i", config.FilePath(), "specify gup.conf file path to import")
rootCmd.AddCommand(importCmd)
return cmd
}

func runImport(cmd *cobra.Command, args []string) int {
Expand All @@ -50,6 +53,12 @@ func runImport(cmd *cobra.Command, args []string) int {
return 1
}

cpus, err := cmd.Flags().GetInt("jobs")
if err != nil {
print.Err(fmt.Errorf("%s: %w", "can not parse command line argument (--jobs)", err))
return 1
}

if !file.IsFile(confFile) {
print.Err(fmt.Errorf("%s is not found", confFile))
return 1
Expand All @@ -67,5 +76,5 @@ func runImport(cmd *cobra.Command, args []string) int {
}

print.Info("start update based on " + confFile)
return update(pkgs, dryRun, notify)
return update(pkgs, dryRun, notify, cpus)
}
4 changes: 4 additions & 0 deletions cmd/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"io"
"os"
"runtime"
"strings"
"testing"

Expand Down Expand Up @@ -70,12 +71,15 @@ func Test_runImport_Error(t *testing.T) {
if tt.name == "argument parse error (--dry-run)" {
tt.args.cmd.Flags().StringP("input", "i", config.FilePath(), "specify gup.conf file path to import")
tt.args.cmd.Flags().BoolP("notify", "N", false, "enable desktop notifications")
tt.args.cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
} else if tt.name == "argument parse error (--input)" {
tt.args.cmd.Flags().BoolP("dry-run", "n", false, "perform the trial update with no changes")
tt.args.cmd.Flags().BoolP("notify", "N", false, "enable desktop notifications")
tt.args.cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
} else if tt.name == "argument parse error (--notify)" {
tt.args.cmd.Flags().BoolP("dry-run", "n", false, "perform the trial update with no changes")
tt.args.cmd.Flags().StringP("input", "i", config.FilePath(), "specify gup.conf file path to import")
tt.args.cmd.Flags().IntP("jobs", "j", runtime.NumCPU(), "Specify the number of CPU cores to use")
}

orgStdout := print.Stdout
Expand Down
20 changes: 9 additions & 11 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ import (
"github.com/spf13/cobra"
)

var listCmd = &cobra.Command{
Use: "list",
Short: "List up command name with package path and version under $GOPATH/bin or $GOBIN",
Long: `List up command name with package path and version under $GOPATH/bin or $GOBIN`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(list(cmd, args))
},
}

func init() {
rootCmd.AddCommand(listCmd)
func newListCmd() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List up command name with package path and version under $GOPATH/bin or $GOBIN",
Long: `List up command name with package path and version under $GOPATH/bin or $GOBIN`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(list(cmd, args))
},
}
}

func list(cmd *cobra.Command, args []string) int {
Expand Down
22 changes: 11 additions & 11 deletions cmd/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import (
"github.com/spf13/cobra"
)

var removeCmd = &cobra.Command{
Use: "remove",
Short: "Remove the binary under $GOPATH/bin or $GOBIN",
Long: `Remove command in $GOPATH/bin or $GOBIN.
func newRemoveCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "Remove the binary under $GOPATH/bin or $GOBIN",
Long: `Remove command in $GOPATH/bin or $GOBIN.
If you want to specify multiple binaries at once, separate them with space.
[e.g.] gup remove a_cmd b_cmd c_cmd`,
Run: func(cmd *cobra.Command, args []string) {
OsExit(remove(cmd, args))
},
}
Run: func(cmd *cobra.Command, args []string) {
OsExit(remove(cmd, args))
},
}
cmd.Flags().BoolP("force", "f", false, "Forcibly remove the file")

func init() {
removeCmd.Flags().BoolP("force", "f", false, "Forcibly remove the file")
rootCmd.AddCommand(removeCmd)
return cmd
}

func remove(cmd *cobra.Command, args []string) int {
Expand Down
10 changes: 10 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ func Execute() {
rootCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.SilenceUsage = true
rootCmd.SilenceErrors = true

rootCmd.AddCommand(newCheckCmd())
rootCmd.AddCommand(newCompletionCmd())
rootCmd.AddCommand(newExportCmd())
rootCmd.AddCommand(newImportCmd())
rootCmd.AddCommand(newListCmd())
rootCmd.AddCommand(newRemoveCmd())
rootCmd.AddCommand(newUpdateCmd())
rootCmd.AddCommand(newVersionCmd())

if err := rootCmd.Execute(); err != nil {
print.Err(err)
}
Expand Down
Loading

0 comments on commit 301eef4

Please sign in to comment.