| // 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 bufpluginconfig defines the buf.plugin.yaml file. |
| package bufpluginconfig |
| |
| import ( |
| "context" |
| "fmt" |
| "os" |
| "path/filepath" |
| "sort" |
| "strings" |
| |
| "github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufplugin/bufpluginref" |
| "github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/encoding" |
| "github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/storage" |
| ) |
| |
| const ( |
| // ExternalConfigFilePath is the default configuration file path for v1. |
| ExternalConfigFilePath = "buf.plugin.yaml" |
| // V1Version is the version string used to indicate the v1 version of the buf.plugin.yaml file. |
| V1Version = "v1" |
| ) |
| |
| // AllConfigFilePaths are all acceptable config file paths without overrides. |
| // |
| // These are in the order we should check. |
| var AllConfigFilePaths = []string{ |
| ExternalConfigFilePath, |
| } |
| |
| // Config is the plugin config. |
| type Config struct { |
| // Name is the name of the plugin (e.g. 'buf.build/protocolbuffers/go'). |
| Name bufpluginref.PluginIdentity |
| // PluginVersion is the version of the plugin's implementation |
| // (e.g. the protoc-gen-connect-go implementation is v0.2.0). |
| // |
| // This excludes any other details found in the buf.plugin.yaml |
| // or plugin source (e.g. Dockerfile) that would otherwise influence |
| // the plugin's behavior. |
| PluginVersion string |
| // SourceURL is an optional attribute used to specify where the source |
| // for the plugin can be found. |
| SourceURL string |
| // Description is an optional attribute to provide a more detailed |
| // description for the plugin. |
| Description string |
| // Dependencies are the dependencies this plugin has on other plugins. |
| // |
| // An example of a dependency might be a 'protoc-gen-go-grpc' plugin |
| // which depends on the 'protoc-gen-go' generated code. |
| Dependencies []bufpluginref.PluginReference |
| // OutputLanguages is a list of output languages the plugin supports. |
| OutputLanguages []string |
| // Registry is the registry configuration, which lets the user specify |
| // dependencies and other metadata that applies to a specific |
| // remote generation registry (e.g. the Go module proxy, NPM registry, |
| // etc). |
| Registry *RegistryConfig |
| // SPDXLicenseID is the license of the plugin, which should be one of |
| // the identifiers defined in https://spdx.org/licenses |
| SPDXLicenseID string |
| // LicenseURL specifies where the plugin's license can be found. |
| LicenseURL string |
| } |
| |
| // RegistryConfig is the configuration for the registry of a plugin. |
| // |
| // Only one field will be set. |
| type RegistryConfig struct { |
| Go *GoRegistryConfig |
| NPM *NPMRegistryConfig |
| Maven *MavenRegistryConfig |
| Swift *SwiftRegistryConfig |
| // Options is the set of options passed into the plugin for the |
| // remote registryv1alpha1. |
| // |
| // For now, all options are string values. This could eventually |
| // support other types (like JSON Schema and Terraform variables), |
| // where strings are the default value unless otherwise specified. |
| // |
| // Note that some legacy plugins don't always express their options |
| // as key value pairs. For example, protoc-gen-java has an option |
| // that can be passed like so: |
| // |
| // java_opt=annotate_code |
| // |
| // In those cases, the option value in this map will be set to |
| // the empty string, and the option will be propagated to the |
| // compiler without the '=' delimiter. |
| Options map[string]string |
| } |
| |
| // GoRegistryConfig is the registry configuration for a Go plugin. |
| type GoRegistryConfig struct { |
| MinVersion string |
| Deps []*GoRegistryDependencyConfig |
| } |
| |
| // GoRegistryDependencyConfig is the go registry dependency configuration. |
| type GoRegistryDependencyConfig struct { |
| Module string |
| Version string |
| } |
| |
| // NPMRegistryConfig is the registry configuration for a JavaScript NPM plugin. |
| type NPMRegistryConfig struct { |
| RewriteImportPathSuffix string |
| Deps []*NPMRegistryDependencyConfig |
| ImportStyle string |
| } |
| |
| // NPMRegistryDependencyConfig is the npm registry dependency configuration. |
| type NPMRegistryDependencyConfig struct { |
| Package string |
| Version string |
| } |
| |
| // MavenRegistryConfig is the registry configuration for a Maven plugin. |
| type MavenRegistryConfig struct { |
| // Compiler specifies Java and/or Kotlin compiler settings for remote packages. |
| Compiler MavenCompilerConfig |
| // Deps are dependencies for the remote package. |
| Deps []MavenDependencyConfig |
| // AdditionalRuntimes tracks additional runtimes (like the 'lite' runtime). |
| // This is used to support multiple artifacts targeting different runtimes, plugin options, and dependencies. |
| AdditionalRuntimes []MavenRuntimeConfig |
| } |
| |
| // MavenCompilerConfig specifies compiler settings for Java and/or Kotlin. |
| type MavenCompilerConfig struct { |
| Java MavenCompilerJavaConfig |
| Kotlin MavenCompilerKotlinConfig |
| } |
| |
| // MavenCompilerJavaConfig specifies compiler settings for Java code. |
| type MavenCompilerJavaConfig struct { |
| // Encoding specifies the encoding of the source files (default: UTF-8). |
| Encoding string |
| // Release specifies the target Java release (default: 8). |
| Release int |
| // Source specifies the source bytecode level (default: 8). |
| Source int |
| // Target specifies the target bytecode level (default: 8). |
| Target int |
| } |
| |
| // MavenCompilerKotlinConfig specifies compiler settings for Kotlin code. |
| type MavenCompilerKotlinConfig struct { |
| // APIVersion specifies the Kotlin API version to target. |
| APIVersion string |
| // JVMTarget specifies the target version of the JVM bytecode (default: 1.8) |
| JVMTarget string |
| // LanguageVersion is used to provide source compatibility with the specified Kotlin version. |
| LanguageVersion string |
| // Version of the Kotlin compiler to use (required for Kotlin plugins). |
| Version string |
| } |
| |
| // MavenDependencyConfig defines a runtime dependency for a remote package artifact. |
| type MavenDependencyConfig struct { |
| GroupID string |
| ArtifactID string |
| Version string |
| Classifier string |
| // Extension is the file extension, also known as the Maven type. |
| Extension string |
| } |
| |
| // MavenRuntimeConfig is used to specify additional runtimes for a given plugin. |
| type MavenRuntimeConfig struct { |
| // Name is the required, unique name for the runtime in MavenRegistryConfig.AdditionalRuntimes. |
| Name string |
| // Deps contains the Maven dependencies for the runtime. Overrides MavenRegistryConfig.Deps. |
| Deps []MavenDependencyConfig |
| // Options contains the Maven plugin options for the runtime. Overrides RegistryConfig.Options. |
| Options []string |
| } |
| |
| // SwiftRegistryConfig is the registry configuration for a Swift plugin. |
| type SwiftRegistryConfig struct { |
| // Dependencies are dependencies for the remote package. |
| Dependencies []SwiftRegistryDependencyConfig |
| } |
| |
| // SwiftRegistryDependencyConfig is the swift registry dependency configuration. |
| type SwiftRegistryDependencyConfig struct { |
| // Source specifies the source of the dependency. |
| Source string |
| // Package is the name of the Swift package. |
| Package string |
| // Version is the version of the Swift package. |
| Version string |
| // Products are the names of the products available to import. |
| Products []string |
| // Platforms are the minimum versions for platforms the package supports. |
| Platforms SwiftRegistryDependencyPlatformConfig |
| // SwiftVersions are the versions of Swift the package supports. |
| SwiftVersions []string |
| } |
| |
| // SwiftRegistryDependencyPlatformConfig is the swift registry dependency platform configuration. |
| type SwiftRegistryDependencyPlatformConfig struct { |
| // macOS specifies the version of the macOS platform. |
| MacOS string |
| // iOS specifies the version of the iOS platform. |
| IOS string |
| // TVOS specifies the version of the tvOS platform. |
| TVOS string |
| // WatchOS specifies the version of the watchOS platform. |
| WatchOS string |
| } |
| |
| // ConfigOption is an optional option used when loading a Config. |
| type ConfigOption func(*configOptions) |
| |
| // WithOverrideRemote will update the remote found in the plugin name and dependencies. |
| func WithOverrideRemote(remote string) ConfigOption { |
| return func(options *configOptions) { |
| options.overrideRemote = remote |
| } |
| } |
| |
| // GetConfigForBucket gets the Config for the YAML data at ConfigFilePath. |
| // |
| // If the data is of length 0, returns the default config. |
| func GetConfigForBucket(ctx context.Context, readBucket storage.ReadBucket, options ...ConfigOption) (*Config, error) { |
| return getConfigForBucket(ctx, readBucket, options) |
| } |
| |
| // GetConfigForData gets the Config for the given JSON or YAML data. |
| // |
| // If the data is of length 0, returns the default config. |
| func GetConfigForData(ctx context.Context, data []byte, options ...ConfigOption) (*Config, error) { |
| return getConfigForData(ctx, data, options) |
| } |
| |
| // ExistingConfigFilePath checks if a configuration file exists, and if so, returns the path |
| // within the ReadBucket of this configuration file. |
| // |
| // Returns empty string and no error if no configuration file exists. |
| func ExistingConfigFilePath(ctx context.Context, readBucket storage.ReadBucket) (string, error) { |
| for _, configFilePath := range AllConfigFilePaths { |
| exists, err := storage.Exists(ctx, readBucket, configFilePath) |
| if err != nil { |
| return "", err |
| } |
| if exists { |
| return configFilePath, nil |
| } |
| } |
| return "", nil |
| } |
| |
| // ParseConfig parses the file at the given path as a Config. |
| func ParseConfig(config string, options ...ConfigOption) (*Config, error) { |
| var data []byte |
| var err error |
| switch filepath.Ext(config) { |
| case ".json", ".yaml", ".yml": |
| data, err = os.ReadFile(config) |
| if err != nil { |
| return nil, fmt.Errorf("could not read file: %w", err) |
| } |
| default: |
| return nil, fmt.Errorf("invalid extension %s, must be .json, .yaml or .yml", filepath.Ext(config)) |
| } |
| var externalConfig ExternalConfig |
| if err := encoding.UnmarshalJSONOrYAMLStrict(data, &externalConfig); err != nil { |
| return nil, fmt.Errorf("failed to unmarshal plugin config: %w", err) |
| } |
| switch externalConfig.Version { |
| case V1Version: |
| return newConfig(externalConfig, options) |
| } |
| return nil, fmt.Errorf("invalid plugin configuration version: must be one of %v", AllConfigFilePaths) |
| } |
| |
| // PluginOptionsToOptionsSlice converts a map representation of plugin options to a slice of the form '<key>=<value>' or '<key>' for empty values. |
| func PluginOptionsToOptionsSlice(pluginOptions map[string]string) []string { |
| if pluginOptions == nil { |
| return nil |
| } |
| options := make([]string, 0, len(pluginOptions)) |
| for key, value := range pluginOptions { |
| if len(value) > 0 { |
| options = append(options, key+"="+value) |
| } else { |
| options = append(options, key) |
| } |
| } |
| sort.Strings(options) |
| return options |
| } |
| |
| // OptionsSliceToPluginOptions converts a slice of plugin options to a map (using the first '=' as a delimiter between key and value). |
| // If no '=' is found, the option will be stored in the map with an empty string value. |
| func OptionsSliceToPluginOptions(options []string) map[string]string { |
| if options == nil { |
| return nil |
| } |
| pluginOptions := make(map[string]string, len(options)) |
| for _, option := range options { |
| fields := strings.SplitN(option, "=", 2) |
| if len(fields) == 2 { |
| pluginOptions[fields[0]] = fields[1] |
| } else { |
| pluginOptions[option] = "" |
| } |
| } |
| return pluginOptions |
| } |
| |
| // ExternalConfig represents the on-disk representation |
| // of the plugin configuration at version v1. |
| type ExternalConfig struct { |
| Version string `json:"version,omitempty" yaml:"version,omitempty"` |
| Name string `json:"name,omitempty" yaml:"name,omitempty"` |
| PluginVersion string `json:"plugin_version,omitempty" yaml:"plugin_version,omitempty"` |
| SourceURL string `json:"source_url,omitempty" yaml:"source_url,omitempty"` |
| Description string `json:"description,omitempty" yaml:"description,omitempty"` |
| Deps []ExternalDependency `json:"deps,omitempty" yaml:"deps,omitempty"` |
| OutputLanguages []string `json:"output_languages,omitempty" yaml:"output_languages,omitempty"` |
| Registry ExternalRegistryConfig `json:"registry,omitempty" yaml:"registry,omitempty"` |
| SPDXLicenseID string `json:"spdx_license_id,omitempty" yaml:"spdx_license_id,omitempty"` |
| LicenseURL string `json:"license_url,omitempty" yaml:"license_url,omitempty"` |
| } |
| |
| // ExternalDependency represents a dependency on another plugin. |
| type ExternalDependency struct { |
| Plugin string `json:"plugin,omitempty" yaml:"plugin,omitempty"` |
| Revision int `json:"revision,omitempty" yaml:"revision,omitempty"` |
| } |
| |
| // ExternalRegistryConfig is the external configuration for the registry |
| // of a plugin. |
| type ExternalRegistryConfig struct { |
| Go *ExternalGoRegistryConfig `json:"go,omitempty" yaml:"go,omitempty"` |
| NPM *ExternalNPMRegistryConfig `json:"npm,omitempty" yaml:"npm,omitempty"` |
| Maven *ExternalMavenRegistryConfig `json:"maven,omitempty" yaml:"maven,omitempty"` |
| Swift *ExternalSwiftRegistryConfig `json:"swift,omitempty" yaml:"swift,omitempty"` |
| Opts []string `json:"opts,omitempty" yaml:"opts,omitempty"` |
| } |
| |
| // ExternalGoRegistryConfig is the external registry configuration for a Go plugin. |
| type ExternalGoRegistryConfig struct { |
| // The minimum Go version required by the plugin. |
| MinVersion string `json:"min_version,omitempty" yaml:"min_version,omitempty"` |
| Deps []struct { |
| Module string `json:"module,omitempty" yaml:"module,omitempty"` |
| Version string `json:"version,omitempty" yaml:"version,omitempty"` |
| } `json:"deps,omitempty" yaml:"deps,omitempty"` |
| } |
| |
| // ExternalNPMRegistryConfig is the external registry configuration for a JavaScript NPM plugin. |
| type ExternalNPMRegistryConfig struct { |
| RewriteImportPathSuffix string `json:"rewrite_import_path_suffix,omitempty" yaml:"rewrite_import_path_suffix,omitempty"` |
| Deps []struct { |
| Package string `json:"package,omitempty" yaml:"package,omitempty"` |
| Version string `json:"version,omitempty" yaml:"version,omitempty"` |
| } `json:"deps,omitempty" yaml:"deps,omitempty"` |
| // The import style used for the "type" field in the package.json file. |
| // Must be one of "module" or "commonjs". |
| ImportStyle string `json:"import_style,omitempty" yaml:"import_style,omitempty"` |
| } |
| |
| // ExternalMavenRegistryConfig is the external registry configuration for a Maven plugin. |
| type ExternalMavenRegistryConfig struct { |
| Compiler ExternalMavenCompilerConfig `json:"compiler" yaml:"compiler"` |
| Deps []string `json:"deps,omitempty" yaml:"deps,omitempty"` |
| AdditionalRuntimes []ExternalMavenRuntimeConfig `json:"additional_runtimes,omitempty" yaml:"additional_runtimes,omitempty"` |
| } |
| |
| // ExternalMavenCompilerConfig configures compiler settings for Maven remote packages. |
| type ExternalMavenCompilerConfig struct { |
| Java ExternalMavenCompilerJavaConfig `json:"java" yaml:"java"` |
| Kotlin ExternalMavenCompilerKotlinConfig `json:"kotlin" yaml:"kotlin"` |
| } |
| |
| // ExternalMavenCompilerJavaConfig configures the Java compiler settings for remote packages. |
| type ExternalMavenCompilerJavaConfig struct { |
| // Encoding specifies the encoding of the source files (default: UTF-8). |
| Encoding string `json:"encoding" yaml:"encoding"` |
| // Release specifies the target Java release (default: 8). |
| Release int `json:"release" yaml:"release"` |
| // Source specifies the source bytecode level (default: 8). |
| Source int `json:"source" yaml:"source"` |
| // Target specifies the target bytecode level (default: 8). |
| Target int `json:"target" yaml:"target"` |
| } |
| |
| // ExternalMavenCompilerKotlinConfig configures the Kotlin compiler settings for remote packages. |
| type ExternalMavenCompilerKotlinConfig struct { |
| // APIVersion specifies the Kotlin API version to target. |
| APIVersion string `json:"api_version" yaml:"api_version"` |
| // JVMTarget specifies the target version of the JVM bytecode (default: 1.8) |
| JVMTarget string `json:"jvm_target" yaml:"jvm_target"` |
| // LanguageVersion is used to provide source compatibility with the specified Kotlin version. |
| LanguageVersion string `json:"language_version" yaml:"language_version"` |
| // Version of the Kotlin compiler to use (required for Kotlin plugins). |
| Version string `json:"version" yaml:"version"` |
| } |
| |
| // ExternalMavenRuntimeConfig allows configuring additional runtimes for remote packages. |
| // These can specify different dependencies and compiler options than the default runtime. |
| // This is used to support a single plugin supporting both full and lite Protobuf runtimes. |
| type ExternalMavenRuntimeConfig struct { |
| // Name contains the Maven runtime name (e.g. 'lite'). |
| Name string `json:"name" yaml:"name"` |
| // Deps contains the Maven dependencies for the runtime. Overrides ExternalMavenRuntimeConfig.Deps. |
| Deps []string `json:"deps,omitempty" yaml:"deps,omitempty"` |
| // Opts contains the Maven plugin options for the runtime. Overrides ExternalRegistryConfig.Opts. |
| Opts []string `json:"opts,omitempty" yaml:"opts,omitempty"` |
| } |
| |
| // ExternalSwiftRegistryConfig is the registry configuration for a Swift plugin. |
| type ExternalSwiftRegistryConfig struct { |
| // Deps are dependencies for the remote package. |
| Deps []ExternalSwiftRegistryDependencyConfig `json:"deps,omitempty" yaml:"deps,omitempty"` |
| } |
| |
| // ExternalSwiftRegistryDependencyConfig is the swift registry dependency configuration. |
| type ExternalSwiftRegistryDependencyConfig struct { |
| // Source is the URL of the Swift package. |
| Source string `json:"source,omitempty" yaml:"source,omitempty"` |
| // Package is the name of the Swift package. |
| Package string `json:"package,omitempty" yaml:"package,omitempty"` |
| // Version is the version of the Swift package. |
| Version string `json:"version,omitempty" yaml:"version,omitempty"` |
| // Products are the names of the products available to import. |
| Products []string `json:"products,omitempty" yaml:"products,omitempty"` |
| // Platforms are the minimum versions for platforms the package supports. |
| Platforms ExternalSwiftRegistryDependencyPlatformConfig `json:"platforms,omitempty" yaml:"platforms,omitempty"` |
| // SwiftVersions are the versions of Swift the package supports. |
| SwiftVersions []string `json:"swift_versions,omitempty" yaml:"swift_versions,omitempty"` |
| } |
| |
| // ExternalSwiftRegistryDependencyPlatformConfig is the swift registry dependency platform configuration. |
| type ExternalSwiftRegistryDependencyPlatformConfig struct { |
| // macOS specifies the version of the macOS platform. |
| MacOS string `json:"macos,omitempty" yaml:"macos,omitempty"` |
| // iOS specifies the version of the iOS platform. |
| IOS string `json:"ios,omitempty" yaml:"ios,omitempty"` |
| // TVOS specifies the version of the tvOS platform. |
| TVOS string `json:"tvos,omitempty" yaml:"tvos,omitempty"` |
| // WatchOS specifies the version of the watchOS platform. |
| WatchOS string `json:"watchos,omitempty" yaml:"watchos,omitempty"` |
| } |
| |
| type externalConfigVersion struct { |
| Version string `json:"version,omitempty" yaml:"version,omitempty"` |
| } |
| |
| type configOptions struct { |
| overrideRemote string |
| } |