|
1 |
| -#!/usr/bin/env python |
2 |
| -from __future__ import absolute_import |
3 |
| - |
4 |
| -import locale |
5 |
| -import logging |
6 |
| -import os |
7 |
| -import optparse |
8 |
| -import warnings |
9 |
| - |
10 |
| -import sys |
11 |
| -import re |
12 |
| - |
13 |
| -# 2016-06-17 [email protected]: urllib3 1.14 added optional support for socks, |
14 |
| -# but if invoked (i.e. imported), it will issue a warning to stderr if socks |
15 |
| -# isn't available. requests unconditionally imports urllib3's socks contrib |
16 |
| -# module, triggering this warning. The warning breaks DEP-8 tests (because of |
17 |
| -# the stderr output) and is just plain annoying in normal usage. I don't want |
18 |
| -# to add socks as yet another dependency for pip, nor do I want to allow-stder |
19 |
| -# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to |
20 |
| -# be done before the import of pip9.vcs. |
21 |
| -from pip9._vendor.urllib3.exceptions import DependencyWarning |
22 |
| -warnings.filterwarnings("ignore", category=DependencyWarning) # noqa |
23 |
| - |
24 |
| -# We want to inject the use of SecureTransport as early as possible so that any |
25 |
| -# references or sessions or what have you are ensured to have it, however we |
26 |
| -# only want to do this in the case that we're running on macOS and the linked |
27 |
| -# OpenSSL is too old to handle TLSv1.2 |
28 |
| -try: |
29 |
| - import ssl |
30 |
| -except ImportError: |
31 |
| - pass |
32 |
| -else: |
33 |
| - if (sys.platform == "darwin" and |
34 |
| - getattr(ssl, "OPENSSL_VERSION_NUMBER", 0) < 0x1000100f): # OpenSSL 1.0.1 |
35 |
| - try: |
36 |
| - from pip9._vendor.urllib3.contrib import securetransport |
37 |
| - except (ImportError, OSError): |
38 |
| - pass |
39 |
| - else: |
40 |
| - securetransport.inject_into_urllib3() |
41 |
| - |
42 |
| -from pip9.exceptions import InstallationError, CommandError, PipError |
43 |
| -from pip9.utils import get_installed_distributions, get_prog |
44 |
| -from pip9.utils import deprecation, dist_is_editable |
45 |
| -from pip9.vcs import git, mercurial, subversion, bazaar # noqa |
46 |
| -from pip9.baseparser import ConfigOptionParser, UpdatingDefaultsHelpFormatter |
47 |
| -from pip9.commands import get_summaries, get_similar_commands |
48 |
| -from pip9.commands import commands_dict |
49 |
| -from pip9._vendor.urllib3.exceptions import InsecureRequestWarning |
50 |
| - |
51 |
| - |
52 |
| -# assignment for flake8 to be happy |
53 |
| - |
54 |
| -# This fixes a peculiarity when importing via __import__ - as we are |
55 |
| -# initialising the pip module, "from pip9.import cmdoptions" is recursive |
56 |
| -# and appears not to work properly in that situation. |
57 |
| -import pip9.cmdoptions |
58 |
| -cmdoptions = pip9.cmdoptions |
59 |
| - |
60 |
| -# The version as used in the setup.py and the docs conf.py |
61 |
| -__version__ = "9.0.3" |
62 |
| - |
63 |
| - |
64 |
| -logger = logging.getLogger(__name__) |
65 |
| - |
66 |
| -# Hide the InsecureRequestWarning from urllib3 |
67 |
| -warnings.filterwarnings("ignore", category=InsecureRequestWarning) |
68 |
| - |
69 |
| - |
70 |
| -def autocomplete(): |
71 |
| - """Command and option completion for the main option parser (and options) |
72 |
| - and its subcommands (and options). |
73 |
| -
|
74 |
| - Enable by sourcing one of the completion shell scripts (bash, zsh or fish). |
75 |
| - """ |
76 |
| - # Don't complete if user hasn't sourced bash_completion file. |
77 |
| - if 'PIP_AUTO_COMPLETE' not in os.environ: |
78 |
| - return |
79 |
| - cwords = os.environ['COMP_WORDS'].split()[1:] |
80 |
| - cword = int(os.environ['COMP_CWORD']) |
81 |
| - try: |
82 |
| - current = cwords[cword - 1] |
83 |
| - except IndexError: |
84 |
| - current = '' |
85 |
| - |
86 |
| - subcommands = [cmd for cmd, summary in get_summaries()] |
87 |
| - options = [] |
88 |
| - # subcommand |
89 |
| - try: |
90 |
| - subcommand_name = [w for w in cwords if w in subcommands][0] |
91 |
| - except IndexError: |
92 |
| - subcommand_name = None |
93 |
| - |
94 |
| - parser = create_main_parser() |
95 |
| - # subcommand options |
96 |
| - if subcommand_name: |
97 |
| - # special case: 'help' subcommand has no options |
98 |
| - if subcommand_name == 'help': |
99 |
| - sys.exit(1) |
100 |
| - # special case: list locally installed dists for uninstall command |
101 |
| - if subcommand_name == 'uninstall' and not current.startswith('-'): |
102 |
| - installed = [] |
103 |
| - lc = current.lower() |
104 |
| - for dist in get_installed_distributions(local_only=True): |
105 |
| - if dist.key.startswith(lc) and dist.key not in cwords[1:]: |
106 |
| - installed.append(dist.key) |
107 |
| - # if there are no dists installed, fall back to option completion |
108 |
| - if installed: |
109 |
| - for dist in installed: |
110 |
| - print(dist) |
111 |
| - sys.exit(1) |
112 |
| - |
113 |
| - subcommand = commands_dict[subcommand_name]() |
114 |
| - options += [(opt.get_opt_string(), opt.nargs) |
115 |
| - for opt in subcommand.parser.option_list_all |
116 |
| - if opt.help != optparse.SUPPRESS_HELP] |
117 |
| - |
118 |
| - # filter out previously specified options from available options |
119 |
| - prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] |
120 |
| - options = [(x, v) for (x, v) in options if x not in prev_opts] |
121 |
| - # filter options by current input |
122 |
| - options = [(k, v) for k, v in options if k.startswith(current)] |
123 |
| - for option in options: |
124 |
| - opt_label = option[0] |
125 |
| - # append '=' to options which require args |
126 |
| - if option[1]: |
127 |
| - opt_label += '=' |
128 |
| - print(opt_label) |
129 |
| - else: |
130 |
| - # show main parser options only when necessary |
131 |
| - if current.startswith('-') or current.startswith('--'): |
132 |
| - opts = [i.option_list for i in parser.option_groups] |
133 |
| - opts.append(parser.option_list) |
134 |
| - opts = (o for it in opts for o in it) |
135 |
| - |
136 |
| - subcommands += [i.get_opt_string() for i in opts |
137 |
| - if i.help != optparse.SUPPRESS_HELP] |
138 |
| - |
139 |
| - print(' '.join([x for x in subcommands if x.startswith(current)])) |
140 |
| - sys.exit(1) |
141 |
| - |
142 |
| - |
143 |
| -def create_main_parser(): |
144 |
| - parser_kw = { |
145 |
| - 'usage': '\n%prog <command> [options]', |
146 |
| - 'add_help_option': False, |
147 |
| - 'formatter': UpdatingDefaultsHelpFormatter(), |
148 |
| - 'name': 'global', |
149 |
| - 'prog': get_prog(), |
150 |
| - } |
151 |
| - |
152 |
| - parser = ConfigOptionParser(**parser_kw) |
153 |
| - parser.disable_interspersed_args() |
154 |
| - |
155 |
| - pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
156 |
| - parser.version = 'pip %s from %s (python %s)' % ( |
157 |
| - __version__, pip_pkg_dir, sys.version[:3]) |
158 |
| - |
159 |
| - # add the general options |
160 |
| - gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) |
161 |
| - parser.add_option_group(gen_opts) |
162 |
| - |
163 |
| - parser.main = True # so the help formatter knows |
164 |
| - |
165 |
| - # create command listing for description |
166 |
| - command_summaries = get_summaries() |
167 |
| - description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] |
168 |
| - parser.description = '\n'.join(description) |
169 |
| - |
170 |
| - return parser |
171 |
| - |
172 |
| - |
173 |
| -def parseopts(args): |
174 |
| - parser = create_main_parser() |
175 |
| - |
176 |
| - # Note: parser calls disable_interspersed_args(), so the result of this |
177 |
| - # call is to split the initial args into the general options before the |
178 |
| - # subcommand and everything else. |
179 |
| - # For example: |
180 |
| - # args: ['--timeout=5', 'install', '--user', 'INITools'] |
181 |
| - # general_options: ['--timeout==5'] |
182 |
| - # args_else: ['install', '--user', 'INITools'] |
183 |
| - general_options, args_else = parser.parse_args(args) |
184 |
| - |
185 |
| - # --version |
186 |
| - if general_options.version: |
187 |
| - sys.stdout.write(parser.version) |
188 |
| - sys.stdout.write(os.linesep) |
189 |
| - sys.exit() |
190 |
| - |
191 |
| - # pip || pip help -> print_help() |
192 |
| - if not args_else or (args_else[0] == 'help' and len(args_else) == 1): |
193 |
| - parser.print_help() |
194 |
| - sys.exit() |
195 |
| - |
196 |
| - # the subcommand name |
197 |
| - cmd_name = args_else[0] |
198 |
| - |
199 |
| - if cmd_name not in commands_dict: |
200 |
| - guess = get_similar_commands(cmd_name) |
201 |
| - |
202 |
| - msg = ['unknown command "%s"' % cmd_name] |
203 |
| - if guess: |
204 |
| - msg.append('maybe you meant "%s"' % guess) |
205 |
| - |
206 |
| - raise CommandError(' - '.join(msg)) |
207 |
| - |
208 |
| - # all the args without the subcommand |
209 |
| - cmd_args = args[:] |
210 |
| - cmd_args.remove(cmd_name) |
211 |
| - |
212 |
| - return cmd_name, cmd_args |
213 |
| - |
214 |
| - |
215 |
| -def check_isolated(args): |
216 |
| - isolated = False |
217 |
| - |
218 |
| - if "--isolated" in args: |
219 |
| - isolated = True |
220 |
| - |
221 |
| - return isolated |
222 |
| - |
223 |
| - |
224 |
| -def main(args=None): |
225 |
| - if args is None: |
226 |
| - args = sys.argv[1:] |
227 |
| - |
228 |
| - # Configure our deprecation warnings to be sent through loggers |
229 |
| - deprecation.install_warning_logger() |
230 |
| - |
231 |
| - autocomplete() |
232 |
| - |
233 |
| - try: |
234 |
| - cmd_name, cmd_args = parseopts(args) |
235 |
| - except PipError as exc: |
236 |
| - sys.stderr.write("ERROR: %s" % exc) |
237 |
| - sys.stderr.write(os.linesep) |
238 |
| - sys.exit(1) |
239 |
| - |
240 |
| - # Needed for locale.getpreferredencoding(False) to work |
241 |
| - # in pip9.utils.encoding.auto_decode |
242 |
| - try: |
243 |
| - locale.setlocale(locale.LC_ALL, '') |
244 |
| - except locale.Error as e: |
245 |
| - # setlocale can apparently crash if locale are uninitialized |
246 |
| - logger.debug("Ignoring error %s when setting locale", e) |
247 |
| - command = commands_dict[cmd_name](isolated=check_isolated(cmd_args)) |
248 |
| - return command.main(cmd_args) |
249 |
| - |
250 |
| - |
251 |
| -# ########################################################### |
252 |
| -# # Writing freeze files |
253 |
| - |
254 |
| -class FrozenRequirement(object): |
255 |
| - |
256 |
| - def __init__(self, name, req, editable, comments=()): |
257 |
| - self.name = name |
258 |
| - self.req = req |
259 |
| - self.editable = editable |
260 |
| - self.comments = comments |
261 |
| - |
262 |
| - _rev_re = re.compile(r'-r(\d+)$') |
263 |
| - _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') |
264 |
| - |
265 |
| - @classmethod |
266 |
| - def from_dist(cls, dist, dependency_links): |
267 |
| - location = os.path.normcase(os.path.abspath(dist.location)) |
268 |
| - comments = [] |
269 |
| - from pip9.vcs import vcs, get_src_requirement |
270 |
| - if dist_is_editable(dist) and vcs.get_backend_name(location): |
271 |
| - editable = True |
272 |
| - try: |
273 |
| - req = get_src_requirement(dist, location) |
274 |
| - except InstallationError as exc: |
275 |
| - logger.warning( |
276 |
| - "Error when trying to get requirement for VCS system %s, " |
277 |
| - "falling back to uneditable format", exc |
278 |
| - ) |
279 |
| - req = None |
280 |
| - if req is None: |
281 |
| - logger.warning( |
282 |
| - 'Could not determine repository location of %s', location |
283 |
| - ) |
284 |
| - comments.append( |
285 |
| - '## !! Could not determine repository location' |
286 |
| - ) |
287 |
| - req = dist.as_requirement() |
288 |
| - editable = False |
289 |
| - else: |
290 |
| - editable = False |
291 |
| - req = dist.as_requirement() |
292 |
| - specs = req.specs |
293 |
| - assert len(specs) == 1 and specs[0][0] in ["==", "==="], \ |
294 |
| - 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \ |
295 |
| - (specs, dist) |
296 |
| - version = specs[0][1] |
297 |
| - ver_match = cls._rev_re.search(version) |
298 |
| - date_match = cls._date_re.search(version) |
299 |
| - if ver_match or date_match: |
300 |
| - svn_backend = vcs.get_backend('svn') |
301 |
| - if svn_backend: |
302 |
| - svn_location = svn_backend().get_location( |
303 |
| - dist, |
304 |
| - dependency_links, |
305 |
| - ) |
306 |
| - if not svn_location: |
307 |
| - logger.warning( |
308 |
| - 'Warning: cannot find svn location for %s', req) |
309 |
| - comments.append( |
310 |
| - '## FIXME: could not find svn URL in dependency_links ' |
311 |
| - 'for this package:' |
312 |
| - ) |
313 |
| - else: |
314 |
| - comments.append( |
315 |
| - '# Installing as editable to satisfy requirement %s:' % |
316 |
| - req |
317 |
| - ) |
318 |
| - if ver_match: |
319 |
| - rev = ver_match.group(1) |
320 |
| - else: |
321 |
| - rev = '{%s}' % date_match.group(1) |
322 |
| - editable = True |
323 |
| - req = '%s@%s#egg=%s' % ( |
324 |
| - svn_location, |
325 |
| - rev, |
326 |
| - cls.egg_name(dist) |
327 |
| - ) |
328 |
| - return cls(dist.project_name, req, editable, comments) |
329 |
| - |
330 |
| - @staticmethod |
331 |
| - def egg_name(dist): |
332 |
| - name = dist.egg_name() |
333 |
| - match = re.search(r'-py\d\.\d$', name) |
334 |
| - if match: |
335 |
| - name = name[:match.start()] |
336 |
| - return name |
337 |
| - |
338 |
| - def __str__(self): |
339 |
| - req = self.req |
340 |
| - if self.editable: |
341 |
| - req = '-e %s' % req |
342 |
| - return '\n'.join(list(self.comments) + [str(req)]) + '\n' |
343 |
| - |
344 |
| - |
345 |
| -if __name__ == '__main__': |
346 |
| - sys.exit(main()) |
| 1 | +__version__ = "10.0.1" |
0 commit comments