__init__.py 10 KB

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