Procházet zdrojové kódy

internal/cmd/generate-alias: directly invoke v2 internal_gengo

Now that Cl/167768 removed the dependency on protoc for the generated
test protos, the only remaining dependency is on protoc is for the
import public aliases.

However, we observe that we can avoid protoc since we already have
the file descriptor on hand for the remote targets. Using that,
we can invoke internal_gengo directly and circumvent any need for protoc.

With protoc no longer being a dependency, the integration script
loses its value, so can be deleted.

Change-Id: I522c1e4f2abc47be2817f3bd6b3ff9704b0abb83
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/167770
Reviewed-by: Herbie Ong <herbie@google.com>
Joe Tsai před 6 roky
rodič
revize
f5983a527b

+ 16 - 6
.travis.yml

@@ -1,6 +1,16 @@
-dist: xenial
-script:
-  - ./test.bash
-cache:
-  directories:
-  - .cache
+language: go
+before_install:
+  - mkdir /tmp/go1.12
+  - curl -L -s https://dl.google.com/go/go1.12.linux-amd64.tar.gz | tar -zxf - -C /tmp/go1.12 --strip-components 1
+  - unset GOROOT
+  - (GO111MODULE=on /tmp/go1.12/bin/go mod vendor)
+matrix:
+  include:
+    - go: 1.9.x
+      script: go test -v ./...
+    - go: 1.10.x
+      script: go test -v ./...
+    - go: 1.11.x
+      script: go test -v ./...
+    - go: 1.12.x
+      script: ./test.bash

+ 0 - 335
integration_test.go

