|
8 | 8 | import os
|
9 | 9 | import re
|
10 | 10 | import shlex
|
11 |
| -import getopt |
| 11 | +import optparse |
12 | 12 |
|
13 | 13 | from pip._vendor.six.moves.urllib import parse as urllib_parse
|
14 | 14 | from pip._vendor.six.moves import filterfalse
|
|
17 | 17 | from pip.req.req_install import InstallRequirement
|
18 | 18 | from pip.exceptions import RequirementsFileParseError
|
19 | 19 | from pip.utils import normalize_name
|
| 20 | +from pip import cmdoptions |
20 | 21 |
|
21 | 22 |
|
| 23 | +# ---------------------------------------------------------------------------- |
22 | 24 | # Flags that don't take any options.
|
23 | 25 | parser_flags = set([
|
24 | 26 | '--no-index',
|
|
43 | 45 | '--no-allow-insecure', # Remove in 7.0
|
44 | 46 | ])
|
45 | 47 |
|
46 |
| -# The following options and flags can be used on requirement lines. |
47 |
| -# For example: INITools==0.2 --install-option="--prefix=/opt" |
48 |
| -parser_requirement_flags = set() |
49 |
| -parser_requirement_options = set([ |
50 |
| - '--install-option', |
51 |
| - '--global-option', |
52 |
| -]) |
| 48 | +# ---------------------------------------------------------------------------- |
| 49 | +# Requirement lines may take options. For example: |
| 50 | +# INITools==0.2 --install-option="--prefix=/opt" --global-option="-v" |
| 51 | +# We use optparse to reliably parse these lines. |
| 52 | +_req_parser = optparse.OptionParser(add_help_option=False) |
| 53 | +_req_parser.add_option(cmdoptions.install_options.make()) |
| 54 | +_req_parser.add_option(cmdoptions.global_options.make()) |
| 55 | +_req_parser.disable_interspersed_args() |
| 56 | + |
| 57 | +# By default optparse sys.exits on error occurs. We want to wrap that |
| 58 | +# in our own exception. |
| 59 | +def parser_exit(self, msg): |
| 60 | + raise RequirementsFileParseError(msg) |
| 61 | +_req_parser.exit = parser_exit |
| 62 | + |
| 63 | +# ---------------------------------------------------------------------------- |
| 64 | +# Pre-compiled regex. |
| 65 | +_scheme_re = re.compile(r'^(http|https|file):', re.I) |
| 66 | +_comment_re = re.compile(r'(^|\s)+#.*$') |
53 | 67 |
|
| 68 | +# ---------------------------------------------------------------------------- |
54 | 69 | # The types of lines understood by the requirements file parser.
|
55 | 70 | REQUIREMENT = 0
|
56 | 71 | REQUIREMENT_FILE = 1
|
|
59 | 74 | OPTION = 4
|
60 | 75 | IGNORE = 5
|
61 | 76 |
|
62 |
| -_scheme_re = re.compile(r'^(http|https|file):', re.I) |
63 |
| -_comment_re = re.compile(r'(^|\s)+#.*$') |
64 |
| - |
65 | 77 |
|
66 | 78 | def parse_requirements(filename, finder=None, comes_from=None, options=None, session=None):
|
67 | 79 | """
|
@@ -104,12 +116,6 @@ def parse_content(filename, content, finder=None, comes_from=None, options=None,
|
104 | 116 | # ---------------------------------------------------------------------
|
105 | 117 | if linetype == REQUIREMENT:
|
106 | 118 | req, opts = value
|
107 |
| - |
108 |
| - # InstallRequirement.install() expects these options to be lists. |
109 |
| - if opts: |
110 |
| - for opt in '--global-option', '--install-option': |
111 |
| - opts[opt] = shlex.split(opts[opt]) if opt in opts else [] |
112 |
| - |
113 | 119 | comes_from = '-r %s (line %s)' % (filename, line_number)
|
114 | 120 | isolated = options.isolated_mode if options else False
|
115 | 121 | yield InstallRequirement.from_line(
|
@@ -182,13 +188,10 @@ def parse_content(filename, content, finder=None, comes_from=None, options=None,
|
182 | 188 |
|
183 | 189 | def parse_line(line):
|
184 | 190 | if not line.startswith('-'):
|
| 191 | + # Split the requirements from the options. |
185 | 192 | if ' --' in line:
|
186 | 193 | req, opts = line.split(' --', 1)
|
187 |
| - opts = parse_requirement_options( |
188 |
| - '--%s' % opts, |
189 |
| - parser_requirement_flags, |
190 |
| - parser_requirement_options |
191 |
| - ) |
| 194 | + opts = parse_requirement_options('--%s' % opts) |
192 | 195 | else:
|
193 | 196 | req = line
|
194 | 197 | opts = {}
|
@@ -223,15 +226,20 @@ def parse_line(line):
|
223 | 226 | return IGNORE, line
|
224 | 227 |
|
225 | 228 |
|
226 |
| -def parse_requirement_options(req_line, flags=None, options=None): |
227 |
| - long_opts = [] |
228 |
| - if options: |
229 |
| - long_opts += ['%s=' % i.lstrip('-') for i in options] |
230 |
| - if flags: |
231 |
| - long_opts += [i.lstrip('-') for i in flags] |
| 229 | +def parse_requirement_options(args): |
| 230 | + args = shlex.split(args) |
| 231 | + opts, _ = _req_parser.parse_args(args) |
| 232 | + |
| 233 | + if opts.install_options: |
| 234 | + opts.install_options = flat_shlex_split(opts.install_options) |
| 235 | + if opts.global_options: |
| 236 | + opts.global_options = flat_shlex_split(opts.global_options) |
232 | 237 |
|
233 |
| - opts, _ = getopt.getopt(shlex.split(req_line), '', long_opts) |
234 |
| - return dict(opts) |
| 238 | + for opt, value in opts.__dict__.items(): |
| 239 | + if value is None: |
| 240 | + delattr(opts, opt) |
| 241 | + |
| 242 | + return opts.__dict__ |
235 | 243 |
|
236 | 244 |
|
237 | 245 | # -----------------------------------------------------------------------------
|
@@ -281,4 +289,12 @@ def partition_line(line):
|
281 | 289 | return firstword, rest
|
282 | 290 |
|
283 | 291 |
|
| 292 | +def flat_shlex_split(x): |
| 293 | + ''' |
| 294 | + >>> flat_shlex_split(['--one --two', '--three "4" --five']) |
| 295 | + ['--one', '--two', '--three', '4', '--five'] |
| 296 | + ''' |
| 297 | + return [j for i in x for j in shlex.split(i)] |
| 298 | + |
| 299 | + |
284 | 300 | __all__ = 'parse_requirements'
|
0 commit comments