baseparser.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. """Base option parser setup"""
  2. import sys
  3. import optparse
  4. import os
  5. import textwrap
  6. from distutils.util import strtobool
  7. from pip.backwardcompat import ConfigParser, string_types
  8. from pip.locations import default_config_file
  9. from pip.util import get_terminal_size, get_prog
  10. from pip._vendor import pkg_resources
  11. class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
  12. """A prettier/less verbose help formatter for optparse."""
  13. def __init__(self, *args, **kwargs):
  14. # help position must be aligned with __init__.parseopts.description
  15. kwargs['max_help_position'] = 30
  16. kwargs['indent_increment'] = 1
  17. kwargs['width'] = get_terminal_size()[0] - 2
  18. optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs)
  19. def format_option_strings(self, option):
  20. return self._format_option_strings(option, ' <%s>', ', ')
  21. def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '):
  22. """
  23. Return a comma-separated list of option strings and metavars.
  24. :param option: tuple of (short opt, long opt), e.g: ('-f', '--format')
  25. :param mvarfmt: metavar format string - evaluated as mvarfmt % metavar
  26. :param optsep: separator
  27. """
  28. opts = []
  29. if option._short_opts:
  30. opts.append(option._short_opts[0])
  31. if option._long_opts:
  32. opts.append(option._long_opts[0])
  33. if len(opts) > 1:
  34. opts.insert(1, optsep)
  35. if option.takes_value():
  36. metavar = option.metavar or option.dest.lower()
  37. opts.append(mvarfmt % metavar.lower())
  38. return ''.join(opts)
  39. def format_heading(self, heading):
  40. if heading == 'Options':
  41. return ''
  42. return heading + ':\n'
  43. def format_usage(self, usage):
  44. """
  45. Ensure there is only one newline between usage and the first heading
  46. if there is no description.
  47. """
  48. msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), " ")
  49. return msg
  50. def format_description(self, description):
  51. # leave full control over description to us
  52. if description:
  53. if hasattr(self.parser, 'main'):
  54. label = 'Commands'
  55. else:
  56. label = 'Description'
  57. #some doc strings have inital newlines, some don't
  58. description = description.lstrip('\n')
  59. #some doc strings have final newlines and spaces, some don't
  60. description = description.rstrip()
  61. #dedent, then reindent
  62. description = self.indent_lines(textwrap.dedent(description), " ")
  63. description = '%s:\n%s\n' % (label, description)
  64. return description
  65. else:
  66. return ''
  67. def format_epilog(self, epilog):
  68. # leave full control over epilog to us
  69. if epilog:
  70. return epilog
  71. else:
  72. return ''
  73. def indent_lines(self, text, indent):
  74. new_lines = [indent + line for line in text.split('\n')]
  75. return "\n".join(new_lines)
  76. class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
  77. """Custom help formatter for use in ConfigOptionParser that updates
  78. the defaults before expanding them, allowing them to show up correctly
  79. in the help listing"""
  80. def expand_default(self, option):
  81. if self.parser is not None:
  82. self.parser.update_defaults(self.parser.defaults)
  83. return optparse.IndentedHelpFormatter.expand_default(self, option)
  84. class CustomOptionParser(optparse.OptionParser):
  85. def insert_option_group(self, idx, *args, **kwargs):
  86. """Insert an OptionGroup at a given position."""
  87. group = self.add_option_group(*args, **kwargs)
  88. self.option_groups.pop()
  89. self.option_groups.insert(idx, group)
  90. return group
  91. @property
  92. def option_list_all(self):
  93. """Get a list of all options, including those in option groups."""
  94. res = self.option_list[:]
  95. for i in self.option_groups:
  96. res.extend(i.option_list)
  97. return res
  98. class ConfigOptionParser(CustomOptionParser):
  99. """Custom option parser which updates its defaults by checking the
  100. configuration files and environmental variables"""
  101. def __init__(self, *args, **kwargs):
  102. self.config = ConfigParser.RawConfigParser()
  103. self.name = kwargs.pop('name')
  104. self.files = self.get_config_files()
  105. if self.files:
  106. self.config.read(self.files)
  107. assert self.name
  108. optparse.OptionParser.__init__(self, *args, **kwargs)
  109. def get_config_files(self):
  110. config_file = os.environ.get('PIP_CONFIG_FILE', False)
  111. if config_file == os.devnull:
  112. return []
  113. if config_file and os.path.exists(config_file):
  114. return [config_file]
  115. return [default_config_file]
  116. def check_default(self, option, key, val):
  117. try:
  118. return option.check_value(key, val)
  119. except optparse.OptionValueError:
  120. e = sys.exc_info()[1]
  121. print("An error occurred during configuration: %s" % e)
  122. sys.exit(3)
  123. def update_defaults(self, defaults):
  124. """Updates the given defaults with values from the config files and
  125. the environ. Does a little special handling for certain types of
  126. options (lists)."""
  127. # Then go and look for the other sources of configuration:
  128. config = {}
  129. # 1. config files
  130. for section in ('global', self.name):
  131. config.update(self.normalize_keys(self.get_config_section(section)))
  132. # 2. environmental variables
  133. config.update(self.normalize_keys(self.get_environ_vars()))
  134. # Then set the options with those values
  135. for key, val in config.items():
  136. option = self.get_option(key)
  137. if option is not None:
  138. # ignore empty values
  139. if not val:
  140. continue
  141. if option.action in ('store_true', 'store_false', 'count'):
  142. val = strtobool(val)
  143. if option.action == 'append':
  144. val = val.split()
  145. val = [self.check_default(option, key, v) for v in val]
  146. else:
  147. val = self.check_default(option, key, val)
  148. defaults[option.dest] = val
  149. return defaults
  150. def normalize_keys(self, items):
  151. """Return a config dictionary with normalized keys regardless of
  152. whether the keys were specified in environment variables or in config
  153. files"""
  154. normalized = {}
  155. for key, val in items:
  156. key = key.replace('_', '-')
  157. if not key.startswith('--'):
  158. key = '--%s' % key # only prefer long opts
  159. normalized[key] = val
  160. return normalized
  161. def get_config_section(self, name):
  162. """Get a section of a configuration"""
  163. if self.config.has_section(name):
  164. return self.config.items(name)
  165. return []
  166. def get_environ_vars(self, prefix='PIP_'):
  167. """Returns a generator with all environmental vars with prefix PIP_"""
  168. for key, val in os.environ.items():
  169. if key.startswith(prefix):
  170. yield (key.replace(prefix, '').lower(), val)
  171. def get_default_values(self):
  172. """Overridding to make updating the defaults after instantiation of
  173. the option parser possible, update_defaults() does the dirty work."""
  174. if not self.process_default_values:
  175. # Old, pre-Optik 1.5 behaviour.
  176. return optparse.Values(self.defaults)
  177. defaults = self.update_defaults(self.defaults.copy()) # ours
  178. for option in self._get_all_options():
  179. default = defaults.get(option.dest)
  180. if isinstance(default, string_types):
  181. opt_str = option.get_opt_string()
  182. defaults[option.dest] = option.check_value(opt_str, default)
  183. return optparse.Values(defaults)
  184. def error(self, msg):
  185. self.print_usage(sys.stderr)
  186. self.exit(2, "%s\n" % msg)