@@ -1,335 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import (
-	"archive/tar"
-	"bytes"
-	"compress/gzip"
-	"flag"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"strings"
-	"testing"
-	"time"
-)
-
-var (
-	regenerate = flag.Bool("regenerate", false, "regenerate files")
-
-	protobufVersion = "3.7.0"
-	golangVersions  = []string{"1.9.7", "1.10.8", "1.11.5", "1.12"}
-	golangLatest    = golangVersions[len(golangVersions)-1]
-
-	// purgeTimeout determines the maximum age of unused sub-directories.
-	purgeTimeout = 30 * 24 * time.Hour // 1 month
-
-	// Variables initialized by mustInitDeps.
-	goPath     string
-	modulePath string
-)
-
-func Test(t *testing.T) {
-	mustInitDeps(t)
-
-	if *regenerate {
-		t.Run("Generate", func(t *testing.T) {
-			fmt.Print(mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-protos", "-execute"))
-			files := strings.Split(strings.TrimSpace(mustRunCommand(t, ".", "git", "ls-files", "*.go")), "\n")
-			mustRunCommand(t, ".", append([]string{"gofmt", "-w"}, files...)...)
-		})
-		t.SkipNow()
-	}
-
-	for _, v := range golangVersions {
-		t.Run("Go"+v, func(t *testing.T) {
-			runGo := func(label, workDir string, args ...string) {
-				args[0] += v
-				t.Run(label, func(t *testing.T) {
-					t.Parallel()
-					mustRunCommand(t, workDir, args...)
-				})
-			}
-			workDir := filepath.Join(goPath, "src", modulePath)
-			runGo("Build", workDir, "go", "build", "./...")
-			runGo("TestNormal", workDir, "go", "test", "-race", "./...")
-			runGo("TestReimpl", workDir, "go", "test", "-race", "-tags", "proto_reimpl", "./...")
-		})
-	}
-
-	t.Run("GeneratedGoFiles", func(t *testing.T) {
-		diff := mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-protos")
-		if strings.TrimSpace(diff) != "" {
-			t.Fatalf("stale generated files:\n%v", diff)
-		}
-	})
-	t.Run("FormattedGoFiles", func(t *testing.T) {
-		files := strings.Split(strings.TrimSpace(mustRunCommand(t, ".", "git", "ls-files", "*.go")), "\n")
-		diff := mustRunCommand(t, ".", append([]string{"gofmt", "-d"}, files...)...)
-		if strings.TrimSpace(diff) != "" {
-			t.Fatalf("unformatted source files:\n%v", diff)
-		}
-	})
-	t.Run("CommittedGitChanges", func(t *testing.T) {
-		diff := mustRunCommand(t, ".", "git", "diff", "--no-prefix", "HEAD")
-		if strings.TrimSpace(diff) != "" {
-			t.Fatalf("uncommitted changes:\n%v", diff)
-		}
-	})
-	t.Run("TrackedGitFiles", func(t *testing.T) {
-		diff := mustRunCommand(t, ".", "git", "ls-files", "--others", "--exclude-standard")
-		if strings.TrimSpace(diff) != "" {
-			t.Fatalf("untracked files:\n%v", diff)
-		}
-	})
-}
-
-func mustInitDeps(t *testing.T) {
-	check := func(err error) {
-		t.Helper()
-		if err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	// Determine the directory to place the test directory.
-	repoRoot, err := os.Getwd()
-	check(err)
-	testDir := filepath.Join(repoRoot, ".cache")
-	check(os.MkdirAll(testDir, 0775))
-
-	// Travis-CI has a hard-coded timeout where it kills the test after
-	// 10 minutes of a lack of activity on stdout.
-	// We work around this restriction by periodically printing the timestamp.
-	ticker := time.NewTicker(5 * time.Minute)
-	done := make(chan struct{})
-	go func() {
-		now := time.Now()
-		for {
-			select {
-			case t := <-ticker.C:
-				fmt.Printf("\tt=%0.fmin\n", t.Sub(now).Minutes())
-			case <-done:
-				return
-			}
-		}
-	}()
-	defer close(done)
-	defer ticker.Stop()
-
-	// Delete the current directory if non-empty,
-	// which only occurs if a dependency failed to initialize properly.
-	var workingDir string
-	defer func() {
-		if workingDir != "" {
-			os.RemoveAll(workingDir) // best-effort
-		}
-	}()
-
-	// Delete other sub-directories that are no longer relevant.
-	defer func() {
-		subDirs := map[string]bool{"bin": true, "gocache": true, "gopath": true}
-		subDirs["protobuf-"+protobufVersion] = true
-		for _, v := range golangVersions {
-			subDirs["go"+v] = true
-		}
-
-		now := time.Now()
-		fis, _ := ioutil.ReadDir(testDir)
-		for _, fi := range fis {
-			if subDirs[fi.Name()] {
-				os.Chtimes(filepath.Join(testDir, fi.Name()), now, now) // best-effort
-				continue
-			}
-			if now.Sub(fi.ModTime()) < purgeTimeout {
-				continue
-			}
-			fmt.Printf("delete %v\n", fi.Name())
-			os.RemoveAll(filepath.Join(testDir, fi.Name())) // best-effort
-		}
-	}()
-
-	// The bin directory contains symlinks to each tool by version.
-	// It is safe to delete this directory and run the test script from scratch.
-	binPath := filepath.Join(testDir, "bin")
-	check(os.RemoveAll(binPath))
-	check(os.Mkdir(binPath, 0775))
-	check(os.Setenv("PATH", binPath+":"+os.Getenv("PATH")))
-	registerBinary := func(name, path string) {
-		check(os.Symlink(path, filepath.Join(binPath, name)))
-	}
-
-	// Download and build the protobuf toolchain.
-	// We avoid downloading the pre-compiled binaries since they do not contain
-	// the conformance test runner.
-	workingDir = filepath.Join(testDir, "protobuf-"+protobufVersion)
-	if _, err := os.Stat(workingDir); err != nil {
-		fmt.Printf("download %v\n", filepath.Base(workingDir))
-		url := fmt.Sprintf("https://github.com/google/protobuf/releases/download/v%v/protobuf-all-%v.tar.gz", protobufVersion, protobufVersion)
-		downloadArchive(check, workingDir, url, "protobuf-"+protobufVersion)
-
-		fmt.Printf("build %v\n", filepath.Base(workingDir))
-		mustRunCommand(t, workingDir, "./autogen.sh")
-		mustRunCommand(t, workingDir, "./configure")
-		mustRunCommand(t, workingDir, "make")
-		mustRunCommand(t, filepath.Join(workingDir, "conformance"), "make")
-	}
-	patchProtos(check, workingDir)
-	check(os.Setenv("PROTOBUF_ROOT", workingDir)) // for generate-protos
-	registerBinary("conform-test-runner", filepath.Join(workingDir, "conformance", "conformance-test-runner"))
-	registerBinary("protoc", filepath.Join(workingDir, "src", "protoc"))
-	workingDir = ""
-
-	// Download each Go toolchain version.
-	for _, v := range golangVersions {
-		workingDir = filepath.Join(testDir, "go"+v)
-		if _, err := os.Stat(workingDir); err != nil {
-			fmt.Printf("download %v\n", filepath.Base(workingDir))
-			url := fmt.Sprintf("https://dl.google.com/go/go%v.%v-%v.tar.gz", v, runtime.GOOS, runtime.GOARCH)
-			downloadArchive(check, workingDir, url, "go")
-		}
-		registerBinary("go"+v, filepath.Join(workingDir, "bin", "go"))
-	}
-	registerBinary("go", filepath.Join(testDir, "go"+golangLatest, "bin", "go"))
-	registerBinary("gofmt", filepath.Join(testDir, "go"+golangLatest, "bin", "gofmt"))
-	workingDir = ""
-
-	// Travis-CI sets GOROOT, which confuses invocations of the Go toolchain.
-	// Explicitly clear GOROOT, so each toolchain uses their default GOROOT.
-	check(os.Unsetenv("GOROOT"))
-
-	// Set a cache directory within the test directory.
-	check(os.Setenv("GOCACHE", filepath.Join(testDir, "gocache")))
-
-	// Setup GOPATH for pre-module support (i.e., go1.10 and earlier).
-	goPath = filepath.Join(testDir, "gopath")
-	modulePath = strings.TrimSpace(mustRunCommand(t, testDir, "go", "list", "-m", "-f", "{{.Path}}"))
-	check(os.RemoveAll(filepath.Join(goPath, "src")))
-	check(os.MkdirAll(filepath.Join(goPath, "src", filepath.Dir(modulePath)), 0775))
-	check(os.Symlink(repoRoot, filepath.Join(goPath, "src", modulePath)))
-	mustRunCommand(t, repoRoot, "go", "mod", "tidy")
-	mustRunCommand(t, repoRoot, "go", "mod", "vendor")
-	check(os.Setenv("GOPATH", goPath))
-}
-
-func downloadArchive(check func(error), dstPath, srcURL, skipPrefix string) {
-	check(os.RemoveAll(dstPath))
-
-	resp, err := http.Get(srcURL)
-	check(err)
-	defer resp.Body.Close()
-
-	zr, err := gzip.NewReader(resp.Body)
-	check(err)
-
-	tr := tar.NewReader(zr)
-	for {
-		h, err := tr.Next()
-		if err == io.EOF {
-			return
-		}
-		check(err)
-
-		// Skip directories or files outside the prefix directory.
-		if len(skipPrefix) > 0 {
-			if !strings.HasPrefix(h.Name, skipPrefix) {
-				continue
-			}
-			if len(h.Name) > len(skipPrefix) && h.Name[len(skipPrefix)] != '/' {
-				continue
-			}
-		}
-
-		path := strings.TrimPrefix(strings.TrimPrefix(h.Name, skipPrefix), "/")
-		path = filepath.Join(dstPath, filepath.FromSlash(path))
-		mode := os.FileMode(h.Mode & 0777)
-		switch h.Typeflag {
-		case tar.TypeReg:
-			b, err := ioutil.ReadAll(tr)
-			check(err)
-			check(ioutil.WriteFile(path, b, mode))
-		case tar.TypeDir:
-			check(os.Mkdir(path, mode))
-		}
-	}
-}
-
-// patchProtos patches proto files with v2 locations of Go packages.
-// TODO: Commit these changes upstream.
-func patchProtos(check func(error), repoRoot string) {
-	javaPackageRx := regexp.MustCompile(`^option\s+java_package\s*=\s*".*"\s*;\s*$`)
-	goPackageRx := regexp.MustCompile(`^option\s+go_package\s*=\s*".*"\s*;\s*$`)
-	files := map[string]string{
-		"src/google/protobuf/any.proto":             "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/api.proto":             "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/duration.proto":        "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/empty.proto":           "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/field_mask.proto":      "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/source_context.proto":  "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/struct.proto":          "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/timestamp.proto":       "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/type.proto":            "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/wrappers.proto":        "github.com/golang/protobuf/v2/types/known;known_proto",
-		"src/google/protobuf/descriptor.proto":      "github.com/golang/protobuf/v2/types/descriptor;descriptor_proto",
-		"src/google/protobuf/compiler/plugin.proto": "github.com/golang/protobuf/v2/types/plugin;plugin_proto",
-		"conformance/conformance.proto":             "github.com/golang/protobuf/v2/internal/testprotos/conformance;conformance_proto",
-	}
-	for pbpath, gopath := range files {
-		b, err := ioutil.ReadFile(filepath.Join(repoRoot, pbpath))
-		check(err)
-		ss := strings.Split(string(b), "\n")
-
-		// Locate java_package and (possible) go_package options.
-		javaPackageIdx, goPackageIdx := -1, -1
-		for i, s := range ss {
-			if javaPackageIdx < 0 && javaPackageRx.MatchString(s) {
-				javaPackageIdx = i
-			}
-			if goPackageIdx < 0 && goPackageRx.MatchString(s) {
-				goPackageIdx = i
-			}
-		}
-
-		// Ensure the proto file has the correct go_package option.
-		opt := `option go_package = "` + gopath + `";`
-		if goPackageIdx >= 0 {
-			if ss[goPackageIdx] == opt {
-				continue // no changes needed
-			}
-			ss[goPackageIdx] = opt
-		} else {
-			// Insert go_package option before java_package option.
-			ss = append(ss[:javaPackageIdx], append([]string{opt}, ss[javaPackageIdx:]...)...)
-		}
-
-		fmt.Println("patch " + pbpath)
-		b = []byte(strings.Join(ss, "\n"))
-		check(ioutil.WriteFile(filepath.Join(repoRoot, pbpath), b, 0664))
-	}
-}
-
-func mustRunCommand(t *testing.T, dir string, args ...string) string {
-	t.Helper()
-	stdout := new(bytes.Buffer)
-	combined := new(bytes.Buffer)
-	cmd := exec.Command(args[0], args[1:]...)
-	cmd.Dir = dir
-	cmd.Env = append(os.Environ(), "PWD="+dir)
-	cmd.Stdout = io.MultiWriter(stdout, combined)
-	cmd.Stderr = combined
-	if err := cmd.Run(); err != nil {
-		t.Fatalf("executing (%v): %v\n%s", strings.Join(args, " "), err, combined.String())
-	}
-	return stdout.String()
-}

+ 114 - 0
internal/cmd/generate-alias/main.go

@@ -0,0 +1,114 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run . -execute
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"strings"
+
+	"github.com/golang/protobuf/proto"
+	gengo "github.com/golang/protobuf/v2/cmd/protoc-gen-go/internal_gengo"
+	"github.com/golang/protobuf/v2/protogen"
+	"github.com/golang/protobuf/v2/reflect/protodesc"
+	"github.com/golang/protobuf/v2/reflect/protoreflect"
+
+	descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
+	knownpb "github.com/golang/protobuf/v2/types/known"
+	pluginpb "github.com/golang/protobuf/v2/types/plugin"
+)
+
+func main() {
+	run := flag.Bool("execute", false, "Write generated files to destination.")
+	flag.Parse()
+
+	// Set of generated proto packages to forward to v2.
+	files := []struct {
+		goPkg  string
+		pbDesc protoreflect.FileDescriptor
+	}{{
+		goPkg:  "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor",
+		pbDesc: descriptorpb.File_google_protobuf_descriptor_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/protoc-gen-go/plugin;plugin_go",
+		pbDesc: pluginpb.File_google_protobuf_compiler_plugin_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/any;any",
+		pbDesc: knownpb.File_google_protobuf_any_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/duration;duration",
+		pbDesc: knownpb.File_google_protobuf_duration_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/timestamp;timestamp",
+		pbDesc: knownpb.File_google_protobuf_timestamp_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/wrappers;wrappers",
+		pbDesc: knownpb.File_google_protobuf_wrappers_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/struct;structpb",
+		pbDesc: knownpb.File_google_protobuf_struct_proto,
+	}, {
+		goPkg:  "github.com/golang/protobuf/ptypes/empty;empty",
+		pbDesc: knownpb.File_google_protobuf_empty_proto,
+	}}
+
+	// For each package, construct a proto file that public imports the package.
+	var req pluginpb.CodeGeneratorRequest
+	for _, file := range files {
+		pkgPath := file.goPkg[:strings.IndexByte(file.goPkg, ';')]
+		fd := &descriptorpb.FileDescriptorProto{
+			Name:             proto.String(pkgPath + "/" + path.Base(pkgPath) + ".proto"),
+			Syntax:           proto.String(file.pbDesc.Syntax().String()),
+			Dependency:       []string{file.pbDesc.Path()},
+			PublicDependency: []int32{0},
+			Options:          &descriptorpb.FileOptions{GoPackage: proto.String(file.goPkg)},
+		}
+		req.ProtoFile = append(req.ProtoFile, protodesc.ToFileDescriptorProto(file.pbDesc), fd)
+		req.FileToGenerate = append(req.FileToGenerate, fd.GetName())
+	}
+
+	// Use the internal logic of protoc-gen-go to generate the files.
+	gen, err := protogen.New(&req, nil)
+	check(err)
+	for _, file := range gen.Files {
+		if file.Generate {
+			gengo.GenerateFile(gen, file)
+		}
+	}
+
+	// Write the generated files.
+	resp := gen.Response()
+	if resp.Error != nil {
+		panic("gengo error: " + resp.GetError())
+	}
+	for _, file := range resp.File {
+		relPath, err := filepath.Rel(filepath.FromSlash("github.com/golang/protobuf"), file.GetName())
+		check(err)
+
+		check(ioutil.WriteFile(relPath+".bak", []byte(file.GetContent()), 0664))
+		if *run {
+			fmt.Println("#", relPath)
+			check(os.Rename(relPath+".bak", relPath))
+		} else {
+			cmd := exec.Command("diff", relPath, relPath+".bak", "-N", "-u")
+			cmd.Stdout = os.Stdout
+			cmd.Run()
+			os.Remove(relPath + ".bak") // best-effort delete
+		}
+	}
+}
+
+func check(err error) {
+	if err != nil {
+		panic(err)
+	}
+}

+ 0 - 146
internal/cmd/generate-protos/main.go

@@ -1,146 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:generate go run . -execute
-
-package main
-
-import (
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"strings"
-
-	gengo "github.com/golang/protobuf/v2/cmd/protoc-gen-go/internal_gengo"
-	"github.com/golang/protobuf/v2/protogen"
-)
-
-func init() {
-	// When the environment variable RUN_AS_PROTOC_PLUGIN is set,
-	// we skip running main and instead act as a protoc plugin.
-	// This allows the binary to pass itself to protoc.
-	if os.Getenv("RUN_AS_PROTOC_PLUGIN") == "1" {
-		protogen.Run(nil, func(gen *protogen.Plugin) error {
-			for _, file := range gen.Files {
-				if file.Generate {
-					gengo.GenerateFile(gen, file)
-				}
-			}
-			return nil
-		})
-		os.Exit(0)
-	}
-}
-
-var (
-	run        bool
-	protoRoot  string
-	repoRoot   string
-	modulePath string
-)
-
-func main() {
-	flag.BoolVar(&run, "execute", false, "Write generated files to destination.")
-	flag.StringVar(&protoRoot, "protoroot", os.Getenv("PROTOBUF_ROOT"), "The root of the protobuf source tree.")
-	flag.Parse()
-	if protoRoot == "" {
-		panic("protobuf source root is not set")
-	}
-
-	// Determine repository root path.
-	out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
-	check(err)
-	repoRoot = strings.TrimSpace(string(out))
-
-	// Determine the module path.
-	cmd := exec.Command("go", "list", "-m", "-f", "{{.Path}}")
-	cmd.Dir = repoRoot
-	out, err = cmd.CombinedOutput()
-	check(err)
-	modulePath = strings.TrimSpace(string(out))
-
-	generateLocalProtos()
-}
-
-func generateLocalProtos() {
-	tmpDir, err := ioutil.TempDir(repoRoot, "tmp")
-	check(err)
-	defer os.RemoveAll(tmpDir)
-
-	// Generate all local proto files.
-	dirs := []struct {
-		path string
-	}{
-		{path: "protoc-gen-go"},
-		{path: "ptypes"},
-	}
-	for _, d := range dirs {
-		srcDir := filepath.Join(repoRoot, filepath.FromSlash(d.path))
-		filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, err error) error {
-			if !strings.HasSuffix(srcPath, ".proto") {
-				return nil
-			}
-
-			impPath := tmpDir
-
-			relPath, err := filepath.Rel(repoRoot, srcPath)
-			check(err)
-			relPath = filepath.Join(filepath.FromSlash(modulePath), relPath)
-
-			dstDir := filepath.Join(tmpDir, filepath.Dir(relPath))
-			check(os.MkdirAll(dstDir, 0775))
-			check(os.Link(srcPath, filepath.Join(tmpDir, relPath)))
-
-			protoc("-I"+filepath.Join(protoRoot, "src"), "-I"+impPath, "--go_out="+tmpDir, relPath)
-			return nil
-		})
-	}
-
-	syncOutput(repoRoot, filepath.Join(tmpDir, filepath.FromSlash(modulePath)))
-}
-
-func protoc(args ...string) {
-	cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0])
-	cmd.Args = append(cmd.Args, args...)
-	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_PLUGIN=1")
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		fmt.Println(args)
-		fmt.Printf("executing: %v\n%s\n", strings.Join(cmd.Args, " "), out)
-	}
-	check(err)
-}
-
-func syncOutput(dstDir, srcDir string) {
-	filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
-		if !strings.HasSuffix(srcPath, ".go") {
-			return nil
-		}
-		relPath, err := filepath.Rel(srcDir, srcPath)
-		check(err)
-		dstPath := filepath.Join(dstDir, relPath)
-
-		if run {
-			fmt.Println("#", relPath)
-			b, err := ioutil.ReadFile(srcPath)
-			check(err)
-			check(os.MkdirAll(filepath.Dir(dstPath), 0775))
-			check(ioutil.WriteFile(dstPath, b, 0664))
-		} else {
-			cmd := exec.Command("diff", dstPath, srcPath, "-N", "-u")
-			cmd.Stdout = os.Stdout
-			cmd.Run()
-		}
-		return nil
-	})
-}
-
-func check(err error) {
-	if err != nil {
-		panic(err)
-	}
-}

