func Apply()

in pkg/bundle/patch/package.go [85:196]


func Apply(spec *bundlev1.Patch, b *bundlev1.Bundle, values map[string]interface{}, o ...OptionFunc) (*bundlev1.Bundle, error) {
	// Validate spec
	if err := Validate(spec); err != nil {
		return nil, fmt.Errorf("unable to validate spec: %w", err)
	}
	if b == nil {
		return nil, fmt.Errorf("cannot process nil bundle")
	}

	// Prepare selectors
	if len(spec.Spec.Rules) == 0 {
		return nil, fmt.Errorf("empty bundle patch")
	}

	// Copy bundle
	bCopy, ok := proto.Clone(b).(*bundlev1.Bundle)
	if !ok {
		return nil, fmt.Errorf("the cloned bundle does not have the expected type: %T", bCopy)
	}
	if bCopy.Packages == nil {
		bCopy.Packages = []*bundlev1.Package{}
	}

	// Default evaluation options
	dopts := &options{
		stopAtRuleID:      "",
		stopAtRuleIndex:   -1,
		ignoreRuleIDs:     []string{},
		ignoreRuleIndexes: []int{},
	}

	// Apply functions
	for _, opt := range o {
		opt(dopts)
	}

	// Process all creation rule first
	for i, r := range spec.Spec.Rules {
		// Ignore nil rule
		if r == nil {
			continue
		}

		// Ignore non creation rules and non strict matcher
		if !r.Package.Create || r.Selector.MatchPath.Strict == "" {
			continue
		}
		if shouldIgnoreThisRule(i, r.Id, dopts) {
			continue
		}
		if shouldStopAtThisRule(i, r.Id, dopts) {
			break
		}

		// Create a package
		p := &bundlev1.Package{
			Name: r.Selector.MatchPath.Strict,
		}

		_, err := executeRule(r, p, values)
		if err != nil {
			return nil, fmt.Errorf("unable to execute rule index %d: %w", i, err)
		}

		// Add created package
		bCopy.Packages = append(bCopy.Packages, p)
	}

	for ri, r := range spec.Spec.Rules {
		// Ignore nil rule
		if r == nil {
			continue
		}
		if shouldIgnoreThisRule(ri, r.Id, dopts) {
			continue
		}
		if shouldStopAtThisRule(ri, r.Id, dopts) {
			break
		}

		// Process all packages
		for i, p := range bCopy.Packages {
			action, err := executeRule(r, p, values)
			if err != nil {
				return nil, fmt.Errorf("unable to execute rule index %d: %w", ri, err)
			}

			switch action {
			case packagedRemoved:
				bCopy.Packages = append(bCopy.Packages[:i], bCopy.Packages[i+1:]...)
			case packageUpdated:
				if WithAnnotations(spec) {
					// Add annotations to mark package as patched.
					bundle.Annotate(p, "patched", "true")
					bundle.Annotate(p, spec.Meta.Name, "true")
				}
				bCopy.Packages[i] = p
			case packageUnchanged:
				// No changes
			default:
			}
		}
	}

	// Sort packages
	sort.SliceStable(bCopy.Packages, func(i, j int) bool {
		return bCopy.Packages[i].Name < bCopy.Packages[j].Name
	})

	// No error
	return bCopy, nil
}