1"""
2shared options and groups
3
4The principle here is to define options once, but *not* instantiate them
5globally. One reason being that options with action='append' can carry state
6between parses. pip parses general options twice internally, and shouldn't
7pass on state. To be consistent, all options will follow this design.
8
9"""
10from __future__ import absolute_import
11
12from functools import partial
13from optparse import OptionGroup, SUPPRESS_HELP, Option
14import warnings
15
16from pip9.index import (
17    FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_binary,
18    fmt_ctl_no_use_wheel)
19from pip9.models import PyPI
20from pip9.locations import USER_CACHE_DIR, src_prefix
21from pip9.utils.hashes import STRONG_HASHES
22
23
24def make_option_group(group, parser):
25    """
26    Return an OptionGroup object
27    group  -- assumed to be dict with 'name' and 'options' keys
28    parser -- an optparse Parser
29    """
30    option_group = OptionGroup(parser, group['name'])
31    for option in group['options']:
32        option_group.add_option(option())
33    return option_group
34
35
36def resolve_wheel_no_use_binary(options):
37    if not options.use_wheel:
38        control = options.format_control
39        fmt_ctl_no_use_wheel(control)
40
41
42def check_install_build_global(options, check_options=None):
43    """Disable wheels if per-setup.py call options are set.
44
45    :param options: The OptionParser options to update.
46    :param check_options: The options to check, if not supplied defaults to
47        options.
48    """
49    if check_options is None:
50        check_options = options
51
52    def getname(n):
53        return getattr(check_options, n, None)
54    names = ["build_options", "global_options", "install_options"]
55    if any(map(getname, names)):
56        control = options.format_control
57        fmt_ctl_no_binary(control)
58        warnings.warn(
59            'Disabling all use of wheels due to the use of --build-options '
60            '/ --global-options / --install-options.', stacklevel=2)
61
62
63###########
64# options #
65###########
66
67help_ = partial(
68    Option,
69    '-h', '--help',
70    dest='help',
71    action='help',
72    help='Show help.')
73
74isolated_mode = partial(
75    Option,
76    "--isolated",
77    dest="isolated_mode",
78    action="store_true",
79    default=False,
80    help=(
81        "Run pip in an isolated mode, ignoring environment variables and user "
82        "configuration."
83    ),
84)
85
86require_virtualenv = partial(
87    Option,
88    # Run only if inside a virtualenv, bail if not.
89    '--require-virtualenv', '--require-venv',
90    dest='require_venv',
91    action='store_true',
92    default=False,
93    help=SUPPRESS_HELP)
94
95verbose = partial(
96    Option,
97    '-v', '--verbose',
98    dest='verbose',
99    action='count',
100    default=0,
101    help='Give more output. Option is additive, and can be used up to 3 times.'
102)
103
104version = partial(
105    Option,
106    '-V', '--version',
107    dest='version',
108    action='store_true',
109    help='Show version and exit.')
110
111quiet = partial(
112    Option,
113    '-q', '--quiet',
114    dest='quiet',
115    action='count',
116    default=0,
117    help=('Give less output. Option is additive, and can be used up to 3'
118          ' times (corresponding to WARNING, ERROR, and CRITICAL logging'
119          ' levels).')
120)
121
122log = partial(
123    Option,
124    "--log", "--log-file", "--local-log",
125    dest="log",
126    metavar="path",
127    help="Path to a verbose appending log."
128)
129
130no_input = partial(
131    Option,
132    # Don't ask for input
133    '--no-input',
134    dest='no_input',
135    action='store_true',
136    default=False,
137    help=SUPPRESS_HELP)
138
139proxy = partial(
140    Option,
141    '--proxy',
142    dest='proxy',
143    type='str',
144    default='',
145    help="Specify a proxy in the form [user:passwd@]proxy.server:port.")
146
147retries = partial(
148    Option,
149    '--retries',
150    dest='retries',
151    type='int',
152    default=5,
153    help="Maximum number of retries each connection should attempt "
154         "(default %default times).")
155
156timeout = partial(
157    Option,
158    '--timeout', '--default-timeout',
159    metavar='sec',
160    dest='timeout',
161    type='float',
162    default=15,
163    help='Set the socket timeout (default %default seconds).')
164
165default_vcs = partial(
166    Option,
167    # The default version control system for editables, e.g. 'svn'
168    '--default-vcs',
169    dest='default_vcs',
170    type='str',
171    default='',
172    help=SUPPRESS_HELP)
173
174skip_requirements_regex = partial(
175    Option,
176    # A regex to be used to skip requirements
177    '--skip-requirements-regex',
178    dest='skip_requirements_regex',
179    type='str',
180    default='',
181    help=SUPPRESS_HELP)
182
183
184def exists_action():
185    return Option(
186        # Option when path already exist
187        '--exists-action',
188        dest='exists_action',
189        type='choice',
190        choices=['s', 'i', 'w', 'b', 'a'],
191        default=[],
192        action='append',
193        metavar='action',
194        help="Default action when a path already exists: "
195        "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.")
196
197
198cert = partial(
199    Option,
200    '--cert',
201    dest='cert',
202    type='str',
203    metavar='path',
204    help="Path to alternate CA bundle.")
205
206client_cert = partial(
207    Option,
208    '--client-cert',
209    dest='client_cert',
210    type='str',
211    default=None,
212    metavar='path',
213    help="Path to SSL client certificate, a single file containing the "
214         "private key and the certificate in PEM format.")
215
216index_url = partial(
217    Option,
218    '-i', '--index-url', '--pypi-url',
219    dest='index_url',
220    metavar='URL',
221    default=PyPI.simple_url,
222    help="Base URL of Python Package Index (default %default). "
223         "This should point to a repository compliant with PEP 503 "
224         "(the simple repository API) or a local directory laid out "
225         "in the same format.")
226
227
228def extra_index_url():
229    return Option(
230        '--extra-index-url',
231        dest='extra_index_urls',
232        metavar='URL',
233        action='append',
234        default=[],
235        help="Extra URLs of package indexes to use in addition to "
236             "--index-url. Should follow the same rules as "
237             "--index-url."
238    )
239
240
241no_index = partial(
242    Option,
243    '--no-index',
244    dest='no_index',
245    action='store_true',
246    default=False,
247    help='Ignore package index (only looking at --find-links URLs instead).')
248
249
250def find_links():
251    return Option(
252        '-f', '--find-links',
253        dest='find_links',
254        action='append',
255        default=[],
256        metavar='url',
257        help="If a url or path to an html file, then parse for links to "
258             "archives. If a local path or file:// url that's a directory, "
259             "then look for archives in the directory listing.")
260
261
262def allow_external():
263    return Option(
264        "--allow-external",
265        dest="allow_external",
266        action="append",
267        default=[],
268        metavar="PACKAGE",
269        help=SUPPRESS_HELP,
270    )
271
272
273allow_all_external = partial(
274    Option,
275    "--allow-all-external",
276    dest="allow_all_external",
277    action="store_true",
278    default=False,
279    help=SUPPRESS_HELP,
280)
281
282
283def trusted_host():
284    return Option(
285        "--trusted-host",
286        dest="trusted_hosts",
287        action="append",
288        metavar="HOSTNAME",
289        default=[],
290        help="Mark this host as trusted, even though it does not have valid "
291             "or any HTTPS.",
292    )
293
294
295# Remove after 7.0
296no_allow_external = partial(
297    Option,
298    "--no-allow-external",
299    dest="allow_all_external",
300    action="store_false",
301    default=False,
302    help=SUPPRESS_HELP,
303)
304
305
306# Remove --allow-insecure after 7.0
307def allow_unsafe():
308    return Option(
309        "--allow-unverified", "--allow-insecure",
310        dest="allow_unverified",
311        action="append",
312        default=[],
313        metavar="PACKAGE",
314        help=SUPPRESS_HELP,
315    )
316
317# Remove after 7.0
318no_allow_unsafe = partial(
319    Option,
320    "--no-allow-insecure",
321    dest="allow_all_insecure",
322    action="store_false",
323    default=False,
324    help=SUPPRESS_HELP
325)
326
327# Remove after 1.5
328process_dependency_links = partial(
329    Option,
330    "--process-dependency-links",
331    dest="process_dependency_links",
332    action="store_true",
333    default=False,
334    help="Enable the processing of dependency links.",
335)
336
337
338def constraints():
339    return Option(
340        '-c', '--constraint',
341        dest='constraints',
342        action='append',
343        default=[],
344        metavar='file',
345        help='Constrain versions using the given constraints file. '
346        'This option can be used multiple times.')
347
348
349def requirements():
350    return Option(
351        '-r', '--requirement',
352        dest='requirements',
353        action='append',
354        default=[],
355        metavar='file',
356        help='Install from the given requirements file. '
357        'This option can be used multiple times.')
358
359
360def editable():
361    return Option(
362        '-e', '--editable',
363        dest='editables',
364        action='append',
365        default=[],
366        metavar='path/url',
367        help=('Install a project in editable mode (i.e. setuptools '
368              '"develop mode") from a local project path or a VCS url.'),
369    )
370
371src = partial(
372    Option,
373    '--src', '--source', '--source-dir', '--source-directory',
374    dest='src_dir',
375    metavar='dir',
376    default=src_prefix,
377    help='Directory to check out editable projects into. '
378    'The default in a virtualenv is "<venv path>/src". '
379    'The default for global installs is "<current dir>/src".'
380)
381
382# XXX: deprecated, remove in 9.0
383use_wheel = partial(
384    Option,
385    '--use-wheel',
386    dest='use_wheel',
387    action='store_true',
388    default=True,
389    help=SUPPRESS_HELP,
390)
391
392# XXX: deprecated, remove in 9.0
393no_use_wheel = partial(
394    Option,
395    '--no-use-wheel',
396    dest='use_wheel',
397    action='store_false',
398    default=True,
399    help=('Do not Find and prefer wheel archives when searching indexes and '
400          'find-links locations. DEPRECATED in favour of --no-binary.'),
401)
402
403
404def _get_format_control(values, option):
405    """Get a format_control object."""
406    return getattr(values, option.dest)
407
408
409def _handle_no_binary(option, opt_str, value, parser):
410    existing = getattr(parser.values, option.dest)
411    fmt_ctl_handle_mutual_exclude(
412        value, existing.no_binary, existing.only_binary)
413
414
415def _handle_only_binary(option, opt_str, value, parser):
416    existing = getattr(parser.values, option.dest)
417    fmt_ctl_handle_mutual_exclude(
418        value, existing.only_binary, existing.no_binary)
419
420
421def no_binary():
422    return Option(
423        "--no-binary", dest="format_control", action="callback",
424        callback=_handle_no_binary, type="str",
425        default=FormatControl(set(), set()),
426        help="Do not use binary packages. Can be supplied multiple times, and "
427             "each time adds to the existing value. Accepts either :all: to "
428             "disable all binary packages, :none: to empty the set, or one or "
429             "more package names with commas between them. Note that some "
430             "packages are tricky to compile and may fail to install when "
431             "this option is used on them.")
432
433
434def only_binary():
435    return Option(
436        "--only-binary", dest="format_control", action="callback",
437        callback=_handle_only_binary, type="str",
438        default=FormatControl(set(), set()),
439        help="Do not use source packages. Can be supplied multiple times, and "
440             "each time adds to the existing value. Accepts either :all: to "
441             "disable all source packages, :none: to empty the set, or one or "
442             "more package names with commas between them. Packages without "
443             "binary distributions will fail to install when this option is "
444             "used on them.")
445
446
447cache_dir = partial(
448    Option,
449    "--cache-dir",
450    dest="cache_dir",
451    default=USER_CACHE_DIR,
452    metavar="dir",
453    help="Store the cache data in <dir>."
454)
455
456no_cache = partial(
457    Option,
458    "--no-cache-dir",
459    dest="cache_dir",
460    action="store_false",
461    help="Disable the cache.",
462)
463
464no_deps = partial(
465    Option,
466    '--no-deps', '--no-dependencies',
467    dest='ignore_dependencies',
468    action='store_true',
469    default=False,
470    help="Don't install package dependencies.")
471
472build_dir = partial(
473    Option,
474    '-b', '--build', '--build-dir', '--build-directory',
475    dest='build_dir',
476    metavar='dir',
477    help='Directory to unpack packages into and build in.'
478)
479
480ignore_requires_python = partial(
481    Option,
482    '--ignore-requires-python',
483    dest='ignore_requires_python',
484    action='store_true',
485    help='Ignore the Requires-Python information.')
486
487install_options = partial(
488    Option,
489    '--install-option',
490    dest='install_options',
491    action='append',
492    metavar='options',
493    help="Extra arguments to be supplied to the setup.py install "
494         "command (use like --install-option=\"--install-scripts=/usr/local/"
495         "bin\"). Use multiple --install-option options to pass multiple "
496         "options to setup.py install. If you are using an option with a "
497         "directory path, be sure to use absolute path.")
498
499global_options = partial(
500    Option,
501    '--global-option',
502    dest='global_options',
503    action='append',
504    metavar='options',
505    help="Extra global options to be supplied to the setup.py "
506         "call before the install command.")
507
508no_clean = partial(
509    Option,
510    '--no-clean',
511    action='store_true',
512    default=False,
513    help="Don't clean up build directories.")
514
515pre = partial(
516    Option,
517    '--pre',
518    action='store_true',
519    default=False,
520    help="Include pre-release and development versions. By default, "
521         "pip only finds stable versions.")
522
523disable_pip_version_check = partial(
524    Option,
525    "--disable-pip-version-check",
526    dest="disable_pip_version_check",
527    action="store_true",
528    default=False,
529    help="Don't periodically check PyPI to determine whether a new version "
530         "of pip is available for download. Implied with --no-index.")
531
532# Deprecated, Remove later
533always_unzip = partial(
534    Option,
535    '-Z', '--always-unzip',
536    dest='always_unzip',
537    action='store_true',
538    help=SUPPRESS_HELP,
539)
540
541
542def _merge_hash(option, opt_str, value, parser):
543    """Given a value spelled "algo:digest", append the digest to a list
544    pointed to in a dict by the algo name."""
545    if not parser.values.hashes:
546        parser.values.hashes = {}
547    try:
548        algo, digest = value.split(':', 1)
549    except ValueError:
550        parser.error('Arguments to %s must be a hash name '
551                     'followed by a value, like --hash=sha256:abcde...' %
552                     opt_str)
553    if algo not in STRONG_HASHES:
554        parser.error('Allowed hash algorithms for %s are %s.' %
555                     (opt_str, ', '.join(STRONG_HASHES)))
556    parser.values.hashes.setdefault(algo, []).append(digest)
557
558
559hash = partial(
560    Option,
561    '--hash',
562    # Hash values eventually end up in InstallRequirement.hashes due to
563    # __dict__ copying in process_line().
564    dest='hashes',
565    action='callback',
566    callback=_merge_hash,
567    type='string',
568    help="Verify that the package's archive matches this "
569         'hash before installing. Example: --hash=sha256:abcdef...')
570
571
572require_hashes = partial(
573    Option,
574    '--require-hashes',
575    dest='require_hashes',
576    action='store_true',
577    default=False,
578    help='Require a hash to check each requirement against, for '
579         'repeatable installs. This option is implied when any package in a '
580         'requirements file has a --hash option.')
581
582
583##########
584# groups #
585##########
586
587general_group = {
588    'name': 'General Options',
589    'options': [
590        help_,
591        isolated_mode,
592        require_virtualenv,
593        verbose,
594        version,
595        quiet,
596        log,
597        no_input,
598        proxy,
599        retries,
600        timeout,
601        default_vcs,
602        skip_requirements_regex,
603        exists_action,
604        trusted_host,
605        cert,
606        client_cert,
607        cache_dir,
608        no_cache,
609        disable_pip_version_check,
610    ]
611}
612
613non_deprecated_index_group = {
614    'name': 'Package Index Options',
615    'options': [
616        index_url,
617        extra_index_url,
618        no_index,
619        find_links,
620        process_dependency_links,
621    ]
622}
623
624index_group = {
625    'name': 'Package Index Options (including deprecated options)',
626    'options': non_deprecated_index_group['options'] + [
627        allow_external,
628        allow_all_external,
629        no_allow_external,
630        allow_unsafe,
631        no_allow_unsafe,
632    ]
633}
634