+ 3 - 2
protoc-gen-go/descriptor/descriptor.pb.go

@@ -161,7 +161,7 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawdesc = []byte{
-	// 172 bytes of the wire-encoded FileDescriptorProto
+	// 180 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72,
@@ -172,7 +172,8 @@ var xxx_File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_prot
 	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65,
 	0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3b,
-	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x00,
+	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x32,
 }
 
 var xxx_File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawdesc)

+ 0 - 3
protoc-gen-go/descriptor/descriptor.proto

@@ -1,3 +0,0 @@
-syntax = "proto2";
-option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";
-import public "google/protobuf/descriptor.proto";

+ 2 - 2
protoc-gen-go/plugin/plugin.pb.go

@@ -29,7 +29,7 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_protoc_gen_go_plugin_plugin_proto_rawdesc = []byte{
-	// 164 bytes of the wire-encoded FileDescriptorProto
+	// 172 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69,
@@ -40,7 +40,7 @@ var xxx_File_github_com_golang_protobuf_protoc_gen_go_plugin_plugin_proto_rawdes
 	0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 	0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67,
 	0x6f, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x3b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f,
-	0x67, 0x6f, 0x50, 0x00,
+	0x67, 0x6f, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32,
 }
 
 var xxx_File_github_com_golang_protobuf_protoc_gen_go_plugin_plugin_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_protoc_gen_go_plugin_plugin_proto_rawdesc)

