diff --git a/pkg/build/package.go b/pkg/build/package.go index 344d75537..80cc72f25 100644 --- a/pkg/build/package.go +++ b/pkg/build/package.go @@ -177,6 +177,9 @@ replaces = {{ $dep }} {{- if .Dependencies.ProviderPriority }} provider_priority = {{ .Dependencies.ProviderPriority }} {{- end }} +{{- if .Dependencies.ReplacesPriority }} +replaces_priority = {{ .Dependencies.ReplacesPriority }} +{{- end }} {{- if .Scriptlets.Trigger.Paths }} triggers = {{ range $item := .Scriptlets.Trigger.Paths }}{{ $item }} {{ end }} {{- end }} diff --git a/pkg/config/config.go b/pkg/config/config.go index a62f02027..5bda3910a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -161,6 +161,30 @@ func (cfg *Configuration) applySubstitutionsForProvides() error { return nil } +func (cfg *Configuration) applySubstitutionsForPriorities() error { + nw := buildConfigMap(cfg) + var err error + cfg.Package.Dependencies.ProviderPriority, err = util.MutateStringFromMap(nw, cfg.Package.Dependencies.ProviderPriority) + if err != nil { + return fmt.Errorf("failed to apply replacement to provides %q: %w", cfg.Package.Dependencies.ProviderPriority, err) + } + cfg.Package.Dependencies.ReplacesPriority, err = util.MutateStringFromMap(nw, cfg.Package.Dependencies.ReplacesPriority) + if err != nil { + return fmt.Errorf("failed to apply replacement to provides %q: %w", cfg.Package.Dependencies.ReplacesPriority, err) + } + for _, sp := range cfg.Subpackages { + sp.Dependencies.ProviderPriority, err = util.MutateStringFromMap(nw, sp.Dependencies.ProviderPriority) + if err != nil { + return fmt.Errorf("failed to apply replacement to provides %q: %w", sp.Dependencies.ProviderPriority, err) + } + sp.Dependencies.ReplacesPriority, err = util.MutateStringFromMap(nw, sp.Dependencies.ReplacesPriority) + if err != nil { + return fmt.Errorf("failed to apply replacement to provides %q: %w", sp.Dependencies.ReplacesPriority, err) + } + } + return nil +} + func (cfg *Configuration) applySubstitutionsForRuntime() error { nw := buildConfigMap(cfg) for i, runtime := range cfg.Package.Dependencies.Runtime { @@ -532,9 +556,12 @@ type Dependencies struct { Provides []string `json:"provides,omitempty" yaml:"provides,omitempty"` // Optional: List of replace objectives Replaces []string `json:"replaces,omitempty" yaml:"replaces,omitempty"` - // Optional: An integer compared against other equal package provides used to - // determine priority - ProviderPriority int `json:"provider-priority,omitempty" yaml:"provider-priority,omitempty"` + // Optional: An integer string compared against other equal package provides used to + // determine priority of provides + ProviderPriority string `json:"provider-priority,omitempty" yaml:"provider-priority,omitempty"` + // Optional: An integer string compared against other equal package provides used to + // determine priority of file replacements + ReplacesPriority string `json:"replaces-priority,omitempty" yaml:"replaces-priority,omitempty"` // List of self-provided dependencies found outside of lib directories // ("lib", "usr/lib", "lib64", or "usr/lib64"). @@ -780,7 +807,8 @@ func ParseConfiguration(ctx context.Context, configurationFilePath string, opts Runtime: replaceAll(replacer, sp.Dependencies.Runtime), Provides: replaceAll(replacer, sp.Dependencies.Provides), Replaces: replaceAll(replacer, sp.Dependencies.Replaces), - ProviderPriority: sp.Dependencies.ProviderPriority, + ProviderPriority: replacer.Replace(sp.Dependencies.ProviderPriority), + ReplacesPriority: replacer.Replace(sp.Dependencies.ReplacesPriority), }, Options: sp.Options, Scriptlets: Scriptlets{ @@ -953,6 +981,9 @@ func ParseConfiguration(ctx context.Context, configurationFilePath string, opts if err := cfg.applySubstitutionsForPackages(); err != nil { return nil, err } + if err := cfg.applySubstitutionsForPriorities(); err != nil { + return nil, err + } // Propagate all child pipelines cfg.propagatePipelines() @@ -1004,6 +1035,9 @@ func (cfg Configuration) validate() error { // TODO: try to validate value of .package.version + if err := validateDependenciesPriorities(cfg.Package.Dependencies); err != nil { + return ErrInvalidConfiguration{Problem: errors.New("prioritiy must convert to integer")} + } if err := validatePipelines(cfg.Pipeline); err != nil { return ErrInvalidConfiguration{Problem: err} } @@ -1012,7 +1046,9 @@ func (cfg Configuration) validate() error { if !packageNameRegex.MatchString(sp.Name) { return ErrInvalidConfiguration{Problem: fmt.Errorf("subpackage name %q (subpackages index: %d) must match regex %q", sp.Name, i, packageNameRegex)} } - + if err := validateDependenciesPriorities(sp.Dependencies); err != nil { + return ErrInvalidConfiguration{Problem: errors.New("prioritiy must convert to integer")} + } if err := validatePipelines(sp.Pipeline); err != nil { return ErrInvalidConfiguration{Problem: err} } @@ -1038,6 +1074,20 @@ func validatePipelines(ps []Pipeline) error { return nil } +func validateDependenciesPriorities(deps Dependencies) error { + priorities := []string{deps.ProviderPriority, deps.ProviderPriority} + for _, priority := range priorities { + if priority == "" { + continue + } + _, err := strconv.Atoi(priority) + if err != nil { + return err + } + } + return nil +} + // PackageURLs returns a list of package URLs ("purls") for the given // configuration. The first PURL is always the origin package, and any subsequent // items are the PURLs for the Configuration's subpackages. For more information diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index d0139fb31..3decdec5d 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -140,6 +140,43 @@ subpackages: require.True(t, cfg.Subpackages[0].Options.NoProvides) } +func Test_rangeSubstitutionsPriorities(t *testing.T) { + ctx := slogtest.TestContextWithLogger(t) + + fp := filepath.Join(os.TempDir(), "melange-test-applySubstitutionsInRangePriorities") + if err := os.WriteFile(fp, []byte(` +package: + name: range-substitutions + version: 0.0.1 + epoch: 7 + description: example using a range in subpackages + +data: + - name: I-am-a-range + items: + a: 10 + b: 20 + +subpackages: + - range: I-am-a-range + name: ${{range.key}} + description: Check priorities are ${{range.value}} + dependencies: + provider-priority: ${{range.value}} + replaces-priority: ${{range.value}} + runtime: + - wow-some-kinda-dynamically-linked-library-i-guess=1.0 +`), 0644); err != nil { + t.Fatal(err) + } + cfg, err := ParseConfiguration(ctx, fp) + if err != nil { + t.Fatalf("failed to parse configuration: %s", err) + } + require.Equal(t, cfg.Subpackages[0].Dependencies.ProviderPriority, "10") + require.Equal(t, cfg.Subpackages[0].Dependencies.ReplacesPriority, "10") +} + func Test_propagatePipelines(t *testing.T) { ctx := slogtest.TestContextWithLogger(t) diff --git a/pkg/config/schema.json b/pkg/config/schema.json index 591606372..f6f18ca78 100644 --- a/pkg/config/schema.json +++ b/pkg/config/schema.json @@ -195,8 +195,12 @@ "description": "Optional: List of replace objectives" }, "provider-priority": { - "type": "integer", - "description": "Optional: An integer compared against other equal package provides used to\ndetermine priority" + "type": "string", + "description": "Optional: An integer string compared against other equal package provides used to\ndetermine priority of provides" + }, + "replaces-priority": { + "type": "string", + "description": "Optional: An integer string compared against other equal package provides used to\ndetermine priority of file replacements" } }, "additionalProperties": false,