extensions file now in YAML format
This commit is contained in:
parent
2f3b0481de
commit
29e833dfef
@ -173,12 +173,13 @@ def __init__(self, root, **kwargs):
|
||||
self.metadata_dir = kwargs.get('metadata_dir', '.spack')
|
||||
self.hash_len = kwargs.get('hash_len', None)
|
||||
|
||||
self.spec_file_name = 'spec'
|
||||
self.extension_file_name = 'extensions'
|
||||
self.spec_file_name = 'spec.yaml'
|
||||
self.extension_file_name = 'extensions.yaml'
|
||||
|
||||
# Cache of already written/read extension maps.
|
||||
self._extension_maps = {}
|
||||
|
||||
|
||||
@property
|
||||
def hidden_file_paths(self):
|
||||
return (self.metadata_dir)
|
||||
@ -208,14 +209,13 @@ def write_spec(self, spec, path):
|
||||
"""Write a spec out to a file."""
|
||||
_check_concrete(spec)
|
||||
with open(path, 'w') as f:
|
||||
f.write(spec.to_yaml())
|
||||
spec.to_yaml(f)
|
||||
|
||||
|
||||
def read_spec(self, path):
|
||||
"""Read the contents of a file and parse them as a spec"""
|
||||
with open(path) as f:
|
||||
yaml_text = f.read()
|
||||
spec = Spec.from_yaml(yaml_text)
|
||||
spec = Spec.from_yaml(f)
|
||||
|
||||
# Specs read from actual installations are always concrete
|
||||
spec._normal = True
|
||||
@ -262,18 +262,51 @@ def create_install_directory(self, spec):
|
||||
def all_specs(self):
|
||||
if not os.path.isdir(self.root):
|
||||
return []
|
||||
spec_files = glob.glob("%s/*/*/*/.spack/spec" % self.root)
|
||||
|
||||
pattern = join_path(
|
||||
self.root, '*', '*', '*', self.metadata_dir, self.spec_file_name)
|
||||
spec_files = glob.glob(pattern)
|
||||
return [self.read_spec(s) for s in spec_files]
|
||||
|
||||
|
||||
@memoized
|
||||
def specs_by_hash(self):
|
||||
by_hash = {}
|
||||
for spec in self.all_specs():
|
||||
by_hash[spec.dag_hash()] = spec
|
||||
return by_hash
|
||||
|
||||
|
||||
def extension_file_path(self, spec):
|
||||
"""Gets full path to an installed package's extension file"""
|
||||
_check_concrete(spec)
|
||||
return join_path(self.metadata_path(spec), self.extension_file_name)
|
||||
|
||||
|
||||
def _write_extensions(self, spec, extensions):
|
||||
path = self.extension_file_path(spec)
|
||||
|
||||
# Create a temp file in the same directory as the actual file.
|
||||
dirname, basename = os.path.split(path)
|
||||
tmp = tempfile.NamedTemporaryFile(
|
||||
prefix=basename, dir=dirname, delete=False)
|
||||
|
||||
# write tmp file
|
||||
with tmp:
|
||||
yaml.dump({
|
||||
'extensions' : [
|
||||
{ ext.name : {
|
||||
'hash' : ext.dag_hash(),
|
||||
'path' : str(ext.prefix)
|
||||
}} for ext in sorted(extensions.values())]
|
||||
}, tmp, default_flow_style=False)
|
||||
|
||||
# Atomic update by moving tmpfile on top of old one.
|
||||
os.rename(tmp.name, path)
|
||||
|
||||
|
||||
def _extension_map(self, spec):
|
||||
"""Get a dict<name -> spec> for all extensions currnetly
|
||||
"""Get a dict<name -> spec> for all extensions currently
|
||||
installed for this package."""
|
||||
_check_concrete(spec)
|
||||
|
||||
@ -283,16 +316,26 @@ def _extension_map(self, spec):
|
||||
self._extension_maps[spec] = {}
|
||||
|
||||
else:
|
||||
by_hash = self.specs_by_hash()
|
||||
exts = {}
|
||||
with open(path) as ext_file:
|
||||
for line in ext_file:
|
||||
try:
|
||||
spec = Spec(line.strip())
|
||||
exts[spec.name] = spec
|
||||
except spack.error.SpackError, e:
|
||||
# TODO: do something better here -- should be
|
||||
# resilient to corrupt files.
|
||||
raise InvalidExtensionSpecError(str(e))
|
||||
yaml_file = yaml.load(ext_file)
|
||||
for entry in yaml_file['extensions']:
|
||||
name = next(iter(entry))
|
||||
dag_hash = entry[name]['hash']
|
||||
prefix = entry[name]['path']
|
||||
|
||||
if not dag_hash in by_hash:
|
||||
raise InvalidExtensionSpecError(
|
||||
"Spec %s not found in %s." % (dag_hash, prefix))
|
||||
|
||||
ext_spec = by_hash[dag_hash]
|
||||
if not prefix == ext_spec.prefix:
|
||||
raise InvalidExtensionSpecError(
|
||||
"Prefix %s does not match spec with hash %s: %s"
|
||||
% (prefix, dag_hash, ext_spec))
|
||||
|
||||
exts[ext_spec.name] = ext_spec
|
||||
self._extension_maps[spec] = exts
|
||||
|
||||
return self._extension_maps[spec]
|
||||
@ -300,6 +343,7 @@ def _extension_map(self, spec):
|
||||
|
||||
def extension_map(self, spec):
|
||||
"""Defensive copying version of _extension_map() for external API."""
|
||||
_check_concrete(spec)
|
||||
return self._extension_map(spec).copy()
|
||||
|
||||
|
||||
@ -319,23 +363,6 @@ def check_activated(self, spec, ext_spec):
|
||||
raise NoSuchExtensionError(spec, ext_spec)
|
||||
|
||||
|
||||
def _write_extensions(self, spec, extensions):
|
||||
path = self.extension_file_path(spec)
|
||||
|
||||
# Create a temp file in the same directory as the actual file.
|
||||
dirname, basename = os.path.split(path)
|
||||
tmp = tempfile.NamedTemporaryFile(
|
||||
prefix=basename, dir=dirname, delete=False)
|
||||
|
||||
# Write temp file.
|
||||
with tmp:
|
||||
for extension in sorted(extensions.values()):
|
||||
tmp.write("%s\n" % extension)
|
||||
|
||||
# Atomic update by moving tmpfile on top of old one.
|
||||
os.rename(tmp.name, path)
|
||||
|
||||
|
||||
def add_extension(self, spec, ext_spec):
|
||||
_check_concrete(spec)
|
||||
_check_concrete(ext_spec)
|
||||
@ -362,7 +389,6 @@ def remove_extension(self, spec, ext_spec):
|
||||
self._write_extensions(spec, exts)
|
||||
|
||||
|
||||
|
||||
class DirectoryLayoutError(SpackError):
|
||||
"""Superclass for directory layout errors."""
|
||||
def __init__(self, message):
|
||||
|
@ -603,13 +603,14 @@ def to_node_dict(self):
|
||||
return { self.name : d }
|
||||
|
||||
|
||||
def to_yaml(self):
|
||||
def to_yaml(self, stream=None):
|
||||
node_list = []
|
||||
for s in self.traverse(order='pre'):
|
||||
node = s.to_node_dict()
|
||||
node[s.name]['hash'] = s.dag_hash()
|
||||
node_list.append(node)
|
||||
return yaml.dump({ 'spec' : node_list }, default_flow_style=False)
|
||||
return yaml.dump({ 'spec' : node_list },
|
||||
stream=stream, default_flow_style=False)
|
||||
|
||||
|
||||
@staticmethod
|
||||
@ -633,9 +634,12 @@ def from_node_dict(node):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_yaml(string):
|
||||
def from_yaml(stream):
|
||||
"""Construct a spec from YAML.
|
||||
|
||||
Parameters:
|
||||
stream -- string or file object to read from.
|
||||
|
||||
TODO: currently discards hashes. Include hashes when they
|
||||
represent more than the DAG does.
|
||||
|
||||
@ -644,7 +648,7 @@ def from_yaml(string):
|
||||
spec = None
|
||||
|
||||
try:
|
||||
yfile = yaml.load(string)
|
||||
yfile = yaml.load(stream)
|
||||
except MarkedYAMLError, e:
|
||||
raise SpackYAMLError("error parsing YMAL spec:", str(e))
|
||||
|
||||
|
@ -152,7 +152,8 @@ def test_handle_unknown_package(self):
|
||||
# Now check that even without the package files, we know
|
||||
# enough to read a spec from the spec file.
|
||||
for spec, path in installed_specs.items():
|
||||
spec_from_file = self.layout.read_spec(join_path(path, '.spack', 'spec'))
|
||||
spec_from_file = self.layout.read_spec(
|
||||
join_path(path, '.spack', 'spec.yaml'))
|
||||
|
||||
# To satisfy these conditions, directory layouts need to
|
||||
# read in concrete specs from their install dirs somehow.
|
||||
|
Loading…
Reference in New Issue
Block a user