storj/scripts/check-mod-tidy.go
2019-04-24 18:33:01 +03:00

113 lines
2.4 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// +build ignore
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
"github.com/kylelemons/godebug/diff"
)
var modfile = flag.String("mod", "go.mod", "original mod file")
func main() {
flag.Parse()
tempdir, err := ioutil.TempDir("", "check-mod-tidy")
checkf(err, "failed to create a temporary directory: %v\n", err)
defer func() {
err := os.RemoveAll(tempdir)
fmt.Fprintf(os.Stderr, "failed to delete temporary directory: %v\n", err)
}()
err = copyDir(".", tempdir)
checkf(err, "failed to copy directory: %v\n", err)
workingDir, err := os.Getwd()
checkf(err, "failed to get working directory: %v\n", err)
err = os.Chdir(tempdir)
checkf(err, "failed to change directory: %v\n", err)
defer os.Chdir(workingDir)
original, err := ioutil.ReadFile(*modfile)
checkf(err, "failed to read %q: %v\n", *modfile, err)
err = ioutil.WriteFile("go.mod", original, 0755)
checkf(err, "failed to write go.mod: %v\n", err)
err = tidy()
checkf(err, "failed to tidy go.mod: %v\n", err)
changed, err := ioutil.ReadFile("go.mod")
checkf(err, "failed to read go.mod: %v\n", err)
if !bytes.Equal(original, changed) {
diff, removed := difflines(string(original), string(changed))
fmt.Fprintln(os.Stderr, "go.mod is not tidy")
fmt.Fprintln(os.Stderr, diff)
if removed {
os.Exit(1)
}
}
}
func tidy() error {
var err error
for repeat := 2; repeat > 0; repeat-- {
cmd := exec.Command("go", "mod", "tidy")
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
err = cmd.Run()
if err != nil {
fmt.Fprintf(os.Stderr, "go mod tidy failed, retrying: %v", err)
continue
}
break
}
return err
}
func copyDir(src, dst string) error {
cmd := exec.Command("cp", "-a", src, dst)
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
return cmd.Run()
}
func checkf(err error, format string, args ...interface{}) {
if err == nil {
return
}
fmt.Fprintf(os.Stderr, format, args...)
os.Exit(1)
}
func difflines(a, b string) (patch string, removed bool) {
alines, blines := strings.Split(a, "\n"), strings.Split(b, "\n")
chunks := diff.DiffChunks(alines, blines)
buf := new(bytes.Buffer)
for _, c := range chunks {
for _, line := range c.Added {
fmt.Fprintf(buf, "+%s\n", line)
}
for _, line := range c.Deleted {
fmt.Fprintf(buf, "-%s\n", line)
removed = true
}
}
return strings.TrimRight(buf.String(), "\n"), removed
}