Limit number of concurrent goroutines
This commit is contained in:
parent
5fd9bc851b
commit
62dadc53bf
12 changed files with 206 additions and 103 deletions
58
app/app.go
58
app/app.go
|
|
@ -4,7 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"gitlab.com/revalus/grm/commands"
|
||||
"gitlab.com/revalus/grm/config"
|
||||
|
|
@ -24,28 +24,34 @@ type GitRepositoryManager struct {
|
|||
configuration config.Configuration
|
||||
}
|
||||
|
||||
func (g *GitRepositoryManager) Parse(args []string) {
|
||||
checkCriticalError := func(err error) {
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v", err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
func (g *GitRepositoryManager) Parse(args []string) error {
|
||||
arguments, err := config.ParseCliArguments(APP_NAME, APP_DESCRIPTION, args)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
arguments, err := config.ParseCliArguments(APP_NAME, APP_DESCRIPTION, args)
|
||||
checkCriticalError(err)
|
||||
|
||||
configFileContent, err := getFileContent(arguments.ConfigurationFile)
|
||||
checkCriticalError(err)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
fileExcension, err := getFileExcension(arguments.ConfigurationFile)
|
||||
checkCriticalError(err)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
configuration, err := config.GetRepositoryConfig(configFileContent, fileExcension)
|
||||
checkCriticalError(err)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
g.cliArguments = arguments
|
||||
g.configuration = configuration
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GitRepositoryManager) Run(w io.Writer) int {
|
||||
|
|
@ -55,7 +61,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||
|
||||
exitCode := 0
|
||||
|
||||
if len(g.cliArguments.LimitTags) != 0 {
|
||||
if len(g.cliArguments.LimitToTags) != 0 {
|
||||
err := g.limitTags()
|
||||
if err != nil {
|
||||
echo.ErrorfMsg(err.Error())
|
||||
|
|
@ -63,7 +69,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||
}
|
||||
}
|
||||
|
||||
if g.cliArguments.LimitName != "" {
|
||||
if g.cliArguments.LimitToName != "" {
|
||||
err := g.limitName()
|
||||
if err != nil {
|
||||
echo.ErrorfMsg(err.Error())
|
||||
|
|
@ -90,7 +96,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||
return exitCode
|
||||
}
|
||||
|
||||
func (g GitRepositoryManager) describeStatus(status commands.CommandStatus) {
|
||||
func describeStatus(status commands.CommandStatus) {
|
||||
if status.Error {
|
||||
echo.RedMessageF("Repository \"%v\": an error occurred: %v", status.Name, status.Message)
|
||||
return
|
||||
|
|
@ -107,7 +113,7 @@ func (g *GitRepositoryManager) limitTags() error {
|
|||
limitedTagsTmp := []config.RepositoryConfig{}
|
||||
|
||||
for _, item := range g.configuration.Repositories {
|
||||
if checkAnyOfItemInSlice(item.Tags, g.cliArguments.LimitTags) {
|
||||
if checkAnyOfItemInSlice(item.Tags, g.cliArguments.LimitToTags) {
|
||||
limitedTagsTmp = append(limitedTagsTmp, item)
|
||||
}
|
||||
}
|
||||
|
|
@ -120,7 +126,7 @@ func (g *GitRepositoryManager) limitTags() error {
|
|||
|
||||
func (g *GitRepositoryManager) limitName() error {
|
||||
for _, item := range g.configuration.Repositories {
|
||||
if g.cliArguments.LimitName == item.Name {
|
||||
if g.cliArguments.LimitToName == item.Name {
|
||||
g.configuration.Repositories = []config.RepositoryConfig{item}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -129,13 +135,19 @@ func (g *GitRepositoryManager) limitName() error {
|
|||
}
|
||||
|
||||
func (g *GitRepositoryManager) runCommand(cmd commands.Command) {
|
||||
statusChan := make(chan commands.CommandStatus)
|
||||
routines := make(chan struct{}, g.cliArguments.Routines)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, repo := range g.configuration.Repositories {
|
||||
go cmd.Command(repo, statusChan)
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
for range g.configuration.Repositories {
|
||||
g.describeStatus(<-statusChan)
|
||||
go func(r config.RepositoryConfig) {
|
||||
defer wg.Done()
|
||||
routines <- struct{}{}
|
||||
describeStatus(cmd.Command(r))
|
||||
|
||||
<-routines
|
||||
}(repo)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
|||
130
app/app_test.go
130
app/app_test.go
|
|
@ -31,7 +31,7 @@ func (emt ExpectedMessageTester) Write(p []byte) (n int, err error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig, cmdStatus chan commands.CommandStatus) {
|
||||
func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig) commands.CommandStatus {
|
||||
status := commands.CommandStatus{
|
||||
Name: repoCfg.Name,
|
||||
Changed: false,
|
||||
|
|
@ -46,7 +46,7 @@ func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig, cmdStatus c
|
|||
status.Changed = true
|
||||
}
|
||||
|
||||
cmdStatus <- status
|
||||
return status
|
||||
}
|
||||
|
||||
func prepareConfigContent() (string, string) {
|
||||
|
|
@ -122,9 +122,10 @@ func TestOutputFromSync(t *testing.T) {
|
|||
Workspace: "/tmp",
|
||||
},
|
||||
cliArguments: config.CliArguments{
|
||||
Sync: true,
|
||||
Version: true,
|
||||
Color: false,
|
||||
Sync: true,
|
||||
Version: true,
|
||||
Color: false,
|
||||
Routines: 10,
|
||||
},
|
||||
}
|
||||
emt := ExpectedMessageTester{
|
||||
|
|
@ -140,7 +141,8 @@ func TestOutputFromSync(t *testing.T) {
|
|||
func TestLimitTags(t *testing.T) {
|
||||
grm := GitRepositoryManager{
|
||||
cliArguments: config.CliArguments{
|
||||
LimitTags: []string{"example"},
|
||||
LimitToTags: []string{"example"},
|
||||
Routines: 10,
|
||||
},
|
||||
configuration: config.Configuration{
|
||||
Repositories: []config.RepositoryConfig{
|
||||
|
|
@ -169,7 +171,8 @@ func TestLimitTags(t *testing.T) {
|
|||
func TestLimitName(t *testing.T) {
|
||||
grm := GitRepositoryManager{
|
||||
cliArguments: config.CliArguments{
|
||||
LimitName: "notExample",
|
||||
LimitToName: "notExample",
|
||||
Routines: 10,
|
||||
},
|
||||
configuration: config.Configuration{
|
||||
Repositories: []config.RepositoryConfig{
|
||||
|
|
@ -196,7 +199,8 @@ func TestLimitName(t *testing.T) {
|
|||
func TestRunWithNotExistingNameInLimit(t *testing.T) {
|
||||
grm := GitRepositoryManager{
|
||||
cliArguments: config.CliArguments{
|
||||
LimitName: "not-existing-name",
|
||||
LimitToName: "not-existing-name",
|
||||
Routines: 10,
|
||||
},
|
||||
configuration: config.Configuration{
|
||||
Repositories: []config.RepositoryConfig{
|
||||
|
|
@ -221,7 +225,8 @@ func TestRunWithNotExistingNameInLimit(t *testing.T) {
|
|||
func TestRunWithNotExistingTagsInLimit(t *testing.T) {
|
||||
grm := GitRepositoryManager{
|
||||
cliArguments: config.CliArguments{
|
||||
LimitTags: []string{"not-existing-tag"},
|
||||
LimitToTags: []string{"not-existing-tag"},
|
||||
Routines: 10,
|
||||
},
|
||||
configuration: config.Configuration{
|
||||
Repositories: []config.RepositoryConfig{
|
||||
|
|
@ -249,7 +254,8 @@ func TestGetStatusOutput(t *testing.T) {
|
|||
Workspace: "/tmp",
|
||||
},
|
||||
cliArguments: config.CliArguments{
|
||||
Status: true,
|
||||
Status: true,
|
||||
Routines: 10,
|
||||
},
|
||||
}
|
||||
emt := ExpectedMessageTester{
|
||||
|
|
@ -262,6 +268,106 @@ func TestGetStatusOutput(t *testing.T) {
|
|||
if status != 0 {
|
||||
t.Errorf("Expected to get status %v, instead o this got %v", 1, status)
|
||||
}
|
||||
// Output:
|
||||
// Info: Current status of repositories
|
||||
}
|
||||
|
||||
func TestDescribeStatusErrorNoColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
"Repository \"Test\": an error occurred: test\n",
|
||||
},
|
||||
}
|
||||
echo.Color(false)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Error: true,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
||||
func TestDescribeStatusErrorColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
fmt.Sprintf("%vRepository \"Test\": an error occurred: test%v\n", echo.ColorRed, echo.ColorReset),
|
||||
},
|
||||
}
|
||||
echo.Color(true)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Error: true,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
||||
func TestDescribeStatusChangedNoColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
"Repository \"Test\": test\n",
|
||||
},
|
||||
}
|
||||
echo.Color(false)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Changed: true,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
||||
func TestDescribeStatusChangedColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
fmt.Sprintf("%vRepository \"Test\": test%v\n", echo.ColorYellow, echo.ColorReset),
|
||||
},
|
||||
}
|
||||
echo.Color(true)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Changed: true,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
||||
func TestDescribeStatusNoChangeNoColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
"Repository \"Test\": test\n",
|
||||
},
|
||||
}
|
||||
echo.Color(false)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Changed: false,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
||||
func TestDescribeStatusNoChangeColor(t *testing.T) {
|
||||
emt := ExpectedMessageTester{
|
||||
expectedMessages: []string{
|
||||
fmt.Sprintf("%vRepository \"Test\": test%v\n", echo.ColorGreen, echo.ColorReset),
|
||||
},
|
||||
}
|
||||
echo.Color(true)
|
||||
echo.Output(emt)
|
||||
status := commands.CommandStatus{
|
||||
Name: "Test",
|
||||
Message: "test",
|
||||
Changed: false,
|
||||
}
|
||||
|
||||
describeStatus(status)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue