-
Notifications
You must be signed in to change notification settings - Fork 75
/
bufimagemodify.go
356 lines (326 loc) · 11.7 KB
/
bufimagemodify.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bufimagemodify
import (
"context"
"fmt"
"path"
"strconv"
"strings"
)
import (
"go.uber.org/zap"
"google.golang.org/protobuf/types/descriptorpb"
)
import (
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufimage"
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufmodule/bufmoduleref"
"github.com/apache/dubbo-kubernetes/pkg/bufman/gen/data/datawkt"
"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/protoversion"
)
// Modifier modifies Images.
type Modifier interface {
// Modify modifies the Image.
Modify(context.Context, bufimage.Image) error
}
// NewMultiModifier returns a new Modifier for the given Modifiers.
func NewMultiModifier(modifiers ...Modifier) Modifier {
switch len(modifiers) {
case 0:
return nil
case 1:
return modifiers[0]
default:
return newMultiModifier(modifiers)
}
}
// ModifierFunc is a convenience type that implements the Modifier interface.
type ModifierFunc func(context.Context, bufimage.Image) error
// Modify invokes the ModifierFunc with the given context and image.
func (m ModifierFunc) Modify(ctx context.Context, image bufimage.Image) error {
return m(ctx, image)
}
// Sweeper is used to mark-and-sweep SourceCodeInfo_Locations from images.
type Sweeper interface {
// Sweep implements the ModifierFunc signature so that the Sweeper
// can be used as a Modifier.
Sweep(context.Context, bufimage.Image) error
// mark is un-exported so that the Sweeper cannot be implemented
// outside of this package.
mark(string, []int32)
}
// NewFileOptionSweeper constructs a new file option Sweeper that removes
// the SourceCodeInfo_Locations associated with the marks.
func NewFileOptionSweeper() Sweeper {
return newFileOptionSweeper()
}
// Merge merges the given modifiers together so that they are run in the order
// they are provided. This is particularly useful for constructing a modifier
// from its initial 'nil' value.
//
// var modifier Modifier
// if config.JavaMultipleFiles {
// modifier = Merge(modifier, JavaMultipleFiles)
// }
func Merge(left Modifier, right Modifier) Modifier {
if left == nil {
return right
}
if right == nil {
return left
}
return NewMultiModifier(left, right)
}
// CcEnableArenas returns a Modifier that sets the cc_enable_arenas
// file option to the given value in all of the files contained in
// the Image.
func CcEnableArenas(
logger *zap.Logger,
sweeper Sweeper,
value bool,
overrides map[string]string,
) (Modifier, error) {
validatedOverrides, err := stringOverridesToBoolOverrides(overrides)
if err != nil {
return nil, fmt.Errorf("invalid override for %s: %w", CcEnableArenasID, err)
}
return ccEnableArenas(logger, sweeper, value, validatedOverrides), nil
}
// GoPackage returns a Modifier that sets the go_package file option
// according to the given defaultImportPathPrefix, exceptions, and
// overrides.
func GoPackage(
logger *zap.Logger,
sweeper Sweeper,
defaultImportPathPrefix string,
except []bufmoduleref.ModuleIdentity,
moduleOverrides map[bufmoduleref.ModuleIdentity]string,
overrides map[string]string,
) (Modifier, error) {
return goPackage(
logger,
sweeper,
defaultImportPathPrefix,
except,
moduleOverrides,
overrides,
)
}
// JavaMultipleFiles returns a Modifier that sets the java_multiple_files
// file option to the given value in all of the files contained in
// the Image. If the preserveExistingValue is set to true, then the
// java_multiple_files option will be preserved if set.
func JavaMultipleFiles(
logger *zap.Logger,
sweeper Sweeper,
value bool,
overrides map[string]string,
preserveExistingValue bool,
) (Modifier, error) {
validatedOverrides, err := stringOverridesToBoolOverrides(overrides)
if err != nil {
return nil, fmt.Errorf("invalid override for %s: %w", JavaMultipleFilesID, err)
}
return javaMultipleFiles(logger, sweeper, value, validatedOverrides, preserveExistingValue), nil
}
// JavaOuterClassname returns a Modifier that sets the java_outer_classname file option
// in all of the files contained in the Image based on the PascalCase of their filename.
// If the preserveExistingValue is set to true, then the java_outer_classname option will
// be preserved if set.
func JavaOuterClassname(
logger *zap.Logger,
sweeper Sweeper,
overrides map[string]string,
preserveExistingValue bool,
) Modifier {
return javaOuterClassname(logger, sweeper, overrides, preserveExistingValue)
}
// JavaPackage returns a Modifier that sets the java_package file option
// according to the given packagePrefix.
func JavaPackage(
logger *zap.Logger,
sweeper Sweeper,
defaultPrefix string,
except []bufmoduleref.ModuleIdentity,
moduleOverrides map[bufmoduleref.ModuleIdentity]string,
overrides map[string]string,
) (Modifier, error) {
return javaPackage(
logger,
sweeper,
defaultPrefix,
except,
moduleOverrides,
overrides,
)
}
// JavaStringCheckUtf8 returns a Modifier that sets the java_string_check_utf8 file option according
// to the given value.
func JavaStringCheckUtf8(
logger *zap.Logger,
sweeper Sweeper,
value bool,
overrides map[string]string,
) (Modifier, error) {
validatedOverrides, err := stringOverridesToBoolOverrides(overrides)
if err != nil {
return nil, fmt.Errorf("invalid override for %s: %w", JavaStringCheckUtf8ID, err)
}
return javaStringCheckUtf8(logger, sweeper, value, validatedOverrides), nil
}
// OptimizeFor returns a Modifier that sets the optimize_for file
// option to the given value in all of the files contained in
// the Image.
func OptimizeFor(
logger *zap.Logger,
sweeper Sweeper,
defaultOptimizeFor descriptorpb.FileOptions_OptimizeMode,
except []bufmoduleref.ModuleIdentity,
moduleOverrides map[bufmoduleref.ModuleIdentity]descriptorpb.FileOptions_OptimizeMode,
overrides map[string]string,
) (Modifier, error) {
validatedOverrides, err := stringOverridesToOptimizeModeOverrides(overrides)
if err != nil {
return nil, fmt.Errorf("invalid override for %s: %w", OptimizeForID, err)
}
return optimizeFor(logger, sweeper, defaultOptimizeFor, except, moduleOverrides, validatedOverrides), nil
}
// GoPackageImportPathForFile returns the go_package import path for the given
// ImageFile. If the package contains a version suffix, and if there are more
// than two components, concatenate the final two components. Otherwise, we
// exclude the ';' separator and adopt the default behavior from the import path.
//
// For example, an ImageFile with `package acme.weather.v1;` will include `;weatherv1`
// in the `go_package` declaration so that the generated package is named as such.
func GoPackageImportPathForFile(imageFile bufimage.ImageFile, importPathPrefix string) string {
goPackageImportPath := path.Join(importPathPrefix, path.Dir(imageFile.Path()))
packageName := imageFile.FileDescriptor().GetPackage()
if _, ok := protoversion.NewPackageVersionForPackage(packageName); ok {
parts := strings.Split(packageName, ".")
if len(parts) >= 2 {
goPackageImportPath += ";" + parts[len(parts)-2] + parts[len(parts)-1]
}
}
return goPackageImportPath
}
// ObjcClassPrefix returns a Modifier that sets the objc_class_prefix file option
// according to the package name. It is set to the uppercase first letter of each package sub-name,
// not including the package version, with the following rules:
// - If the resulting abbreviation is 2 characters, add "X".
// - If the resulting abbreviation is 1 character, add "XX".
// - If the resulting abbreviation is "GPB", change it to "GPX".
// "GPB" is reserved by Google for the Protocol Buffers implementation.
func ObjcClassPrefix(
logger *zap.Logger,
sweeper Sweeper,
defaultPrefix string,
except []bufmoduleref.ModuleIdentity,
moduleOverride map[bufmoduleref.ModuleIdentity]string,
overrides map[string]string,
) Modifier {
return objcClassPrefix(logger, sweeper, defaultPrefix, except, moduleOverride, overrides)
}
// CsharpNamespace returns a Modifier that sets the csharp_namespace file option
// according to the package name. It is set to the package name with each package sub-name capitalized.
func CsharpNamespace(
logger *zap.Logger,
sweeper Sweeper,
except []bufmoduleref.ModuleIdentity,
moduleOverrides map[bufmoduleref.ModuleIdentity]string,
overrides map[string]string,
) Modifier {
return csharpNamespace(
logger,
sweeper,
except,
moduleOverrides,
overrides,
)
}
// PhpNamespace returns a Modifier that sets the php_namespace file option
// according to the package name. It is set to the package name with each package sub-name capitalized
// and each "." replaced with "\\".
func PhpNamespace(
logger *zap.Logger,
sweeper Sweeper,
overrides map[string]string,
) Modifier {
return phpNamespace(logger, sweeper, overrides)
}
// PhpMetadataNamespace returns a Modifier that sets the php_metadata_namespace file option
// according to the package name. It appends "\\GPBMetadata" to the heuristic used by PhpNamespace.
func PhpMetadataNamespace(
logger *zap.Logger,
sweeper Sweeper,
overrides map[string]string,
) Modifier {
return phpMetadataNamespace(logger, sweeper, overrides)
}
// RubyPackage returns a Modifier that sets the ruby_package file option
// according to the given packagePrefix. It is set to the package name with each package sub-name capitalized
// and each "." replaced with "::".
func RubyPackage(
logger *zap.Logger,
sweeper Sweeper,
except []bufmoduleref.ModuleIdentity,
moduleOverrides map[bufmoduleref.ModuleIdentity]string,
overrides map[string]string,
) Modifier {
return rubyPackage(
logger,
sweeper,
except,
moduleOverrides,
overrides,
)
}
// isWellKnownType returns true if the given path is one of the well-known types.
func isWellKnownType(ctx context.Context, imageFile bufimage.ImageFile) bool {
return datawkt.Exists(imageFile.Path())
}
// int32SliceIsEqual returns true if x and y contain the same elements.
func int32SliceIsEqual(x []int32, y []int32) bool {
if len(x) != len(y) {
return false
}
for i, elem := range x {
if elem != y[i] {
return false
}
}
return true
}
func stringOverridesToBoolOverrides(stringOverrides map[string]string) (map[string]bool, error) {
validatedOverrides := make(map[string]bool, len(stringOverrides))
for fileImportPath, overrideString := range stringOverrides {
overrideBool, err := strconv.ParseBool(overrideString)
if err != nil {
return nil, fmt.Errorf("non-boolean override %s set for file %s", overrideString, fileImportPath)
}
validatedOverrides[fileImportPath] = overrideBool
}
return validatedOverrides, nil
}
func stringOverridesToOptimizeModeOverrides(stringOverrides map[string]string) (map[string]descriptorpb.FileOptions_OptimizeMode, error) {
validatedOverrides := make(map[string]descriptorpb.FileOptions_OptimizeMode, len(stringOverrides))
for fileImportPath, stringOverride := range stringOverrides {
optimizeMode, ok := descriptorpb.FileOptions_OptimizeMode_value[stringOverride]
if !ok {
return nil, fmt.Errorf("invalid optimize mode %s set for file %s", stringOverride, fileImportPath)
}
validatedOverrides[fileImportPath] = descriptorpb.FileOptions_OptimizeMode(optimizeMode)
}
return validatedOverrides, nil
}