cmd/bundle: add -tags flag

Adds a "-tags" flag that'll allow build tags
to be passed in and added to the very top of the
generated and bundled file.

For example, when generating h2_bundle.go for
net/http, we'll now be able to do:

    bundle -tags '!nethttpomithttp2' -o h2_bundle.go
                -prefix http2 golang.org/x/net/http2

Updates golang/go#35082

Change-Id: I55edd7227aec8641b60ba560c79e0d50d0692d52
Reviewed-on: https://go-review.googlesource.com/c/tools/+/205017
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/bundle/main.go b/cmd/bundle/main.go
index 7e95d58..a75b566 100644
--- a/cmd/bundle/main.go
+++ b/cmd/bundle/main.go
@@ -7,7 +7,7 @@
 //
 // Usage:
 //
-//	bundle [-o file] [-dst path] [-pkg name] [-prefix p] [-import old=new] <src>
+//	bundle [-o file] [-dst path] [-pkg name] [-prefix p] [-import old=new] [-tags build_constraints] <src>
 //
 // The src argument specifies the import path of the package to bundle.
 // The bundling of a directory of source files into a single source file
@@ -33,6 +33,7 @@
 // corresponding symbols.
 // Bundle also must write a package declaration in the output and must
 // choose a name to use in that declaration.
+// Build constraints for the generated file can be specified using the -tags option.
 // If the -package option is given, bundle uses that name.
 // Otherwise, if the -dst option is given, bundle uses the last
 // element of the destination import path.
@@ -59,12 +60,14 @@
 // Bundle golang.org/x/net/http2 for inclusion in net/http,
 // prefixing all identifiers by "http2" instead of "http2_",
 // and rewriting the import "golang.org/x/net/http2/hpack"
-// to "internal/golang.org/x/net/http2/hpack":
+// to "internal/golang.org/x/net/http2/hpack", and also include
+// a "!nethttpomithttp2" build constraint:
 //
 //	cd $GOROOT/src/net/http
 //	bundle -o h2_bundle.go \
 //		-prefix http2 \
 //		-import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack \
+//		-tags '!nethttpomithttp2' \
 //		golang.org/x/net/http2
 //
 // Two ways to update the http2 bundle:
@@ -107,6 +110,7 @@
 	pkgName    = flag.String("pkg", "", "set destination package `name` (default taken from current directory)")
 	prefix     = flag.String("prefix", "&_", "set bundled identifier prefix to `p` (default is \"&_\", where & stands for the original name)")
 	underscore = flag.Bool("underscore", false, "rewrite golang.org/x/* to internal/x/* imports; temporary workaround for golang.org/issue/16333")
+	buildTags  = flag.String("tags", "", "the build constraints to be inserted into the generated file")
 
 	importMap = map[string]string{}
 )
@@ -160,7 +164,7 @@
 		}
 	}
 
-	code, err := bundle(args[0], *dstPath, *pkgName, *prefix)
+	code, err := bundle(args[0], *dstPath, *pkgName, *prefix, *buildTags)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -189,7 +193,7 @@
 
 var ctxt = &build.Default
 
-func bundle(src, dst, dstpkg, prefix string) ([]byte, error) {
+func bundle(src, dst, dstpkg, prefix, buildTags string) ([]byte, error) {
 	// Load the initial package.
 	conf := loader.Config{ParserMode: parser.ParseComments, Build: ctxt}
 	conf.TypeCheckFuncBodies = func(p string) bool { return p == src }
@@ -237,9 +241,12 @@
 	}
 
 	var out bytes.Buffer
+	if buildTags != "" {
+		fmt.Fprintf(&out, "// +build %s\n\n", buildTags)
+	}
 
 	fmt.Fprintf(&out, "// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.\n")
-	if *outputFile != "" {
+	if *outputFile != "" && buildTags == "" {
 		fmt.Fprintf(&out, "//go:generate bundle %s\n", strings.Join(os.Args[1:], " "))
 	} else {
 		fmt.Fprintf(&out, "//   $ bundle %s\n", strings.Join(os.Args[1:], " "))
diff --git a/cmd/bundle/main_test.go b/cmd/bundle/main_test.go
index b96f7d9..149f609 100644
--- a/cmd/bundle/main_test.go
+++ b/cmd/bundle/main_test.go
@@ -41,7 +41,7 @@
 	})
 
 	os.Args = os.Args[:1] // avoid e.g. -test=short in the output
-	out, err := bundle("initial", "github.com/dest", "dest", "prefix")
+	out, err := bundle("initial", "github.com/dest", "dest", "prefix", "tag")
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/cmd/bundle/testdata/out.golden b/cmd/bundle/testdata/out.golden
index 5260fdd..ed18e3d 100644
--- a/cmd/bundle/testdata/out.golden
+++ b/cmd/bundle/testdata/out.golden
@@ -1,3 +1,5 @@
+// +build tag
+
 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
 //   $ bundle