Skip to content

Commit

Permalink
Turn required package variable source into a func
Browse files Browse the repository at this point in the history
Signed-off-by: Mikalai Radchuk <mradchuk@redhat.com>
  • Loading branch information
m1kola committed Nov 2, 2023
1 parent 3f60963 commit fb7fc7d
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 196 deletions.
30 changes: 17 additions & 13 deletions internal/resolution/variablesources/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,23 @@ func (o *OperatorVariableSource) GetVariables(ctx context.Context) ([]deppy.Vari
return nil, err
}

// build required package variable sources
for _, operator := range operatorList.Items {
rps, err := NewRequiredPackageVariableSource(
o.catalogClient,
operator.Spec.PackageName,
InVersionRange(operator.Spec.Version),
InChannel(operator.Spec.Channel),
)
if err != nil {
return nil, err
}
variableSources = append(variableSources, rps)
allBundles, err := o.catalogClient.Bundles(ctx)
if err != nil {
return nil, err
}

requiredPackages, err := MakeRequiredPackageVariables(allBundles, operatorList.Items)
if err != nil {
return nil, err
}

return variableSources.GetVariables(ctx)
variables, err := variableSources.GetVariables(ctx)
if err != nil {
return nil, err
}

for _, v := range requiredPackages {
variables = append(variables, v)
}
return variables, nil
}
114 changes: 37 additions & 77 deletions internal/resolution/variablesources/required_package.go
Original file line number Diff line number Diff line change
@@ -1,104 +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 {
catalogClient BundleProvider

packageName string
versionRange string
channelName string
predicates []catalogfilter.Predicate[catalogmetadata.Bundle]
}

func NewRequiredPackageVariableSource(catalogClient BundleProvider, packageName string, options ...RequiredPackageVariableSourceOption) (*RequiredPackageVariableSource, error) {
if packageName == "" {
return nil, fmt.Errorf("package name must not be empty")
}
r := &RequiredPackageVariableSource{
catalogClient: catalogClient,

packageName: packageName,
predicates: []catalogfilter.Predicate[catalogmetadata.Bundle]{catalogfilter.WithPackageName(packageName)},
}
for _, option := range options {
if err := option(r); err != nil {
return nil, err
if versionRange != "" {
vr, err := mmsemver.NewConstraint(versionRange)
if err != nil {
return nil, fmt.Errorf("invalid version range '%s': %w", versionRange, err)
}
predicates = append(predicates, catalogfilter.InMastermindsSemverRange(vr))
}
}
return r, nil
}

func (r *RequiredPackageVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) {
resultSet, err := r.catalogClient.Bundles(ctx)
if 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 '%s' matching version '%s' found in channel '%s'", packageName, versionRange, channelName)
}
if versionRange != "" {
return nil, fmt.Errorf("no package '%s' matching version '%s' found", packageName, versionRange)
}
if channelName != "" {
return nil, fmt.Errorf("no package '%s' found in channel '%s'", packageName, channelName)
}
return nil, fmt.Errorf("no package '%s' found", packageName)
}
sort.SliceStable(resultSet, func(i, j int) bool {
return catalogsort.ByVersion(resultSet[i], resultSet[j])
})

resultSet = catalogfilter.Filter(resultSet, 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
}
Loading

0 comments on commit fb7fc7d

Please sign in to comment.