diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py index 93c10a910fdcdf515fba56ee77b43ca7053a1b5e..e3f1ae3a77339d2a43fb75951790e7766c6879d2 100644 --- a/lib/spack/spack/cmd/find.py +++ b/lib/spack/spack/cmd/find.py @@ -199,7 +199,7 @@ def query_arguments(args): explicit = True if args.implicit: explicit = False - q_args = {'installed': installed, 'known': known, "explicit": explicit} + q_args = {'installed': installed, 'known': known, "explicit": explicit, "reverse_flags": True} return q_args diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index 9fdf3045b28846459eee1bd948a4c1d2fe0d6328..75b7cf8d912c1ae598a875b0507196cd4153c993 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -86,7 +86,7 @@ def concretize_specs(specs, allow_multiple_matches=False, force=False): specs_from_cli = [] # List of specs that match expressions given via command line has_errors = False for spec in specs: - matching = spack.installed_db.query(spec) + matching = spack.installed_db.query(spec, reverse_flags=True) # For each spec provided, make sure it refers to only one package. # Fail and ask user to be unambiguous if it doesn't if not allow_multiple_matches and len(matching) > 1: diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index e768ddf5feb1391147745899da815ee0ad3dd7be..116e1128147ac35f620b62db4d2d9bcab35b98fb 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -512,7 +512,7 @@ def installed_extensions_for(self, extendee_spec): # skips unknown packages # TODO: conditional way to do this instead of catching exceptions - def query(self, query_spec=any, known=any, installed=True, explicit=any): + def query(self, query_spec=any, known=any, installed=True, explicit=any, reverse_flags=False): """Run a query on the database. ``query_spec`` @@ -557,19 +557,19 @@ def query(self, query_spec=any, known=any, installed=True, explicit=any): if known is not any and spack.repo.exists( rec.spec.name) != known: continue - if query_spec is any or rec.spec.satisfies(query_spec): + if query_spec is any or rec.spec.satisfies(query_spec, reverse_flags=reverse_flags): results.append(rec.spec) return sorted(results) - def query_one(self, query_spec, known=any, installed=True): + def query_one(self, query_spec, known=any, installed=True, reverse_flags=False): """Query for exactly one spec that matches the query spec. Raises an assertion error if more than one spec matches the query. Returns None if no installed package matches. """ - concrete_specs = self.query(query_spec, known, installed) + concrete_specs = self.query(query_spec, known, installed, reverse_flags) assert len(concrete_specs) <= 1 return concrete_specs[0] if concrete_specs else None diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 16b61236a96fed76398866984a744cd1eabaa01f..0221ca6452bd2803f5cea776ad4685c8b28c0480 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -373,7 +373,14 @@ def __init__(self, spec): super(FlagMap, self).__init__() self.spec = spec - def satisfies(self, other, strict=False): + def satisfies(self, other, strict=False, reverse=False): + test = other.copy() + for f in _valid_compiler_flags: + if f not in test: + test[f] = [] + return test._satisfies(self, True) if reverse else self._satisfies(other, strict) + + def _satisfies(self, other, strict=False): if strict or (self.spec and self.spec._concrete): return all(f in self and set(self[f]) <= set(other[f]) for f in other) @@ -1468,7 +1475,7 @@ def _autospec(self, spec_like): except SpecError: return parse_anonymous_spec(spec_like, self.name) - def satisfies(self, other, deps=True, strict=False): + def satisfies(self, other, deps=True, strict=False, reverse_flags=False): """Determine if this spec satisfies all constraints of another. There are two senses for satisfies: @@ -1531,7 +1538,9 @@ def satisfies(self, other, deps=True, strict=False): if not self.compiler_flags.satisfies( other.compiler_flags, - strict=strict): + strict=strict, + reverse=reverse_flags): + return False # If we need to descend into dependencies, do it, otherwise we're done. @@ -2028,44 +2037,44 @@ def do_parse(self): specs = [] try: - while self.next: - # TODO: clean this parsing up a bit + while self.next or self.previous: if self.previous: + # The previous spec grabbed the head of this one specs.append(self.spec(self.previous.value)) + self.previous = None + continue + if self.accept(ID): - self.previous = self.token + parameter = self.token.value if self.accept(EQ): - if not specs: - specs.append(self.spec(None)) + # Anonymous spec starting with <parameter>= if self.accept(QT): self.token.value = self.token.value[1:-1] else: self.expect(ID) - specs[-1]._add_flag( - self.previous.value, self.token.value) + value = self.token.value + if not specs: + specs.append(self.spec(None)) + specs[-1]._add_flag(parameter, value) else: - specs.append(self.spec(self.previous.value)) - self.previous = None + # Just a normal spec + specs.append(self.spec(self.token.value)) + elif self.accept(HASH): specs.append(self.spec_by_hash()) elif self.accept(DEP): - if not specs: - self.previous = self.token - specs.append(self.spec(None)) - self.previous = None if self.accept(HASH): - specs[-1]._add_dependency(self.spec_by_hash()) + dep = self.spec_by_hash() else: self.expect(ID) - specs[-1]._add_dependency(self.spec(self.token.value)) + dep = self.spec(self.token.value) + if not specs: + specs.append(self.spec(None)) + specs[-1]._add_dependency(dep) else: - # Attempt to construct an anonymous spec, but check that - # the first token is valid - # TODO: Is this check even necessary, or will it all be Lex - # errors now? - specs.append(self.spec(None, True)) + specs.append(self.spec(None)) except spack.parse.ParseError, e: raise SpecParseError(e) @@ -2094,7 +2103,7 @@ def spec_by_hash(self): return matches[0] - def spec(self, name, check_valid_token=False): + def spec(self, name): """Parse a spec out of the input. If a spec is supplied, then initialize and return it instead of creating a new one.""" if name: @@ -2127,35 +2136,21 @@ def spec(self, name, check_valid_token=False): # unspecified or not. added_version = False - if self.previous and self.previous.value == DEP: - if self.accept(HASH): - spec.add_dependency(self.spec_by_hash()) - else: - self.expect(ID) - if self.accept(EQ): - raise SpecParseError(spack.parse.ParseError( - "", "", "Expected dependency received anonymous spec")) - spec.add_dependency(self.spec(self.token.value)) - while self.next: if self.accept(AT): vlist = self.version_list() for version in vlist: spec._add_version(version) added_version = True - check_valid_token = False elif self.accept(ON): spec._add_variant(self.variant(), True) - check_valid_token = False elif self.accept(OFF): spec._add_variant(self.variant(), False) - check_valid_token = False elif self.accept(PCT): spec._set_compiler(self.compiler()) - check_valid_token = False elif self.accept(ID): self.previous = self.token @@ -2170,9 +2165,7 @@ def spec(self, name, check_valid_token=False): return spec else: - if check_valid_token: - self.unexpected_token() - break + self.unexpected_token() # If there was no version in the spec, consier it an open range if not added_version: