Skip to content

Commit 7b18087

Browse files
authored
protoc-gen-go: more standard import organization (#719)
Split imports into standard library and third-party imports. Decide between the two based on the presence of a ".", which is the same heuristic used by goimports. Allow plugins to register packages to import, so gRPC imports don't sit awkwardly in a separate import () block.
1 parent c8b73fb commit 7b18087

File tree

38 files changed

+109
-62
lines changed

38 files changed

+109
-62
lines changed

conformance/internal/conformance_proto/conformance.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jsonpb/jsonpb_test_proto/more_test_objects.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jsonpb/jsonpb_test_proto/test_objects.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/proto3_proto/proto3.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/test_proto/test.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/descriptor/descriptor.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/generator/generator.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ type Generator struct {
420420
packageNames map[GoImportPath]GoPackageName // Imported package names in the current file.
421421
usedPackages map[GoImportPath]bool // Packages used in current file.
422422
usedPackageNames map[GoPackageName]bool // Package names used in the current file.
423+
addedImports map[GoImportPath]bool // Additional imports to emit.
423424
typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
424425
init []string // Lines to emit in the init function.
425426
indent string
@@ -542,6 +543,13 @@ func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName {
542543
return name
543544
}
544545

546+
// AddImport adds a package to the generated file's import section.
547+
// It returns the name used for the package.
548+
func (g *Generator) AddImport(importPath GoImportPath) GoPackageName {
549+
g.addedImports[importPath] = true
550+
return g.GoPackageName(importPath)
551+
}
552+
545553
var globalPackageNames = map[GoPackageName]bool{
546554
"fmt": true,
547555
"math": true,
@@ -1109,6 +1117,7 @@ func (g *Generator) generate(file *FileDescriptor) {
11091117
g.usedPackages = make(map[GoImportPath]bool)
11101118
g.packageNames = make(map[GoImportPath]GoPackageName)
11111119
g.usedPackageNames = make(map[GoPackageName]bool)
1120+
g.addedImports = make(map[GoImportPath]bool)
11121121
for name := range globalPackageNames {
11131122
g.usedPackageNames[name] = true
11141123
}
@@ -1266,14 +1275,7 @@ func (g *Generator) weak(i int32) bool {
12661275

12671276
// Generate the imports
12681277
func (g *Generator) generateImports() {
1269-
g.P("import (")
1270-
// We almost always need a proto import. Rather than computing when we
1271-
// do, which is tricky when there's a plugin, just import it and
1272-
// reference it later. The same argument applies to the fmt and math packages.
1273-
g.P(g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto")
1274-
g.P(g.Pkg["fmt"] + ` "fmt"`)
1275-
g.P(g.Pkg["math"] + ` "math"`)
1276-
imports := make(map[GoImportPath]bool)
1278+
imports := make(map[GoImportPath]GoPackageName)
12771279
for i, s := range g.file.Dependency {
12781280
fd := g.fileByName(s)
12791281
importPath := fd.importPath
@@ -1286,18 +1288,41 @@ func (g *Generator) generateImports() {
12861288
continue
12871289
}
12881290
// Do not import a package twice.
1289-
if imports[importPath] {
1291+
if _, ok := imports[importPath]; ok {
12901292
continue
12911293
}
1292-
imports[importPath] = true
12931294
// We need to import all the dependencies, even if we don't reference them,
12941295
// because other code and tools depend on having the full transitive closure
12951296
// of protocol buffer types in the binary.
12961297
packageName := g.GoPackageName(importPath)
12971298
if _, ok := g.usedPackages[importPath]; !ok {
12981299
packageName = "_"
12991300
}
1300-
g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath)
1301+
imports[importPath] = packageName
1302+
}
1303+
for importPath := range g.addedImports {
1304+
imports[importPath] = g.GoPackageName(importPath)
1305+
}
1306+
g.P("import (")
1307+
// Standard library imports.
1308+
g.P(g.Pkg["fmt"] + ` "fmt"`)
1309+
g.P(g.Pkg["math"] + ` "math"`)
1310+
for importPath, packageName := range imports {
1311+
if !strings.Contains(string(importPath), ".") {
1312+
g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath)
1313+
}
1314+
}
1315+
g.P()
1316+
// Third-party imports.
1317+
//
1318+
// We almost always need a proto import. Rather than computing when we
1319+
// do, which is tricky when there's a plugin, just import it and
1320+
// reference it later. The same argument applies to the fmt and math packages.
1321+
g.P(g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto")
1322+
for importPath, packageName := range imports {
1323+
if strings.Contains(string(importPath), ".") {
1324+
g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath)
1325+
}
13011326
}
13021327
g.P(")")
13031328
g.P()

protoc-gen-go/grpc/grpc.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ package grpc
3636

3737
import (
3838
"fmt"
39-
"path"
4039
"strconv"
4140
"strings"
4241

@@ -83,8 +82,6 @@ var (
8382
// Init initializes the plugin.
8483
func (g *grpc) Init(gen *generator.Generator) {
8584
g.gen = gen
86-
contextPkg = generator.RegisterUniquePackageName("context", nil)
87-
grpcPkg = generator.RegisterUniquePackageName("grpc", nil)
8885
}
8986

9087
// Given a type name defined in a .proto, return its object.
@@ -108,6 +105,9 @@ func (g *grpc) Generate(file *generator.FileDescriptor) {
108105
return
109106
}
110107

108+
contextPkg = string(g.gen.AddImport(contextPkgPath))
109+
grpcPkg = string(g.gen.AddImport(grpcPkgPath))
110+
111111
g.P("// Reference imports to suppress errors if they are not otherwise used.")
112112
g.P("var _ ", contextPkg, ".Context")
113113
g.P("var _ ", grpcPkg, ".ClientConn")
@@ -126,14 +126,6 @@ func (g *grpc) Generate(file *generator.FileDescriptor) {
126126

127127
// GenerateImports generates the import declaration for this file.
128128
func (g *grpc) GenerateImports(file *generator.FileDescriptor) {
129-
if len(file.FileDescriptorProto.Service) == 0 {
130-
return
131-
}
132-
g.P("import (")
133-
g.P(contextPkg, " ", generator.GoImportPath(path.Join(string(g.gen.ImportPrefix), contextPkgPath)))
134-
g.P(grpcPkg, " ", generator.GoImportPath(path.Join(string(g.gen.ImportPrefix), grpcPkgPath)))
135-
g.P(")")
136-
g.P()
137129
}
138130

139131
// reservedClientName records whether a client name is reserved on the client side.

protoc-gen-go/testdata/deprecated/deprecated.pb.go

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/testdata/extension_base/extension_base.pb.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)