Headless specs and /hash spec specification

This commit is contained in:
Gregory Becker 2015-09-23 17:37:12 -07:00
parent f9c8c4d216
commit 7989a7f903
4 changed files with 70 additions and 11 deletions

View File

@ -196,6 +196,7 @@ def install(self, prefix):
class when(object):
def __init__(self, spec):
pkg = get_calling_module_name()
# self.spec = spack.spec.Spec(spec)
self.spec = parse_anonymous_spec(spec, pkg)
def __call__(self, method):

View File

@ -153,6 +153,8 @@ def all_packages(self):
@memoized
def exists(self, pkg_name):
"""Whether a package with the supplied name exists ."""
if pkg_name == "any-pkg-name":
return True
return os.path.exists(self.filename_for_package_name(pkg_name))

View File

@ -108,6 +108,7 @@
import spack.error
import spack.compilers as compilers
from spack.cmd.find import display_specs
from spack.version import *
from spack.util.string import *
from spack.util.prefix import Prefix
@ -504,7 +505,7 @@ def virtual(self):
@staticmethod
def is_virtual(name):
"""Test if a name is virtual without requiring a Spec."""
return not spack.db.exists(name)
return name != "any-pkg-name" and not spack.db.exists(name)
@property
@ -820,6 +821,9 @@ def concretize(self):
with requirements of its pacakges. See flatten() and normalize() for
more details on this.
"""
if self.name == "any-pkg-name":
raise SpecError("Attempting to concretize anonymous spec")
if self._concrete:
return
@ -1255,7 +1259,7 @@ def satisfies(self, other, deps=True, strict=False):
return False
# Otherwise, first thing we care about is whether the name matches
if self.name != other.name:
if self.name != other.name and self.name != "any-pkg-name" and other.name != "any-pkg-name":
return False
if self.versions and other.versions:
@ -1271,7 +1275,10 @@ def satisfies(self, other, deps=True, strict=False):
elif strict and (other.compiler and not self.compiler):
return False
if not self.variants.satisfies(other.variants, strict=strict):
var_strict = strict
if self.name == "any-pkg-name" or other.name == "any-pkg-name":
var_strict = True
if not self.variants.satisfies(other.variants, strict=var_strict):
return False
# Architecture satisfaction is currently just string equality.
@ -1284,7 +1291,10 @@ def satisfies(self, other, deps=True, strict=False):
# If we need to descend into dependencies, do it, otherwise we're done.
if deps:
return self.satisfies_dependencies(other, strict=strict)
deps_strict = strict
if self.name == "any-pkg-name" or other.name == "any-pkg-name":
deps_strict=True
return self.satisfies_dependencies(other, strict=deps_strict)
else:
return True
@ -1644,12 +1654,13 @@ def __repr__(self):
#
# These are possible token types in the spec grammar.
#
DEP, AT, COLON, COMMA, ON, OFF, PCT, EQ, ID = range(9)
HASH, DEP, AT, COLON, COMMA, ON, OFF, PCT, EQ, ID = range(10)
class SpecLexer(spack.parse.Lexer):
"""Parses tokens that make up spack specs."""
def __init__(self):
super(SpecLexer, self).__init__([
(r'/', lambda scanner, val: self.token(HASH, val)),
(r'\^', lambda scanner, val: self.token(DEP, val)),
(r'\@', lambda scanner, val: self.token(AT, val)),
(r'\:', lambda scanner, val: self.token(COLON, val)),
@ -1678,15 +1689,33 @@ def do_parse(self):
if self.accept(ID):
specs.append(self.spec())
elif self.accept(HASH):
specs.append(self.spec_by_hash())
elif self.accept(DEP):
if not specs:
specs.append(self.empty_spec())
self.expect(ID)
specs[-1]._add_dependency(self.spec())
for spec in specs:
print spec
if self.accept(HASH):
specs[-1]._add_dependency(self.spec_by_hash())
else:
self.expect(ID)
specs[-1]._add_dependency(self.spec())
elif self.accept(PCT):
specs.append(self.empty_spec())
specs[-1]._set_compiler(self.compiler())
elif self.accept(ON):
specs.append(self.empty_spec())
specs[-1]._add_variant(self.variant(), True)
elif self.accept(OFF):
specs.append(self.empty_spec())
specs[-1]._add_variant(self.variant(), False)
else:
self.unexpected_token()
except spack.parse.ParseError, e:
raise SpecParseError(e)
@ -1698,12 +1727,33 @@ def parse_compiler(self, text):
return self.compiler()
def spec_by_hash(self):
self.expect(ID)
specs = spack.installed_db.query()
matches = [spec for spec in specs if
spec.dag_hash()[:len(self.token.value)] == self.token.value]
if not matches:
tty.die("%s does not match any installed packages." %self.token.value)
if len(matches) != 1:
tty.error("%s matches multiple installed packages:" %self.token.value)
print
display_specs(matches, long=True)
print
print "You can either:"
print " a) Use a more specific hash, or"
print " b) Specify the package by name."
sys.exit(1)
return matches[0]
def empty_spec(self):
"""Create a Null spec from which dependency constraints can be hung"""
spec = Spec.__new__(Spec)
spec.name = "any-pkg-name"
# spec.name = None
spec.versions = VersionList()
spec.versions = VersionList(':')
spec.variants = VariantMap(spec)
spec.architecture = None
spec.compiler = None
@ -1863,6 +1913,8 @@ def parse_anonymous_spec(spec_like, pkg_name):
if isinstance(spec_like, str):
try:
anon_spec = Spec(spec_like)
if anon_spec.name != pkg_name:
raise SpecParseError(spack.parse.ParseError("","","anon spec created without proper name"))
except SpecParseError:
anon_spec = Spec(pkg_name + spec_like)
if anon_spec.name != pkg_name: raise ValueError(

View File

@ -67,6 +67,10 @@ def update(self, spec):
if type(spec) != spack.spec.Spec:
spec = spack.spec.Spec(spec)
if spec.name == "any-pkg-name":
#The "any" name does not have a package
return
assert(not spec.virtual)
pkg = spec.package