Skip to content

Commit 9e5f447

Browse files
authored
Merge pull request #523 from nerdvegas/issue_492
added support for different behavior of cli arg parsing, per subcommand
2 parents f83be6d + c419a3b commit 9e5f447

File tree

5 files changed

+98
-63
lines changed

5 files changed

+98
-63
lines changed

src/rez/cli/_main.py

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""
2-
The main command-line entry point.
3-
"""
1+
"""The main command-line entry point."""
42
import sys
53
from rez.vendor.argparse import _StoreTrueAction, SUPPRESS
64
from rez.cli._util import subcommands, LazyArgumentParser, _env_var_true
@@ -10,7 +8,8 @@
108

119

1210
class SetupRezSubParser(object):
13-
"""Callback class for lazily setting up rez sub-parsers."""
11+
"""Callback class for lazily setting up rez sub-parsers.
12+
"""
1413
def __init__(self, module_name):
1514
self.module_name = module_name
1615

@@ -86,28 +85,55 @@ def run(command=None):
8685
subparser = parser.add_subparsers(dest='cmd', metavar='COMMAND')
8786
for subcommand in subcommands:
8887
module_name = "rez.cli.%s" % subcommand
88+
8989
subparser.add_parser(
9090
subcommand,
9191
help='', # required so that it can be setup later
9292
setup_subparser=SetupRezSubParser(module_name))
9393

94-
# parse args, but split extras into groups separated by "--"
95-
all_args = ([command] + sys.argv[1:]) if command else sys.argv[1:]
96-
arg_groups = [[]]
97-
for arg in all_args:
98-
if arg == '--':
99-
arg_groups.append([])
100-
continue
101-
arg_groups[-1].append(arg)
102-
opts = parser.parse_args(arg_groups[0])
94+
# construct args list. Note that commands like 'rez-env foo' and
95+
# 'rez env foo' are equivalent
96+
if command:
97+
args = [command] + sys.argv[1:]
98+
elif len(sys.argv) > 1 and sys.argv[1] in subcommands:
99+
command = sys.argv[1]
100+
args = sys.argv[1:]
101+
else:
102+
args = sys.argv[1:]
103+
104+
# parse args depending on subcommand behaviour
105+
if command:
106+
arg_mode = subcommands[command].get("arg_mode")
107+
else:
108+
arg_mode = None
109+
110+
if arg_mode == "grouped":
111+
# args split into groups by '--'
112+
arg_groups = [[]]
113+
for arg in args:
114+
if arg == '--':
115+
arg_groups.append([])
116+
continue
117+
arg_groups[-1].append(arg)
118+
119+
opts = parser.parse_args(arg_groups[0])
120+
extra_arg_groups = arg_groups[1:]
121+
elif arg_mode == "passthrough":
122+
# unknown args passed in first extra_arg_group
123+
opts, extra_args = parser.parse_known_args(args)
124+
extra_arg_groups = [extra_args]
125+
else:
126+
# native arg parsing
127+
opts = parser.parse_args(args)
128+
extra_arg_groups = []
103129

104130
if opts.debug or _env_var_true("REZ_DEBUG"):
105131
exc_type = None
106132
else:
107133
exc_type = RezError
108134

109135
def run_cmd():
110-
return opts.func(opts, opts.parser, arg_groups[1:])
136+
return opts.func(opts, opts.parser, extra_arg_groups)
111137

112138
if opts.profile:
113139
import cProfile
@@ -120,7 +146,6 @@ def run_cmd():
120146
raise
121147
except exc_type as e:
122148
print_error("%s: %s" % (e.__class__.__name__, str(e)))
123-
#print >> sys.stderr, "rez: %s: %s" % (e.__class__.__name__, str(e))
124149
sys.exit(1)
125150

126151
sys.exit(returncode or 0)

src/rez/cli/_util.py

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,54 @@
55
ArgumentError
66

77

8-
subcommands = [
9-
"bind",
10-
"build",
11-
"config",
12-
"context",
13-
"complete",
14-
"depends",
15-
"env",
16-
"forward",
17-
"help",
18-
"interpret",
19-
"python",
20-
"plugins",
21-
"pip",
22-
"release",
23-
"search",
24-
"test",
25-
"view",
26-
"status",
27-
"suite",
28-
"memcache",
29-
"selftest",
30-
"yaml2py",
31-
"diff",
32-
"gui"]
33-
34-
35-
hidden_subcommands = [
36-
"complete",
37-
"forward"]
8+
# Subcommands and their behaviors.
9+
#
10+
# 'arg_mode' determines how cli args are parsed. Values are:
11+
# * 'grouped': Args can be separated by '--'. This causes args to be grouped into
12+
# lists which are then passed as 'extra_arg_groups' to each command.
13+
# * 'passthrough': Unknown args are passed as first list in 'extra_arg_groups'.
14+
# The '--' arg is not treated as a special case.
15+
# * missing: Native python argparse behavior.
16+
#
17+
subcommands = {
18+
"bind": {},
19+
"build": {
20+
"arg_mode": "grouped"
21+
},
22+
"config": {},
23+
"context": {},
24+
"complete": {
25+
"hidden": True
26+
},
27+
"depends": {},
28+
"diff": {},
29+
"env": {
30+
"arg_mode": "grouped"
31+
},
32+
"forward": {
33+
"hidden": True,
34+
"arg_mode": "passthrough"
35+
},
36+
"gui": {},
37+
"help": {},
38+
"interpret": {},
39+
"memcache": {},
40+
"pip": {},
41+
"plugins": {},
42+
"python": {
43+
"arg_mode": "passthrough"
44+
},
45+
"release": {
46+
"arg_mode": "grouped"
47+
},
48+
"search": {},
49+
"selftest": {},
50+
"status": {},
51+
"suite": {},
52+
"test": {},
53+
"view": {},
54+
"yaml2py": {},
55+
}
3856

3957

4058
class LazySubParsersAction(_SubParsersAction):

src/rez/cli/complete.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def setup_parser(parser, completions=False):
1212

1313

1414
def command(opts, parser, extra_arg_groups=None):
15-
from rez.cli._util import subcommands, hidden_subcommands
15+
from rez.cli._util import subcommands
1616
import os
1717
import re
1818

@@ -53,7 +53,8 @@ def _pop_arg(l, p):
5353
subcommand = cmd.split("-", 1)[-1]
5454

5555
if subcommand is None:
56-
cmds = set(subcommands) - set(hidden_subcommands)
56+
cmds = [k for k, v in subcommands.iteritems() if not v.get("hidden")]
57+
5758
if prefix:
5859
cmds = (x for x in cmds if x.startswith(prefix))
5960
print " ".join(cmds)

src/rez/cli/python.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
"""
22
Start a python interpreter or execute a python script within Rez's own execution context.
3+
4+
Unrecognised args are passed directly to the underlying python interpreter.
35
"""
46

57

68
def setup_parser(parser, completions=False):
7-
parser.add_argument(
8-
"-i", "--interactive", action="store_true",
9-
help="inspect interactively after FILE has run")
10-
FILE_action = parser.add_argument(
9+
file_action = parser.add_argument(
1110
"FILE", type=str, nargs='?',
1211
help='python script to execute')
13-
parser.add_argument(
14-
"ARG", type=str, nargs='*',
15-
help='arguments to python script')
16-
parser.add_argument('-c', help="python code to execute", dest='command')
1712

1813
if completions:
1914
from rez.cli._complete_util import FilesCompleter
20-
FILE_action.completer = FilesCompleter(dirs=False,
15+
file_action.completer = FilesCompleter(dirs=False,
2116
file_patterns=["*.py"])
2217

2318

@@ -27,15 +22,11 @@ def command(opts, parser, extra_arg_groups=None):
2722

2823
cmd = [sys.executable, "-E"]
2924

30-
if opts.interactive:
31-
cmd.append("-i")
32-
33-
if opts.command:
34-
cmd.extend(['-c', opts.command])
25+
for arg_group in (extra_arg_groups or []):
26+
cmd.extend(arg_group)
3527

3628
if opts.FILE:
3729
cmd.append(opts.FILE)
38-
cmd.extend(opts.ARG or [])
3930

4031
p = subprocess.Popen(cmd)
4132
sys.exit(p.wait())

src/rez/utils/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22

33
# Update this value to version up Rez. Do not place anything else in this file.
4-
_rez_version = "2.19.1"
4+
_rez_version = "2.20.0"
55

66
try:
77
from rez.vendor.version.version import Version

0 commit comments

Comments
 (0)