Fixed errors caught by spec and concretize tests

This commit is contained in:
Gregory Becker 2016-05-23 16:54:41 -07:00
parent 19c8a52fe1
commit d7612e7aaa
7 changed files with 160 additions and 48 deletions

View file

@ -105,12 +105,25 @@ def __init__(self, name):
self.operating_sys = {} self.operating_sys = {}
self.name = name self.name = name
def to_dict(self):
n = {}
n['targets'] = dict((name, target.to_dict()) for (name, target) in self.targets.items())
n['operating_systems'] = dict((name, os.to_dict()) for (name, os) in self.operating_sys.items())
n['priority'] = self.priority
n['default_front_end_target'] = self.front_end
n['default_back_end_target'] = self.back_end
n['default_target'] = self.default
n['default_front_end_os'] = self.front_os
n['default_back_end_os'] = self.back_os
n['default_os'] = self.default_os
return {self.name: n}
def add_target(self, name, target): def add_target(self, name, target):
"""Used by the platform specific subclass to list available targets. """Used by the platform specific subclass to list available targets.
Raises an error if the platform specifies a name Raises an error if the platform specifies a name
that is reserved by spack as an alias. that is reserved by spack as an alias.
""" """
if name in ['front_end', 'fe', 'back_end', 'be', 'default']: if name in ['frontend', 'fe', 'backend', 'be', 'default_target']:
raise ValueError( raise ValueError(
"%s is a spack reserved alias " "%s is a spack reserved alias "
"and cannot be the name of a target" % name) "and cannot be the name of a target" % name)
@ -135,6 +148,10 @@ def add_operating_system(self, name, os_class):
""" Add the operating_system class object into the """ Add the operating_system class object into the
platform.operating_sys dictionary platform.operating_sys dictionary
""" """
if name in ['frontend', 'fe', 'backend', 'be', 'default_os']:
raise ValueError(
"%s is a spack reserved alias "
"and cannot be the name of an OS" % name)
self.operating_sys[name] = os_class self.operating_sys[name] = os_class
def operating_system(self, name): def operating_system(self, name):
@ -284,15 +301,18 @@ def to_dict(self):
class Arch(object): class Arch(object):
"Architecture is now a class to help with setting attributes" "Architecture is now a class to help with setting attributes"
def __init__(self, platform_os=None, target=None): def __init__(self, platform=None, platform_os=None, target=None):
self.platform = sys_type() self.platform = platform
if platform_os: if platform and platform_os:
platform_os = self.platform.operating_system(platform_os) platform_os = self.platform.operating_system(platform_os)
self.platform_os = platform_os self.platform_os = platform_os
if target: if platform and target:
target = self.platform.target(target) target = self.platform.target(target)
self.target = target self.target = target
# Hooks for parser to use when platform is set after target or os
self.target_string = None
self.os_string = None
@property @property
def concrete(self): def concrete(self):
@ -302,6 +322,7 @@ def concrete(self):
def __str__(self): def __str__(self):
if self.platform or self.platform_os or self.target:
if self.platform.name == 'darwin': if self.platform.name == 'darwin':
os_name = self.platform_os.name os_name = self.platform_os.name
else: else:
@ -309,9 +330,11 @@ def __str__(self):
return (str(self.platform) +"-"+ return (str(self.platform) +"-"+
os_name + "-" + str(self.target)) os_name + "-" + str(self.target))
else:
return ''
def _cmp_key(self): def _cmp_key(self):
platform = self.platform.name platform = self.platform.name if isinstance(self.platform, Platform) else self.platform
os = self.platform_os.name if isinstance(self.platform_os, OperatingSystem) else self.platform_os os = self.platform_os.name if isinstance(self.platform_os, OperatingSystem) else self.platform_os
target = self.target.name if isinstance(self.target, Target) else self.target target = self.target.name if isinstance(self.target, Target) else self.target
return (platform, os, target) return (platform, os, target)
@ -322,7 +345,7 @@ def to_dict(self):
platform_os = self.platform_os platform_os = self.platform_os
target = self.target target = self.target
d['platform'] = self.platform.name d['platform'] = self.platform.to_dict() if self.platform else None
d['platform_os'] = self.platform_os.to_dict() if self.platform_os else None d['platform_os'] = self.platform_os.to_dict() if self.platform_os else None
d['target'] = self.target.to_dict() if self.target else None d['target'] = self.target.to_dict() if self.target else None
@ -350,6 +373,27 @@ def _operating_system_from_dict(os_dict):
operating_system.version = os_dict['version'] operating_system.version = os_dict['version']
return operating_system return operating_system
def _platform_from_dict(platform_dict):
""" Constructs a platform from a dictionary. """
platform = Platform.__new__(Platform)
name, p_dict = platform_dict.items()[0]
platform.name = name
platform.targets = {}
for name, t_dict in p_dict['targets'].items():
platform.add_target(name, _target_from_dict(t_dict))
platform.operating_sys = {}
for name, o_dict in p_dict['operating_systems'].items():
platform.add_operating_system(name, _operating_system_from_dict(o_dict))
platform.priority = p_dict['priority']
platform.front_end = p_dict['default_front_end_target']
platform.back_end = p_dict['default_back_end_target']
platform.default = p_dict['default_target']
platform.front_os = p_dict['default_front_end_os']
platform.back_os = p_dict['default_back_end_os']
platform.default_os = p_dict['default_os']
return platform
def arch_from_dict(d): def arch_from_dict(d):
""" Uses _platform_from_dict, _operating_system_from_dict, _target_from_dict """ Uses _platform_from_dict, _operating_system_from_dict, _target_from_dict
helper methods to recreate the arch tuple from the dictionary read from helper methods to recreate the arch tuple from the dictionary read from
@ -359,14 +403,20 @@ def arch_from_dict(d):
if d is None: if d is None:
return None return None
platform_dict = d['platform']
os_dict = d['platform_os'] os_dict = d['platform_os']
target_dict = d['target'] target_dict = d['target']
platform = _platform_from_dict(platform_dict) if platform_dict else None
target = _target_from_dict(target_dict) if os_dict else None target = _target_from_dict(target_dict) if os_dict else None
platform_os = _operating_system_from_dict(os_dict) if os_dict else None platform_os = _operating_system_from_dict(os_dict) if os_dict else None
arch.platform = platform
arch.target = target arch.target = target
arch.platform_os = platform_os arch.platform_os = platform_os
arch.os_string = None
arch.target_string = None
return arch return arch
@memoized @memoized

