xref: /aosp_15_r20/external/golang-protobuf/internal/cmd/generate-protos/main.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsen//go:generate go run . -execute
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenpackage main
8*1c12ee1eSDan Willemsen
9*1c12ee1eSDan Willemsenimport (
10*1c12ee1eSDan Willemsen	"bytes"
11*1c12ee1eSDan Willemsen	"flag"
12*1c12ee1eSDan Willemsen	"fmt"
13*1c12ee1eSDan Willemsen	"go/format"
14*1c12ee1eSDan Willemsen	"io/ioutil"
15*1c12ee1eSDan Willemsen	"os"
16*1c12ee1eSDan Willemsen	"os/exec"
17*1c12ee1eSDan Willemsen	"path"
18*1c12ee1eSDan Willemsen	"path/filepath"
19*1c12ee1eSDan Willemsen	"regexp"
20*1c12ee1eSDan Willemsen	"sort"
21*1c12ee1eSDan Willemsen	"strconv"
22*1c12ee1eSDan Willemsen	"strings"
23*1c12ee1eSDan Willemsen
24*1c12ee1eSDan Willemsen	gengo "google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo"
25*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/compiler/protogen"
26*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/detrand"
27*1c12ee1eSDan Willemsen)
28*1c12ee1eSDan Willemsen
29*1c12ee1eSDan Willemsenfunc init() {
30*1c12ee1eSDan Willemsen	// Determine repository root path.
31*1c12ee1eSDan Willemsen	out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
32*1c12ee1eSDan Willemsen	check(err)
33*1c12ee1eSDan Willemsen	repoRoot = strings.TrimSpace(string(out))
34*1c12ee1eSDan Willemsen
35*1c12ee1eSDan Willemsen	// Determine the module path.
36*1c12ee1eSDan Willemsen	cmd := exec.Command("go", "list", "-m", "-f", "{{.Path}}")
37*1c12ee1eSDan Willemsen	cmd.Dir = repoRoot
38*1c12ee1eSDan Willemsen	out, err = cmd.CombinedOutput()
39*1c12ee1eSDan Willemsen	check(err)
40*1c12ee1eSDan Willemsen	modulePath = strings.TrimSpace(string(out))
41*1c12ee1eSDan Willemsen
42*1c12ee1eSDan Willemsen	// When the environment variable RUN_AS_PROTOC_PLUGIN is set,
43*1c12ee1eSDan Willemsen	// we skip running main and instead act as a protoc plugin.
44*1c12ee1eSDan Willemsen	// This allows the binary to pass itself to protoc.
45*1c12ee1eSDan Willemsen	if plugin := os.Getenv("RUN_AS_PROTOC_PLUGIN"); plugin != "" {
46*1c12ee1eSDan Willemsen		// Disable deliberate output instability for generated files.
47*1c12ee1eSDan Willemsen		// This is reasonable since we fully control the output.
48*1c12ee1eSDan Willemsen		detrand.Disable()
49*1c12ee1eSDan Willemsen
50*1c12ee1eSDan Willemsen		protogen.Options{}.Run(func(gen *protogen.Plugin) error {
51*1c12ee1eSDan Willemsen			for _, file := range gen.Files {
52*1c12ee1eSDan Willemsen				if file.Generate {
53*1c12ee1eSDan Willemsen					gengo.GenerateVersionMarkers = false
54*1c12ee1eSDan Willemsen					gengo.GenerateFile(gen, file)
55*1c12ee1eSDan Willemsen					generateIdentifiers(gen, file)
56*1c12ee1eSDan Willemsen					generateSourceContextStringer(gen, file)
57*1c12ee1eSDan Willemsen				}
58*1c12ee1eSDan Willemsen			}
59*1c12ee1eSDan Willemsen			gen.SupportedFeatures = gengo.SupportedFeatures
60*1c12ee1eSDan Willemsen			return nil
61*1c12ee1eSDan Willemsen		})
62*1c12ee1eSDan Willemsen		os.Exit(0)
63*1c12ee1eSDan Willemsen	}
64*1c12ee1eSDan Willemsen}
65*1c12ee1eSDan Willemsen
66*1c12ee1eSDan Willemsenvar (
67*1c12ee1eSDan Willemsen	run        bool
68*1c12ee1eSDan Willemsen	protoRoot  string
69*1c12ee1eSDan Willemsen	repoRoot   string
70*1c12ee1eSDan Willemsen	modulePath string
71*1c12ee1eSDan Willemsen
72*1c12ee1eSDan Willemsen	generatedPreamble = []string{
73*1c12ee1eSDan Willemsen		"// Copyright 2019 The Go Authors. All rights reserved.",
74*1c12ee1eSDan Willemsen		"// Use of this source code is governed by a BSD-style",
75*1c12ee1eSDan Willemsen		"// license that can be found in the LICENSE file.",
76*1c12ee1eSDan Willemsen		"",
77*1c12ee1eSDan Willemsen		"// Code generated by generate-protos. DO NOT EDIT.",
78*1c12ee1eSDan Willemsen		"",
79*1c12ee1eSDan Willemsen	}
80*1c12ee1eSDan Willemsen)
81*1c12ee1eSDan Willemsen
82*1c12ee1eSDan Willemsenfunc main() {
83*1c12ee1eSDan Willemsen	flag.BoolVar(&run, "execute", false, "Write generated files to destination.")
84*1c12ee1eSDan Willemsen	flag.StringVar(&protoRoot, "protoroot", os.Getenv("PROTOBUF_ROOT"), "The root of the protobuf source tree.")
85*1c12ee1eSDan Willemsen	flag.Parse()
86*1c12ee1eSDan Willemsen	if protoRoot == "" {
87*1c12ee1eSDan Willemsen		panic("protobuf source root is not set")
88*1c12ee1eSDan Willemsen	}
89*1c12ee1eSDan Willemsen
90*1c12ee1eSDan Willemsen	generateLocalProtos()
91*1c12ee1eSDan Willemsen	generateRemoteProtos()
92*1c12ee1eSDan Willemsen}
93*1c12ee1eSDan Willemsen
94*1c12ee1eSDan Willemsenfunc generateLocalProtos() {
95*1c12ee1eSDan Willemsen	tmpDir, err := ioutil.TempDir(repoRoot, "tmp")
96*1c12ee1eSDan Willemsen	check(err)
97*1c12ee1eSDan Willemsen	defer os.RemoveAll(tmpDir)
98*1c12ee1eSDan Willemsen
99*1c12ee1eSDan Willemsen	// Generate all local proto files (except version-locked files).
100*1c12ee1eSDan Willemsen	dirs := []struct {
101*1c12ee1eSDan Willemsen		path     string
102*1c12ee1eSDan Willemsen		pkgPaths map[string]string // mapping of .proto path to Go package path
103*1c12ee1eSDan Willemsen		annotate map[string]bool   // .proto files to annotate
104*1c12ee1eSDan Willemsen		exclude  map[string]bool   // .proto files to exclude from generation
105*1c12ee1eSDan Willemsen	}{{
106*1c12ee1eSDan Willemsen		path:     "cmd/protoc-gen-go/testdata",
107*1c12ee1eSDan Willemsen		pkgPaths: map[string]string{"cmd/protoc-gen-go/testdata/nopackage/nopackage.proto": "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/nopackage"},
108*1c12ee1eSDan Willemsen		annotate: map[string]bool{"cmd/protoc-gen-go/testdata/annotations/annotations.proto": true},
109*1c12ee1eSDan Willemsen	}, {
110*1c12ee1eSDan Willemsen		path:    "internal/testprotos",
111*1c12ee1eSDan Willemsen		exclude: map[string]bool{"internal/testprotos/irregular/irregular.proto": true},
112*1c12ee1eSDan Willemsen	}}
113*1c12ee1eSDan Willemsen	excludeRx := regexp.MustCompile(`legacy/.*/`)
114*1c12ee1eSDan Willemsen	for _, d := range dirs {
115*1c12ee1eSDan Willemsen		subDirs := map[string]bool{}
116*1c12ee1eSDan Willemsen
117*1c12ee1eSDan Willemsen		srcDir := filepath.Join(repoRoot, filepath.FromSlash(d.path))
118*1c12ee1eSDan Willemsen		filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
119*1c12ee1eSDan Willemsen			if !strings.HasSuffix(srcPath, ".proto") || excludeRx.MatchString(srcPath) {
120*1c12ee1eSDan Willemsen				return nil
121*1c12ee1eSDan Willemsen			}
122*1c12ee1eSDan Willemsen			relPath, err := filepath.Rel(repoRoot, srcPath)
123*1c12ee1eSDan Willemsen			check(err)
124*1c12ee1eSDan Willemsen
125*1c12ee1eSDan Willemsen			srcRelPath, err := filepath.Rel(srcDir, srcPath)
126*1c12ee1eSDan Willemsen			check(err)
127*1c12ee1eSDan Willemsen			subDirs[filepath.Dir(srcRelPath)] = true
128*1c12ee1eSDan Willemsen
129*1c12ee1eSDan Willemsen			if d.exclude[filepath.ToSlash(relPath)] {
130*1c12ee1eSDan Willemsen				return nil
131*1c12ee1eSDan Willemsen			}
132*1c12ee1eSDan Willemsen
133*1c12ee1eSDan Willemsen			opts := "module=" + modulePath
134*1c12ee1eSDan Willemsen			for protoPath, goPkgPath := range d.pkgPaths {
135*1c12ee1eSDan Willemsen				opts += fmt.Sprintf(",M%v=%v", protoPath, goPkgPath)
136*1c12ee1eSDan Willemsen			}
137*1c12ee1eSDan Willemsen			if d.annotate[filepath.ToSlash(relPath)] {
138*1c12ee1eSDan Willemsen				opts += ",annotate_code"
139*1c12ee1eSDan Willemsen			}
140*1c12ee1eSDan Willemsen			protoc("-I"+filepath.Join(protoRoot, "src"), "-I"+repoRoot, "--go_out="+opts+":"+tmpDir, relPath)
141*1c12ee1eSDan Willemsen			return nil
142*1c12ee1eSDan Willemsen		})
143*1c12ee1eSDan Willemsen
144*1c12ee1eSDan Willemsen		// For directories in testdata, generate a test that links in all
145*1c12ee1eSDan Willemsen		// generated packages to ensure that it builds and initializes properly.
146*1c12ee1eSDan Willemsen		// This is done because "go build ./..." does not build sub-packages
147*1c12ee1eSDan Willemsen		// under testdata.
148*1c12ee1eSDan Willemsen		if filepath.Base(d.path) == "testdata" {
149*1c12ee1eSDan Willemsen			var imports []string
150*1c12ee1eSDan Willemsen			for sd := range subDirs {
151*1c12ee1eSDan Willemsen				imports = append(imports, fmt.Sprintf("_ %q", path.Join(modulePath, d.path, filepath.ToSlash(sd))))
152*1c12ee1eSDan Willemsen			}
153*1c12ee1eSDan Willemsen			sort.Strings(imports)
154*1c12ee1eSDan Willemsen
155*1c12ee1eSDan Willemsen			s := strings.Join(append(generatedPreamble, []string{
156*1c12ee1eSDan Willemsen				"package main",
157*1c12ee1eSDan Willemsen				"",
158*1c12ee1eSDan Willemsen				"import (" + strings.Join(imports, "\n") + ")",
159*1c12ee1eSDan Willemsen			}...), "\n")
160*1c12ee1eSDan Willemsen			b, err := format.Source([]byte(s))
161*1c12ee1eSDan Willemsen			check(err)
162*1c12ee1eSDan Willemsen			check(ioutil.WriteFile(filepath.Join(tmpDir, filepath.FromSlash(d.path+"/gen_test.go")), b, 0664))
163*1c12ee1eSDan Willemsen		}
164*1c12ee1eSDan Willemsen	}
165*1c12ee1eSDan Willemsen
166*1c12ee1eSDan Willemsen	syncOutput(repoRoot, tmpDir)
167*1c12ee1eSDan Willemsen}
168*1c12ee1eSDan Willemsen
169*1c12ee1eSDan Willemsenfunc generateRemoteProtos() {
170*1c12ee1eSDan Willemsen	tmpDir, err := ioutil.TempDir(repoRoot, "tmp")
171*1c12ee1eSDan Willemsen	check(err)
172*1c12ee1eSDan Willemsen	defer os.RemoveAll(tmpDir)
173*1c12ee1eSDan Willemsen
174*1c12ee1eSDan Willemsen	// Generate all remote proto files.
175*1c12ee1eSDan Willemsen	files := []struct{ prefix, path, goPkgPath string }{
176*1c12ee1eSDan Willemsen		// Well-known protos.
177*1c12ee1eSDan Willemsen		{"src", "google/protobuf/any.proto", ""},
178*1c12ee1eSDan Willemsen		{"src", "google/protobuf/api.proto", ""},
179*1c12ee1eSDan Willemsen		{"src", "google/protobuf/duration.proto", ""},
180*1c12ee1eSDan Willemsen		{"src", "google/protobuf/empty.proto", ""},
181*1c12ee1eSDan Willemsen		{"src", "google/protobuf/field_mask.proto", ""},
182*1c12ee1eSDan Willemsen		{"src", "google/protobuf/source_context.proto", ""},
183*1c12ee1eSDan Willemsen		{"src", "google/protobuf/struct.proto", ""},
184*1c12ee1eSDan Willemsen		{"src", "google/protobuf/timestamp.proto", ""},
185*1c12ee1eSDan Willemsen		{"src", "google/protobuf/type.proto", ""},
186*1c12ee1eSDan Willemsen		{"src", "google/protobuf/wrappers.proto", ""},
187*1c12ee1eSDan Willemsen
188*1c12ee1eSDan Willemsen		// Compiler protos.
189*1c12ee1eSDan Willemsen		{"src", "google/protobuf/compiler/plugin.proto", ""},
190*1c12ee1eSDan Willemsen		{"src", "google/protobuf/descriptor.proto", ""},
191*1c12ee1eSDan Willemsen
192*1c12ee1eSDan Willemsen		// Conformance protos.
193*1c12ee1eSDan Willemsen		{"", "conformance/conformance.proto", "google.golang.org/protobuf/internal/testprotos/conformance;conformance"},
194*1c12ee1eSDan Willemsen		{"src", "google/protobuf/test_messages_proto2.proto", "google.golang.org/protobuf/internal/testprotos/conformance;conformance"},
195*1c12ee1eSDan Willemsen		{"src", "google/protobuf/test_messages_proto3.proto", "google.golang.org/protobuf/internal/testprotos/conformance;conformance"},
196*1c12ee1eSDan Willemsen
197*1c12ee1eSDan Willemsen		// Benchmark protos.
198*1c12ee1eSDan Willemsen		// TODO: The protobuf repo no longer includes benchmarks.
199*1c12ee1eSDan Willemsen		//       CL removing them says they are superceded by google/fleetbench:
200*1c12ee1eSDan Willemsen		//         https://github.com/protocolbuffers/protobuf/commit/83c499de86224538e5d59adc3d0fa7fdb45b2c72
201*1c12ee1eSDan Willemsen		//       But that project's proto benchmark files are very different:
202*1c12ee1eSDan Willemsen		//         https://github.com/google/fleetbench/tree/main/fleetbench/proto
203*1c12ee1eSDan Willemsen		//       For now, commenting these out until benchmarks in this repo can be
204*1c12ee1eSDan Willemsen		//       reconciled with new fleetbench stuff.
205*1c12ee1eSDan Willemsen		//{"benchmarks", "benchmarks.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks;benchmarks"},
206*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message1/proto2/benchmark_message1_proto2.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message1/proto2;proto2"},
207*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message1/proto3/benchmark_message1_proto3.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message1/proto3;proto3"},
208*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message2/benchmark_message2.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message2;google_message2"},
209*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
210*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_1.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
211*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_2.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
212*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_3.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
213*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_4.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
214*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_5.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
215*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_6.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
216*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_7.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
217*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message3/benchmark_message3_8.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message3;google_message3"},
218*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message4/benchmark_message4.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message4;google_message4"},
219*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message4/benchmark_message4_1.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message4;google_message4"},
220*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message4/benchmark_message4_2.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message4;google_message4"},
221*1c12ee1eSDan Willemsen		//{"benchmarks", "datasets/google_message4/benchmark_message4_3.proto", "google.golang.org/protobuf/internal/testprotos/benchmarks/datasets/google_message4;google_message4"},
222*1c12ee1eSDan Willemsen	}
223*1c12ee1eSDan Willemsen
224*1c12ee1eSDan Willemsen	opts := "module=" + modulePath
225*1c12ee1eSDan Willemsen	for _, file := range files {
226*1c12ee1eSDan Willemsen		if file.goPkgPath != "" {
227*1c12ee1eSDan Willemsen			opts += fmt.Sprintf(",M%v=%v", file.path, file.goPkgPath)
228*1c12ee1eSDan Willemsen		}
229*1c12ee1eSDan Willemsen	}
230*1c12ee1eSDan Willemsen	for _, f := range files {
231*1c12ee1eSDan Willemsen		protoc("-I"+filepath.Join(protoRoot, f.prefix), "--go_out="+opts+":"+tmpDir, f.path)
232*1c12ee1eSDan Willemsen	}
233*1c12ee1eSDan Willemsen
234*1c12ee1eSDan Willemsen	syncOutput(repoRoot, tmpDir)
235*1c12ee1eSDan Willemsen}
236*1c12ee1eSDan Willemsen
237*1c12ee1eSDan Willemsenfunc protoc(args ...string) {
238*1c12ee1eSDan Willemsen	// TODO: Remove --experimental_allow_proto3_optional flag.
239*1c12ee1eSDan Willemsen	cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0], "--experimental_allow_proto3_optional")
240*1c12ee1eSDan Willemsen	cmd.Args = append(cmd.Args, args...)
241*1c12ee1eSDan Willemsen	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_PLUGIN=1")
242*1c12ee1eSDan Willemsen	out, err := cmd.CombinedOutput()
243*1c12ee1eSDan Willemsen	if err != nil {
244*1c12ee1eSDan Willemsen		fmt.Printf("executing: %v\n%s\n", strings.Join(cmd.Args, " "), out)
245*1c12ee1eSDan Willemsen	}
246*1c12ee1eSDan Willemsen	check(err)
247*1c12ee1eSDan Willemsen}
248*1c12ee1eSDan Willemsen
249*1c12ee1eSDan Willemsen// generateIdentifiers generates an internal package for descriptor.proto
250*1c12ee1eSDan Willemsen// and well-known types.
251*1c12ee1eSDan Willemsenfunc generateIdentifiers(gen *protogen.Plugin, file *protogen.File) {
252*1c12ee1eSDan Willemsen	if file.Desc.Package() != "google.protobuf" {
253*1c12ee1eSDan Willemsen		return
254*1c12ee1eSDan Willemsen	}
255*1c12ee1eSDan Willemsen
256*1c12ee1eSDan Willemsen	importPath := modulePath + "/internal/genid"
257*1c12ee1eSDan Willemsen	base := strings.TrimSuffix(path.Base(file.Desc.Path()), ".proto")
258*1c12ee1eSDan Willemsen	g := gen.NewGeneratedFile(importPath+"/"+base+"_gen.go", protogen.GoImportPath(importPath))
259*1c12ee1eSDan Willemsen	for _, s := range generatedPreamble {
260*1c12ee1eSDan Willemsen		g.P(s)
261*1c12ee1eSDan Willemsen	}
262*1c12ee1eSDan Willemsen	g.P("package ", path.Base(importPath))
263*1c12ee1eSDan Willemsen	g.P()
264*1c12ee1eSDan Willemsen
265*1c12ee1eSDan Willemsen	g.P("const ", file.GoDescriptorIdent.GoName, " = ", strconv.Quote(file.Desc.Path()))
266*1c12ee1eSDan Willemsen	g.P()
267*1c12ee1eSDan Willemsen
268*1c12ee1eSDan Willemsen	var processEnums func([]*protogen.Enum)
269*1c12ee1eSDan Willemsen	var processMessages func([]*protogen.Message)
270*1c12ee1eSDan Willemsen	const protoreflectPackage = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect")
271*1c12ee1eSDan Willemsen	processEnums = func(enums []*protogen.Enum) {
272*1c12ee1eSDan Willemsen		for _, enum := range enums {
273*1c12ee1eSDan Willemsen			g.P("// Full and short names for ", enum.Desc.FullName(), ".")
274*1c12ee1eSDan Willemsen			g.P("const (")
275*1c12ee1eSDan Willemsen			g.P(enum.GoIdent.GoName, "_enum_fullname = ", strconv.Quote(string(enum.Desc.FullName())))
276*1c12ee1eSDan Willemsen			g.P(enum.GoIdent.GoName, "_enum_name = ", strconv.Quote(string(enum.Desc.Name())))
277*1c12ee1eSDan Willemsen			g.P(")")
278*1c12ee1eSDan Willemsen			g.P()
279*1c12ee1eSDan Willemsen		}
280*1c12ee1eSDan Willemsen	}
281*1c12ee1eSDan Willemsen	processMessages = func(messages []*protogen.Message) {
282*1c12ee1eSDan Willemsen		for _, message := range messages {
283*1c12ee1eSDan Willemsen			g.P("// Names for ", message.Desc.FullName(), ".")
284*1c12ee1eSDan Willemsen			g.P("const (")
285*1c12ee1eSDan Willemsen			g.P(message.GoIdent.GoName, "_message_name ", protoreflectPackage.Ident("Name"), " = ", strconv.Quote(string(message.Desc.Name())))
286*1c12ee1eSDan Willemsen			g.P(message.GoIdent.GoName, "_message_fullname ", protoreflectPackage.Ident("FullName"), " = ", strconv.Quote(string(message.Desc.FullName())))
287*1c12ee1eSDan Willemsen			g.P(")")
288*1c12ee1eSDan Willemsen			g.P()
289*1c12ee1eSDan Willemsen
290*1c12ee1eSDan Willemsen			if len(message.Fields) > 0 {
291*1c12ee1eSDan Willemsen				g.P("// Field names for ", message.Desc.FullName(), ".")
292*1c12ee1eSDan Willemsen				g.P("const (")
293*1c12ee1eSDan Willemsen				for _, field := range message.Fields {
294*1c12ee1eSDan Willemsen					g.P(message.GoIdent.GoName, "_", field.GoName, "_field_name ", protoreflectPackage.Ident("Name"), " = ", strconv.Quote(string(field.Desc.Name())))
295*1c12ee1eSDan Willemsen				}
296*1c12ee1eSDan Willemsen				g.P()
297*1c12ee1eSDan Willemsen				for _, field := range message.Fields {
298*1c12ee1eSDan Willemsen					g.P(message.GoIdent.GoName, "_", field.GoName, "_field_fullname ", protoreflectPackage.Ident("FullName"), " = ", strconv.Quote(string(field.Desc.FullName())))
299*1c12ee1eSDan Willemsen				}
300*1c12ee1eSDan Willemsen				g.P(")")
301*1c12ee1eSDan Willemsen				g.P()
302*1c12ee1eSDan Willemsen
303*1c12ee1eSDan Willemsen				g.P("// Field numbers for ", message.Desc.FullName(), ".")
304*1c12ee1eSDan Willemsen				g.P("const (")
305*1c12ee1eSDan Willemsen				for _, field := range message.Fields {
306*1c12ee1eSDan Willemsen					g.P(message.GoIdent.GoName, "_", field.GoName, "_field_number ", protoreflectPackage.Ident("FieldNumber"), " = ", field.Desc.Number())
307*1c12ee1eSDan Willemsen				}
308*1c12ee1eSDan Willemsen				g.P(")")
309*1c12ee1eSDan Willemsen				g.P()
310*1c12ee1eSDan Willemsen			}
311*1c12ee1eSDan Willemsen
312*1c12ee1eSDan Willemsen			if len(message.Oneofs) > 0 {
313*1c12ee1eSDan Willemsen				g.P("// Oneof names for ", message.Desc.FullName(), ".")
314*1c12ee1eSDan Willemsen				g.P("const (")
315*1c12ee1eSDan Willemsen				for _, oneof := range message.Oneofs {
316*1c12ee1eSDan Willemsen					g.P(message.GoIdent.GoName, "_", oneof.GoName, "_oneof_name ", protoreflectPackage.Ident("Name"), " = ", strconv.Quote(string(oneof.Desc.Name())))
317*1c12ee1eSDan Willemsen				}
318*1c12ee1eSDan Willemsen				g.P()
319*1c12ee1eSDan Willemsen				for _, oneof := range message.Oneofs {
320*1c12ee1eSDan Willemsen					g.P(message.GoIdent.GoName, "_", oneof.GoName, "_oneof_fullname ", protoreflectPackage.Ident("FullName"), " = ", strconv.Quote(string(oneof.Desc.FullName())))
321*1c12ee1eSDan Willemsen				}
322*1c12ee1eSDan Willemsen				g.P(")")
323*1c12ee1eSDan Willemsen				g.P()
324*1c12ee1eSDan Willemsen			}
325*1c12ee1eSDan Willemsen
326*1c12ee1eSDan Willemsen			processEnums(message.Enums)
327*1c12ee1eSDan Willemsen			processMessages(message.Messages)
328*1c12ee1eSDan Willemsen		}
329*1c12ee1eSDan Willemsen	}
330*1c12ee1eSDan Willemsen	processEnums(file.Enums)
331*1c12ee1eSDan Willemsen	processMessages(file.Messages)
332*1c12ee1eSDan Willemsen}
333*1c12ee1eSDan Willemsen
334*1c12ee1eSDan Willemsen// generateSourceContextStringer generates the implementation for the
335*1c12ee1eSDan Willemsen// protoreflect.SourcePath.String method by using information present
336*1c12ee1eSDan Willemsen// in the descriptor.proto.
337*1c12ee1eSDan Willemsenfunc generateSourceContextStringer(gen *protogen.Plugin, file *protogen.File) {
338*1c12ee1eSDan Willemsen	if file.Desc.Path() != "google/protobuf/descriptor.proto" {
339*1c12ee1eSDan Willemsen		return
340*1c12ee1eSDan Willemsen	}
341*1c12ee1eSDan Willemsen
342*1c12ee1eSDan Willemsen	importPath := modulePath + "/reflect/protoreflect"
343*1c12ee1eSDan Willemsen	g := gen.NewGeneratedFile(importPath+"/source_gen.go", protogen.GoImportPath(importPath))
344*1c12ee1eSDan Willemsen	for _, s := range generatedPreamble {
345*1c12ee1eSDan Willemsen		g.P(s)
346*1c12ee1eSDan Willemsen	}
347*1c12ee1eSDan Willemsen	g.P("package ", path.Base(importPath))
348*1c12ee1eSDan Willemsen	g.P()
349*1c12ee1eSDan Willemsen
350*1c12ee1eSDan Willemsen	var messages []*protogen.Message
351*1c12ee1eSDan Willemsen	for _, message := range file.Messages {
352*1c12ee1eSDan Willemsen		if message.Desc.Name() == "FileDescriptorProto" {
353*1c12ee1eSDan Willemsen			messages = append(messages, message)
354*1c12ee1eSDan Willemsen		}
355*1c12ee1eSDan Willemsen	}
356*1c12ee1eSDan Willemsen	seen := make(map[*protogen.Message]bool)
357*1c12ee1eSDan Willemsen
358*1c12ee1eSDan Willemsen	for len(messages) > 0 {
359*1c12ee1eSDan Willemsen		m := messages[0]
360*1c12ee1eSDan Willemsen		messages = messages[1:]
361*1c12ee1eSDan Willemsen		if seen[m] {
362*1c12ee1eSDan Willemsen			continue
363*1c12ee1eSDan Willemsen		}
364*1c12ee1eSDan Willemsen		seen[m] = true
365*1c12ee1eSDan Willemsen
366*1c12ee1eSDan Willemsen		g.P("func (p *SourcePath) append", m.GoIdent.GoName, "(b []byte) []byte {")
367*1c12ee1eSDan Willemsen		g.P("if len(*p) == 0 { return b }")
368*1c12ee1eSDan Willemsen		g.P("switch (*p)[0] {")
369*1c12ee1eSDan Willemsen		for _, f := range m.Fields {
370*1c12ee1eSDan Willemsen			g.P("case ", f.Desc.Number(), ":")
371*1c12ee1eSDan Willemsen			var cardinality string
372*1c12ee1eSDan Willemsen			switch {
373*1c12ee1eSDan Willemsen			case f.Desc.IsMap():
374*1c12ee1eSDan Willemsen				panic("maps are not supported")
375*1c12ee1eSDan Willemsen			case f.Desc.IsList():
376*1c12ee1eSDan Willemsen				cardinality = "Repeated"
377*1c12ee1eSDan Willemsen			default:
378*1c12ee1eSDan Willemsen				cardinality = "Singular"
379*1c12ee1eSDan Willemsen			}
380*1c12ee1eSDan Willemsen			nextAppender := "nil"
381*1c12ee1eSDan Willemsen			if f.Message != nil {
382*1c12ee1eSDan Willemsen				nextAppender = "(*SourcePath).append" + f.Message.GoIdent.GoName
383*1c12ee1eSDan Willemsen				messages = append(messages, f.Message)
384*1c12ee1eSDan Willemsen			}
385*1c12ee1eSDan Willemsen			g.P("b = p.append", cardinality, "Field(b, ", strconv.Quote(string(f.Desc.Name())), ", ", nextAppender, ")")
386*1c12ee1eSDan Willemsen		}
387*1c12ee1eSDan Willemsen		g.P("}")
388*1c12ee1eSDan Willemsen		g.P("return b")
389*1c12ee1eSDan Willemsen		g.P("}")
390*1c12ee1eSDan Willemsen		g.P()
391*1c12ee1eSDan Willemsen	}
392*1c12ee1eSDan Willemsen}
393*1c12ee1eSDan Willemsen
394*1c12ee1eSDan Willemsenfunc syncOutput(dstDir, srcDir string) {
395*1c12ee1eSDan Willemsen	filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
396*1c12ee1eSDan Willemsen		if !strings.HasSuffix(srcPath, ".go") && !strings.HasSuffix(srcPath, ".meta") {
397*1c12ee1eSDan Willemsen			return nil
398*1c12ee1eSDan Willemsen		}
399*1c12ee1eSDan Willemsen		relPath, err := filepath.Rel(srcDir, srcPath)
400*1c12ee1eSDan Willemsen		check(err)
401*1c12ee1eSDan Willemsen		dstPath := filepath.Join(dstDir, relPath)
402*1c12ee1eSDan Willemsen
403*1c12ee1eSDan Willemsen		if run {
404*1c12ee1eSDan Willemsen			if copyFile(dstPath, srcPath) {
405*1c12ee1eSDan Willemsen				fmt.Println("#", relPath)
406*1c12ee1eSDan Willemsen			}
407*1c12ee1eSDan Willemsen		} else {
408*1c12ee1eSDan Willemsen			cmd := exec.Command("diff", dstPath, srcPath, "-N", "-u")
409*1c12ee1eSDan Willemsen			cmd.Stdout = os.Stdout
410*1c12ee1eSDan Willemsen			cmd.Run()
411*1c12ee1eSDan Willemsen		}
412*1c12ee1eSDan Willemsen		return nil
413*1c12ee1eSDan Willemsen	})
414*1c12ee1eSDan Willemsen}
415*1c12ee1eSDan Willemsen
416*1c12ee1eSDan Willemsenfunc copyFile(dstPath, srcPath string) (changed bool) {
417*1c12ee1eSDan Willemsen	src, err := ioutil.ReadFile(srcPath)
418*1c12ee1eSDan Willemsen	check(err)
419*1c12ee1eSDan Willemsen	check(os.MkdirAll(filepath.Dir(dstPath), 0775))
420*1c12ee1eSDan Willemsen	dst, _ := ioutil.ReadFile(dstPath)
421*1c12ee1eSDan Willemsen	if bytes.Equal(src, dst) {
422*1c12ee1eSDan Willemsen		return false
423*1c12ee1eSDan Willemsen	}
424*1c12ee1eSDan Willemsen	check(ioutil.WriteFile(dstPath, src, 0664))
425*1c12ee1eSDan Willemsen	return true
426*1c12ee1eSDan Willemsen}
427*1c12ee1eSDan Willemsen
428*1c12ee1eSDan Willemsenfunc check(err error) {
429*1c12ee1eSDan Willemsen	if err != nil {
430*1c12ee1eSDan Willemsen		panic(err)
431*1c12ee1eSDan Willemsen	}
432*1c12ee1eSDan Willemsen}
433