summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpsakievich <psakiev@sandia.gov>2021-08-16 20:21:57 -0600
committerGitHub <noreply@github.com>2021-08-16 19:21:57 -0700
commita81ec88c6cfc009346232fbb26b807bb47c64430 (patch)
tree20fcc3f3ab876a889cbf57ead96e7afad11f9a48
parent657a5c85cc45ce8c9ccd33de80aebd652aea742c (diff)
downloadspack-a81ec88c6cfc009346232fbb26b807bb47c64430.tar.gz
spack-a81ec88c6cfc009346232fbb26b807bb47c64430.tar.bz2
spack-a81ec88c6cfc009346232fbb26b807bb47c64430.tar.xz
spack-a81ec88c6cfc009346232fbb26b807bb47c64430.zip
Allow environment views to be sym/hard link and copy types (#24832)
Add link type to spack.yaml format Add tests to verify link behavior is correct for installed files for all three view types Co-authored-by: vsoch <vsoch@users.noreply.github.com>
-rw-r--r--lib/spack/spack/cmd/view.py15
-rw-r--r--lib/spack/spack/environment.py20
-rw-r--r--lib/spack/spack/filesystem_view.py23
-rw-r--r--lib/spack/spack/schema/env.py3
-rw-r--r--lib/spack/spack/test/cmd/env.py29
5 files changed, 74 insertions, 16 deletions
diff --git a/lib/spack/spack/cmd/view.py b/lib/spack/spack/cmd/view.py
index 7c745a4da0..f795c17a1c 100644
--- a/lib/spack/spack/cmd/view.py
+++ b/lib/spack/spack/cmd/view.py
@@ -42,12 +42,7 @@ import spack.environment as ev
import spack.schema.projections
import spack.store
from spack.config import validate
-from spack.filesystem_view import (
- YamlFilesystemView,
- view_copy,
- view_hardlink,
- view_symlink,
-)
+from spack.filesystem_view import YamlFilesystemView, view_func_parser
from spack.util import spack_yaml as s_yaml
description = "project packages to a compact naming scheme on the filesystem."
@@ -187,12 +182,10 @@ def view(parser, args):
ordered_projections = {}
# What method are we using for this view
- if args.action in ("hardlink", "hard"):
- link_fn = view_hardlink
- elif args.action in ("copy", "relocate"):
- link_fn = view_copy
+ if args.action in actions_link:
+ link_fn = view_func_parser(args.action)
else:
- link_fn = view_symlink
+ link_fn = view_func_parser('symlink')
view = YamlFilesystemView(
path, spack.store.layout,
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index cc5a066abb..6fa7f62553 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -34,7 +34,11 @@ import spack.util.lock as lk
import spack.util.path
import spack.util.spack_json as sjson
import spack.util.spack_yaml as syaml
-from spack.filesystem_view import YamlFilesystemView
+from spack.filesystem_view import (
+ YamlFilesystemView,
+ inverse_view_func_parser,
+ view_func_parser,
+)
from spack.spec import Spec
from spack.spec_list import InvalidSpecConstraintError, SpecList
from spack.util.path import substitute_path_variables
@@ -456,12 +460,13 @@ def _eval_conditional(string):
class ViewDescriptor(object):
def __init__(self, base_path, root, projections={}, select=[], exclude=[],
- link=default_view_link):
+ link=default_view_link, link_type='symlink'):
self.base = base_path
self.root = spack.util.path.canonicalize_path(root)
self.projections = projections
self.select = select
self.exclude = exclude
+ self.link_type = view_func_parser(link_type)
self.link = link
def select_fn(self, spec):
@@ -475,7 +480,8 @@ class ViewDescriptor(object):
self.projections == other.projections,
self.select == other.select,
self.exclude == other.exclude,
- self.link == other.link])
+ self.link == other.link,
+ self.link_type == other.link_type])
def to_dict(self):
ret = syaml.syaml_dict([('root', self.root)])
@@ -490,6 +496,8 @@ class ViewDescriptor(object):
ret['select'] = self.select
if self.exclude:
ret['exclude'] = self.exclude
+ if self.link_type:
+ ret['link_type'] = inverse_view_func_parser(self.link_type)
if self.link != default_view_link:
ret['link'] = self.link
return ret
@@ -501,7 +509,8 @@ class ViewDescriptor(object):
d.get('projections', {}),
d.get('select', []),
d.get('exclude', []),
- d.get('link', default_view_link))
+ d.get('link', default_view_link),
+ d.get('link_type', 'symlink'))
@property
def _current_root(self):
@@ -565,7 +574,8 @@ class ViewDescriptor(object):
raise SpackEnvironmentViewError(msg)
return YamlFilesystemView(root, spack.store.layout,
ignore_conflicts=True,
- projections=self.projections)
+ projections=self.projections,
+ link=self.link_type)
def __contains__(self, spec):
"""Is the spec described by the view descriptor
diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py
index dd872d712f..68cf7c156c 100644
--- a/lib/spack/spack/filesystem_view.py
+++ b/lib/spack/spack/filesystem_view.py
@@ -98,6 +98,29 @@ def view_copy(src, dst, view, spec=None):
)
+def view_func_parser(parsed_name):
+ # What method are we using for this view
+ if parsed_name in ("hardlink", "hard"):
+ return view_hardlink
+ elif parsed_name in ("copy", "relocate"):
+ return view_copy
+ elif parsed_name in ("add", "symlink", "soft"):
+ return view_symlink
+ else:
+ raise ValueError("invalid link type for view: '%s'" % parsed_name)
+
+
+def inverse_view_func_parser(view_type):
+ # get string based on view type
+ if view_type is view_hardlink:
+ link_name = 'hardlink'
+ elif view_type is view_copy:
+ link_name = 'copy'
+ else:
+ link_name = 'symlink'
+ return link_name
+
+
class FilesystemView(object):
"""
Governs a filesystem view that is located at certain root-directory.
diff --git a/lib/spack/spack/schema/env.py b/lib/spack/spack/schema/env.py
index 82971505e4..de6a5d9568 100644
--- a/lib/spack/spack/schema/env.py
+++ b/lib/spack/spack/schema/env.py
@@ -126,6 +126,9 @@ schema = {
'type': 'string',
'pattern': '(roots|all)',
},
+ 'link_type': {
+ 'type': 'string'
+ },
'select': {
'type': 'array',
'items': {
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
index e680507322..8ead966655 100644
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -1948,6 +1948,35 @@ env:
(spec.version, spec.compiler.name)))
+@pytest.mark.parametrize('link_type', ['hardlink', 'copy', 'symlink'])
+def test_view_link_type(link_type, tmpdir, mock_fetch, mock_packages, mock_archive,
+ install_mockery):
+ filename = str(tmpdir.join('spack.yaml'))
+ viewdir = str(tmpdir.join('view'))
+ with open(filename, 'w') as f:
+ f.write("""\
+env:
+ specs:
+ - mpileaks
+ view:
+ default:
+ root: %s
+ link_type: %s""" % (viewdir, link_type))
+ with tmpdir.as_cwd():
+ env('create', 'test', './spack.yaml')
+ with ev.read('test'):
+ install()
+
+ test = ev.read('test')
+
+ for spec in test.roots():
+ file_path = test.default_view.view()._root
+ file_to_test = os.path.join(
+ file_path, spec.name)
+ assert os.path.isfile(file_to_test)
+ assert os.path.islink(file_to_test) == (link_type == 'symlink')
+
+
def test_view_link_all(tmpdir, mock_fetch, mock_packages, mock_archive,
install_mockery):
filename = str(tmpdir.join('spack.yaml'))