View file

@ -210,8 +210,20 @@ def _concretize_target(self, spec):
spec.architecture.target = spec.root.architecture.target spec.architecture.target = spec.root.architecture.target
else: else:
spec.architecture.target = spec.architecture.platform.target('default_target') spec.architecture.target = spec.architecture.platform.target('default_target')
print spec.architecture, spec.architecture.platform, spec.architecture.platform_os, spec.architecture.target
return True #changed return True #changed
def _concretize_platform(self, spec):
if spec.architecture.platform is not None and isinstance(
spec.architecture.platform, spack.architecture.Platform):
return False
if spec.root.architecture and spec.root.architecture.platform:
if isinstance(spec.root.architecture.platform,spack.architecture.Platform):
spec.architecture.platform = spec.root.architecture.platform
else:
spec.architecture.platform = spack.architecture.sys_type()
return True #changed?
def concretize_architecture(self, spec): def concretize_architecture(self, spec):
"""If the spec is empty provide the defaults of the platform. If the """If the spec is empty provide the defaults of the platform. If the
architecture is not a basestring, then check if either the platform, architecture is not a basestring, then check if either the platform,
@ -229,7 +241,8 @@ def concretize_architecture(self, spec):
return True return True
# Concretize the operating_system and target based of the spec # Concretize the operating_system and target based of the spec
ret = any((self._concretize_operating_system(spec), ret = any((self._concretize_platform(spec),
self._concretize_operating_system(spec),
self._concretize_target(spec))) self._concretize_target(spec)))
return ret return ret

