Skip to content

Commit a293ec6

Browse files
bufdevdoriable
andauthored
Add swift_prefix to managed mode (#4215)
Co-authored-by: Doria Keung <[email protected]>
1 parent b40fd73 commit a293ec6

File tree

9 files changed

+233
-3
lines changed

9 files changed

+233
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [Unreleased]
44

5+
- Add `swift_prefix` to managed mode.
56
- Add `textDocument/rename` and `textDocument/prepareRename` support for `buf lsp serve`.
67
- Fix panic in LSP for empty option paths.
78
- Fix support for multi-arch image manifests for `buf beta registry plugin push`.

private/bufpkg/bufconfig/buf_gen_yaml_file.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ type externalGenerateManagedConfigV1 struct {
333333
GoPackagePrefix externalGoPackagePrefixConfigV1 `json:"go_package_prefix,omitempty" yaml:"go_package_prefix,omitempty"`
334334
ObjcClassPrefix externalObjcClassPrefixConfigV1 `json:"objc_class_prefix,omitempty" yaml:"objc_class_prefix,omitempty"`
335335
RubyPackage externalRubyPackageConfigV1 `json:"ruby_package,omitempty" yaml:"ruby_package,omitempty"`
336+
SwiftPrefix externalSwiftPrefixConfigV1 `json:"swift_prefix,omitempty" yaml:"swift_prefix,omitempty"`
336337
// Override maps from a file option to a file path then to the value.
337338
Override map[string]map[string]string `json:"override,omitempty" yaml:"override,omitempty"`
338339
}
@@ -460,6 +461,20 @@ func (e externalRubyPackageConfigV1) isEmpty() bool {
460461
return len(e.Except) == 0 && len(e.Override) == 0
461462
}
462463

464+
// externalSwiftPrefixConfigV1 represents the swift_prefix config in a v1 buf.gen.yaml file.
465+
type externalSwiftPrefixConfigV1 struct {
466+
Default string `json:"default,omitempty" yaml:"default,omitempty"`
467+
Except []string `json:"except,omitempty" yaml:"except,omitempty"`
468+
Override map[string]string `json:"override,omitempty" yaml:"override,omitempty"`
469+
}
470+
471+
// isEmpty returns true is the config is empty.
472+
func (e externalSwiftPrefixConfigV1) isEmpty() bool {
473+
return e.Default == "" &&
474+
len(e.Except) == 0 &&
475+
len(e.Override) == 0
476+
}
477+
463478
// externalObjcClassPrefixConfigV1 represents the objc_class_prefix config in a v1 buf.gen.yaml file.
464479
type externalObjcClassPrefixConfigV1 struct {
465480
Default string `json:"default,omitempty" yaml:"default,omitempty"`

private/bufpkg/bufconfig/generate_config_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,57 @@ func TestParseConfigFromExternalV1(t *testing.T) {
600600
},
601601
},
602602
},
603+
{
604+
description: "managed_mode_swift_prefix",
605+
externalConfig: externalBufGenYAMLFileV1{
606+
Version: "v1",
607+
Plugins: []externalGeneratePluginConfigV1{
608+
{
609+
Plugin: "go",
610+
Out: "go/out",
611+
},
612+
},
613+
Managed: externalGenerateManagedConfigV1{
614+
Enabled: true,
615+
SwiftPrefix: externalSwiftPrefixConfigV1{
616+
Default: "foo",
617+
Except: []string{"buf.build/acme/foo"},
618+
Override: map[string]string{
619+
"buf.build/acme/petapis": "pet",
620+
},
621+
},
622+
},
623+
},
624+
expectedConfig: &generateConfig{
625+
generatePluginConfigs: []GeneratePluginConfig{
626+
&generatePluginConfig{
627+
generatePluginConfigType: GeneratePluginConfigTypeLocalOrProtocBuiltin,
628+
name: "go",
629+
out: "go/out",
630+
},
631+
},
632+
generateManagedConfig: &generateManagedConfig{
633+
enabled: true,
634+
disables: []ManagedDisableRule{
635+
&managedDisableRule{
636+
fileOption: FileOptionSwiftPrefix,
637+
moduleFullName: "buf.build/acme/foo",
638+
},
639+
},
640+
overrides: []ManagedOverrideRule{
641+
&managedOverrideRule{
642+
fileOption: FileOptionSwiftPrefix,
643+
value: "foo",
644+
},
645+
&managedOverrideRule{
646+
fileOption: FileOptionSwiftPrefix,
647+
moduleFullName: "buf.build/acme/petapis",
648+
value: "pet",
649+
},
650+
},
651+
},
652+
},
653+
},
603654
{
604655
description: "managed_mode_per_file_override",
605656
externalConfig: externalBufGenYAMLFileV1{

private/bufpkg/bufconfig/generate_managed_config.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,32 @@ func newGenerateManagedConfigFromExternalV1(
387387
disables = append(disables, rubyPackageDisables...)
388388
overrides = append(overrides, rubyPackageOverrides...)
389389
}
390+
if externalSwiftPrefix := externalConfig.SwiftPrefix; !externalSwiftPrefix.isEmpty() {
391+
if externalSwiftPrefix.Default != "" {
392+
// objc class prefix allows empty default
393+
defaultOverride, err := NewManagedOverrideRuleForFileOption(
394+
"",
395+
"",
396+
FileOptionSwiftPrefix,
397+
externalSwiftPrefix.Default,
398+
)
399+
if err != nil {
400+
return nil, err
401+
}
402+
overrides = append(overrides, defaultOverride)
403+
}
404+
swiftPrefixDisables, swiftPrefixOverrides, err := disablesAndOverridesFromExceptAndOverrideV1(
405+
FileOptionSwiftPrefix,
406+
externalSwiftPrefix.Except,
407+
FileOptionSwiftPrefix,
408+
externalSwiftPrefix.Override,
409+
)
410+
if err != nil {
411+
return nil, err
412+
}
413+
disables = append(disables, swiftPrefixDisables...)
414+
overrides = append(overrides, swiftPrefixOverrides...)
415+
}
390416
perFileOverrides, err := overrideRulesForPerFileOverridesV1(externalConfig.Override)
391417
if err != nil {
392418
return nil, err

private/bufpkg/bufconfig/generate_managed_option.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const (
6565
FileOptionRubyPackage
6666
// FileOptionRubyPackageSuffix is the file option ruby_package_suffix.
6767
FileOptionRubyPackageSuffix
68+
// FileOptionSwiftPrefix is the file option swift_prefix.
69+
FileOptionSwiftPrefix
6870
)
6971

7072
// String implements fmt.Stringer.
@@ -117,6 +119,7 @@ var (
117119
FileOptionPhpMetadataNamespaceSuffix: "php_metadata_namespace_suffix",
118120
FileOptionRubyPackage: "ruby_package",
119121
FileOptionRubyPackageSuffix: "ruby_package_suffix",
122+
FileOptionSwiftPrefix: "swift_prefix",
120123
}
121124
stringToFileOption = map[string]FileOption{
122125
"java_package": FileOptionJavaPackage,
@@ -137,6 +140,7 @@ var (
137140
"php_metadata_namespace_suffix": FileOptionPhpMetadataNamespaceSuffix,
138141
"ruby_package": FileOptionRubyPackage,
139142
"ruby_package_suffix": FileOptionRubyPackageSuffix,
143+
"swift_prefix": FileOptionSwiftPrefix,
140144
}
141145
fileOptionToParseOverrideValueFunc = map[FileOption]func(any) (any, error){
142146
FileOptionJavaPackage: parseOverrideValue[string],
@@ -157,6 +161,7 @@ var (
157161
FileOptionPhpMetadataNamespaceSuffix: parseOverrideValue[string],
158162
FileOptionRubyPackage: parseOverrideValue[string],
159163
FileOptionRubyPackageSuffix: parseOverrideValue[string],
164+
FileOptionSwiftPrefix: parseOverrideValue[string],
160165
}
161166
fieldOptionToString = map[FieldOption]string{
162167
FieldOptionJSType: "jstype",
@@ -258,7 +263,8 @@ func getOverrideValue(fileOptionName string, fieldOptionName string, value any)
258263
FileOptionPhpMetadataNamespace,
259264
FileOptionPhpMetadataNamespaceSuffix,
260265
FileOptionRubyPackage,
261-
FileOptionRubyPackageSuffix:
266+
FileOptionRubyPackageSuffix,
267+
FileOptionSwiftPrefix:
262268
return value, nil
263269

264270
case FileOptionOptimizeFor:

private/bufpkg/bufimage/bufimagemodify/bufimagemodify.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func Modify(
4545
modifyPhpMetadataNamespace,
4646
modifyPhpNamespace,
4747
modifyRubyPackage,
48+
modifySwiftPrefix,
4849
modifyJsType,
4950
},
5051
options...,
@@ -163,6 +164,20 @@ func ModifyRubyPackage(
163164
)
164165
}
165166

167+
// ModifySwiftPrefix modifies the swift_prefix file option.
168+
func ModifySwiftPrefix(
169+
image bufimage.Image,
170+
config bufconfig.GenerateManagedConfig,
171+
options ...ModifyOption,
172+
) error {
173+
return modifyImageForSingleOption(
174+
image,
175+
config,
176+
modifySwiftPrefix,
177+
options...,
178+
)
179+
}
180+
166181
// ModifyCcEnableArenas modifies the cc_enable_arenas file option.
167182
func ModifyCcEnableArenas(
168183
image bufimage.Image,

private/bufpkg/bufimage/bufimagemodify/bufimagemodify_test.go

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func TestModifyImage(t *testing.T) {
9999
PhpMetadataNamespace: proto.String(`Foo\Empty_\GPBMetadata`),
100100
PhpNamespace: proto.String(`Foo\Empty_`),
101101
RubyPackage: proto.String("Foo::Empty"),
102+
SwiftPrefix: proto.String("Foo_Empty_"),
102103
},
103104
"foo_empty/without_package.proto": {
104105
// CcEnableArena's default value is true
@@ -125,7 +126,7 @@ func TestModifyImage(t *testing.T) {
125126
PhpNamespace: proto.String(`Bar\All`),
126127
PyGenericServices: proto.Bool(false),
127128
RubyPackage: proto.String("Bar::All"),
128-
SwiftPrefix: proto.String("bar"),
129+
SwiftPrefix: proto.String("Bar_All_"),
129130
},
130131
"bar_all/without_package.proto": {
131132
CcEnableArenas: proto.Bool(true),
@@ -546,6 +547,65 @@ func TestModifyImageFile(
546547
"foo_all/with_package.proto": {objcClassPrefixPath},
547548
},
548549
},
550+
{
551+
description: "swift_prefix",
552+
dirPathToFullName: map[string]string{
553+
filepath.Join("testdata", "foo"): "buf.build/acme/foo",
554+
filepath.Join("testdata", "bar"): "buf.build/acme/bar",
555+
},
556+
config: bufconfig.NewGenerateManagedConfig(
557+
true,
558+
[]bufconfig.ManagedDisableRule{
559+
newTestManagedDisableRule(t, "foo_empty/with_package.proto", "", "", bufconfig.FileOptionSwiftPrefix, bufconfig.FieldOptionUnspecified),
560+
},
561+
[]bufconfig.ManagedOverrideRule{
562+
newTestFileOptionOverrideRule(t, "", "buf.build/acme/bar", bufconfig.FileOptionSwiftPrefix, "BAR"),
563+
newTestFileOptionOverrideRule(t, "", "buf.build/acme/foo", bufconfig.FileOptionSwiftPrefix, "FOO"),
564+
newTestFileOptionOverrideRule(t, "foo_all", "buf.build/acme/foo", bufconfig.FileOptionSwiftPrefix, "FOOALL"),
565+
},
566+
),
567+
modifyFunc: modifySwiftPrefix,
568+
filePathToExpectedOptions: map[string]*descriptorpb.FileOptions{
569+
"bar_empty/with_package.proto": {
570+
SwiftPrefix: proto.String("BAR"),
571+
},
572+
"bar_empty/without_package.proto": {
573+
SwiftPrefix: proto.String("BAR"),
574+
},
575+
// disabled
576+
"foo_empty/with_package.proto": nil,
577+
// no package
578+
"foo_empty/without_package.proto": {
579+
SwiftPrefix: proto.String("FOO"),
580+
},
581+
"foo_all/with_package.proto": {
582+
ObjcClassPrefix: proto.String("foo"),
583+
CcEnableArenas: proto.Bool(true),
584+
CcGenericServices: proto.Bool(true),
585+
CsharpNamespace: proto.String("foo"),
586+
GoPackage: proto.String("foo"),
587+
JavaGenericServices: proto.Bool(true),
588+
JavaMultipleFiles: proto.Bool(true),
589+
JavaOuterClassname: proto.String("foo"),
590+
JavaPackage: proto.String("foo"),
591+
JavaStringCheckUtf8: proto.Bool(true),
592+
OptimizeFor: descriptorpb.FileOptions_CODE_SIZE.Enum(),
593+
PhpClassPrefix: proto.String("foo"),
594+
PhpMetadataNamespace: proto.String("foo"),
595+
PhpNamespace: proto.String("foo"),
596+
PyGenericServices: proto.Bool(true),
597+
RubyPackage: proto.String("foo"),
598+
SwiftPrefix: proto.String("FOOALL"),
599+
},
600+
},
601+
filePathToExpectedMarkedLocationPaths: map[string][][]int32{
602+
"bar_empty/with_package.proto": {swiftPrefixPath},
603+
"bar_empty/without_package.proto": {swiftPrefixPath},
604+
"foo_empty/without_package.proto": {swiftPrefixPath},
605+
"foo_all/without_package.proto": {swiftPrefixPath},
606+
"foo_all/with_package.proto": {swiftPrefixPath},
607+
},
608+
},
549609
}
550610
for _, testcase := range testcases {
551611
for _, includeSourceInfo := range []bool{true, false} {

private/bufpkg/bufimage/bufimagemodify/file_option.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ var (
5656
// phpNamespacePath is the SourceCodeInfo path for the php_namespace option.
5757
// Ref: https://github.com/protocolbuffers/protobuf/blob/61689226c0e3ec88287eaed66164614d9c4f2bf7/src/google/protobuf/descriptor.proto#L443
5858
phpNamespacePath = []int32{8, 41}
59-
6059
// rubyPackagePath is the SourceCodeInfo path for the ruby_package option.
6160
// https://github.com/protocolbuffers/protobuf/blob/61689226c0e3ec88287eaed66164614d9c4f2bf7/src/google/protobuf/descriptor.proto#L453
6261
rubyPackagePath = []int32{8, 45}
62+
// swiftPrefixPath is the SourceCodeInfo path for the swift_prefix option.
63+
// https://github.com/protocolbuffers/protobuf/blob/61689226c0e3ec88287eaed66164614d9c4f2bf7/src/google/protobuf/descriptor.proto#L434
64+
swiftPrefixPath = []int32{8, 39}
6365
)
6466

6567
func modifyJavaOuterClass(
@@ -359,6 +361,43 @@ func modifyRubyPackage(
359361
)
360362
}
361363

364+
func modifySwiftPrefix(
365+
sweeper internal.MarkSweeper,
366+
imageFile bufimage.ImageFile,
367+
config bufconfig.GenerateManagedConfig,
368+
options ...ModifyOption,
369+
) error {
370+
modifyOptions := newModifyOptions()
371+
for _, option := range options {
372+
option(modifyOptions)
373+
}
374+
return modifyStringOption(
375+
sweeper,
376+
imageFile,
377+
config,
378+
modifyOptions.preserveExisting,
379+
bufconfig.FileOptionSwiftPrefix,
380+
bufconfig.FileOptionUnspecified,
381+
bufconfig.FileOptionUnspecified,
382+
func(bufimage.ImageFile) stringOverrideOptions {
383+
return stringOverrideOptions{value: swiftPrefixValue(imageFile)}
384+
},
385+
func(imageFile bufimage.ImageFile, _ stringOverrideOptions) string {
386+
return swiftPrefixValue(imageFile)
387+
},
388+
func(options *descriptorpb.FileOptions) string {
389+
return options.GetSwiftPrefix()
390+
},
391+
func(options *descriptorpb.FileOptions, value string) {
392+
options.SwiftPrefix = proto.String(value)
393+
},
394+
func(options *descriptorpb.FileOptions) bool {
395+
return options != nil && options.SwiftPrefix != nil
396+
},
397+
swiftPrefixPath,
398+
)
399+
}
400+
362401
func modifyCcEnableArenas(
363402
sweeper internal.MarkSweeper,
364403
imageFile bufimage.ImageFile,

private/bufpkg/bufimage/bufimagemodify/override.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,20 @@ func rubyPackageValue(imageFile bufimage.ImageFile) string {
422422
}
423423
return strings.Join(packageParts, "::")
424424
}
425+
426+
// swiftPrefixValue returns the swift_prefix for the given ImageFile based on its
427+
// package declaration. If the image file doesn't have a package declaration, an
428+
// empty string is returned.
429+
func swiftPrefixValue(imageFile bufimage.ImageFile) string {
430+
pkg := imageFile.FileDescriptorProto().GetPackage()
431+
if pkg == "" {
432+
return ""
433+
}
434+
packageParts := strings.Split(pkg, ".")
435+
for i, part := range packageParts {
436+
packageParts[i] = xstrings.ToPascalCase(part)
437+
}
438+
// We add a "_" as the suffix since this emulates the default behavior if swift_prefix
439+
// is not set.
440+
return strings.Join(packageParts, "_") + "_"
441+
}

0 commit comments

Comments
 (0)