Rework command reference in docs, add spack commands
command
- command reference now includes usage for all Spack commands as output by `spack help`. Each command usage links to any related section in the docs. - added `spack commands` command which can list command names, subcommands, and generate RST docs for commands. - added `llnl.util.argparsewriter`, which analyzes an argparse parser and calls hooks for description, usage, options, and subcommands
This commit is contained in:
parent
1b998cbeee
commit
b98cdf098a
7 changed files with 459 additions and 20 deletions
|
@ -1,9 +1,9 @@
|
||||||
=============
|
=================
|
||||||
Command Index
|
Command Reference
|
||||||
=============
|
=================
|
||||||
|
|
||||||
This is an alphabetical list of commands with links to the places they
|
This is a reference for all commands in the Spack command line interface.
|
||||||
appear in the documentation.
|
The same information is available through :ref:`spack-help`.
|
||||||
|
|
||||||
.. hlist::
|
Commands that also have sections in the main documentation have a link to
|
||||||
:columns: 3
|
"More documentation".
|
||||||
|
|
|
@ -76,19 +76,23 @@
|
||||||
#
|
#
|
||||||
# Find all the `cmd-spack-*` references and add them to a command index
|
# Find all the `cmd-spack-*` references and add them to a command index
|
||||||
#
|
#
|
||||||
command_names = []
|
import spack
|
||||||
|
command_names = spack.cmd.all_commands
|
||||||
|
documented_commands = set()
|
||||||
for filename in glob('*rst'):
|
for filename in glob('*rst'):
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
match = re.match('.. _(cmd-spack-.*):', line)
|
match = re.match('.. _cmd-(spack-.*):', line)
|
||||||
if match:
|
if match:
|
||||||
command_names.append(match.group(1).strip())
|
documented_commands.add(match.group(1).strip())
|
||||||
|
|
||||||
|
os.environ['COLUMNS'] = '120'
|
||||||
shutil.copy('command_index.in', 'command_index.rst')
|
shutil.copy('command_index.in', 'command_index.rst')
|
||||||
with open('command_index.rst', 'a') as index:
|
with open('command_index.rst', 'a') as index:
|
||||||
index.write('\n')
|
subprocess.Popen(
|
||||||
for cmd in sorted(command_names):
|
[spack_root + '/bin/spack', 'commands', '--format=rst'] + list(
|
||||||
index.write(' * :ref:`%s`\n' % cmd)
|
documented_commands),
|
||||||
|
stdout=index)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run sphinx-apidoc
|
# Run sphinx-apidoc
|
||||||
|
@ -115,7 +119,7 @@
|
||||||
# This also avoids issues where some of these symbols shadow core spack
|
# This also avoids issues where some of these symbols shadow core spack
|
||||||
# modules. Sphinx will complain about duplicate docs when this happens.
|
# modules. Sphinx will complain about duplicate docs when this happens.
|
||||||
#
|
#
|
||||||
import fileinput, spack
|
import fileinput
|
||||||
handling_spack = False
|
handling_spack = False
|
||||||
for line in fileinput.input('spack.rst', inplace=1):
|
for line in fileinput.input('spack.rst', inplace=1):
|
||||||
if handling_spack:
|
if handling_spack:
|
||||||
|
|
222
lib/spack/llnl/util/argparsewriter.py
Normal file
222
lib/spack/llnl/util/argparsewriter.py
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/spack/spack
|
||||||
|
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
from __future__ import print_function
|
||||||
|
import re
|
||||||
|
import argparse
|
||||||
|
import errno
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class ArgparseWriter(object):
|
||||||
|
"""Analyzes an argparse ArgumentParser for easy generation of help."""
|
||||||
|
def __init__(self):
|
||||||
|
self.level = 0
|
||||||
|
|
||||||
|
def _write(self, parser, root=True, level=0):
|
||||||
|
self.parser = parser
|
||||||
|
self.level = level
|
||||||
|
actions = parser._actions
|
||||||
|
|
||||||
|
# allow root level to be flattened with rest of commands
|
||||||
|
if type(root) == int:
|
||||||
|
self.level = root
|
||||||
|
root = True
|
||||||
|
|
||||||
|
# go through actions and split them into optionals, positionals,
|
||||||
|
# and subcommands
|
||||||
|
optionals = []
|
||||||
|
positionals = []
|
||||||
|
subcommands = []
|
||||||
|
for action in actions:
|
||||||
|
if action.option_strings:
|
||||||
|
optionals.append(action)
|
||||||
|
elif isinstance(action, argparse._SubParsersAction):
|
||||||
|
for subaction in action._choices_actions:
|
||||||
|
subparser = action._name_parser_map[subaction.dest]
|
||||||
|
subcommands.append(subparser)
|
||||||
|
else:
|
||||||
|
positionals.append(action)
|
||||||
|
|
||||||
|
groups = parser._mutually_exclusive_groups
|
||||||
|
fmt = parser._get_formatter()
|
||||||
|
description = parser.description
|
||||||
|
|
||||||
|
def action_group(function, actions):
|
||||||
|
for action in actions:
|
||||||
|
arg = fmt._format_action_invocation(action)
|
||||||
|
help = action.help if action.help else ''
|
||||||
|
function(arg, re.sub('\n', ' ', help))
|
||||||
|
|
||||||
|
if root:
|
||||||
|
self.begin_command(parser.prog)
|
||||||
|
|
||||||
|
if description:
|
||||||
|
self.description(parser.description)
|
||||||
|
|
||||||
|
usage = fmt._format_usage(None, actions, groups, '').strip()
|
||||||
|
self.usage(usage)
|
||||||
|
|
||||||
|
if positionals:
|
||||||
|
self.begin_positionals()
|
||||||
|
action_group(self.positional, positionals)
|
||||||
|
self.end_positionals()
|
||||||
|
|
||||||
|
if optionals:
|
||||||
|
self.begin_optionals()
|
||||||
|
action_group(self.optional, optionals)
|
||||||
|
self.end_optionals()
|
||||||
|
|
||||||
|
if subcommands:
|
||||||
|
self.begin_subcommands(subcommands)
|
||||||
|
for subparser in subcommands:
|
||||||
|
self._write(subparser, root=True, level=level + 1)
|
||||||
|
self.end_subcommands(subcommands)
|
||||||
|
|
||||||
|
if root:
|
||||||
|
self.end_command(parser.prog)
|
||||||
|
|
||||||
|
def write(self, parser, root=True):
|
||||||
|
"""Write out details about an ArgumentParser.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parser (ArgumentParser): an ``argparse`` parser
|
||||||
|
root (bool or int): if bool, whether to include the root parser;
|
||||||
|
or ``1`` to flatten the root parser with first-level
|
||||||
|
subcommands
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self._write(parser, root, level=0)
|
||||||
|
except IOError as e:
|
||||||
|
# swallow pipe errors
|
||||||
|
if e.errno != errno.EPIPE:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def begin_command(self, prog):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def end_command(self, prog):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def description(self, description):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def usage(self, usage):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def begin_positionals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def positional(self, name, help):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def end_positionals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def begin_optionals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def optional(self, option, help):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def end_optionals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def begin_subcommands(self, subcommands):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def end_subcommands(self, subcommands):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_rst_levels = ['=', '-', '^', '~', ':', '`']
|
||||||
|
|
||||||
|
|
||||||
|
class ArgparseRstWriter(ArgparseWriter):
|
||||||
|
"""Write argparse output as rst sections."""
|
||||||
|
|
||||||
|
def __init__(self, out=sys.stdout, rst_levels=_rst_levels,
|
||||||
|
strip_root_prog=True):
|
||||||
|
"""Create a new ArgparseRstWriter.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
out (file object): file to write to
|
||||||
|
rst_levels (list of str): list of characters
|
||||||
|
for rst section headings
|
||||||
|
strip_root_prog (bool): if ``True``, strip the base command name
|
||||||
|
from subcommands in output
|
||||||
|
"""
|
||||||
|
super(ArgparseWriter, self).__init__()
|
||||||
|
self.out = out
|
||||||
|
self.rst_levels = rst_levels
|
||||||
|
self.strip_root_prog = strip_root_prog
|
||||||
|
|
||||||
|
def line(self, string=''):
|
||||||
|
self.out.write('%s\n' % string)
|
||||||
|
|
||||||
|
def begin_command(self, prog):
|
||||||
|
self.line()
|
||||||
|
self.line('----')
|
||||||
|
self.line()
|
||||||
|
self.line('.. _%s:\n' % prog.replace(' ', '-'))
|
||||||
|
self.line('%s' % prog)
|
||||||
|
self.line(self.rst_levels[self.level] * len(prog) + '\n')
|
||||||
|
|
||||||
|
def description(self, description):
|
||||||
|
self.line('%s\n' % description)
|
||||||
|
|
||||||
|
def usage(self, usage):
|
||||||
|
self.line('.. code-block:: console\n')
|
||||||
|
self.line(' %s\n' % usage)
|
||||||
|
|
||||||
|
def begin_positionals(self):
|
||||||
|
self.line()
|
||||||
|
self.line('**Positional arguments**\n')
|
||||||
|
|
||||||
|
def positional(self, name, help):
|
||||||
|
self.line(name)
|
||||||
|
self.line(' %s\n' % help)
|
||||||
|
|
||||||
|
def begin_optionals(self):
|
||||||
|
self.line()
|
||||||
|
self.line('**Optional arguments**\n')
|
||||||
|
|
||||||
|
def optional(self, opts, help):
|
||||||
|
self.line('``%s``' % opts)
|
||||||
|
self.line(' %s\n' % help)
|
||||||
|
|
||||||
|
def begin_subcommands(self, subcommands):
|
||||||
|
self.line()
|
||||||
|
self.line('**Subcommands**\n')
|
||||||
|
self.line('.. hlist::')
|
||||||
|
self.line(' :columns: 4\n')
|
||||||
|
|
||||||
|
for cmd in subcommands:
|
||||||
|
prog = cmd.prog
|
||||||
|
if self.strip_root_prog:
|
||||||
|
prog = re.sub(r'^[^ ]* ', '', prog)
|
||||||
|
|
||||||
|
self.line(' * :ref:`%s <%s>`'
|
||||||
|
% (prog, cmd.prog.replace(' ', '-')))
|
||||||
|
self.line()
|
|
@ -45,6 +45,7 @@
|
||||||
# Commands that modify configuration by default modify the *highest*
|
# Commands that modify configuration by default modify the *highest*
|
||||||
# priority scope.
|
# priority scope.
|
||||||
default_modify_scope = spack.config.highest_precedence_scope().name
|
default_modify_scope = spack.config.highest_precedence_scope().name
|
||||||
|
|
||||||
# Commands that list configuration list *all* scopes by default.
|
# Commands that list configuration list *all* scopes by default.
|
||||||
default_list_scope = None
|
default_list_scope = None
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@
|
||||||
command_path = os.path.join(spack.lib_path, "spack", "cmd")
|
command_path = os.path.join(spack.lib_path, "spack", "cmd")
|
||||||
|
|
||||||
#: Names of all commands
|
#: Names of all commands
|
||||||
commands = []
|
all_commands = []
|
||||||
|
|
||||||
|
|
||||||
def python_name(cmd_name):
|
def python_name(cmd_name):
|
||||||
|
@ -76,8 +77,8 @@ def cmd_name(python_name):
|
||||||
for file in os.listdir(command_path):
|
for file in os.listdir(command_path):
|
||||||
if file.endswith(".py") and not re.search(ignore_files, file):
|
if file.endswith(".py") and not re.search(ignore_files, file):
|
||||||
cmd = re.sub(r'.py$', '', file)
|
cmd = re.sub(r'.py$', '', file)
|
||||||
commands.append(cmd_name(cmd))
|
all_commands.append(cmd_name(cmd))
|
||||||
commands.sort()
|
all_commands.sort()
|
||||||
|
|
||||||
|
|
||||||
def remove_options(parser, *options):
|
def remove_options(parser, *options):
|
||||||
|
|
142
lib/spack/spack/cmd/commands.py
Normal file
142
lib/spack/spack/cmd/commands.py
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/spack/spack
|
||||||
|
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from llnl.util.argparsewriter import ArgparseWriter, ArgparseRstWriter
|
||||||
|
|
||||||
|
import spack.main
|
||||||
|
from spack.main import section_descriptions
|
||||||
|
|
||||||
|
|
||||||
|
description = "list available spack commands"
|
||||||
|
section = "developer"
|
||||||
|
level = "long"
|
||||||
|
|
||||||
|
|
||||||
|
#: list of command formatters
|
||||||
|
formatters = {}
|
||||||
|
|
||||||
|
|
||||||
|
def formatter(func):
|
||||||
|
"""Decorator used to register formatters"""
|
||||||
|
formatters[func.__name__] = func
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def setup_parser(subparser):
|
||||||
|
subparser.add_argument(
|
||||||
|
'--format', default='names', choices=formatters,
|
||||||
|
help='format to be used to print the output (default: names)')
|
||||||
|
subparser.add_argument(
|
||||||
|
'documented_commands', nargs=argparse.REMAINDER,
|
||||||
|
help='list of documented commands to cross-references')
|
||||||
|
|
||||||
|
|
||||||
|
class SpackArgparseRstWriter(ArgparseRstWriter):
|
||||||
|
"""RST writer tailored for spack documentation."""
|
||||||
|
|
||||||
|
def __init__(self, documented_commands, out=sys.stdout):
|
||||||
|
super(SpackArgparseRstWriter, self).__init__(out)
|
||||||
|
self.documented = documented_commands if documented_commands else []
|
||||||
|
|
||||||
|
def usage(self, *args):
|
||||||
|
super(SpackArgparseRstWriter, self).usage(*args)
|
||||||
|
cmd = re.sub(' ', '-', self.parser.prog)
|
||||||
|
if cmd in self.documented:
|
||||||
|
self.line()
|
||||||
|
self.line(':ref:`More documentation <cmd-%s>`' % cmd)
|
||||||
|
|
||||||
|
|
||||||
|
class SubcommandWriter(ArgparseWriter):
|
||||||
|
def begin_command(self, prog):
|
||||||
|
print(' ' * self.level + prog)
|
||||||
|
|
||||||
|
|
||||||
|
@formatter
|
||||||
|
def subcommands(args):
|
||||||
|
parser = spack.main.make_argument_parser()
|
||||||
|
spack.main.add_all_commands(parser)
|
||||||
|
SubcommandWriter().write(parser)
|
||||||
|
|
||||||
|
|
||||||
|
def rst_index(out=sys.stdout):
|
||||||
|
out.write('\n')
|
||||||
|
|
||||||
|
index = spack.main.index_commands()
|
||||||
|
sections = index['long']
|
||||||
|
|
||||||
|
dmax = max(len(section_descriptions.get(s, s)) for s in sections) + 2
|
||||||
|
cmax = max(len(c) for _, c in sections.items()) + 60
|
||||||
|
|
||||||
|
row = "%s %s\n" % ('=' * dmax, '=' * cmax)
|
||||||
|
line = '%%-%ds %%s\n' % dmax
|
||||||
|
|
||||||
|
out.write(row)
|
||||||
|
out.write(line % (" Category ", " Commands "))
|
||||||
|
out.write(row)
|
||||||
|
for section, commands in sorted(sections.items()):
|
||||||
|
description = section_descriptions.get(section, section)
|
||||||
|
|
||||||
|
for i, cmd in enumerate(sorted(commands)):
|
||||||
|
description = description.capitalize() if i == 0 else ''
|
||||||
|
ref = ':ref:`%s <spack-%s>`' % (cmd, cmd)
|
||||||
|
comma = ',' if i != len(commands) - 1 else ''
|
||||||
|
bar = '| ' if i % 8 == 0 else ' '
|
||||||
|
out.write(line % (description, bar + ref + comma))
|
||||||
|
out.write(row)
|
||||||
|
|
||||||
|
|
||||||
|
@formatter
|
||||||
|
def rst(args):
|
||||||
|
# print an index to each command
|
||||||
|
rst_index()
|
||||||
|
print()
|
||||||
|
|
||||||
|
# create a parser with all commands
|
||||||
|
parser = spack.main.make_argument_parser()
|
||||||
|
spack.main.add_all_commands(parser)
|
||||||
|
|
||||||
|
# get documented commands from the command line
|
||||||
|
documented_commands = set(args.documented_commands)
|
||||||
|
|
||||||
|
# print sections for each command and subcommand
|
||||||
|
SpackArgparseRstWriter(documented_commands).write(parser, root=1)
|
||||||
|
|
||||||
|
|
||||||
|
@formatter
|
||||||
|
def names(args):
|
||||||
|
for cmd in spack.cmd.all_commands:
|
||||||
|
print(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def commands(parser, args):
|
||||||
|
|
||||||
|
# Print to stdout
|
||||||
|
formatters[args.format](args)
|
||||||
|
return
|
|
@ -100,14 +100,14 @@ def set_working_dir():
|
||||||
|
|
||||||
def add_all_commands(parser):
|
def add_all_commands(parser):
|
||||||
"""Add all spack subcommands to the parser."""
|
"""Add all spack subcommands to the parser."""
|
||||||
for cmd in spack.cmd.commands:
|
for cmd in spack.cmd.all_commands:
|
||||||
parser.add_command(cmd)
|
parser.add_command(cmd)
|
||||||
|
|
||||||
|
|
||||||
def index_commands():
|
def index_commands():
|
||||||
"""create an index of commands by section for this help level"""
|
"""create an index of commands by section for this help level"""
|
||||||
index = {}
|
index = {}
|
||||||
for command in spack.cmd.commands:
|
for command in spack.cmd.all_commands:
|
||||||
cmd_module = spack.cmd.get_module(command)
|
cmd_module = spack.cmd.get_module(command)
|
||||||
|
|
||||||
# make sure command modules have required properties
|
# make sure command modules have required properties
|
||||||
|
@ -166,7 +166,7 @@ def format_help_sections(self, level):
|
||||||
self.actions = self._subparsers._actions[-1]._get_subactions()
|
self.actions = self._subparsers._actions[-1]._get_subactions()
|
||||||
|
|
||||||
# make a set of commands not yet added.
|
# make a set of commands not yet added.
|
||||||
remaining = set(spack.cmd.commands)
|
remaining = set(spack.cmd.all_commands)
|
||||||
|
|
||||||
def add_group(group):
|
def add_group(group):
|
||||||
formatter.start_section(group.title)
|
formatter.start_section(group.title)
|
||||||
|
|
70
lib/spack/spack/test/cmd/commands.py
Normal file
70
lib/spack/spack/test/cmd/commands.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/spack/spack
|
||||||
|
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
import re
|
||||||
|
|
||||||
|
from llnl.util.argparsewriter import ArgparseWriter
|
||||||
|
|
||||||
|
import spack.cmd
|
||||||
|
import spack.main
|
||||||
|
from spack.main import SpackCommand
|
||||||
|
|
||||||
|
commands = SpackCommand('commands')
|
||||||
|
|
||||||
|
parser = spack.main.make_argument_parser()
|
||||||
|
spack.main.add_all_commands(parser)
|
||||||
|
|
||||||
|
|
||||||
|
def test_commands_by_name():
|
||||||
|
"""Test default output of spack commands."""
|
||||||
|
out = commands()
|
||||||
|
assert out.strip().split('\n') == sorted(spack.cmd.all_commands)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subcommands():
|
||||||
|
"""Test subcommand traversal."""
|
||||||
|
out = commands('--format=subcommands')
|
||||||
|
assert 'spack mirror create' in out
|
||||||
|
assert 'spack buildcache list' in out
|
||||||
|
assert 'spack repo add' in out
|
||||||
|
assert 'spack pkg diff' in out
|
||||||
|
assert 'spack url parse' in out
|
||||||
|
assert 'spack view symlink' in out
|
||||||
|
|
||||||
|
class Subcommands(ArgparseWriter):
|
||||||
|
def begin_command(self, prog):
|
||||||
|
assert prog in out
|
||||||
|
|
||||||
|
Subcommands().write(parser)
|
||||||
|
|
||||||
|
|
||||||
|
def test_rst():
|
||||||
|
"""Do some simple sanity checks of the rst writer."""
|
||||||
|
out = commands('--format=rst')
|
||||||
|
|
||||||
|
class Subcommands(ArgparseWriter):
|
||||||
|
def begin_command(self, prog):
|
||||||
|
assert prog in out
|
||||||
|
assert re.sub(r' ', '-', prog) in out
|
||||||
|
Subcommands().write(parser)
|
Loading…
Reference in a new issue