View file

@ -99,6 +99,7 @@
import itertools import itertools
import hashlib import hashlib
import base64 import base64
import imp
from StringIO import StringIO from StringIO import StringIO
from operator import attrgetter from operator import attrgetter
import yaml import yaml
@ -107,6 +108,7 @@
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.lang import * from llnl.util.lang import *
from llnl.util.tty.color import * from llnl.util.tty.color import *
from llnl.util.filesystem import join_path
import spack import spack
import spack.architecture import spack.architecture
@ -119,6 +121,7 @@
from spack.version import * from spack.version import *
from spack.util.string import * from spack.util.string import *
from spack.util.prefix import Prefix from spack.util.prefix import Prefix
from spack.util.naming import mod_to_class
from spack.virtual import ProviderIndex from spack.virtual import ProviderIndex
from spack.build_environment import get_path_from_module, load_module from spack.build_environment import get_path_from_module, load_module
@ -535,10 +538,24 @@ def _add_flag(self, name, value):
Known flags currently include "arch" Known flags currently include "arch"
""" """
valid_flags = FlagMap.valid_compiler_flags() valid_flags = FlagMap.valid_compiler_flags()
if name == 'os' or name == 'operating_system': # if name == 'arch' or name == 'architecture':
# platform, op_sys, target = value.split('-')
# print platform, op_sys, target, '+++++++'
# self._set_platform(platform)
# self._set_os(op_sys)
# self._set_target(target)
if name == 'platform':
self._set_platform(value)
elif name == 'os' or name == 'operating_system':
if self.architecture.platform:
self._set_os(value) self._set_os(value)
else:
self.architecture.os_string = value
elif name == 'target': elif name == 'target':
if self.architecture.platform:
self._set_target(value) self._set_target(value)
else:
self.architecture.target_string = value
elif name in valid_flags: elif name in valid_flags:
assert(self.compiler_flags is not None) assert(self.compiler_flags is not None)
self.compiler_flags[name] = value.split() self.compiler_flags[name] = value.split()
@ -551,6 +568,39 @@ def _set_compiler(self, compiler):
"Spec for '%s' cannot have two compilers." % self.name) "Spec for '%s' cannot have two compilers." % self.name)
self.compiler = compiler self.compiler = compiler
def _set_platform(self, value):
"""Called by the parser to set the architecture platform"""
if isinstance(value, basestring):
mod_path = spack.platform_path
mod_string = 'spack.platformss'
names = list_modules(mod_path)
if value in names:
# Create a platform object from the name
mod_name = mod_string + value
path = join_path(mod_path, value) + '.py'
mod = imp.load_source(mod_name, path)
class_name = mod_to_class(value)
if not hasattr(mod, class_name):
tty.die('No class %s defined in %s' % (class_name, mod_name))
cls = getattr(mod, class_name)
if not inspect.isclass(cls):
tty.die('%s.%s is not a class' % (mod_name, class_name))
platform = cls()
else:
tty.die("No platform class %s defined." % value)
else:
# The value is a platform
platform = value
self.architecture.platform = platform
# Set os and target if we previously got strings for them
if self.architecture.os_string:
self._set_os(self.architecture.os_string)
self.architecture.os_string = None
if self.architecture.target_string:
self._set_target(self.architecture.target_string)
self.architecture.target_string = None
def _set_os(self, value): def _set_os(self, value):
"""Called by the parser to set the architecture operating system""" """Called by the parser to set the architecture operating system"""
@ -1016,6 +1066,7 @@ def _expand_virtual_packages(self):
changed = True changed = True
spec.dependencies = DependencyMap() spec.dependencies = DependencyMap()
replacement.dependencies = DependencyMap() replacement.dependencies = DependencyMap()
replacement.architecture = self.architecture
# TODO: could this and the stuff in _dup be cleaned up? # TODO: could this and the stuff in _dup be cleaned up?
def feq(cfield, sfield): def feq(cfield, sfield):
@ -1426,7 +1477,6 @@ def constrain(self, other, deps=True):
other.variants[v]) other.variants[v])
# TODO: Check out the logic here # TODO: Check out the logic here
print self.architecture, other.architecture, "^^^^^^^^^^^^^^^^^^^^^^^"
if self.architecture is not None and other.architecture is not None: if self.architecture is not None and other.architecture is not None:
if self.architecture.platform is not None and other.architecture.platform is not None: if self.architecture.platform is not None and other.architecture.platform is not None:
if self.architecture.platform != other.architecture.platform: if self.architecture.platform != other.architecture.platform:
@ -1831,8 +1881,7 @@ def _cmp_node(self):
self.variants, self.variants,
self.architecture, self.architecture,
self.compiler, self.compiler,
self.compiler_flags, self.compiler_flags)
self.dag_hash())
def eq_node(self, other): def eq_node(self, other):
@ -1946,7 +1995,7 @@ def write(s, c):
if self.variants: if self.variants:
write(fmt % str(self.variants), c) write(fmt % str(self.variants), c)
elif c == '=': elif c == '=':
if self.architecture: if self.architecture and str(self.architecture):
write(fmt % (' arch' + c + str(self.architecture)), c) write(fmt % (' arch' + c + str(self.architecture)), c)
elif c == '#': elif c == '#':
out.write('-' + fmt % (self.dag_hash(7))) out.write('-' + fmt % (self.dag_hash(7)))
@ -2004,7 +2053,7 @@ def write(s, c):
if self.variants: if self.variants:
write(fmt % str(self.variants), '+') write(fmt % str(self.variants), '+')
elif named_str == 'ARCHITECTURE': elif named_str == 'ARCHITECTURE':
if self.architecture: if self.architecture and str(self.architecture):
write(fmt % str(self.architecture), ' arch=') write(fmt % str(self.architecture), ' arch=')
elif named_str == 'SHA1': elif named_str == 'SHA1':
if self.dependencies: if self.dependencies:
@ -2054,13 +2103,13 @@ def __cmp__(self, other):
self.variants, other.variants) self.variants, other.variants)
#Target #Target
if self.target != other.target: if self.architecture != other.architecture:
return spack.pkgsort.target_compare(pkgname, return spack.pkgsort.architecture_compare(pkgname,
self.target, other.target) self.architecture, other.architecture)
#Dependency is not configurable #Dependency is not configurable
if self.dep_hash() != other.dep_hash(): if self.dependencies != other.dependencies:
return -1 if self.dep_hash() < other.dep_hash() else 1 return -1 if self.dependencies < other.dependencies else 1
#Equal specs #Equal specs
return 0 return 0
@ -2181,6 +2230,11 @@ def do_parse(self):
raise SpecParseError(e) raise SpecParseError(e)
# If the spec has an os or a target and no platform, give it the default platform
for spec in specs:
for s in spec.traverse():
if s.architecture.os_string or s.architecture.target_string:
s._set_platform(spack.architecture.sys_type())
return specs return specs
@ -2401,7 +2455,6 @@ class SpecError(spack.error.SpackError):
def __init__(self, message): def __init__(self, message):
super(SpecError, self).__init__(message) super(SpecError, self).__init__(message)
class SpecParseError(SpecError): class SpecParseError(SpecError):
"""Wrapper for ParseError for when we're parsing specs.""" """Wrapper for ParseError for when we're parsing specs."""
def __init__(self, parse_error): def __init__(self, parse_error):

