def compress_subproperties(properties): """ Combine all subproperties into their parent properties Requires: for every subproperty, there is a parent property. All features are explicitly expressed. This rule probably shouldn't be needed, but build-request.expand-no-defaults is being abused for unintended purposes and it needs help """ result = [] matched_subs = set() all_subs = set() for p in properties: f = p.feature() if not f.subfeature(): subs = __select_subproperties(p, properties) if subs: matched_subs.update(subs) subvalues = "-".join(sub.value() for sub in subs) result.append(b2.build.property.Property(p.feature(), p.value() + "-" + subvalues, p.condition())) else: result.append(p) else: all_subs.add(p) # TODO: this variables are used just for debugging. What's the overhead? assert all_subs == matched_subs return result
def expand_composites (properties): """ Expand all composite properties in the set so that all components are explicitly expressed. """ explicit_features = set(p.feature() for p in properties) result = [] # now expand composite features for p in properties: expanded = expand_composite(p) for x in expanded: if not x in result: f = x.feature() if f.free(): result.append (x) elif not x in properties: # x is the result of expansion if not f in explicit_features: # not explicitly-specified if any(r.feature() == f for r in result): raise FeatureConflict( "expansions of composite features result in " "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % (f.name(), [r.value() for r in result if r.feature() == f] + [x.value()], p)) else: result.append (x) elif any(r.feature() == f for r in result): raise FeatureConflict ("explicitly-specified values of non-free feature '%s' conflict\n" "existing values: '%s'\nvalue from expanding '%s': '%s'" % (f, [r.value() for r in result if r.feature() == f], p, x.value())) else: result.append (x) return result
def refine(properties, requirements): """ Refines 'properties' by overriding any non-free properties for which a different value is specified in 'requirements'. Conditional requirements are just added without modification. Returns the resulting list of properties. """ # The result has no duplicates, so we store it in a set result = set() # Records all requirements. required = {} # All the elements of requirements should be present in the result # Record them so that we can handle 'properties'. for r in requirements: # Don't consider conditional requirements. if not r.condition(): required[r.feature()] = r for p in properties: # Skip conditional properties if p.condition(): result.add(p) # No processing for free properties elif p.feature().free(): result.add(p) else: if required.has_key(p.feature()): result.add(required[p.feature()]) else: result.add(p) return sequence.unique(list(result) + requirements)
def find_satisfied_condition(conditions, ps): """Returns the first element of 'property-sets' which is a subset of 'properties', or an empty list if no such element exists.""" features = set(p.feature() for p in ps.all()) for condition in conditions: found_all = True for i in condition.all(): found = False if i.value(): found = i.value() in ps.get(i.feature()) else: # Handle value-less properties like '<architecture>' (compare with # '<architecture>x86'). # If $(i) is a value-less property it should match default # value of an optional property. See the first line in the # example below: # # property set properties result # <a> <b>foo <b>foo match # <a> <b>foo <a>foo <b>foo no match # <a>foo <b>foo <b>foo no match # <a>foo <b>foo <a>foo <b>foo match found = not i.feature() in features found_all = found_all and found if found_all: return condition return None
def minimize (properties): """ Given an expanded property set, eliminate all redundancy: properties which are elements of other (composite) properties in the set will be eliminated. Non-symmetric properties equal to default values will be eliminated, unless the override a value from some composite property. Implicit properties will be expressed without feature grist, and sub-property values will be expressed as elements joined to the corresponding main property. """ if __debug__: from .property import Property assert is_iterable_typed(properties, Property) # remove properties implied by composite features components = [] component_features = set() for property in properties: if property in __composite_properties: cs = __composite_properties[property] components.extend(cs) component_features.update(c.feature for c in cs) properties = b2.util.set.difference (properties, components) # handle subfeatures and implicit features # move subfeatures to the end of the list properties = [p for p in properties if not p.feature.subfeature] +\ [p for p in properties if p.feature.subfeature] result = [] while properties: p = properties[0] f = p.feature # locate all subproperties of $(x[1]) in the property set subproperties = [x for x in properties if is_subfeature_of(p, x.feature)] if subproperties: # reconstitute the joined property name subproperties.sort () joined = b2.build.property.Property(p.feature, p.value + '-' + '-'.join ([sp.value for sp in subproperties])) result.append(joined) properties = b2.util.set.difference(properties[1:], subproperties) else: # eliminate properties whose value is equal to feature's # default and which are not symmetric and which do not # contradict values implied by composite properties. # since all component properties of composites in the set # have been eliminated, any remaining property whose # feature is the same as a component of a composite in the # set must have a non-redundant value. if p.value != f.default or f.symmetric or f in component_features: result.append (p) properties = properties[1:] return result
def compress_subproperties (properties): """ Combine all subproperties into their parent properties Requires: for every subproperty, there is a parent property. All features are explicitly expressed. This rule probably shouldn't be needed, but build-request.expand-no-defaults is being abused for unintended purposes and it needs help """ from .property import Property assert is_iterable_typed(properties, Property) result = [] matched_subs = set() all_subs = set() for p in properties: f = p.feature if not f.subfeature: subs = [x for x in properties if is_subfeature_of(p, x.feature)] if subs: matched_subs.update(subs) subvalues = '-'.join (sub.value for sub in subs) result.append(Property( p.feature, p.value + '-' + subvalues, p.condition)) else: result.append(p) else: all_subs.add(p) # TODO: this variables are used just for debugging. What's the overhead? assert all_subs == matched_subs return result
def compress_subproperties(properties): """ Combine all subproperties into their parent properties Requires: for every subproperty, there is a parent property. All features are explicitly expressed. This rule probably shouldn't be needed, but build-request.expand-no-defaults is being abused for unintended purposes and it needs help """ from .property import Property assert is_iterable_typed(properties, Property) result = [] matched_subs = set() all_subs = set() for p in properties: f = p.feature if not f.subfeature: subs = [x for x in properties if is_subfeature_of(p, x.feature)] if subs: matched_subs.update(subs) subvalues = '-'.join(sub.value for sub in subs) result.append( Property(p.feature, p.value + '-' + subvalues, p.condition)) else: result.append(p) else: all_subs.add(p) # TODO: this variables are used just for debugging. What's the overhead? assert all_subs == matched_subs return result
def compress_subproperties(properties): """ Combine all subproperties into their parent properties Requires: for every subproperty, there is a parent property. All features are explicitly expressed. This rule probably shouldn't be needed, but build-request.expand-no-defaults is being abused for unintended purposes and it needs help """ result = [] matched_subs = set() all_subs = set() for p in properties: f = p.feature() if not f.subfeature(): subs = __select_subproperties(p, properties) if subs: matched_subs.update(subs) subvalues = '-'.join(sub.value() for sub in subs) result.append( b2.build.property.Property(p.feature(), p.value() + '-' + subvalues, p.condition())) else: result.append(p) else: all_subs.add(p) # TODO: this variables are used just for debugging. What's the overhead? assert all_subs == matched_subs return result
def add_defaults(properties): """ Given a set of properties, add default values for features not represented in the set. Note: if there's there's ordinary feature F1 and composite feature F2, which includes some value for F1, and both feature have default values, then the default value of F1 will be added, not the value in F2. This might not be right idea: consider feature variant : debug ... ; <variant>debug : .... <runtime-debugging>on feature <runtime-debugging> : off on ; Here, when adding default for an empty property set, we'll get <variant>debug <runtime_debugging>off and that's kind of strange. """ if __debug__: from .property import Property assert is_iterable_typed(properties, Property) result = [x for x in properties] handled_features = set() for p in properties: # We don't add default for conditional properties. We don't want # <variant>debug:<define>DEBUG to be takes as specified value for <variant> if not p.condition(): handled_features.add(p.feature()) missing_top = [f for f in __all_top_features if not f in handled_features] more = defaults(missing_top) result.extend(more) for p in more: handled_features.add(p.feature()) # Add defaults for subfeatures of features which are present for p in result[:]: s = p.feature().subfeatures() more = defaults([ s for s in p.feature().subfeatures() if not s in handled_features ]) for p in more: handled_features.add(p.feature()) result.extend(more) return result
def add_defaults (properties): """ Given a set of properties, add default values for features not represented in the set. Note: if there's there's ordinary feature F1 and composite feature F2, which includes some value for F1, and both feature have default values, then the default value of F1 will be added, not the value in F2. This might not be right idea: consider feature variant : debug ... ; <variant>debug : .... <runtime-debugging>on feature <runtime-debugging> : off on ; Here, when adding default for an empty property set, we'll get <variant>debug <runtime_debugging>off and that's kind of strange. """ if __debug__: from .property import Property assert is_iterable_typed(properties, Property) result = [x for x in properties] handled_features = set() for p in properties: # We don't add default for conditional properties. We don't want # <variant>debug:<define>DEBUG to be takes as specified value for <variant> if not p.condition(): handled_features.add(p.feature()) missing_top = [f for f in __all_top_features if not f in handled_features] more = defaults(missing_top) result.extend(more) for p in more: handled_features.add(p.feature()) # Add defaults for subfeatures of features which are present for p in result[:]: s = p.feature().subfeatures() more = defaults([s for s in p.feature().subfeatures() if not s in handled_features]) for p in more: handled_features.add(p.feature()) result.extend(more) return result