-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🌱 Part 4: Reduce number of variable sources. Required packages #500
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,64 @@ | ||
package variablesources | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sort" | ||
|
||
mmsemver "github.com/Masterminds/semver/v3" | ||
"github.com/operator-framework/deppy/pkg/deppy" | ||
"github.com/operator-framework/deppy/pkg/deppy/input" | ||
|
||
operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" | ||
"github.com/operator-framework/operator-controller/internal/catalogmetadata" | ||
catalogfilter "github.com/operator-framework/operator-controller/internal/catalogmetadata/filter" | ||
catalogsort "github.com/operator-framework/operator-controller/internal/catalogmetadata/sort" | ||
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables" | ||
) | ||
|
||
var _ input.VariableSource = &RequiredPackageVariableSource{} | ||
// MakeRequiredPackageVariables returns a variable which represent | ||
// explicit requirement for a package from an user. | ||
// This is when an user explicitly asks "install this" via Operator API. | ||
func MakeRequiredPackageVariables(allBundles []*catalogmetadata.Bundle, operators []operatorsv1alpha1.Operator) ([]*olmvariables.RequiredPackageVariable, error) { | ||
result := make([]*olmvariables.RequiredPackageVariable, 0, len(operators)) | ||
|
||
type RequiredPackageVariableSourceOption func(*RequiredPackageVariableSource) error | ||
for _, operator := range operators { | ||
packageName := operator.Spec.PackageName | ||
channelName := operator.Spec.Channel | ||
versionRange := operator.Spec.Version | ||
|
||
func InVersionRange(versionRange string) RequiredPackageVariableSourceOption { | ||
return func(r *RequiredPackageVariableSource) error { | ||
if versionRange != "" { | ||
vr, err := mmsemver.NewConstraint(versionRange) | ||
if err == nil { | ||
r.versionRange = versionRange | ||
r.predicates = append(r.predicates, catalogfilter.InMastermindsSemverRange(vr)) | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("invalid version range '%s': %w", versionRange, err) | ||
predicates := []catalogfilter.Predicate[catalogmetadata.Bundle]{ | ||
catalogfilter.WithPackageName(packageName), | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
func InChannel(channelName string) RequiredPackageVariableSourceOption { | ||
return func(r *RequiredPackageVariableSource) error { | ||
if channelName != "" { | ||
r.channelName = channelName | ||
r.predicates = append(r.predicates, catalogfilter.InChannel(channelName)) | ||
predicates = append(predicates, catalogfilter.InChannel(channelName)) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
type RequiredPackageVariableSource struct { | ||
allBundles []*catalogmetadata.Bundle | ||
|
||
packageName string | ||
versionRange string | ||
channelName string | ||
predicates []catalogfilter.Predicate[catalogmetadata.Bundle] | ||
} | ||
|
||
func NewRequiredPackageVariableSource(allBundles []*catalogmetadata.Bundle, packageName string, options ...RequiredPackageVariableSourceOption) (*RequiredPackageVariableSource, error) { | ||
if packageName == "" { | ||
return nil, fmt.Errorf("package name must not be empty") | ||
} | ||
r := &RequiredPackageVariableSource{ | ||
allBundles: allBundles, | ||
if versionRange != "" { | ||
vr, err := mmsemver.NewConstraint(versionRange) | ||
if err != nil { | ||
return nil, fmt.Errorf("invalid version range %q: %w", versionRange, err) | ||
} | ||
predicates = append(predicates, catalogfilter.InMastermindsSemverRange(vr)) | ||
} | ||
|
||
packageName: packageName, | ||
predicates: []catalogfilter.Predicate[catalogmetadata.Bundle]{catalogfilter.WithPackageName(packageName)}, | ||
} | ||
for _, option := range options { | ||
if err := option(r); err != nil { | ||
return nil, err | ||
resultSet := catalogfilter.Filter(allBundles, catalogfilter.And(predicates...)) | ||
if len(resultSet) == 0 { | ||
if versionRange != "" && channelName != "" { | ||
return nil, fmt.Errorf("no package %q matching version %q found in channel %q", packageName, versionRange, channelName) | ||
} | ||
if versionRange != "" { | ||
return nil, fmt.Errorf("no package %q matching version %q found", packageName, versionRange) | ||
} | ||
if channelName != "" { | ||
return nil, fmt.Errorf("no package %q found in channel %q", packageName, channelName) | ||
} | ||
Comment on lines
+45
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about building up the error message as we're building the predicates (since we're already making the necessary conditional checks as we go)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'm not in favour of this approach because:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the emphasis on readability here. |
||
return nil, fmt.Errorf("no package %q found", packageName) | ||
} | ||
} | ||
return r, nil | ||
} | ||
sort.SliceStable(resultSet, func(i, j int) bool { | ||
return catalogsort.ByVersion(resultSet[i], resultSet[j]) | ||
}) | ||
|
||
func (r *RequiredPackageVariableSource) GetVariables(_ context.Context) ([]deppy.Variable, error) { | ||
resultSet := catalogfilter.Filter(r.allBundles, catalogfilter.And(r.predicates...)) | ||
if len(resultSet) == 0 { | ||
return nil, r.notFoundError() | ||
result = append(result, olmvariables.NewRequiredPackageVariable(packageName, resultSet)) | ||
} | ||
sort.SliceStable(resultSet, func(i, j int) bool { | ||
return catalogsort.ByVersion(resultSet[i], resultSet[j]) | ||
}) | ||
return []deppy.Variable{ | ||
olmvariables.NewRequiredPackageVariable(r.packageName, resultSet), | ||
}, nil | ||
} | ||
|
||
func (r *RequiredPackageVariableSource) notFoundError() error { | ||
if r.versionRange != "" && r.channelName != "" { | ||
return fmt.Errorf("no package '%s' matching version '%s' found in channel '%s'", r.packageName, r.versionRange, r.channelName) | ||
} | ||
if r.versionRange != "" { | ||
return fmt.Errorf("no package '%s' matching version '%s' found", r.packageName, r.versionRange) | ||
} | ||
if r.channelName != "" { | ||
return fmt.Errorf("no package '%s' found in channel '%s'", r.packageName, r.channelName) | ||
} | ||
return fmt.Errorf("no package '%s' found", r.packageName) | ||
return result, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I had similar comments on previous parts of this refactoring & most of our errors use double quotation marks I updated the format here.
I'm happy to revert this and move into a separate PR if this is too distracting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on keeping this