From c46413539ed11764effefea79014c63e93414699 Mon Sep 17 00:00:00 2001 From: Mithun Ayachit Date: Wed, 12 Feb 2020 06:05:24 -0600 Subject: [PATCH] replace WaitGroup with errgroup to allow error handling and propagation The program now exits with a non-zero code when errors are encountered while reading and/or writing files. This now also introduces Go Modules for dependency management --- .travis.yml | 6 +++--- go.mod | 5 +++++ go.sum | 2 ++ main.go | 20 ++++++++++++-------- main_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/.travis.yml b/.travis.yml index 9fdc7d8..606f878 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,13 @@ -dist: xenial +dist: bionic git: depth: 3 language: go go: - - "1.x" - - "1.10.x" + - 1.13.x before_script: - go get golang.org/x/lint/golint script: + - go mod tidy - gofmt -d -e -l -s . - golint -set_exit_status ./... - go test -v ./... diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3ab7c66 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/google/addlicense + +go 1.13 + +require golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0d5bc22 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/main.go b/main.go index 4d08891..e47a2d8 100644 --- a/main.go +++ b/main.go @@ -26,8 +26,9 @@ import ( "os" "path/filepath" "strings" - "sync" "time" + + "golang.org/x/sync/errgroup" ) const helpText = `Usage: addlicense [flags] pattern [pattern ...] @@ -92,23 +93,26 @@ func main() { ch := make(chan *file, 1000) done := make(chan struct{}) go func() { - var wg sync.WaitGroup + var wg errgroup.Group for f := range ch { - wg.Add(1) - go func(f *file) { - defer wg.Done() + f := f // https://golang.org/doc/faq#closures_and_goroutines + wg.Go(func() error { modified, err := addLicense(f.path, f.mode, t, data) if err != nil { log.Printf("%s: %v", f.path, err) - return + return err } if *verbose && modified { log.Printf("%s modified", f.path) } - }(f) + return nil + }) } - wg.Wait() + err := wg.Wait() close(done) + if err != nil { + os.Exit(1) + } }() for _, d := range flag.Args() { diff --git a/main_test.go b/main_test.go index 334d170..407d3e3 100644 --- a/main_test.go +++ b/main_test.go @@ -87,3 +87,55 @@ func TestMultiyear(t *testing.T) { } run(t, "diff", samplefile, sampleLicensed) } + +func TestWriteErrors(t *testing.T) { + if os.Getenv("RUNME") != "" { + main() + return + } + + tmp := tempDir(t) + t.Logf("tmp dir: %s", tmp) + samplefile := filepath.Join(tmp, "file.c") + + run(t, "cp", "testdata/initial/file.c", samplefile) + run(t, "chmod", "0444", samplefile) + cmd := exec.Command(os.Args[0], + "-test.run=TestWriteErrors", + "-l", "apache", "-c", "Google LLC", "-y", "2018", + samplefile, + ) + cmd.Env = []string{"RUNME=1"} + out, err := cmd.CombinedOutput() + if err == nil { + run(t, "chmod", "0644", samplefile) + t.Fatalf("TestWriteErrors exited with a zero exit code.\n%s", out) + } + run(t, "chmod", "0644", samplefile) +} + +func TestReadErrors(t *testing.T) { + if os.Getenv("RUNME") != "" { + main() + return + } + + tmp := tempDir(t) + t.Logf("tmp dir: %s", tmp) + samplefile := filepath.Join(tmp, "file.c") + + run(t, "cp", "testdata/initial/file.c", samplefile) + run(t, "chmod", "a-r", samplefile) + cmd := exec.Command(os.Args[0], + "-test.run=TestReadErrors", + "-l", "apache", "-c", "Google LLC", "-y", "2018", + samplefile, + ) + cmd.Env = []string{"RUNME=1"} + out, err := cmd.CombinedOutput() + if err == nil { + run(t, "chmod", "0644", samplefile) + t.Fatalf("TestWriteErrors exited with a zero exit code.\n%s", out) + } + run(t, "chmod", "0644", samplefile) +}