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
This commit is contained in:
parent
ea7648ff84
commit
47e60d5ef8
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
import spack.config
|
import spack.config
|
||||||
|
import spack.environment
|
||||||
import spack.modules
|
import spack.modules
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.store
|
import spack.store
|
||||||
@ -42,16 +43,23 @@ class ConstraintAction(argparse.Action):
|
|||||||
|
|
||||||
To obtain the specs from a command the function must be called.
|
To obtain the specs from a command the function must be called.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
# Query specs from command line
|
# Query specs from command line
|
||||||
self.values = values
|
self.values = values
|
||||||
namespace.constraint = values
|
namespace.constraint = values
|
||||||
namespace.specs = self._specs
|
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):
|
def _specs(self, **kwargs):
|
||||||
qspecs = spack.cmd.parse_specs(self.values)
|
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.
|
# return everything for an empty query.
|
||||||
if not qspecs:
|
if not qspecs:
|
||||||
return spack.store.db.query(**kwargs)
|
return spack.store.db.query(**kwargs)
|
||||||
@ -66,6 +74,16 @@ def _specs(self, **kwargs):
|
|||||||
return sorted(specs.values())
|
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(
|
_arguments['constraint'] = Args(
|
||||||
'constraint', nargs=argparse.REMAINDER, action=ConstraintAction,
|
'constraint', nargs=argparse.REMAINDER, action=ConstraintAction,
|
||||||
help='constraint to select a subset of installed packages')
|
help='constraint to select a subset of installed packages')
|
||||||
|
@ -37,7 +37,8 @@ def setup_parser(subparser):
|
|||||||
const='deps',
|
const='deps',
|
||||||
help='show full dependency DAG of installed packages')
|
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',
|
subparser.add_argument('-f', '--show-flags',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -49,11 +50,11 @@ def setup_parser(subparser):
|
|||||||
help='show full compiler specs')
|
help='show full compiler specs')
|
||||||
implicit_explicit = subparser.add_mutually_exclusive_group()
|
implicit_explicit = subparser.add_mutually_exclusive_group()
|
||||||
implicit_explicit.add_argument(
|
implicit_explicit.add_argument(
|
||||||
'-e', '--explicit',
|
'-x', '--explicit',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='show only specs that were installed explicitly')
|
help='show only specs that were installed explicitly')
|
||||||
implicit_explicit.add_argument(
|
implicit_explicit.add_argument(
|
||||||
'-E', '--implicit',
|
'-X', '--implicit',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='show only specs that were installed as dependencies')
|
help='show only specs that were installed as dependencies')
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
|
@ -55,9 +55,7 @@ def setup_parser(subparser):
|
|||||||
help='prompt the list of modules associated with a constraint'
|
help='prompt the list of modules associated with a constraint'
|
||||||
)
|
)
|
||||||
add_loads_arguments(loads_parser)
|
add_loads_arguments(loads_parser)
|
||||||
arguments.add_common_arguments(
|
arguments.add_common_arguments(loads_parser, ['constraint'])
|
||||||
loads_parser, ['constraint']
|
|
||||||
)
|
|
||||||
|
|
||||||
return sp
|
return sp
|
||||||
|
|
||||||
|
@ -851,7 +851,8 @@ def query(
|
|||||||
installed=True,
|
installed=True,
|
||||||
explicit=any,
|
explicit=any,
|
||||||
start_date=None,
|
start_date=None,
|
||||||
end_date=None
|
end_date=None,
|
||||||
|
hashes=None
|
||||||
):
|
):
|
||||||
"""Run a query on the database
|
"""Run a query on the database
|
||||||
|
|
||||||
@ -885,19 +886,26 @@ def query(
|
|||||||
end_date (datetime, optional): filters the query discarding
|
end_date (datetime, optional): filters the query discarding
|
||||||
specs that have been installed after ``end_date``.
|
specs that have been installed after ``end_date``.
|
||||||
|
|
||||||
|
hashes (container): list or set of hashes that we can use to
|
||||||
|
restrict the search
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list of specs that match the query
|
list of specs that match the query
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO: Specs are a lot like queries. Should there be a
|
# TODO: Specs are a lot like queries. Should there be a
|
||||||
# TODO: wildcard spec object, and should specs have attributes
|
# TODO: wildcard spec object, and should specs have attributes
|
||||||
# TODO: like installed and known that can be queried? Or are
|
# TODO: like installed and known that can be queried? Or are
|
||||||
# TODO: these really special cases that only belong here?
|
# TODO: these really special cases that only belong here?
|
||||||
|
|
||||||
|
# TODO: handling of hashes restriction is not particularly elegant.
|
||||||
with self.read_transaction():
|
with self.read_transaction():
|
||||||
# Just look up concrete specs with hashes; no fancy search.
|
# Just look up concrete specs with hashes; no fancy search.
|
||||||
if isinstance(query_spec, spack.spec.Spec) and query_spec.concrete:
|
if isinstance(query_spec, spack.spec.Spec) and query_spec.concrete:
|
||||||
|
|
||||||
hash_key = query_spec.dag_hash()
|
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]
|
return [self._data[hash_key].spec]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
@ -909,6 +917,9 @@ def query(
|
|||||||
end_date = end_date or datetime.datetime.max
|
end_date = end_date or datetime.datetime.max
|
||||||
|
|
||||||
for key, rec in self._data.items():
|
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:
|
if installed is not any and rec.installed != installed:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
import llnl.util.filesystem as fs
|
import llnl.util.filesystem as fs
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
|
import spack.error
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.schema.env
|
import spack.schema.env
|
||||||
import spack.util.spack_json as sjson
|
import spack.util.spack_json as sjson
|
||||||
@ -389,9 +390,15 @@ def repair(environment_name):
|
|||||||
|
|
||||||
|
|
||||||
def read(environment_name):
|
def read(environment_name):
|
||||||
|
"""Read environment state from disk."""
|
||||||
# Check that env is in a consistent state on disk
|
# Check that env is in a consistent state on disk
|
||||||
env_root = root(environment_name)
|
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
|
# Read env.yaml file
|
||||||
env_yaml = spack.config._read_config_file(
|
env_yaml = spack.config._read_config_file(
|
||||||
fs.join_path(env_root, 'env.yaml'),
|
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' %
|
tty.msg('Using Spack config %s scope at %s' %
|
||||||
(config_name, config_dir))
|
(config_name, config_dir))
|
||||||
spack.config.config.push_scope(ConfigScope(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``.
|
||||||
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user