You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

315 lines
10 KiB

  1. from __future__ import absolute_import
  2. import logging
  3. import os
  4. import optparse
  5. import warnings
  6. import sys
  7. import re
  8. from pip.exceptions import InstallationError, CommandError, PipError
  9. from pip.utils import get_installed_distributions, get_prog
  10. from pip.utils import deprecation
  11. from pip.vcs import git, mercurial, subversion, bazaar # noqa
  12. from pip.baseparser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
  13. from pip.commands import get_summaries, get_similar_commands
  14. from pip.commands import commands_dict
  15. from pip._vendor.requests.packages.urllib3.exceptions import (
  16. InsecureRequestWarning,
  17. )
  18. # assignment for flake8 to be happy
  19. # This fixes a peculiarity when importing via __import__ - as we are
  20. # initialising the pip module, "from pip import cmdoptions" is recursive
  21. # and appears not to work properly in that situation.
  22. import pip.cmdoptions
  23. cmdoptions = pip.cmdoptions
  24. # The version as used in the setup.py and the docs conf.py
  25. __version__ = "7.1.0"
  26. logger = logging.getLogger(__name__)
  27. # Hide the InsecureRequestWArning from urllib3
  28. warnings.filterwarnings("ignore", category=InsecureRequestWarning)
  29. def autocomplete():
  30. """Command and option completion for the main option parser (and options)
  31. and its subcommands (and options).
  32. Enable by sourcing one of the completion shell scripts (bash or zsh).
  33. """
  34. # Don't complete if user hasn't sourced bash_completion file.
  35. if 'PIP_AUTO_COMPLETE' not in os.environ:
  36. return
  37. cwords = os.environ['COMP_WORDS'].split()[1:]
  38. cword = int(os.environ['COMP_CWORD'])
  39. try:
  40. current = cwords[cword - 1]
  41. except IndexError:
  42. current = ''
  43. subcommands = [cmd for cmd, summary in get_summaries()]
  44. options = []
  45. # subcommand
  46. try:
  47. subcommand_name = [w for w in cwords if w in subcommands][0]
  48. except IndexError:
  49. subcommand_name = None
  50. parser = create_main_parser()
  51. # subcommand options
  52. if subcommand_name:
  53. # special case: 'help' subcommand has no options
  54. if subcommand_name == 'help':
  55. sys.exit(1)
  56. # special case: list locally installed dists for uninstall command
  57. if subcommand_name == 'uninstall' and not current.startswith('-'):
  58. installed = []
  59. lc = current.lower()
  60. for dist in get_installed_distributions(local_only=True):
  61. if dist.key.startswith(lc) and dist.key not in cwords[1:]:
  62. installed.append(dist.key)
  63. # if there are no dists installed, fall back to option completion
  64. if installed:
  65. for dist in installed:
  66. print(dist)
  67. sys.exit(1)
  68. subcommand = commands_dict[subcommand_name]()
  69. options += [(opt.get_opt_string(), opt.nargs)
  70. for opt in subcommand.parser.option_list_all
  71. if opt.help != optparse.SUPPRESS_HELP]
  72. # filter out previously specified options from available options
  73. prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]]
  74. options = [(x, v) for (x, v) in options if x not in prev_opts]
  75. # filter options by current input
  76. options = [(k, v) for k, v in options if k.startswith(current)]
  77. for option in options:
  78. opt_label = option[0]
  79. # append '=' to options which require args
  80. if option[1]:
  81. opt_label += '='
  82. print(opt_label)
  83. else:
  84. # show main parser options only when necessary
  85. if current.startswith('-') or current.startswith('--'):
  86. opts = [i.option_list for i in parser.option_groups]
  87. opts.append(parser.option_list)
  88. opts = (o for it in opts for o in it)
  89. subcommands += [i.get_opt_string() for i in opts
  90. if i.help != optparse.SUPPRESS_HELP]
  91. print(' '.join([x for x in subcommands if x.startswith(current)]))
  92. sys.exit(1)
  93. def create_main_parser():
  94. parser_kw = {
  95. 'usage': '\n%prog <command> [options]',
  96. 'add_help_option': False,
  97. 'formatter': UpdatingDefaultsHelpFormatter(),
  98. 'name': 'global',
  99. 'prog': get_prog(),
  100. }
  101. parser = ConfigOptionParser(**parser_kw)
  102. parser.disable_interspersed_args()
  103. pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  104. parser.version = 'pip %s from %s (python %s)' % (
  105. __version__, pip_pkg_dir, sys.version[:3])
  106. # add the general options
  107. gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
  108. parser.add_option_group(gen_opts)
  109. parser.main = True # so the help formatter knows
  110. # create command listing for description
  111. command_summaries = get_summaries()
  112. description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries]
  113. parser.description = '\n'.join(description)
  114. return parser
  115. def parseopts(args):
  116. parser = create_main_parser()
  117. # Note: parser calls disable_interspersed_args(), so the result of this
  118. # call is to split the initial args into the general options before the
  119. # subcommand and everything else.
  120. # For example:
  121. # args: ['--timeout=5', 'install', '--user', 'INITools']
  122. # general_options: ['--timeout==5']
  123. # args_else: ['install', '--user', 'INITools']
  124. general_options, args_else = parser.parse_args(args)
  125. # --version
  126. if general_options.version:
  127. sys.stdout.write(parser.version)
  128. sys.stdout.write(os.linesep)
  129. sys.exit()
  130. # pip || pip help -> print_help()
  131. if not args_else or (args_else[0] == 'help' and len(args_else) == 1):
  132. parser.print_help()
  133. sys.exit()
  134. # the subcommand name
  135. cmd_name = args_else[0]
  136. if cmd_name not in commands_dict:
  137. guess = get_similar_commands(cmd_name)
  138. msg = ['unknown command "%s"' % cmd_name]
  139. if guess:
  140. msg.append('maybe you meant "%s"' % guess)
  141. raise CommandError(' - '.join(msg))
  142. # all the args without the subcommand
  143. cmd_args = args[:]
  144. cmd_args.remove(cmd_name)
  145. return cmd_name, cmd_args
  146. def check_isolated(args):
  147. isolated = False
  148. if "--isolated" in args:
  149. isolated = True
  150. return isolated
  151. def main(args=None):
  152. if args is None:
  153. args = sys.argv[1:]
  154. # Enable our Deprecation Warnings
  155. for deprecation_warning in deprecation.DEPRECATIONS:
  156. warnings.simplefilter("default", deprecation_warning)
  157. # Configure our deprecation warnings to be sent through loggers
  158. deprecation.install_warning_logger()
  159. autocomplete()
  160. try:
  161. cmd_name, cmd_args = parseopts(args)
  162. except PipError as exc:
  163. sys.stderr.write("ERROR: %s" % exc)
  164. sys.stderr.write(os.linesep)
  165. sys.exit(1)
  166. command = commands_dict[cmd_name](isolated=check_isolated(cmd_args))
  167. return command.main(cmd_args)
  168. # ###########################################################
  169. # # Writing freeze files
  170. class FrozenRequirement(object):
  171. def __init__(self, name, req, editable, comments=()):
  172. self.name = name
  173. self.req = req
  174. self.editable = editable
  175. self.comments = comments
  176. _rev_re = re.compile(r'-r(\d+)$')
  177. _date_re = re.compile(r'-(20\d\d\d\d\d\d)$')
  178. @classmethod
  179. def from_dist(cls, dist, dependency_links, find_tags=False):
  180. location = os.path.normcase(os.path.abspath(dist.location))
  181. comments = []
  182. from pip.vcs import vcs, get_src_requirement
  183. if vcs.get_backend_name(location):
  184. editable = True
  185. try:
  186. req = get_src_requirement(dist, location, find_tags)
  187. except InstallationError as exc:
  188. logger.warning(
  189. "Error when trying to get requirement for VCS system %s, "
  190. "falling back to uneditable format", exc
  191. )
  192. req = None
  193. if req is None:
  194. logger.warning(
  195. 'Could not determine repository location of %s', location
  196. )
  197. comments.append(
  198. '## !! Could not determine repository location'
  199. )
  200. req = dist.as_requirement()
  201. editable = False
  202. else:
  203. editable = False
  204. req = dist.as_requirement()
  205. specs = req.specs
  206. assert len(specs) == 1 and specs[0][0] in ["==", "==="], \
  207. 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \
  208. (specs, dist)
  209. version = specs[0][1]
  210. ver_match = cls._rev_re.search(version)
  211. date_match = cls._date_re.search(version)
  212. if ver_match or date_match:
  213. svn_backend = vcs.get_backend('svn')
  214. if svn_backend:
  215. svn_location = svn_backend().get_location(
  216. dist,
  217. dependency_links,
  218. )
  219. if not svn_location:
  220. logger.warning(
  221. 'Warning: cannot find svn location for %s', req)
  222. comments.append(
  223. '## FIXME: could not find svn URL in dependency_links '
  224. 'for this package:'
  225. )
  226. else:
  227. comments.append(
  228. '# Installing as editable to satisfy requirement %s:' %
  229. req
  230. )
  231. if ver_match:
  232. rev = ver_match.group(1)
  233. else:
  234. rev = '{%s}' % date_match.group(1)
  235. editable = True
  236. req = '%s@%s#egg=%s' % (
  237. svn_location,
  238. rev,
  239. cls.egg_name(dist)
  240. )
  241. return cls(dist.project_name, req, editable, comments)
  242. @staticmethod
  243. def egg_name(dist):
  244. name = dist.egg_name()
  245. match = re.search(r'-py\d\.\d$', name)
  246. if match:
  247. name = name[:match.start()]
  248. return name
  249. def __str__(self):
  250. req = self.req
  251. if self.editable:
  252. req = '-e %s' % req
  253. return '\n'.join(list(self.comments) + [str(req)]) + '\n'
  254. if __name__ == '__main__':
  255. sys.exit(main())