+ 0 - 3
protoc-gen-go/plugin/plugin.proto

@@ -1,3 +0,0 @@
-syntax = "proto2";
-option go_package = "github.com/golang/protobuf/protoc-gen-go/plugin;plugin_go";
-import public "google/protobuf/compiler/plugin.proto";

+ 4 - 3
ptypes/any/any.pb.go

@@ -26,15 +26,16 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_any_any_proto_rawdesc = []byte{
-	// 127 bytes of the wire-encoded FileDescriptorProto
+	// 131 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
 	0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
 	0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x27, 0x5a, 0x25,
+	0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
 	0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
 	0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
-	0x73, 0x2f, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x33,
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_any_any_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_ptypes_any_any_proto_rawdesc)

+ 0 - 3
ptypes/any/any.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/any";
-import public "google/protobuf/any.proto";

+ 4 - 4
ptypes/duration/duration.pb.go

@@ -26,17 +26,17 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_duration_duration_proto_rawdesc = []byte{
-	// 147 bytes of the wire-encoded FileDescriptorProto
+	// 156 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
 	0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
 	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
 	0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2c, 0x5a, 0x2a, 0x67,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
 	0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
 	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
-	0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_duration_duration_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_ptypes_duration_duration_proto_rawdesc)

+ 0 - 3
ptypes/duration/duration.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/duration";
-import public "google/protobuf/duration.proto";

