Use param files with go-protoc (#3190)

If Bazel uses a param file for the args to go-protoc, go-protoc will
in turn use a param file for protoc.
diff --git a/go/tools/builders/asm.go b/go/tools/builders/asm.go
index 18f9f84..1e3a8ba 100644
--- a/go/tools/builders/asm.go
+++ b/go/tools/builders/asm.go
@@ -30,7 +30,7 @@
 // Go rules as an action.
 func asm(args []string) error {
 	// Parse arguments.
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/builder.go b/go/tools/builders/builder.go
index 8ccd746..a0ff0dc 100644
--- a/go/tools/builders/builder.go
+++ b/go/tools/builders/builder.go
@@ -28,7 +28,7 @@
 	log.SetFlags(0)
 	log.SetPrefix("builder: ")
 
-	args, err := expandParamsFiles(os.Args[1:])
+	args, _, err := expandParamsFiles(os.Args[1:])
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/go/tools/builders/compile.go b/go/tools/builders/compile.go
index f22ac43..b83c9a7 100644
--- a/go/tools/builders/compile.go
+++ b/go/tools/builders/compile.go
@@ -29,7 +29,7 @@
 
 func compile(args []string) error {
 	// Parse arguments.
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/compilepkg.go b/go/tools/builders/compilepkg.go
index 19572c5..09e3ef6 100644
--- a/go/tools/builders/compilepkg.go
+++ b/go/tools/builders/compilepkg.go
@@ -33,7 +33,7 @@
 
 func compilePkg(args []string) error {
 	// Parse arguments.
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/cover.go b/go/tools/builders/cover.go
index efaab8b..d387a18 100644
--- a/go/tools/builders/cover.go
+++ b/go/tools/builders/cover.go
@@ -28,7 +28,7 @@
 // cover transforms a source file with "go tool cover". It is invoked by the
 // Go rules as an action.
 func cover(args []string) error {
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/env.go b/go/tools/builders/env.go
index b4b5ede..4307e69 100644
--- a/go/tools/builders/env.go
+++ b/go/tools/builders/env.go
@@ -176,7 +176,9 @@
 // expandParamsFiles looks for arguments in args of the form
 // "-param=filename". When it finds these arguments it reads the file "filename"
 // and replaces the argument with its content.
-func expandParamsFiles(args []string) ([]string, error) {
+// It returns the expanded arguments as well as a bool that is true if any param
+// files have been passed.
+func expandParamsFiles(args []string) ([]string, bool, error) {
 	var paramsIndices []int
 	for i, arg := range args {
 		if strings.HasPrefix(arg, "-param=") {
@@ -184,7 +186,7 @@
 		}
 	}
 	if len(paramsIndices) == 0 {
-		return args, nil
+		return args, false, nil
 	}
 	var expandedArgs []string
 	last := 0
@@ -195,12 +197,12 @@
 		fileName := args[pi][len("-param="):]
 		fileArgs, err := readParamsFile(fileName)
 		if err != nil {
-			return nil, err
+			return nil, true, err
 		}
 		expandedArgs = append(expandedArgs, fileArgs...)
 	}
 	expandedArgs = append(expandedArgs, args[last:]...)
-	return expandedArgs, nil
+	return expandedArgs, true, nil
 }
 
 // readParamsFiles parses a Bazel params file in "shell" format. The file
diff --git a/go/tools/builders/generate_test_main.go b/go/tools/builders/generate_test_main.go
index 3ae6fb6..a85e110 100644
--- a/go/tools/builders/generate_test_main.go
+++ b/go/tools/builders/generate_test_main.go
@@ -228,7 +228,7 @@
 
 func genTestMain(args []string) error {
 	// Prepare our flags
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/info.go b/go/tools/builders/info.go
index 852a98e..f7f1fd0 100644
--- a/go/tools/builders/info.go
+++ b/go/tools/builders/info.go
@@ -24,7 +24,7 @@
 )
 
 func run(args []string) error {
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/link.go b/go/tools/builders/link.go
index 70c9334..7ba8daf 100644
--- a/go/tools/builders/link.go
+++ b/go/tools/builders/link.go
@@ -32,7 +32,7 @@
 
 func link(args []string) error {
 	// Parse arguments.
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/nogo_main.go b/go/tools/builders/nogo_main.go
index e30bffb..97c683e 100644
--- a/go/tools/builders/nogo_main.go
+++ b/go/tools/builders/nogo_main.go
@@ -62,7 +62,7 @@
 // run returns an error if there is a problem loading the package or if any
 // analysis fails.
 func run(args []string) error {
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return fmt.Errorf("error reading paramfiles: %v", err)
 	}
diff --git a/go/tools/builders/pack.go b/go/tools/builders/pack.go
index 61324f4..14d3976 100644
--- a/go/tools/builders/pack.go
+++ b/go/tools/builders/pack.go
@@ -38,7 +38,7 @@
 // handle them, and ar may not be available (cpp.ar_executable is libtool
 // on darwin).
 func pack(args []string) error {
-	args, err := expandParamsFiles(args)
+	args, _, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
diff --git a/go/tools/builders/protoc.go b/go/tools/builders/protoc.go
index 44e6f84..46a9f01 100644
--- a/go/tools/builders/protoc.go
+++ b/go/tools/builders/protoc.go
@@ -41,7 +41,7 @@
 
 func run(args []string) error {
 	// process the args
-	args, err := expandParamsFiles(args)
+	args, useParamFile, err := expandParamsFiles(args)
 	if err != nil {
 		return err
 	}
@@ -89,7 +89,24 @@
 		"--descriptor_set_in", strings.Join(descriptors, string(os.PathListSeparator)),
 	}
 	protoc_args = append(protoc_args, flags.Args()...)
-	cmd := exec.Command(*protoc, protoc_args...)
+
+	var cmd *exec.Cmd
+	if useParamFile {
+		paramFile, err := ioutil.TempFile(tmpDir, "protoc-*.params")
+		if err != nil {
+			return fmt.Errorf("error creating param file for protoc: %v", err)
+		}
+		for _, arg := range protoc_args {
+			_, err := fmt.Fprintln(paramFile, arg)
+			if err != nil {
+				return fmt.Errorf("error writing param file for protoc: %v", err)
+			}
+		}
+		cmd = exec.Command(*protoc, "@"+paramFile.Name())
+	} else {
+		cmd = exec.Command(*protoc, protoc_args...)
+	}
+
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	if err := cmd.Run(); err != nil {
diff --git a/proto/compiler.bzl b/proto/compiler.bzl
index 2502213..3601c7b 100644
--- a/proto/compiler.bzl
+++ b/proto/compiler.bzl
@@ -112,6 +112,7 @@
     args.add_all(go_srcs, before_each = "-expected")
     args.add_all(imports, before_each = "-import")
     args.add_all(proto_paths.keys())
+    args.use_param_file("-param=%s")
     go.actions.run(
         inputs = depset(
             direct = [