View file

@ -26,12 +26,14 @@ def tearDown(self):
def test_dict_functions_for_architecture(self): def test_dict_functions_for_architecture(self):
arch = Arch() arch = Arch()
arch.platform = spack.architecture.sys_type()
arch.platform_os = arch.platform.operating_system('default_os') arch.platform_os = arch.platform.operating_system('default_os')
arch.target = arch.platform.target('default_target') arch.target = arch.platform.target('default_target')
d = arch.to_dict() d = arch.to_dict()
new_arch = spack.architecture.arch_from_dict(d) new_arch = spack.architecture.arch_from_dict(d)
self.assertEqual(arch, new_arch) self.assertEqual(arch, new_arch)
self.assertTrue( isinstance(arch, Arch) ) self.assertTrue( isinstance(arch, Arch) )

View file

@ -55,8 +55,8 @@ def check_spec(self, abstract, concrete):
if abstract.compiler and abstract.compiler.concrete: if abstract.compiler and abstract.compiler.concrete:
self.assertEqual(abstract.compiler, concrete.compiler) self.assertEqual(abstract.compiler, concrete.compiler)
if abstract.architecture and abstract.architecture.target.concrete: if abstract.architecture and abstract.architecture.concrete:
self.assertEqual(abstract.target, concrete.target) self.assertEqual(abstract.architecture, concrete.architecture)
def check_concretize(self, abstract_spec): def check_concretize(self, abstract_spec):

