1
15
16 package golang
17
18 import (
19 "fmt"
20 "go/build"
21 "log"
22 "path"
23 "path/filepath"
24 "sort"
25 "strings"
26 "sync"
27
28 "github.com/bazelbuild/bazel-gazelle/config"
29 "github.com/bazelbuild/bazel-gazelle/language"
30 "github.com/bazelbuild/bazel-gazelle/language/proto"
31 "github.com/bazelbuild/bazel-gazelle/pathtools"
32 "github.com/bazelbuild/bazel-gazelle/rule"
33 )
34
35 func (gl *goLang) GenerateRules(args language.GenerateArgs) language.GenerateResult {
36
37
38 c := args.Config
39 pcMode := getProtoMode(c)
40
41
42
43 goProtoRules := make(map[string]struct{})
44
45 var protoRuleNames []string
46 protoPackages := make(map[string]proto.Package)
47 protoFileInfo := make(map[string]proto.FileInfo)
48 for _, r := range args.OtherGen {
49 if r.Kind() == "go_proto_library" {
50 if proto := r.AttrString("proto"); proto != "" {
51 goProtoRules[proto] = struct{}{}
52 }
53 if protos := r.AttrStrings("protos"); protos != nil {
54 for _, proto := range protos {
55 goProtoRules[proto] = struct{}{}
56 }
57 }
58
59 }
60 if r.Kind() != "proto_library" {
61 continue
62 }
63 pkg := r.PrivateAttr(proto.PackageKey).(proto.Package)
64 protoPackages[r.Name()] = pkg
65 for name, info := range pkg.Files {
66 protoFileInfo[name] = info
67 }
68 protoRuleNames = append(protoRuleNames, r.Name())
69 }
70 sort.Strings(protoRuleNames)
71 var emptyProtoRuleNames []string
72 for _, r := range args.OtherEmpty {
73 if r.Kind() == "proto_library" {
74 emptyProtoRuleNames = append(emptyProtoRuleNames, r.Name())
75 }
76 }
77
78
79
80 regularFiles := append([]string{}, args.RegularFiles...)
81 genFiles := append([]string{}, args.GenFiles...)
82 if !pcMode.ShouldIncludePregeneratedFiles() {
83 keep := func(f string) bool {
84 for _, suffix := range []string{".pb.go", "_grpc.pb.go"} {
85 if strings.HasSuffix(f, suffix) {
86 if _, ok := protoFileInfo[strings.TrimSuffix(f, suffix)+".proto"]; ok {
87 return false
88 }
89 }
90 }
91 return true
92 }
93 filterFiles(®ularFiles, keep)
94 filterFiles(&genFiles, keep)
95 }
96
97
98
99 var goFiles, otherFiles []string
100 for _, f := range regularFiles {
101 if strings.HasSuffix(f, ".go") {
102 goFiles = append(goFiles, f)
103 } else {
104 otherFiles = append(otherFiles, f)
105 }
106 }
107
108
109
110 var hasTestdata bool
111 for _, sub := range args.Subdirs {
112 if sub == "testdata" {
113 _, ok := gl.goPkgRels[path.Join(args.Rel, "testdata")]
114 hasTestdata = !ok
115 break
116 }
117 }
118
119
120 goFileInfos := make([]fileInfo, len(goFiles))
121 var er *embedResolver
122 for i, name := range goFiles {
123 path := filepath.Join(args.Dir, name)
124 goFileInfos[i] = goFileInfo(path, args.Rel)
125 if len(goFileInfos[i].embeds) > 0 && er == nil {
126 er = newEmbedResolver(args.Dir, args.Rel, c.ValidBuildFileNames, gl.goPkgRels, args.Subdirs, args.RegularFiles, args.GenFiles)
127 }
128 }
129 goPackageMap, goFilesWithUnknownPackage := buildPackages(c, args.Dir, args.Rel, hasTestdata, er, goFileInfos)
130
131
132
133 var protoName string
134 pkg, err := selectPackage(c, args.Dir, goPackageMap)
135 if err != nil {
136 if _, ok := err.(*build.NoGoError); ok {
137 if len(protoPackages) == 1 {
138 for name, ppkg := range protoPackages {
139 if _, ok := goProtoRules[":"+name]; ok {
140
141
142
143 pkg = emptyPackage(c, args.Dir, args.Rel, args.File)
144 break
145 }
146 pkg = &goPackage{
147 name: goProtoPackageName(ppkg),
148 importPath: goProtoImportPath(c, ppkg, args.Rel),
149 proto: protoTargetFromProtoPackage(name, ppkg),
150 }
151 protoName = name
152 break
153 }
154 } else {
155 pkg = emptyPackage(c, args.Dir, args.Rel, args.File)
156 }
157 } else {
158 log.Print(err)
159 }
160 }
161
162
163 if pkg != nil {
164 if pkg.importPath == "" {
165 if err := pkg.inferImportPath(c); err != nil && pkg.firstGoFile() != "" {
166 inferImportPathErrorOnce.Do(func() { log.Print(err) })
167 }
168 }
169 for _, name := range protoRuleNames {
170 ppkg := protoPackages[name]
171 if pkg.importPath == goProtoImportPath(c, ppkg, args.Rel) {
172 protoName = name
173 pkg.proto = protoTargetFromProtoPackage(name, ppkg)
174 break
175 }
176 }
177 }
178
179
180
181 g := &generator{
182 c: c,
183 rel: args.Rel,
184 shouldSetVisibility: shouldSetVisibility(args),
185 }
186 var res language.GenerateResult
187 var rules []*rule.Rule
188 var protoEmbed string
189 for _, name := range protoRuleNames {
190 if _, ok := goProtoRules[":"+name]; ok {
191
192
193
194
195 continue
196 }
197 ppkg := protoPackages[name]
198 var rs []*rule.Rule
199 if name == protoName {
200 protoEmbed, rs = g.generateProto(pcMode, pkg.proto, pkg.importPath)
201 } else {
202 target := protoTargetFromProtoPackage(name, ppkg)
203 importPath := goProtoImportPath(c, ppkg, args.Rel)
204 _, rs = g.generateProto(pcMode, target, importPath)
205 }
206 rules = append(rules, rs...)
207 }
208 for _, name := range emptyProtoRuleNames {
209 goProtoName := strings.TrimSuffix(name, "_proto") + goProtoSuffix
210 res.Empty = append(res.Empty, rule.NewRule("go_proto_library", goProtoName))
211 }
212 if pkg != nil && pcMode == proto.PackageMode && pkg.firstGoFile() == "" {
213
214
215 protoEmbed = ""
216 }
217
218
219 if pkg != nil {
220
221
222
223 cgo := pkg.haveCgo()
224 for _, info := range goFilesWithUnknownPackage {
225 if err := pkg.addFile(c, er, info, cgo); err != nil {
226 log.Print(err)
227 }
228 }
229
230
231 for _, file := range otherFiles {
232 info := otherFileInfo(filepath.Join(args.Dir, file))
233 if err := pkg.addFile(c, er, info, cgo); err != nil {
234 log.Print(err)
235 }
236 }
237
238
239
240
241 regularFileSet := make(map[string]bool)
242 for _, f := range regularFiles {
243 regularFileSet[f] = true
244 }
245
246 consumedFileSet := make(map[string]bool)
247 for _, r := range args.OtherGen {
248 for _, f := range r.AttrStrings("srcs") {
249 consumedFileSet[f] = true
250 }
251 if f := r.AttrString("src"); f != "" {
252 consumedFileSet[f] = true
253 }
254 }
255 for _, f := range genFiles {
256 if regularFileSet[f] || consumedFileSet[f] {
257 continue
258 }
259 info := fileNameInfo(filepath.Join(args.Dir, f))
260 if err := pkg.addFile(c, er, info, cgo); err != nil {
261 log.Print(err)
262 }
263 }
264
265
266 if protoName == "" {
267
268 _, rs := g.generateProto(pcMode, pkg.proto, pkg.importPath)
269 rules = append(rules, rs...)
270 }
271 lib := g.generateLib(pkg, protoEmbed)
272 var libName string
273 if !lib.IsEmpty(goKinds[lib.Kind()]) {
274 libName = lib.Name()
275 }
276 rules = append(rules, lib)
277 g.maybePublishToolLib(lib, pkg)
278 if r := g.maybeGenerateExtraLib(lib, pkg); r != nil {
279 rules = append(rules, r)
280 }
281 if r := g.maybeGenerateAlias(pkg, libName); r != nil {
282 g.maybePublishToolLib(r, pkg)
283 rules = append(rules, r)
284 }
285 rules = append(rules, g.generateBin(pkg, libName))
286 rules = append(rules, g.generateTests(pkg, libName)...)
287 }
288
289 for _, r := range rules {
290 if r.IsEmpty(goKinds[r.Kind()]) {
291 res.Empty = append(res.Empty, r)
292 } else {
293 res.Gen = append(res.Gen, r)
294 res.Imports = append(res.Imports, r.PrivateAttr(config.GazelleImportsKey))
295 }
296 }
297
298 if args.File != nil || len(res.Gen) > 0 {
299 gl.goPkgRels[args.Rel] = true
300 } else {
301 for _, sub := range args.Subdirs {
302 if _, ok := gl.goPkgRels[path.Join(args.Rel, sub)]; ok {
303 gl.goPkgRels[args.Rel] = false
304 break
305 }
306 }
307 }
308
309 return res
310 }
311
312 func filterFiles(files *[]string, pred func(string) bool) {
313 w := 0
314 for r := 0; r < len(*files); r++ {
315 f := (*files)[r]
316 if pred(f) {
317 (*files)[w] = f
318 w++
319 }
320 }
321 *files = (*files)[:w]
322 }
323
324 func buildPackages(c *config.Config, dir, rel string, hasTestdata bool, er *embedResolver, goFiles []fileInfo) (packageMap map[string]*goPackage, goFilesWithUnknownPackage []fileInfo) {
325
326 packageMap = make(map[string]*goPackage)
327 for _, f := range goFiles {
328 if f.packageName == "" {
329 goFilesWithUnknownPackage = append(goFilesWithUnknownPackage, f)
330 continue
331 }
332 if f.packageName == "documentation" {
333
334 continue
335 }
336
337 if _, ok := packageMap[f.packageName]; !ok {
338 packageMap[f.packageName] = &goPackage{
339 name: f.packageName,
340 dir: dir,
341 rel: rel,
342 hasTestdata: hasTestdata,
343 }
344 }
345 if err := packageMap[f.packageName].addFile(c, er, f, false); err != nil {
346 log.Print(err)
347 }
348 }
349 return packageMap, goFilesWithUnknownPackage
350 }
351
352 var inferImportPathErrorOnce sync.Once
353
354
355
356
357 func selectPackage(c *config.Config, dir string, packageMap map[string]*goPackage) (*goPackage, error) {
358 buildablePackages := make(map[string]*goPackage)
359 for name, pkg := range packageMap {
360 if pkg.isBuildable(c) {
361 buildablePackages[name] = pkg
362 }
363 }
364
365 if len(buildablePackages) == 0 {
366 return nil, &build.NoGoError{Dir: dir}
367 }
368
369 if len(buildablePackages) == 1 {
370 for _, pkg := range buildablePackages {
371 return pkg, nil
372 }
373 }
374
375 if pkg, ok := buildablePackages[defaultPackageName(c, dir)]; ok {
376 return pkg, nil
377 }
378
379 err := &build.MultiplePackageError{Dir: dir}
380 for name, pkg := range buildablePackages {
381
382
383
384
385 err.Packages = append(err.Packages, name)
386 err.Files = append(err.Files, pkg.firstGoFile())
387 }
388 return nil, err
389 }
390
391 func emptyPackage(c *config.Config, dir, rel string, f *rule.File) *goPackage {
392 var pkgName string
393 if fileContainsGoBinary(c, f) {
394
395
396
397 pkgName = "main"
398 } else {
399 pkgName = defaultPackageName(c, dir)
400 }
401 pkg := &goPackage{
402 name: pkgName,
403 dir: dir,
404 rel: rel,
405 }
406
407 return pkg
408 }
409
410 func defaultPackageName(c *config.Config, rel string) string {
411 gc := getGoConfig(c)
412 return pathtools.RelBaseName(rel, gc.prefix, "")
413 }
414
415 type generator struct {
416 c *config.Config
417 rel string
418 shouldSetVisibility bool
419 }
420
421 func (g *generator) generateProto(mode proto.Mode, target protoTarget, importPath string) (string, []*rule.Rule) {
422 if !mode.ShouldGenerateRules() && mode != proto.LegacyMode {
423
424
425 return "", nil
426 }
427
428 gc := getGoConfig(g.c)
429 filegroupName := legacyProtoFilegroupName
430 protoName := target.name
431 if protoName == "" {
432 importPath := InferImportPath(g.c, g.rel)
433 protoName = proto.RuleName(importPath)
434 }
435 goProtoName := strings.TrimSuffix(protoName, "_proto") + goProtoSuffix
436 visibility := g.commonVisibility(importPath)
437
438 if mode == proto.LegacyMode {
439 filegroup := rule.NewRule("filegroup", filegroupName)
440 if target.sources.isEmpty() {
441 return "", []*rule.Rule{filegroup}
442 }
443 filegroup.SetAttr("srcs", target.sources.build())
444 if g.shouldSetVisibility {
445 filegroup.SetAttr("visibility", visibility)
446 }
447 return "", []*rule.Rule{filegroup}
448 }
449
450 if target.sources.isEmpty() {
451 return "", []*rule.Rule{
452 rule.NewRule("filegroup", filegroupName),
453 rule.NewRule("go_proto_library", goProtoName),
454 }
455 }
456
457 goProtoLibrary := rule.NewRule("go_proto_library", goProtoName)
458 goProtoLibrary.SetAttr("proto", ":"+protoName)
459 g.setImportAttrs(goProtoLibrary, importPath)
460 if target.hasServices {
461 goProtoLibrary.SetAttr("compilers", gc.goGrpcCompilers)
462 } else if gc.goProtoCompilersSet {
463 goProtoLibrary.SetAttr("compilers", gc.goProtoCompilers)
464 }
465 if g.shouldSetVisibility {
466 goProtoLibrary.SetAttr("visibility", visibility)
467 }
468 goProtoLibrary.SetPrivateAttr(config.GazelleImportsKey, target.imports.build())
469 return goProtoName, []*rule.Rule{goProtoLibrary}
470 }
471
472 func (g *generator) generateLib(pkg *goPackage, embed string) *rule.Rule {
473 gc := getGoConfig(g.c)
474 name := libNameByConvention(gc.goNamingConvention, pkg.importPath, pkg.name)
475 goLibrary := rule.NewRule("go_library", name)
476 if !pkg.library.sources.hasGo() && embed == "" {
477 return goLibrary
478 }
479 var visibility []string
480 if pkg.isCommand() {
481
482 visibility = []string{"//visibility:private"}
483 } else {
484 visibility = g.commonVisibility(pkg.importPath)
485 }
486 g.setCommonAttrs(goLibrary, pkg.rel, visibility, pkg.library, embed)
487 g.setImportAttrs(goLibrary, pkg.importPath)
488 return goLibrary
489 }
490
491 func (g *generator) maybeGenerateAlias(pkg *goPackage, libName string) *rule.Rule {
492 if pkg.isCommand() || libName == "" {
493 return nil
494 }
495 gc := getGoConfig(g.c)
496 if gc.goNamingConvention == goDefaultLibraryNamingConvention {
497 return nil
498 }
499 alias := rule.NewRule("alias", defaultLibName)
500 alias.SetAttr("visibility", g.commonVisibility(pkg.importPath))
501 if gc.goNamingConvention == importAliasNamingConvention {
502 alias.SetAttr("actual", ":"+libName)
503 }
504 return alias
505 }
506
507 func (g *generator) generateBin(pkg *goPackage, library string) *rule.Rule {
508 gc := getGoConfig(g.c)
509 name := binName(pkg.rel, gc.prefix, g.c.RepoRoot)
510 goBinary := rule.NewRule("go_binary", name)
511 if !pkg.isCommand() || pkg.binary.sources.isEmpty() && library == "" {
512 return goBinary
513 }
514 visibility := g.commonVisibility(pkg.importPath)
515 g.setCommonAttrs(goBinary, pkg.rel, visibility, pkg.binary, library)
516 return goBinary
517 }
518
519 func (g *generator) generateTests(pkg *goPackage, library string) []*rule.Rule {
520 gc := getGoConfig(g.c)
521 tests := pkg.tests
522 if len(tests) == 0 && gc.testMode == defaultTestMode {
523 tests = []goTarget{goTarget{}}
524 }
525 var name func(goTarget) string
526 switch gc.testMode {
527 case defaultTestMode:
528 name = func(goTarget) string {
529 return testNameByConvention(gc.goNamingConvention, pkg.importPath)
530 }
531 case fileTestMode:
532 name = func(test goTarget) string {
533 if test.sources.hasGo() {
534 if srcs := test.sources.buildFlat(); len(srcs) == 1 {
535 return testNameFromSingleSource(srcs[0])
536 }
537 }
538 return testNameByConvention(gc.goNamingConvention, pkg.importPath)
539 }
540 }
541 var res []*rule.Rule
542 for i, test := range tests {
543 goTest := rule.NewRule("go_test", name(test))
544 hasGo := test.sources.hasGo()
545 if hasGo || i == 0 {
546 res = append(res, goTest)
547 if !hasGo {
548 continue
549 }
550 }
551 var embed string
552 if test.hasInternalTest {
553 embed = library
554 }
555 g.setCommonAttrs(goTest, pkg.rel, nil, test, embed)
556 if pkg.hasTestdata {
557 goTest.SetAttr("data", rule.GlobValue{Patterns: []string{"testdata/**"}})
558 }
559 }
560 return res
561 }
562
563
564
565 func (g *generator) maybePublishToolLib(lib *rule.Rule, pkg *goPackage) {
566 if pkg.importPath == "golang.org/x/tools/go/analysis/internal/facts" || pkg.importPath == "golang.org/x/tools/internal/facts" {
567
568 lib.SetAttr("visibility", []string{"//visibility:public"})
569 }
570 }
571
572
573
574
575
576 func (g *generator) maybeGenerateExtraLib(lib *rule.Rule, pkg *goPackage) *rule.Rule {
577 gc := getGoConfig(g.c)
578 if gc.prefix != "github.com/golang/protobuf" || gc.prefixRel != "" {
579 return nil
580 }
581
582 var r *rule.Rule
583 switch pkg.importPath {
584 case "github.com/golang/protobuf/descriptor":
585 r = rule.NewRule("go_library", "go_default_library_gen")
586 r.SetAttr("srcs", pkg.library.sources.buildFlat())
587 r.SetAttr("importpath", pkg.importPath)
588 r.SetAttr("visibility", []string{"//visibility:public"})
589 r.SetAttr("deps", []string{
590 "//proto:go_default_library",
591 "@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
592 "@org_golang_google_protobuf//reflect/protodesc:go_default_library",
593 "@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
594 "@org_golang_google_protobuf//runtime/protoimpl:go_default_library",
595 })
596
597 case "github.com/golang/protobuf/jsonpb":
598 r = rule.NewRule("alias", "go_default_library_gen")
599 r.SetAttr("actual", ":go_default_library")
600 r.SetAttr("visibility", []string{"//visibility:public"})
601
602 case "github.com/golang/protobuf/protoc-gen-go/generator":
603 r = rule.NewRule("go_library", "go_default_library_gen")
604 r.SetAttr("srcs", pkg.library.sources.buildFlat())
605 r.SetAttr("importpath", pkg.importPath)
606 r.SetAttr("visibility", []string{"//visibility:public"})
607 r.SetAttr("deps", []string{
608 "//proto:go_default_library",
609 "//protoc-gen-go/generator/internal/remap:go_default_library",
610 "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto",
611 "@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
612 })
613
614 case "github.com/golang/protobuf/ptypes":
615 r = rule.NewRule("go_library", "go_default_library_gen")
616 r.SetAttr("srcs", pkg.library.sources.buildFlat())
617 r.SetAttr("importpath", pkg.importPath)
618 r.SetAttr("visibility", []string{"//visibility:public"})
619 r.SetAttr("deps", []string{
620 "//proto:go_default_library",
621 "@io_bazel_rules_go//proto/wkt:any_go_proto",
622 "@io_bazel_rules_go//proto/wkt:duration_go_proto",
623 "@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
624 "@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
625 "@org_golang_google_protobuf//reflect/protoregistry:go_default_library",
626 })
627 }
628
629 return r
630 }
631
632 func (g *generator) setCommonAttrs(r *rule.Rule, pkgRel string, visibility []string, target goTarget, embed string) {
633 if !target.sources.isEmpty() {
634 r.SetAttr("srcs", target.sources.buildFlat())
635 }
636 if !target.embedSrcs.isEmpty() {
637 r.SetAttr("embedsrcs", target.embedSrcs.build())
638 }
639 if target.cgo {
640 r.SetAttr("cgo", true)
641 }
642 if !target.clinkopts.isEmpty() {
643 r.SetAttr("clinkopts", g.options(target.clinkopts.build(), pkgRel))
644 }
645 if !target.cppopts.isEmpty() {
646 r.SetAttr("cppopts", g.options(target.cppopts.build(), pkgRel))
647 }
648 if !target.copts.isEmpty() {
649 r.SetAttr("copts", g.options(target.copts.build(), pkgRel))
650 }
651 if !target.cxxopts.isEmpty() {
652 r.SetAttr("cxxopts", g.options(target.cxxopts.build(), pkgRel))
653 }
654 if g.shouldSetVisibility && len(visibility) > 0 {
655 r.SetAttr("visibility", visibility)
656 }
657 if embed != "" {
658 r.SetAttr("embed", []string{":" + embed})
659 }
660 r.SetPrivateAttr(config.GazelleImportsKey, target.imports.build())
661 }
662
663 func (g *generator) setImportAttrs(r *rule.Rule, importPath string) {
664 gc := getGoConfig(g.c)
665 r.SetAttr("importpath", importPath)
666
667
668
669
670
671 if gc.goRepositoryMode && gc.moduleMode && pathtools.HasPrefix(importPath, gc.prefix) && gc.prefixRel == "" {
672 if mmcImportPath := pathWithoutSemver(importPath); mmcImportPath != "" {
673 r.SetAttr("importpath_aliases", []string{mmcImportPath})
674 }
675 }
676
677 if gc.importMapPrefix != "" {
678 fromPrefixRel := pathtools.TrimPrefix(g.rel, gc.importMapPrefixRel)
679 importMap := path.Join(gc.importMapPrefix, fromPrefixRel)
680 if importMap != importPath {
681 r.SetAttr("importmap", importMap)
682 }
683 }
684 }
685
686 func (g *generator) commonVisibility(importPath string) []string {
687
688
689
690
691 relIndex := pathtools.Index(g.rel, "internal")
692 importIndex := pathtools.Index(importPath, "internal")
693 visibility := getGoConfig(g.c).goVisibility
694 if relIndex >= 0 {
695 parent := strings.TrimSuffix(g.rel[:relIndex], "/")
696 visibility = append(visibility, fmt.Sprintf("//%s:__subpackages__", parent))
697 } else if importIndex >= 0 {
698
699
700 visibility = append(visibility, "//:__subpackages__")
701 for _, repo := range g.c.Repos {
702 if pathtools.HasPrefix(repo.AttrString("importpath"), importPath[:importIndex]) {
703 visibility = append(visibility, "@"+repo.Name()+"//:__subpackages__")
704 }
705 }
706
707 } else {
708 return []string{"//visibility:public"}
709 }
710
711
712
713 if importIndex >= 0 {
714 gc := getGoConfig(g.c)
715 internalRoot := strings.TrimSuffix(importPath[:importIndex], "/")
716 for _, m := range gc.submodules {
717 if strings.HasPrefix(m.modulePath, internalRoot) {
718 visibility = append(visibility, fmt.Sprintf("@%s//:__subpackages__", m.repoName))
719 }
720 }
721 }
722
723 return visibility
724 }
725
726 var (
727
728
729 shortOptPrefixes = []string{"-I", "-L", "-F"}
730
731
732
733 longOptPrefixes = []string{"-I", "-L", "-F", "-iquote", "-isystem"}
734 )
735
736
737
738
739
740 func (g *generator) options(opts rule.PlatformStrings, pkgRel string) rule.PlatformStrings {
741 fixPath := func(opt string) string {
742 if strings.HasPrefix(opt, "/") {
743 return opt
744 }
745 return path.Clean(path.Join(pkgRel, opt))
746 }
747
748 fixGroups := func(groups []string) ([]string, error) {
749 fixedGroups := make([]string, len(groups))
750 for i, group := range groups {
751 opts := strings.Split(group, optSeparator)
752 fixedOpts := make([]string, len(opts))
753 isPath := false
754 for j, opt := range opts {
755 if isPath {
756 opt = fixPath(opt)
757 isPath = false
758 goto next
759 }
760
761 for _, short := range shortOptPrefixes {
762 if strings.HasPrefix(opt, short) && len(opt) > len(short) {
763 opt = short + fixPath(opt[len(short):])
764 goto next
765 }
766 }
767
768 for _, long := range longOptPrefixes {
769 if opt == long {
770 isPath = true
771 goto next
772 }
773 }
774
775 next:
776 fixedOpts[j] = escapeOption(opt)
777 }
778 fixedGroups[i] = strings.Join(fixedOpts, " ")
779 }
780
781 return fixedGroups, nil
782 }
783
784 opts, errs := opts.MapSlice(fixGroups)
785 if errs != nil {
786 log.Panicf("unexpected error when transforming options with pkg %q: %v", pkgRel, errs)
787 }
788 return opts
789 }
790
791 func escapeOption(opt string) string {
792 return strings.NewReplacer(
793 `\`, `\\`,
794 `'`, `\'`,
795 `"`, `\"`,
796 ` `, `\ `,
797 "\t", "\\\t",
798 "\n", "\\\n",
799 "\r", "\\\r",
800 "$(", "$(",
801 "$", "$$",
802 ).Replace(opt)
803 }
804
805 func shouldSetVisibility(args language.GenerateArgs) bool {
806 if args.File != nil && args.File.HasDefaultVisibility() {
807 return false
808 }
809
810 for _, r := range args.OtherGen {
811
812
813 if r.Kind() == "package" && r.Attr("default_visibility") != nil {
814 return false
815 }
816 }
817 return true
818 }
819
View as plain text