env: consolidate most of spack env status into spack find

- `spack env status` used to show install status; consolidate that into
  `spack find`.

- `spack env status` will still print out whether there is an active
  environment
This commit is contained in:
Todd Gamblin 2018-11-02 12:43:02 -07:00
parent 26a55ff749
commit efad7ac81b
7 changed files with 259 additions and 148 deletions

View File

@ -175,7 +175,8 @@ def disambiguate_spec(spec):
def gray_hash(spec, length): def gray_hash(spec, length):
return colorize('@K{%s}' % spec.dag_hash(length)) h = spec.dag_hash(length) if spec.concrete else '-' * length
return colorize('@K{%s}' % h)
def display_specs(specs, args=None, **kwargs): def display_specs(specs, args=None, **kwargs):
@ -209,7 +210,9 @@ def display_specs(specs, args=None, **kwargs):
show_flags (bool): Show compiler flags with specs show_flags (bool): Show compiler flags with specs
variants (bool): Show variants with specs variants (bool): Show variants with specs
indent (int): indent each line this much indent (int): indent each line this much
decorators (dict): dictionary mappng specs to decorators
header_callback (function): called at start of arch/compiler sections
all_headers (bool): show headers even when arch/compiler aren't defined
""" """
def get_arg(name, default=None): def get_arg(name, default=None):
"""Prefer kwargs, then args, then default.""" """Prefer kwargs, then args, then default."""
@ -226,6 +229,11 @@ def get_arg(name, default=None):
flags = get_arg('show_flags', False) flags = get_arg('show_flags', False)
full_compiler = get_arg('show_full_compiler', False) full_compiler = get_arg('show_full_compiler', False)
variants = get_arg('variants', False) variants = get_arg('variants', False)
all_headers = get_arg('all_headers', False)
decorator = get_arg('decorator', None)
if decorator is None:
decorator = lambda s, f: f
indent = get_arg('indent', 0) indent = get_arg('indent', 0)
ispace = indent * ' ' ispace = indent * ' '
@ -235,7 +243,7 @@ def get_arg(name, default=None):
hashes = True hashes = True
hlen = None hlen = None
nfmt = '.' if namespace else '_' nfmt = '{fullpackage}' if namespace else '{package}'
ffmt = '' ffmt = ''
if full_compiler or flags: if full_compiler or flags:
ffmt += '$%' ffmt += '$%'
@ -247,35 +255,46 @@ def get_arg(name, default=None):
# Make a dict with specs keyed by architecture and compiler. # Make a dict with specs keyed by architecture and compiler.
index = index_by(specs, ('architecture', 'compiler')) index = index_by(specs, ('architecture', 'compiler'))
transform = {'package': decorator, 'fullpackage': decorator}
# Traverse the index and print out each package # Traverse the index and print out each package
for i, (architecture, compiler) in enumerate(sorted(index)): for i, (architecture, compiler) in enumerate(sorted(index)):
if i > 0: if i > 0:
print() print()
header = "%s{%s} / %s{%s}" % (spack.spec.architecture_color, header = "%s{%s} / %s{%s}" % (
architecture, spack.spec.compiler_color, spack.spec.architecture_color,
compiler) architecture if architecture else 'no arch',
spack.spec.compiler_color,
compiler if compiler else 'no compiler')
# Sometimes we want to display specs that are not yet concretized. # Sometimes we want to display specs that are not yet concretized.
# If they don't have a compiler / architecture attached to them, # If they don't have a compiler / architecture attached to them,
# then skip the header # then skip the header
if architecture is not None or compiler is not None: if all_headers or (architecture is not None or compiler is not None):
sys.stdout.write(ispace) sys.stdout.write(ispace)
tty.hline(colorize(header), char='-') tty.hline(colorize(header), char='-')
specs = index[(architecture, compiler)] specs = index[(architecture, compiler)]
specs.sort() specs.sort()
abbreviated = [s.cformat(format_string) for s in specs]
if mode == 'paths': if mode == 'paths':
# Print one spec per line along with prefix path # Print one spec per line along with prefix path
abbreviated = [s.cformat(format_string, transform=transform)
for s in specs]
width = max(len(s) for s in abbreviated) width = max(len(s) for s in abbreviated)
width += 2 width += 2
format = " %%-%ds%%s" % width
for abbrv, spec in zip(abbreviated, specs): for abbrv, spec in zip(abbreviated, specs):
prefix = gray_hash(spec, hlen) if hashes else '' # optional hash prefix for paths
print(ispace + prefix + (format % (abbrv, spec.prefix))) h = gray_hash(spec, hlen) if hashes else ''
# only show prefix for concrete specs
prefix = spec.prefix if spec.concrete else ''
# print it all out at once
fmt = "%%s%%s %%-%ds%%s" % width
print(fmt % (ispace, h, abbrv, prefix))
elif mode == 'deps': elif mode == 'deps':
for spec in specs: for spec in specs:
@ -285,24 +304,25 @@ def get_arg(name, default=None):
prefix=(lambda s: gray_hash(s, hlen)) if hashes else None)) prefix=(lambda s: gray_hash(s, hlen)) if hashes else None))
elif mode == 'short': elif mode == 'short':
# Print columns of output if not printing flags
if not flags and not full_compiler:
def fmt(s): def fmt(s):
string = "" string = ""
if hashes: if hashes:
string += gray_hash(s, hlen) + ' ' string += gray_hash(s, hlen) + ' '
string += s.cformat('$-%s$@%s' % (nfmt, vfmt)) string += s.cformat(
'$%s$@%s' % (nfmt, vfmt), transform=transform)
return string return string
if not flags and not full_compiler:
# Print columns of output if not printing flags
colify((fmt(s) for s in specs), indent=indent) colify((fmt(s) for s in specs), indent=indent)
# Print one entry per line if including flags
else: else:
# Print one entry per line if including flags
for spec in specs: for spec in specs:
# Print the hash if necessary # Print the hash if necessary
hsh = gray_hash(spec, hlen) + ' ' if hashes else '' hsh = gray_hash(spec, hlen) + ' ' if hashes else ''
print(ispace + hsh + spec.cformat(format_string)) print(ispace + hsh + spec.cformat(
format_string, transform=transform))
else: else:
raise ValueError( raise ValueError(

View File

@ -271,26 +271,19 @@ def env_list(args):
# env status # env status
# #
def env_status_setup_parser(subparser): def env_status_setup_parser(subparser):
"""get install status of specs in an environment""" """print whether there is an active environment"""
subparser.add_argument(
'env', nargs='?', help='name of environment to show status for')
arguments.add_common_arguments(
subparser,
['recurse_dependencies', 'long', 'very_long'])
def env_status(args): def env_status(args):
env = ev.get_env(args, 'env status', required=False) env = ev.get_env(args, 'env status', required=False)
if not env: if env:
if env.path == os.getcwd():
tty.msg('Using %s in current directory: %s'
% (ev.manifest_name, env.path))
else:
tty.msg('In environment %s' % env.name)
else:
tty.msg('No active environment') tty.msg('No active environment')
return
# TODO: option to show packages w/ multiple instances?
env.status(
sys.stdout, recurse_dependencies=args.recurse_dependencies,
hashes=args.long or args.very_long,
hashlen=None if args.very_long else 7,
install_status=True)
# #

View File

@ -2,15 +2,17 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details. # Spack Project Developers. See the top-level COPYRIGHT file for details.
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
from __future__ import print_function
import sys
import llnl.util.tty as tty import llnl.util.tty as tty
import llnl.util.tty.color as color
import llnl.util.lang import llnl.util.lang
import spack.environment as ev
import spack.repo import spack.repo
import spack.cmd.common.arguments as arguments import spack.cmd.common.arguments as arguments
from spack.cmd import display_specs from spack.cmd import display_specs
from spack.util.string import plural
description = "list and search installed packages" description = "list and search installed packages"
section = "basic" section = "basic"
@ -40,6 +42,9 @@ def setup_parser(subparser):
arguments.add_common_arguments( arguments.add_common_arguments(
subparser, ['long', 'very_long', 'tags']) subparser, ['long', 'very_long', 'tags'])
subparser.add_argument('-c', '--show-concretized',
action='store_true',
help='show concretized specs in an environment')
subparser.add_argument('-f', '--show-flags', subparser.add_argument('-f', '--show-flags',
action='store_true', action='store_true',
dest='show_flags', dest='show_flags',
@ -116,12 +121,42 @@ def query_arguments(args):
return q_args return q_args
def setup_env(env):
"""Create a function for decorating specs when in an environment."""
def strip_build(seq):
return set(s.copy(deps=('link', 'run')) for s in seq)
added = set(strip_build(env.added_specs()))
roots = set(strip_build(env.roots()))
removed = set(strip_build(env.removed_specs()))
def decorator(spec, fmt):
# add +/-/* to show added/removed/root specs
if spec in roots:
return color.colorize('@*{%s}' % fmt)
elif spec in removed:
return color.colorize('@K{%s}' % fmt)
else:
return '%s' % fmt
return decorator, added, roots, removed
def find(parser, args): def find(parser, args):
q_args = query_arguments(args) q_args = query_arguments(args)
query_specs = args.specs(**q_args) results = args.specs(**q_args)
decorator = lambda s, f: f
added = set()
removed = set()
env = ev.get_env(args, 'find', required=False)
if env:
decorator, added, roots, removed = setup_env(env)
# Exit early if no package matches the constraint # Exit early if no package matches the constraint
if not query_specs and args.constraint: if not results and args.constraint:
msg = "No package matches the query: {0}" msg = "No package matches the query: {0}"
msg = msg.format(' '.join(args.constraint)) msg = msg.format(' '.join(args.constraint))
tty.msg(msg) tty.msg(msg)
@ -130,10 +165,29 @@ def find(parser, args):
# If tags have been specified on the command line, filter by tags # If tags have been specified on the command line, filter by tags
if args.tags: if args.tags:
packages_with_tags = spack.repo.path.packages_with_tags(*args.tags) packages_with_tags = spack.repo.path.packages_with_tags(*args.tags)
query_specs = [x for x in query_specs if x.name in packages_with_tags] results = [x for x in results if x.name in packages_with_tags]
# Display the result # Display the result
if sys.stdout.isatty(): if env:
tty.msg("%d installed packages." % len(query_specs)) tty.msg('In environment %s' % env.name)
display_specs(query_specs, args) print()
tty.msg('Root specs')
if not env.user_specs:
print('none')
else:
display_specs(
env.user_specs, args,
decorator=lambda s, f: color.colorize('@*{%s}' % f))
print()
if args.show_concretized:
tty.msg('Concretized roots')
display_specs(
env.specs_by_hash.values(), args, decorator=decorator)
print()
tty.msg("%s" % plural(len(results), 'installed package'))
display_specs(results, args, decorator=decorator, all_headers=True)

View File

@ -13,7 +13,6 @@
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 llnl.util.tty.color as color
import spack.error import spack.error
import spack.repo import spack.repo
@ -152,7 +151,7 @@ def get_env(args, cmd_name, required=True):
""" """
# try arguments # try arguments
env = args.env env = getattr(args, 'env', None)
# try a manifest file in the current directory # try a manifest file in the current directory
if not env: if not env:
@ -356,6 +355,11 @@ def clear(self):
self._repo = None # RepoPath for this env (memoized) self._repo = None # RepoPath for this env (memoized)
self._previous_active = None # previously active environment self._previous_active = None # previously active environment
@property
def internal(self):
"""Whether this environment is managed by Spack."""
return self.path.startswith(env_path)
@property @property
def name(self): def name(self):
"""Human-readable representation of the environment. """Human-readable representation of the environment.
@ -363,7 +367,7 @@ def name(self):
This is the path for directory environments, and just the name This is the path for directory environments, and just the name
for named environments. for named environments.
""" """
if self.path.startswith(env_path): if self.internal:
return os.path.basename(self.path) return os.path.basename(self.path)
else: else:
return self.path return self.path
@ -625,46 +629,6 @@ def install_all(self, args=None):
os.remove(build_log_link) os.remove(build_log_link)
os.symlink(spec.package.build_log_path, build_log_link) os.symlink(spec.package.build_log_path, build_log_link)
def status(self, stream, **kwargs):
"""List the specs in an environment."""
tty.msg('In environment %s' % self.name)
concretized = [(spec, self.specs_by_hash[h])
for spec, h in zip(self.concretized_user_specs,
self.concretized_order)]
added = [s for s in self.user_specs
if s not in self.concretized_user_specs]
removed = [(s, c) for s, c in concretized if s not in self.user_specs]
current = [(s, c) for s, c in concretized if s in self.user_specs]
def write_kind(s):
color.cwrite('@c{%s}\n' % color.cescape(s), stream)
def write_user_spec(s, c):
color.cwrite('@%s{----} %s\n' % (c, color.cescape(s)), stream)
if added:
write_kind('added:')
for s in added:
write_user_spec(s, 'g')
if current:
if added:
stream.write('\n')
write_kind('concrete:')
for s, c in current:
write_user_spec(s, 'K')
stream.write(c.tree(**kwargs))
if removed:
if added or current:
stream.write('\n')
write_kind('removed:')
for s, c in removed:
write_user_spec(s, 'r')
stream.write(c.tree(**kwargs))
def all_specs_by_hash(self): def all_specs_by_hash(self):
"""Map of hashes to spec for all specs in this environment.""" """Map of hashes to spec for all specs in this environment."""
hashes = {} hashes = {}
@ -682,6 +646,50 @@ def all_hashes(self):
"""Return all specs, even those a user spec would shadow.""" """Return all specs, even those a user spec would shadow."""
return list(self.all_specs_by_hash().keys()) return list(self.all_specs_by_hash().keys())
def roots(self):
"""Specs explicitly requested by the user *in this environment*.
Yields both added and installed specs that have user specs in
`spack.yaml`.
"""
concretized = dict(self.concretized_specs())
for spec in self.user_specs:
concrete = concretized.get(spec)
yield concrete if concrete else spec
def added_specs(self):
"""Specs that are not yet installed.
Yields the user spec for non-concretized specs, and the concrete
spec for already concretized but not yet installed specs.
"""
concretized = dict(self.concretized_specs())
for spec in self.user_specs:
concrete = concretized.get(spec)
if not concrete:
yield spec
elif not concrete.package.installed:
yield concrete
def concretized_specs(self):
"""Tuples of (user spec, concrete spec) for all concrete specs."""
for s, h in zip(self.concretized_user_specs, self.concretized_order):
yield (s, self.specs_by_hash[h])
def removed_specs(self):
"""Tuples of (user spec, concrete spec) for all specs that will be
removed on nexg concretize."""
needed = set()
for s, c in self.concretized_specs():
if s in self.user_specs:
for d in c.traverse():
needed.add(d)
for s, c in self.concretized_specs():
for d in c.traverse():
if d not in needed:
yield d
def _get_environment_specs(self, recurse_dependencies=True): def _get_environment_specs(self, recurse_dependencies=True):
"""Returns the specs of all the packages in an environment. """Returns the specs of all the packages in an environment.

View File

@ -546,7 +546,7 @@ def environment_modifications(self):
# tokens uppercase. # tokens uppercase.
transform = {} transform = {}
for token in _valid_tokens: for token in _valid_tokens:
transform[token] = str.upper transform[token] = lambda spec, string: str.upper(string)
for x in env: for x in env:
# Ensure all the tokens are valid in this context # Ensure all the tokens are valid in this context

View File

@ -2906,7 +2906,7 @@ def _cmp_node(self):
"""Comparison key for just *this node* and not its deps.""" """Comparison key for just *this node* and not its deps."""
return (self.name, return (self.name,
self.namespace, self.namespace,
self.versions, tuple(self.versions),
self.variants, self.variants,
self.architecture, self.architecture,
self.compiler, self.compiler,
@ -2964,6 +2964,7 @@ def format(self, format_string='$_$@$%@+$+$=', **kwargs):
You can also use full-string versions, which elide the prefixes:: You can also use full-string versions, which elide the prefixes::
${PACKAGE} Package name ${PACKAGE} Package name
${FULLPACKAGE} Full package name (with namespace)
${VERSION} Version ${VERSION} Version
${COMPILER} Full compiler string ${COMPILER} Full compiler string
${COMPILERNAME} Compiler name ${COMPILERNAME} Compiler name
@ -2995,11 +2996,9 @@ def format(self, format_string='$_$@$%@+$+$=', **kwargs):
Args: Args:
format_string (str): string containing the format to be expanded format_string (str): string containing the format to be expanded
**kwargs (dict): the following list of keywords is supported Keyword Args:
color (bool): True if returned string is colored
- color (bool): True if returned string is colored transform (dict): maps full-string formats to a callable \
- transform (dict): maps full-string formats to a callable \
that accepts a string and returns another one that accepts a string and returns another one
Examples: Examples:
@ -3019,16 +3018,18 @@ def format(self, format_string='$_$@$%@+$+$=', **kwargs):
color = kwargs.get('color', False) color = kwargs.get('color', False)
# Dictionary of transformations for named tokens # Dictionary of transformations for named tokens
token_transforms = {} token_transforms = dict(
token_transforms.update(kwargs.get('transform', {})) (k.upper(), v) for k, v in kwargs.get('transform', {}).items())
length = len(format_string) length = len(format_string)
out = StringIO() out = StringIO()
named = escape = compiler = False named = escape = compiler = False
named_str = fmt = '' named_str = fmt = ''
def write(s, c): def write(s, c=None):
f = color_formats[c] + cescape(s) + '@.' f = cescape(s)
if c is not None:
f = color_formats[c] + f + '@.'
cwrite(f, stream=out, color=color) cwrite(f, stream=out, color=color)
iterator = enumerate(format_string) iterator = enumerate(format_string)
@ -3048,7 +3049,8 @@ def write(s, c):
name = self.name if self.name else '' name = self.name if self.name else ''
out.write(fmt % name) out.write(fmt % name)
elif c == '.': elif c == '.':
out.write(fmt % self.fullname) name = self.fullname if self.fullname else ''
out.write(fmt % name)
elif c == '@': elif c == '@':
if self.versions and self.versions != _any_version: if self.versions and self.versions != _any_version:
write(fmt % (c + str(self.versions)), c) write(fmt % (c + str(self.versions)), c)
@ -3103,60 +3105,63 @@ def write(s, c):
# #
# The default behavior is to leave the string unchanged # The default behavior is to leave the string unchanged
# (`lambda x: x` is the identity function) # (`lambda x: x` is the identity function)
token_transform = token_transforms.get(named_str, lambda x: x) transform = token_transforms.get(named_str, lambda s, x: x)
if named_str == 'PACKAGE': if named_str == 'PACKAGE':
name = self.name if self.name else '' name = self.name if self.name else ''
write(fmt % token_transform(name), '@') write(fmt % transform(self, name))
if named_str == 'VERSION': elif named_str == 'FULLPACKAGE':
name = self.fullname if self.fullname else ''
write(fmt % transform(self, name))
elif named_str == 'VERSION':
if self.versions and self.versions != _any_version: if self.versions and self.versions != _any_version:
write(fmt % token_transform(str(self.versions)), '@') write(fmt % transform(self, str(self.versions)), '@')
elif named_str == 'COMPILER': elif named_str == 'COMPILER':
if self.compiler: if self.compiler:
write(fmt % token_transform(self.compiler), '%') write(fmt % transform(self, self.compiler), '%')
elif named_str == 'COMPILERNAME': elif named_str == 'COMPILERNAME':
if self.compiler: if self.compiler:
write(fmt % token_transform(self.compiler.name), '%') write(fmt % transform(self, self.compiler.name), '%')
elif named_str in ['COMPILERVER', 'COMPILERVERSION']: elif named_str in ['COMPILERVER', 'COMPILERVERSION']:
if self.compiler: if self.compiler:
write( write(
fmt % token_transform(self.compiler.versions), fmt % transform(self, self.compiler.versions),
'%' '%'
) )
elif named_str == 'COMPILERFLAGS': elif named_str == 'COMPILERFLAGS':
if self.compiler: if self.compiler:
write( write(
fmt % token_transform(str(self.compiler_flags)), fmt % transform(self, str(self.compiler_flags)),
'%' '%'
) )
elif named_str == 'OPTIONS': elif named_str == 'OPTIONS':
if self.variants: if self.variants:
write(fmt % token_transform(str(self.variants)), '+') write(fmt % transform(self, str(self.variants)), '+')
elif named_str in ["ARCHITECTURE", "PLATFORM", "TARGET", "OS"]: elif named_str in ["ARCHITECTURE", "PLATFORM", "TARGET", "OS"]:
if self.architecture and str(self.architecture): if self.architecture and str(self.architecture):
if named_str == "ARCHITECTURE": if named_str == "ARCHITECTURE":
write( write(
fmt % token_transform(str(self.architecture)), fmt % transform(self, str(self.architecture)),
'=' '='
) )
elif named_str == "PLATFORM": elif named_str == "PLATFORM":
platform = str(self.architecture.platform) platform = str(self.architecture.platform)
write(fmt % token_transform(platform), '=') write(fmt % transform(self, platform), '=')
elif named_str == "OS": elif named_str == "OS":
operating_sys = str(self.architecture.platform_os) operating_sys = str(self.architecture.platform_os)
write(fmt % token_transform(operating_sys), '=') write(fmt % transform(self, operating_sys), '=')
elif named_str == "TARGET": elif named_str == "TARGET":
target = str(self.architecture.target) target = str(self.architecture.target)
write(fmt % token_transform(target), '=') write(fmt % transform(self, target), '=')
elif named_str == 'SHA1': elif named_str == 'SHA1':
if self.dependencies: if self.dependencies:
out.write(fmt % token_transform(str(self.dag_hash(7)))) out.write(fmt % transform(self, str(self.dag_hash(7))))
elif named_str == 'SPACK_ROOT': elif named_str == 'SPACK_ROOT':
out.write(fmt % token_transform(spack.paths.prefix)) out.write(fmt % transform(self, spack.paths.prefix))
elif named_str == 'SPACK_INSTALL': elif named_str == 'SPACK_INSTALL':
out.write(fmt % token_transform(spack.store.root)) out.write(fmt % transform(self, spack.store.root))
elif named_str == 'PREFIX': elif named_str == 'PREFIX':
out.write(fmt % token_transform(self.prefix)) out.write(fmt % transform(self, self.prefix))
elif named_str.startswith('HASH'): elif named_str.startswith('HASH'):
if named_str.startswith('HASH:'): if named_str.startswith('HASH:'):
_, hashlen = named_str.split(':') _, hashlen = named_str.split(':')
@ -3165,7 +3170,7 @@ def write(s, c):
hashlen = None hashlen = None
out.write(fmt % (self.dag_hash(hashlen))) out.write(fmt % (self.dag_hash(hashlen)))
elif named_str == 'NAMESPACE': elif named_str == 'NAMESPACE':
out.write(fmt % token_transform(self.namespace)) out.write(fmt % transform(self.namespace))
named = False named = False

View File

@ -28,6 +28,7 @@
concretize = SpackCommand('concretize') concretize = SpackCommand('concretize')
stage = SpackCommand('stage') stage = SpackCommand('stage')
uninstall = SpackCommand('uninstall') uninstall = SpackCommand('uninstall')
find = SpackCommand('find')
def test_add(): def test_add():
@ -156,32 +157,62 @@ def test_remove_after_concretize():
def test_remove_command(): def test_remove_command():
env('create', 'test') env('create', 'test')
assert 'test' in env('list')
with ev.read('test'): with ev.read('test'):
add('mpileaks') add('mpileaks')
assert 'mpileaks' in env('status', 'test') assert 'mpileaks' in find()
assert 'mpileaks@' not in find()
assert 'mpileaks@' not in find('--show-concretized')
with ev.read('test'): with ev.read('test'):
remove('mpileaks') remove('mpileaks')
assert 'mpileaks' not in env('status', 'test') assert 'mpileaks' not in find()
assert 'mpileaks@' not in find()
assert 'mpileaks@' not in find('--show-concretized')
with ev.read('test'): with ev.read('test'):
add('mpileaks') add('mpileaks')
assert 'mpileaks' in env('status', 'test') assert 'mpileaks' in find()
assert 'mpileaks@' not in find()
assert 'mpileaks@' not in find('--show-concretized')
with ev.read('test'):
concretize()
assert 'mpileaks' in find()
assert 'mpileaks@' not in find()
assert 'mpileaks@' in find('--show-concretized')
with ev.read('test'):
remove('mpileaks')
assert 'mpileaks' not in find()
# removed but still in last concretized specs
assert 'mpileaks@' in find('--show-concretized')
with ev.read('test'):
concretize()
assert 'mpileaks' not in find()
assert 'mpileaks@' not in find()
# now the lockfile is regenerated and it's gone.
assert 'mpileaks@' not in find('--show-concretized')
def test_environment_status(): def test_environment_status(capfd, tmpdir):
e = ev.create('test') with capfd.disabled():
e.add('mpileaks') with tmpdir.as_cwd():
e.concretize() assert 'No active environment' in env('status')
e.add('python')
mock_stream = StringIO() with ev.create('test'):
e.status(mock_stream) assert 'In environment test' in env('status')
list_content = mock_stream.getvalue()
assert 'mpileaks' in list_content with ev.Environment('local_dir'):
assert 'python' in list_content assert os.path.join(os.getcwd(), 'local_dir') in env('status')
mpileaks_spec = e.specs_by_hash[e.concretized_order[0]]
assert mpileaks_spec.format() in list_content e = ev.Environment('myproject')
e.write()
with tmpdir.join('myproject').as_cwd():
with e:
assert 'in current directory' in env('status')
def test_to_lockfile_dict(): def test_to_lockfile_dict():
@ -309,8 +340,8 @@ def test_init_with_file_and_remove(tmpdir):
out = env('list') out = env('list')
assert 'test' in out assert 'test' in out
out = env('status', 'test') with ev.read('test'):
assert 'mpileaks' in out assert 'mpileaks' in find()
env('remove', '-y', 'test') env('remove', '-y', 'test')