113 lines
2.4 KiB
Go
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
|
||
|
}
|