github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/solver/constraints.go (about) 1 package solver 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/go-air/gini/logic" 8 "github.com/go-air/gini/z" 9 ) 10 11 // Constraint implementations limit the circumstances under which a 12 // particular Variable can appear in a solution. 13 type Constraint interface { 14 String(subject Identifier) string 15 apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit 16 order() []Identifier 17 anchor() bool 18 } 19 20 // zeroConstraint is returned by ConstraintOf in error cases. 21 type zeroConstraint struct{} 22 23 var _ Constraint = zeroConstraint{} 24 25 func (zeroConstraint) String(subject Identifier) string { 26 return "" 27 } 28 29 func (zeroConstraint) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit { 30 return z.LitNull 31 } 32 33 func (zeroConstraint) order() []Identifier { 34 return nil 35 } 36 37 func (zeroConstraint) anchor() bool { 38 return false 39 } 40 41 // AppliedConstraint values compose a single Constraint with the 42 // Variable it applies to. 43 type AppliedConstraint struct { 44 Variable Variable 45 Constraint Constraint 46 } 47 48 // String implements fmt.Stringer and returns a human-readable message 49 // representing the receiver. 50 func (a AppliedConstraint) String() string { 51 return a.Constraint.String(a.Variable.Identifier()) 52 } 53 54 type mandatory struct{} 55 56 func (constraint mandatory) String(subject Identifier) string { 57 return fmt.Sprintf("%s is mandatory", subject) 58 } 59 60 func (constraint mandatory) apply(_ *logic.C, lm *litMapping, subject Identifier) z.Lit { 61 return lm.LitOf(subject) 62 } 63 64 func (constraint mandatory) order() []Identifier { 65 return nil 66 } 67 68 func (constraint mandatory) anchor() bool { 69 return true 70 } 71 72 // Mandatory returns a Constraint that will permit only solutions that 73 // contain a particular Variable. 74 func Mandatory() Constraint { 75 return mandatory{} 76 } 77 78 type prohibited struct{} 79 80 func (constraint prohibited) String(subject Identifier) string { 81 return fmt.Sprintf("%s is prohibited", subject) 82 } 83 84 func (constraint prohibited) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit { 85 return lm.LitOf(subject).Not() 86 } 87 88 func (constraint prohibited) order() []Identifier { 89 return nil 90 } 91 92 func (constraint prohibited) anchor() bool { 93 return false 94 } 95 96 // Prohibited returns a Constraint that will reject any solution that 97 // contains a particular Variable. Callers may also decide to omit 98 // an Variable from input to Solve rather than apply such a 99 // Constraint. 100 func Prohibited() Constraint { 101 return prohibited{} 102 } 103 104 type dependency []Identifier 105 106 func (constraint dependency) String(subject Identifier) string { 107 if len(constraint) == 0 { 108 return fmt.Sprintf("%s has a dependency without any candidates to satisfy it", subject) 109 } 110 s := make([]string, len(constraint)) 111 for i, each := range constraint { 112 s[i] = string(each) 113 } 114 return fmt.Sprintf("%s requires at least one of %s", subject, strings.Join(s, ", ")) 115 } 116 117 func (constraint dependency) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit { 118 m := lm.LitOf(subject).Not() 119 for _, each := range constraint { 120 m = c.Or(m, lm.LitOf(each)) 121 } 122 return m 123 } 124 125 func (constraint dependency) order() []Identifier { 126 return constraint 127 } 128 129 func (constraint dependency) anchor() bool { 130 return false 131 } 132 133 // Dependency returns a Constraint that will only permit solutions 134 // containing a given Variable on the condition that at least one 135 // of the Variables identified by the given Identifiers also 136 // appears in the solution. Identifiers appearing earlier in the 137 // argument list have higher preference than those appearing later. 138 func Dependency(ids ...Identifier) Constraint { 139 return dependency(ids) 140 } 141 142 type conflict Identifier 143 144 func (constraint conflict) String(subject Identifier) string { 145 return fmt.Sprintf("%s conflicts with %s", subject, constraint) 146 } 147 148 func (constraint conflict) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit { 149 return c.Or(lm.LitOf(subject).Not(), lm.LitOf(Identifier(constraint)).Not()) 150 } 151 152 func (constraint conflict) order() []Identifier { 153 return nil 154 } 155 156 func (constraint conflict) anchor() bool { 157 return false 158 } 159 160 // Conflict returns a Constraint that will permit solutions containing 161 // either the constrained Variable, the Variable identified by 162 // the given Identifier, or neither, but not both. 163 func Conflict(id Identifier) Constraint { 164 return conflict(id) 165 } 166 167 type leq struct { 168 ids []Identifier 169 n int 170 } 171 172 func (constraint leq) String(subject Identifier) string { 173 s := make([]string, len(constraint.ids)) 174 for i, each := range constraint.ids { 175 s[i] = string(each) 176 } 177 return fmt.Sprintf("%s permits at most %d of %s", subject, constraint.n, strings.Join(s, ", ")) 178 } 179 180 func (constraint leq) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit { 181 ms := make([]z.Lit, len(constraint.ids)) 182 for i, each := range constraint.ids { 183 ms[i] = lm.LitOf(each) 184 } 185 return c.CardSort(ms).Leq(constraint.n) 186 } 187 188 func (constraint leq) order() []Identifier { 189 return nil 190 } 191 192 func (constraint leq) anchor() bool { 193 return false 194 } 195 196 // AtMost returns a Constraint that forbids solutions that contain 197 // more than n of the Variables identified by the given 198 // Identifiers. 199 func AtMost(n int, ids ...Identifier) Constraint { 200 return leq{ 201 ids: ids, 202 n: n, 203 } 204 }