summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2018-07-31 01:23:19 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2018-11-09 00:31:24 -0800
commit47e60d5ef8c539c3abe99c6d7d3d721730268397 (patch)
tree79afb77831c9cbc74421134ab4e2064f67c0347c /lib
parentea7648ff84661089834a5d9f0005c6af820c2634 (diff)
downloadspack-47e60d5ef8c539c3abe99c6d7d3d721730268397.tar.gz
spack-47e60d5ef8c539c3abe99c6d7d3d721730268397.tar.bz2
spack-47e60d5ef8c539c3abe99c6d7d3d721730268397.tar.xz
spack-47e60d5ef8c539c3abe99c6d7d3d721730268397.zip
env: add --env argument to `spack find`
- add a common argument for `-e/--env` - modify the database to support queries on subsets of hashes - allow `spack find` to be filtered by hashes in an environment
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/common/arguments.py20
-rw-r--r--lib/spack/spack/cmd/find.py7
-rw-r--r--lib/spack/spack/cmd/modules/__init__.py4
-rw-r--r--lib/spack/spack/database.py15
-rw-r--r--lib/spack/spack/environment.py15
5 files changed, 52 insertions, 9 deletions
diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py
index 7eeded8daa..84f61a12cc 100644
--- a/lib/spack/spack/cmd/common/arguments.py
+++ b/lib/spack/spack/cmd/common/arguments.py
@@ -8,6 +8,7 @@ import argparse
import spack.cmd
import spack.config
+import spack.environment
import spack.modules
import spack.spec
import spack.store
@@ -42,16 +43,23 @@ class ConstraintAction(argparse.Action):
To obtain the specs from a command the function must be called.
"""
-
def __call__(self, parser, namespace, values, option_string=None):
# Query specs from command line
self.values = values
namespace.constraint = values
namespace.specs = self._specs
+ # env comes from EnvAction if --env is provided
+ self.env = None if not hasattr(namespace, 'env') else namespace.env
+
def _specs(self, **kwargs):
qspecs = spack.cmd.parse_specs(self.values)
+ # If an environment is provided, we'll restrict the search to
+ # only its installed packages.
+ if self.env:
+ kwargs['hashes'] = set(self.env.specs_by_hash.keys())
+
# return everything for an empty query.
if not qspecs:
return spack.store.db.query(**kwargs)
@@ -66,6 +74,16 @@ class ConstraintAction(argparse.Action):
return sorted(specs.values())
+class EnvAction(argparse.Action):
+ """Records the environment to which a command applies."""
+ def __call__(self, parser, namespace, env_name, option_string=None):
+ namespace.env = spack.environment.read(env_name)
+
+
+_arguments['env'] = Args(
+ '-e', '--env', action=EnvAction, default=None,
+ help="run this command on a specific environment")
+
_arguments['constraint'] = Args(
'constraint', nargs=argparse.REMAINDER, action=ConstraintAction,
help='constraint to select a subset of installed packages')
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index 0e8e2ef5f0..5c7a508a46 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -37,7 +37,8 @@ def setup_parser(subparser):
const='deps',
help='show full dependency DAG of installed packages')
- arguments.add_common_arguments(subparser, ['long', 'very_long', 'tags'])
+ arguments.add_common_arguments(
+ subparser, ['env', 'long', 'very_long', 'tags'])
subparser.add_argument('-f', '--show-flags',
action='store_true',
@@ -49,11 +50,11 @@ def setup_parser(subparser):
help='show full compiler specs')
implicit_explicit = subparser.add_mutually_exclusive_group()
implicit_explicit.add_argument(
- '-e', '--explicit',
+ '-x', '--explicit',
action='store_true',
help='show only specs that were installed explicitly')
implicit_explicit.add_argument(
- '-E', '--implicit',
+ '-X', '--implicit',
action='store_true',
help='show only specs that were installed as dependencies')
subparser.add_argument(
diff --git a/lib/spack/spack/cmd/modules/__init__.py b/lib/spack/spack/cmd/modules/__init__.py
index 598130c4da..00f008b2cf 100644
--- a/lib/spack/spack/cmd/modules/__init__.py
+++ b/lib/spack/spack/cmd/modules/__init__.py
@@ -55,9 +55,7 @@ def setup_parser(subparser):
help='prompt the list of modules associated with a constraint'
)
add_loads_arguments(loads_parser)
- arguments.add_common_arguments(
- loads_parser, ['constraint']
- )
+ arguments.add_common_arguments(loads_parser, ['constraint'])
return sp
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index ae643ae72c..33942c362f 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -851,7 +851,8 @@ class Database(object):
installed=True,
explicit=any,
start_date=None,
- end_date=None
+ end_date=None,
+ hashes=None
):
"""Run a query on the database
@@ -885,19 +886,26 @@ class Database(object):
end_date (datetime, optional): filters the query discarding
specs that have been installed after ``end_date``.
+ hashes (container): list or set of hashes that we can use to
+ restrict the search
+
Returns:
list of specs that match the query
+
"""
# TODO: Specs are a lot like queries. Should there be a
# TODO: wildcard spec object, and should specs have attributes
# TODO: like installed and known that can be queried? Or are
# TODO: these really special cases that only belong here?
+
+ # TODO: handling of hashes restriction is not particularly elegant.
with self.read_transaction():
# Just look up concrete specs with hashes; no fancy search.
if isinstance(query_spec, spack.spec.Spec) and query_spec.concrete:
hash_key = query_spec.dag_hash()
- if hash_key in self._data:
+ if (hash_key in self._data and
+ (not hashes or hash_key in hashes)):
return [self._data[hash_key].spec]
else:
return []
@@ -909,6 +917,9 @@ class Database(object):
end_date = end_date or datetime.datetime.max
for key, rec in self._data.items():
+ if hashes is not None and rec.spec.dag_hash() not in hashes:
+ continue
+
if installed is not any and rec.installed != installed:
continue
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index 4dc794b2e1..597fa14802 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -31,6 +31,7 @@ from six.moves import zip_longest
import llnl.util.filesystem as fs
import llnl.util.tty as tty
+import spack.error
import spack.repo
import spack.schema.env
import spack.util.spack_json as sjson
@@ -389,9 +390,15 @@ def repair(environment_name):
def read(environment_name):
+ """Read environment state from disk."""
# Check that env is in a consistent state on disk
env_root = root(environment_name)
+ if not os.path.isdir(env_root):
+ raise EnvError("no such environment '%s'" % environment_name)
+ if not os.access(env_root, os.R_OK):
+ raise EnvError("can't read environment '%s'" % environment_name)
+
# Read env.yaml file
env_yaml = spack.config._read_config_file(
fs.join_path(env_root, 'env.yaml'),
@@ -458,3 +465,11 @@ def prepare_config_scope(environment):
tty.msg('Using Spack config %s scope at %s' %
(config_name, config_dir))
spack.config.config.push_scope(ConfigScope(config_name, config_dir))
+
+
+class EnvError(spack.error.SpackError):
+ """Superclass for all errors to do with Spack environments.
+
+ Note that this is called ``EnvError`` to distinguish it from the
+ builtin ``EnvironmentError``.
+ """