1from __future__ import absolute_import 2 3import logging 4import os 5 6from pip._internal.cli import cmdoptions 7from pip._internal.cli.cmdoptions import make_target_python 8from pip._internal.cli.req_command import RequirementCommand, with_cleanup 9from pip._internal.cli.status_codes import SUCCESS 10from pip._internal.req.req_tracker import get_requirement_tracker 11from pip._internal.utils.misc import ensure_dir, normalize_path, write_output 12from pip._internal.utils.temp_dir import TempDirectory 13from pip._internal.utils.typing import MYPY_CHECK_RUNNING 14 15if MYPY_CHECK_RUNNING: 16 from optparse import Values 17 from typing import List 18 19logger = logging.getLogger(__name__) 20 21 22class DownloadCommand(RequirementCommand): 23 """ 24 Download packages from: 25 26 - PyPI (and other indexes) using requirement specifiers. 27 - VCS project urls. 28 - Local project directories. 29 - Local or remote source archives. 30 31 pip also supports downloading from "requirements files", which provide 32 an easy way to specify a whole environment to be downloaded. 33 """ 34 35 usage = """ 36 %prog [options] <requirement specifier> [package-index-options] ... 37 %prog [options] -r <requirements file> [package-index-options] ... 38 %prog [options] <vcs project url> ... 39 %prog [options] <local project path> ... 40 %prog [options] <archive url/path> ...""" 41 42 def add_options(self): 43 # type: () -> None 44 self.cmd_opts.add_option(cmdoptions.constraints()) 45 self.cmd_opts.add_option(cmdoptions.requirements()) 46 self.cmd_opts.add_option(cmdoptions.build_dir()) 47 self.cmd_opts.add_option(cmdoptions.no_deps()) 48 self.cmd_opts.add_option(cmdoptions.global_options()) 49 self.cmd_opts.add_option(cmdoptions.no_binary()) 50 self.cmd_opts.add_option(cmdoptions.only_binary()) 51 self.cmd_opts.add_option(cmdoptions.prefer_binary()) 52 self.cmd_opts.add_option(cmdoptions.src()) 53 self.cmd_opts.add_option(cmdoptions.pre()) 54 self.cmd_opts.add_option(cmdoptions.require_hashes()) 55 self.cmd_opts.add_option(cmdoptions.progress_bar()) 56 self.cmd_opts.add_option(cmdoptions.no_build_isolation()) 57 self.cmd_opts.add_option(cmdoptions.use_pep517()) 58 self.cmd_opts.add_option(cmdoptions.no_use_pep517()) 59 60 self.cmd_opts.add_option( 61 '-d', '--dest', '--destination-dir', '--destination-directory', 62 dest='download_dir', 63 metavar='dir', 64 default=os.curdir, 65 help=("Download packages into <dir>."), 66 ) 67 68 cmdoptions.add_target_python_options(self.cmd_opts) 69 70 index_opts = cmdoptions.make_option_group( 71 cmdoptions.index_group, 72 self.parser, 73 ) 74 75 self.parser.insert_option_group(0, index_opts) 76 self.parser.insert_option_group(0, self.cmd_opts) 77 78 @with_cleanup 79 def run(self, options, args): 80 # type: (Values, List[str]) -> int 81 82 options.ignore_installed = True 83 # editable doesn't really make sense for `pip download`, but the bowels 84 # of the RequirementSet code require that property. 85 options.editables = [] 86 87 cmdoptions.check_dist_restriction(options) 88 89 options.download_dir = normalize_path(options.download_dir) 90 ensure_dir(options.download_dir) 91 92 session = self.get_default_session(options) 93 94 target_python = make_target_python(options) 95 finder = self._build_package_finder( 96 options=options, 97 session=session, 98 target_python=target_python, 99 ) 100 101 req_tracker = self.enter_context(get_requirement_tracker()) 102 103 directory = TempDirectory( 104 delete=not options.no_clean, 105 kind="download", 106 globally_managed=True, 107 ) 108 109 reqs = self.get_requirements(args, options, finder, session) 110 111 preparer = self.make_requirement_preparer( 112 temp_build_dir=directory, 113 options=options, 114 req_tracker=req_tracker, 115 session=session, 116 finder=finder, 117 download_dir=options.download_dir, 118 use_user_site=False, 119 ) 120 121 resolver = self.make_resolver( 122 preparer=preparer, 123 finder=finder, 124 options=options, 125 py_version_info=options.python_version, 126 ) 127 128 self.trace_basic_info(finder) 129 130 requirement_set = resolver.resolve( 131 reqs, check_supported_wheels=True 132 ) 133 134 downloaded = [] # type: List[str] 135 for req in requirement_set.requirements.values(): 136 if req.satisfied_by is None: 137 assert req.name is not None 138 preparer.save_linked_requirement(req) 139 downloaded.append(req.name) 140 if downloaded: 141 write_output('Successfully downloaded %s', ' '.join(downloaded)) 142 143 return SUCCESS 144