+ 4 - 4
ptypes/empty/empty.pb.go

@@ -26,16 +26,16 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_empty_empty_proto_rawdesc = []byte{
-	// 135 bytes of the wire-encoded FileDescriptorProto
+	// 141 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
 	0x70, 0x65, 0x73, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x74, 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
 	0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x50, 0x00, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x3b, 0x65, 0x6d,
+	0x70, 0x74, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_empty_empty_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_ptypes_empty_empty_proto_rawdesc)

+ 0 - 3
ptypes/empty/empty.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/empty";
-import public "google/protobuf/empty.proto";

+ 0 - 3
ptypes/struct/struct.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
-import public "google/protobuf/struct.proto";

+ 6 - 5
ptypes/timestamp/timestamp.pb.go

@@ -26,17 +26,18 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawdesc = []byte{
-	// 151 bytes of the wire-encoded FileDescriptorProto
+	// 161 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
 	0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69,
 	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
 	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
-	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2d,
-	0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
+	0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37,
+	0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
-	0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69,
+	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawdesc)

+ 0 - 3
ptypes/timestamp/timestamp.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/timestamp";
-import public "google/protobuf/timestamp.proto";

+ 4 - 4
ptypes/wrappers/wrappers.pb.go

@@ -34,17 +34,17 @@ func init() {
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_wrappers_wrappers_proto_rawdesc = []byte{
-	// 147 bytes of the wire-encoded FileDescriptorProto
+	// 156 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
 	0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
 	0x70, 0x65, 0x73, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2f, 0x77, 0x72, 0x61,
 	0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
 	0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61,
-	0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2c, 0x5a, 0x2a, 0x67,
+	0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
 	0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
 	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
-	0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x3b, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65,
+	0x72, 0x73, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var xxx_File_github_com_golang_protobuf_ptypes_wrappers_wrappers_proto_rawdesc_gzipped = protoapi.CompressGZIP(xxx_File_github_com_golang_protobuf_ptypes_wrappers_wrappers_proto_rawdesc)

+ 0 - 3
ptypes/wrappers/wrappers.proto

@@ -1,3 +0,0 @@
-syntax = "proto3";
-option go_package = "github.com/golang/protobuf/ptypes/wrappers";
-import public "google/protobuf/wrappers.proto";

+ 1 - 1
regenerate.bash

@@ -4,5 +4,5 @@
 # license that can be found in the LICENSE file.
 
 cd "$(git rev-parse --show-toplevel)"
-go test -v -mod=vendor -timeout=60m -count=1 integration_test.go "$@" -regenerate
+go run ./internal/cmd/generate-alias -execute
 exit $?

+ 31 - 2
test.bash

@@ -4,5 +4,34 @@
 # license that can be found in the LICENSE file.
 
 cd "$(git rev-parse --show-toplevel)"
-go test -v -mod=vendor -timeout=60m -count=1 integration_test.go "$@"
-exit $?
+
+BOLD="\x1b[1mRunning: "
+PASS="\x1b[32mPASS"
+FAIL="\x1b[31mFAIL"
+RESET="\x1b[0m"
+
+echo -e "${BOLD}go test${RESET}"
+RET_TEST=$((go test ./... && go test -tags proto_reimpl ./...) | egrep -v "^(ok|[?])\s+")
+if [[ ! -z "$RET_TEST" ]]; then echo "$RET_TEST"; echo; fi
+
+echo -e "${BOLD}go generate${RESET}"
+RET_GEN=$(go run ./internal/cmd/generate-alias 2>&1)
+if [[ ! -z "$RET_GEN" ]]; then echo "$RET_GEN"; echo; fi
+
+echo -e "${BOLD}go fmt${RESET}"
+RET_FMT=$(gofmt -d $(git ls-files *.go) 2>&1)
+if [[ ! -z "$RET_FMT" ]]; then echo "$RET_FMT"; echo; fi
+
+echo -e "${BOLD}git diff${RESET}"
+RET_DIFF=$(git diff --no-prefix HEAD 2>&1)
+if [[ ! -z "$RET_DIFF" ]]; then echo "$RET_DIFF"; echo; fi
+
+echo -e "${BOLD}git ls-files${RESET}"
+RET_FILES=$(git ls-files --others --exclude-standard 2>&1)
+if [[ ! -z "$RET_FILES" ]]; then echo "$RET_FILES"; echo; fi
+
+if [[ ! -z "$RET_TEST" ]] || [[ ! -z "$RET_GEN" ]] || [ ! -z "$RET_FMT" ] || [[ ! -z "$RET_DIFF" ]] || [[ ! -z "$RET_FILES" ]]; then
+	echo -e "${FAIL}${RESET}"; exit 1
+else
+	echo -e "${PASS}${RESET}"; exit 0
+fi