Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
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)
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
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
Esempio n. 10
0
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
Esempio n. 11
0
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
Esempio n. 12
0
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
Esempio n. 13
0
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
Esempio n. 14
0
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