View file

@ -383,14 +383,14 @@ def test_constrain_compiler(self):
def test_invalid_constraint(self): def test_invalid_constraint(self):
# self.check_invalid_constraint('libelf@0:2.0', 'libelf@2.1:3') self.check_invalid_constraint('libelf@0:2.0', 'libelf@2.1:3')
# self.check_invalid_constraint('libelf@0:2.5%gcc@4.8:4.9', 'libelf@2.1:3%gcc@4.5:4.7') self.check_invalid_constraint('libelf@0:2.5%gcc@4.8:4.9', 'libelf@2.1:3%gcc@4.5:4.7')
# self.check_invalid_constraint('libelf+debug', 'libelf~debug') self.check_invalid_constraint('libelf+debug', 'libelf~debug')
# self.check_invalid_constraint('libelf+debug~foo', 'libelf+debug+foo') self.check_invalid_constraint('libelf+debug~foo', 'libelf+debug+foo')
# self.check_invalid_constraint('libelf debug=2', 'libelf debug=1') self.check_invalid_constraint('libelf debug=2', 'libelf debug=1')
# self.check_invalid_constraint('libelf cppflags="-O3"', 'libelf cppflags="-O2"') self.check_invalid_constraint('libelf cppflags="-O3"', 'libelf cppflags="-O2"')
platform = spack.architecture.sys_type() platform = spack.architecture.sys_type()
if len(platform.operating_sys.keys()) > 1 or len(platform.targets.keys()) > 1: if len(platform.operating_sys.keys()) > 1 or len(platform.targets.keys()) > 1:
os1 = platform.operating_sys.keys()[0] os1 = platform.operating_sys.keys()[0]
@ -439,9 +439,9 @@ def test_constrain_dependency_changed(self):
self.check_constrain_changed('libelf^foo%gcc', 'libelf^foo%gcc@4.5') self.check_constrain_changed('libelf^foo%gcc', 'libelf^foo%gcc@4.5')
self.check_constrain_changed('libelf^foo', 'libelf^foo+debug') self.check_constrain_changed('libelf^foo', 'libelf^foo+debug')
self.check_constrain_changed('libelf^foo', 'libelf^foo~debug') self.check_constrain_changed('libelf^foo', 'libelf^foo~debug')
platform = spack.architecture.sys_type() platform = spack.architecture.sys_type()
default_target = platform.target('default_target').name default_target = platform.target('default_target').name
print default_target
self.check_constrain_changed('libelf^foo', 'libelf^foo target='+default_target) self.check_constrain_changed('libelf^foo', 'libelf^foo target='+default_target)

View file

@ -71,12 +71,6 @@ def check_parse(self, expected, spec=None, remove_arch=True):
spec = expected spec = expected
output = spack.spec.parse(spec) output = spack.spec.parse(spec)
# Remove architectures that get added by parser.
if remove_arch:
for spec in output:
for s in spec.traverse():
s.architecture = None
parsed = (" ".join(str(spec) for spec in output)) parsed = (" ".join(str(spec) for spec in output))
self.assertEqual(expected, parsed) self.assertEqual(expected, parsed)