__init__.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. from __future__ import absolute_import
  2. from collections import deque
  3. import contextlib
  4. import errno
  5. import io
  6. import locale
  7. # we have a submodule named 'logging' which would shadow this if we used the
  8. # regular name:
  9. import logging as std_logging
  10. import re
  11. import os
  12. import posixpath
  13. import shutil
  14. import stat
  15. import subprocess
  16. import sys
  17. import tarfile
  18. import zipfile
  19. from pip.exceptions import InstallationError
  20. from pip.compat import console_to_str, expanduser, stdlib_pkgs
  21. from pip.locations import (
  22. site_packages, user_site, running_under_virtualenv, virtualenv_no_global,
  23. write_delete_marker_file,
  24. )
  25. from pip._vendor import pkg_resources
  26. from pip._vendor.six.moves import input
  27. from pip._vendor.six import PY2
  28. from pip._vendor.retrying import retry
  29. if PY2:
  30. from io import BytesIO as StringIO
  31. else:
  32. from io import StringIO
  33. __all__ = ['rmtree', 'display_path', 'backup_dir',
  34. 'ask', 'splitext',
  35. 'format_size', 'is_installable_dir',
  36. 'is_svn_page', 'file_contents',
  37. 'split_leading_dir', 'has_leading_dir',
  38. 'normalize_path',
  39. 'renames', 'get_terminal_size', 'get_prog',
  40. 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess',
  41. 'captured_stdout', 'ensure_dir',
  42. 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS',
  43. 'get_installed_version']
  44. logger = std_logging.getLogger(__name__)
  45. BZ2_EXTENSIONS = ('.tar.bz2', '.tbz')
  46. XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', '.tar.lz', '.tar.lzma')
  47. ZIP_EXTENSIONS = ('.zip', '.whl')
  48. TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar')
  49. ARCHIVE_EXTENSIONS = (
  50. ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS)
  51. SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS
  52. try:
  53. import bz2 # noqa
  54. SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS
  55. except ImportError:
  56. logger.debug('bz2 module is not available')
  57. try:
  58. # Only for Python 3.3+
  59. import lzma # noqa
  60. SUPPORTED_EXTENSIONS += XZ_EXTENSIONS
  61. except ImportError:
  62. logger.debug('lzma module is not available')
  63. def import_or_raise(pkg_or_module_string, ExceptionType, *args, **kwargs):
  64. try:
  65. return __import__(pkg_or_module_string)
  66. except ImportError:
  67. raise ExceptionType(*args, **kwargs)
  68. def ensure_dir(path):
  69. """os.path.makedirs without EEXIST."""
  70. try:
  71. os.makedirs(path)
  72. except OSError as e:
  73. if e.errno != errno.EEXIST:
  74. raise
  75. def get_prog():
  76. try:
  77. if os.path.basename(sys.argv[0]) in ('__main__.py', '-c'):
  78. return "%s -m pip" % sys.executable
  79. except (AttributeError, TypeError, IndexError):
  80. pass
  81. return 'pip'
  82. # Retry every half second for up to 3 seconds
  83. @retry(stop_max_delay=3000, wait_fixed=500)
  84. def rmtree(dir, ignore_errors=False):
  85. shutil.rmtree(dir, ignore_errors=ignore_errors,
  86. onerror=rmtree_errorhandler)
  87. def rmtree_errorhandler(func, path, exc_info):
  88. """On Windows, the files in .svn are read-only, so when rmtree() tries to
  89. remove them, an exception is thrown. We catch that here, remove the
  90. read-only attribute, and hopefully continue without problems."""
  91. # if file type currently read only
  92. if os.stat(path).st_mode & stat.S_IREAD:
  93. # convert to read/write
  94. os.chmod(path, stat.S_IWRITE)
  95. # use the original function to repeat the operation
  96. func(path)
  97. return
  98. else:
  99. raise
  100. def display_path(path):
  101. """Gives the display value for a given path, making it relative to cwd
  102. if possible."""
  103. path = os.path.normcase(os.path.abspath(path))
  104. if sys.version_info[0] == 2:
  105. path = path.decode(sys.getfilesystemencoding(), 'replace')
  106. path = path.encode(sys.getdefaultencoding(), 'replace')
  107. if path.startswith(os.getcwd() + os.path.sep):
  108. path = '.' + path[len(os.getcwd()):]
  109. return path
  110. def backup_dir(dir, ext='.bak'):
  111. """Figure out the name of a directory to back up the given dir to
  112. (adding .bak, .bak2, etc)"""
  113. n = 1
  114. extension = ext
  115. while os.path.exists(dir + extension):
  116. n += 1
  117. extension = ext + str(n)
  118. return dir + extension
  119. def ask_path_exists(message, options):
  120. for action in os.environ.get('PIP_EXISTS_ACTION', '').split():
  121. if action in options:
  122. return action
  123. return ask(message, options)
  124. def ask(message, options):
  125. """Ask the message interactively, with the given possible responses"""
  126. while 1:
  127. if os.environ.get('PIP_NO_INPUT'):
  128. raise Exception(
  129. 'No input was expected ($PIP_NO_INPUT set); question: %s' %
  130. message
  131. )
  132. response = input(message)
  133. response = response.strip().lower()
  134. if response not in options:
  135. print(
  136. 'Your response (%r) was not one of the expected responses: '
  137. '%s' % (response, ', '.join(options))
  138. )
  139. else:
  140. return response
  141. def format_size(bytes):
  142. if bytes > 1000 * 1000:
  143. return '%.1fMB' % (bytes / 1000.0 / 1000)
  144. elif bytes > 10 * 1000:
  145. return '%ikB' % (bytes / 1000)
  146. elif bytes > 1000:
  147. return '%.1fkB' % (bytes / 1000.0)
  148. else:
  149. return '%ibytes' % bytes
  150. def is_installable_dir(path):
  151. """Return True if `path` is a directory containing a setup.py file."""
  152. if not os.path.isdir(path):
  153. return False
  154. setup_py = os.path.join(path, 'setup.py')
  155. if os.path.isfile(setup_py):
  156. return True
  157. return False
  158. def is_svn_page(html):
  159. """
  160. Returns true if the page appears to be the index page of an svn repository
  161. """
  162. return (re.search(r'<title>[^<]*Revision \d+:', html) and
  163. re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I))
  164. def file_contents(filename):
  165. with open(filename, 'rb') as fp:
  166. return fp.read().decode('utf-8')
  167. def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE):
  168. """Yield pieces of data from a file-like object until EOF."""
  169. while True:
  170. chunk = file.read(size)
  171. if not chunk:
  172. break
  173. yield chunk
  174. def split_leading_dir(path):
  175. path = path.lstrip('/').lstrip('\\')
  176. if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or
  177. '\\' not in path):
  178. return path.split('/', 1)
  179. elif '\\' in path:
  180. return path.split('\\', 1)
  181. else:
  182. return path, ''
  183. def has_leading_dir(paths):
  184. """Returns true if all the paths have the same leading path name
  185. (i.e., everything is in one subdirectory in an archive)"""
  186. common_prefix = None
  187. for path in paths:
  188. prefix, rest = split_leading_dir(path)
  189. if not prefix:
  190. return False
  191. elif common_prefix is None:
  192. common_prefix = prefix
  193. elif prefix != common_prefix:
  194. return False
  195. return True
  196. def normalize_path(path, resolve_symlinks=True):
  197. """
  198. Convert a path to its canonical, case-normalized, absolute version.
  199. """
  200. path = expanduser(path)
  201. if resolve_symlinks:
  202. path = os.path.realpath(path)
  203. else:
  204. path = os.path.abspath(path)
  205. return os.path.normcase(path)
  206. def splitext(path):
  207. """Like os.path.splitext, but take off .tar too"""
  208. base, ext = posixpath.splitext(path)
  209. if base.lower().endswith('.tar'):
  210. ext = base[-4:] + ext
  211. base = base[:-4]
  212. return base, ext
  213. def renames(old, new):
  214. """Like os.renames(), but handles renaming across devices."""
  215. # Implementation borrowed from os.renames().
  216. head, tail = os.path.split(new)
  217. if head and tail and not os.path.exists(head):
  218. os.makedirs(head)
  219. shutil.move(old, new)
  220. head, tail = os.path.split(old)
  221. if head and tail:
  222. try:
  223. os.removedirs(head)
  224. except OSError:
  225. pass
  226. def is_local(path):
  227. """
  228. Return True if path is within sys.prefix, if we're running in a virtualenv.
  229. If we're not in a virtualenv, all paths are considered "local."
  230. """
  231. if not running_under_virtualenv():
  232. return True
  233. return normalize_path(path).startswith(normalize_path(sys.prefix))
  234. def dist_is_local(dist):
  235. """
  236. Return True if given Distribution object is installed locally
  237. (i.e. within current virtualenv).
  238. Always True if we're not in a virtualenv.
  239. """
  240. return is_local(dist_location(dist))
  241. def dist_in_usersite(dist):
  242. """
  243. Return True if given Distribution is installed in user site.
  244. """
  245. norm_path = normalize_path(dist_location(dist))
  246. return norm_path.startswith(normalize_path(user_site))
  247. def dist_in_site_packages(dist):
  248. """
  249. Return True if given Distribution is installed in
  250. distutils.sysconfig.get_python_lib().
  251. """
  252. return normalize_path(
  253. dist_location(dist)
  254. ).startswith(normalize_path(site_packages))
  255. def dist_is_editable(dist):
  256. """Is distribution an editable install?"""
  257. for path_item in sys.path:
  258. egg_link = os.path.join(path_item, dist.project_name + '.egg-link')
  259. if os.path.isfile(egg_link):
  260. return True
  261. return False
  262. def get_installed_distributions(local_only=True,
  263. skip=stdlib_pkgs,
  264. include_editables=True,
  265. editables_only=False,
  266. user_only=False):
  267. """
  268. Return a list of installed Distribution objects.
  269. If ``local_only`` is True (default), only return installations
  270. local to the current virtualenv, if in a virtualenv.
  271. ``skip`` argument is an iterable of lower-case project names to
  272. ignore; defaults to stdlib_pkgs
  273. If ``editables`` is False, don't report editables.
  274. If ``editables_only`` is True , only report editables.
  275. If ``user_only`` is True , only report installations in the user
  276. site directory.
  277. """
  278. if local_only:
  279. local_test = dist_is_local
  280. else:
  281. def local_test(d):
  282. return True
  283. if include_editables:
  284. def editable_test(d):
  285. return True
  286. else:
  287. def editable_test(d):
  288. return not dist_is_editable(d)
  289. if editables_only:
  290. def editables_only_test(d):
  291. return dist_is_editable(d)
  292. else:
  293. def editables_only_test(d):
  294. return True
  295. if user_only:
  296. user_test = dist_in_usersite
  297. else:
  298. def user_test(d):
  299. return True
  300. return [d for d in pkg_resources.working_set
  301. if local_test(d) and
  302. d.key not in skip and
  303. editable_test(d) and
  304. editables_only_test(d) and
  305. user_test(d)
  306. ]
  307. def egg_link_path(dist):
  308. """
  309. Return the path for the .egg-link file if it exists, otherwise, None.
  310. There's 3 scenarios:
  311. 1) not in a virtualenv
  312. try to find in site.USER_SITE, then site_packages
  313. 2) in a no-global virtualenv
  314. try to find in site_packages
  315. 3) in a yes-global virtualenv
  316. try to find in site_packages, then site.USER_SITE
  317. (don't look in global location)
  318. For #1 and #3, there could be odd cases, where there's an egg-link in 2
  319. locations.
  320. This method will just return the first one found.
  321. """
  322. sites = []
  323. if running_under_virtualenv():
  324. if virtualenv_no_global():
  325. sites.append(site_packages)
  326. else:
  327. sites.append(site_packages)
  328. if user_site:
  329. sites.append(user_site)
  330. else:
  331. if user_site:
  332. sites.append(user_site)
  333. sites.append(site_packages)
  334. for site in sites:
  335. egglink = os.path.join(site, dist.project_name) + '.egg-link'
  336. if os.path.isfile(egglink):
  337. return egglink
  338. def dist_location(dist):
  339. """
  340. Get the site-packages location of this distribution. Generally
  341. this is dist.location, except in the case of develop-installed
  342. packages, where dist.location is the source code location, and we
  343. want to know where the egg-link file is.
  344. """
  345. egg_link = egg_link_path(dist)
  346. if egg_link:
  347. return egg_link
  348. return dist.location
  349. def get_terminal_size():
  350. """Returns a tuple (x, y) representing the width(x) and the height(x)
  351. in characters of the terminal window."""
  352. def ioctl_GWINSZ(fd):
  353. try:
  354. import fcntl
  355. import termios
  356. import struct
  357. cr = struct.unpack(
  358. 'hh',
  359. fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')
  360. )
  361. except:
  362. return None
  363. if cr == (0, 0):
  364. return None
  365. return cr
  366. cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
  367. if not cr:
  368. try:
  369. fd = os.open(os.ctermid(), os.O_RDONLY)
  370. cr = ioctl_GWINSZ(fd)
  371. os.close(fd)
  372. except:
  373. pass
  374. if not cr:
  375. cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
  376. return int(cr[1]), int(cr[0])
  377. def current_umask():
  378. """Get the current umask which involves having to set it temporarily."""
  379. mask = os.umask(0)
  380. os.umask(mask)
  381. return mask
  382. def unzip_file(filename, location, flatten=True):
  383. """
  384. Unzip the file (with path `filename`) to the destination `location`. All
  385. files are written based on system defaults and umask (i.e. permissions are
  386. not preserved), except that regular file members with any execute
  387. permissions (user, group, or world) have "chmod +x" applied after being
  388. written. Note that for windows, any execute changes using os.chmod are
  389. no-ops per the python docs.
  390. """
  391. ensure_dir(location)
  392. zipfp = open(filename, 'rb')
  393. try:
  394. zip = zipfile.ZipFile(zipfp, allowZip64=True)
  395. leading = has_leading_dir(zip.namelist()) and flatten
  396. for info in zip.infolist():
  397. name = info.filename
  398. data = zip.read(name)
  399. fn = name
  400. if leading:
  401. fn = split_leading_dir(name)[1]
  402. fn = os.path.join(location, fn)
  403. dir = os.path.dirname(fn)
  404. if fn.endswith('/') or fn.endswith('\\'):
  405. # A directory
  406. ensure_dir(fn)
  407. else:
  408. ensure_dir(dir)
  409. fp = open(fn, 'wb')
  410. try:
  411. fp.write(data)
  412. finally:
  413. fp.close()
  414. mode = info.external_attr >> 16
  415. # if mode and regular file and any execute permissions for
  416. # user/group/world?
  417. if mode and stat.S_ISREG(mode) and mode & 0o111:
  418. # make dest file have execute for user/group/world
  419. # (chmod +x) no-op on windows per python docs
  420. os.chmod(fn, (0o777 - current_umask() | 0o111))
  421. finally:
  422. zipfp.close()
  423. def untar_file(filename, location):
  424. """
  425. Untar the file (with path `filename`) to the destination `location`.
  426. All files are written based on system defaults and umask (i.e. permissions
  427. are not preserved), except that regular file members with any execute
  428. permissions (user, group, or world) have "chmod +x" applied after being
  429. written. Note that for windows, any execute changes using os.chmod are
  430. no-ops per the python docs.
  431. """
  432. ensure_dir(location)
  433. if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'):
  434. mode = 'r:gz'
  435. elif filename.lower().endswith(BZ2_EXTENSIONS):
  436. mode = 'r:bz2'
  437. elif filename.lower().endswith(XZ_EXTENSIONS):
  438. mode = 'r:xz'
  439. elif filename.lower().endswith('.tar'):
  440. mode = 'r'
  441. else:
  442. logger.warning(
  443. 'Cannot determine compression type for file %s', filename,
  444. )
  445. mode = 'r:*'
  446. tar = tarfile.open(filename, mode)
  447. try:
  448. # note: python<=2.5 doesn't seem to know about pax headers, filter them
  449. leading = has_leading_dir([
  450. member.name for member in tar.getmembers()
  451. if member.name != 'pax_global_header'
  452. ])
  453. for member in tar.getmembers():
  454. fn = member.name
  455. if fn == 'pax_global_header':
  456. continue
  457. if leading:
  458. fn = split_leading_dir(fn)[1]
  459. path = os.path.join(location, fn)
  460. if member.isdir():
  461. ensure_dir(path)
  462. elif member.issym():
  463. try:
  464. tar._extract_member(member, path)
  465. except Exception as exc:
  466. # Some corrupt tar files seem to produce this
  467. # (specifically bad symlinks)
  468. logger.warning(
  469. 'In the tar file %s the member %s is invalid: %s',
  470. filename, member.name, exc,
  471. )
  472. continue
  473. else:
  474. try:
  475. fp = tar.extractfile(member)
  476. except (KeyError, AttributeError) as exc:
  477. # Some corrupt tar files seem to produce this
  478. # (specifically bad symlinks)
  479. logger.warning(
  480. 'In the tar file %s the member %s is invalid: %s',
  481. filename, member.name, exc,
  482. )
  483. continue
  484. ensure_dir(os.path.dirname(path))
  485. with open(path, 'wb') as destfp:
  486. shutil.copyfileobj(fp, destfp)
  487. fp.close()
  488. # Update the timestamp (useful for cython compiled files)
  489. tar.utime(member, path)
  490. # member have any execute permissions for user/group/world?
  491. if member.mode & 0o111:
  492. # make dest file have execute for user/group/world
  493. # no-op on windows per python docs
  494. os.chmod(path, (0o777 - current_umask() | 0o111))
  495. finally:
  496. tar.close()
  497. def unpack_file(filename, location, content_type, link):
  498. filename = os.path.realpath(filename)
  499. if (content_type == 'application/zip' or
  500. filename.lower().endswith(ZIP_EXTENSIONS) or
  501. zipfile.is_zipfile(filename)):
  502. unzip_file(
  503. filename,
  504. location,
  505. flatten=not filename.endswith('.whl')
  506. )
  507. elif (content_type == 'application/x-gzip' or
  508. tarfile.is_tarfile(filename) or
  509. filename.lower().endswith(
  510. TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)):
  511. untar_file(filename, location)
  512. elif (content_type and content_type.startswith('text/html') and
  513. is_svn_page(file_contents(filename))):
  514. # We don't really care about this
  515. from pip.vcs.subversion import Subversion
  516. Subversion('svn+' + link.url).unpack(location)
  517. else:
  518. # FIXME: handle?
  519. # FIXME: magic signatures?
  520. logger.critical(
  521. 'Cannot unpack file %s (downloaded from %s, content-type: %s); '
  522. 'cannot detect archive format',
  523. filename, location, content_type,
  524. )
  525. raise InstallationError(
  526. 'Cannot determine archive format of %s' % location
  527. )
  528. def call_subprocess(cmd, show_stdout=True, cwd=None,
  529. on_returncode='raise',
  530. command_desc=None,
  531. extra_environ=None, spinner=None):
  532. # This function's handling of subprocess output is confusing and I
  533. # previously broke it terribly, so as penance I will write a long comment
  534. # explaining things.
  535. #
  536. # The obvious thing that affects output is the show_stdout=
  537. # kwarg. show_stdout=True means, let the subprocess write directly to our
  538. # stdout. Even though it is nominally the default, it is almost never used
  539. # inside pip (and should not be used in new code without a very good
  540. # reason); as of 2016-02-22 it is only used in a few places inside the VCS
  541. # wrapper code. Ideally we should get rid of it entirely, because it
  542. # creates a lot of complexity here for a rarely used feature.
  543. #
  544. # Most places in pip set show_stdout=False. What this means is:
  545. # - We connect the child stdout to a pipe, which we read.
  546. # - By default, we hide the output but show a spinner -- unless the
  547. # subprocess exits with an error, in which case we show the output.
  548. # - If the --verbose option was passed (= loglevel is DEBUG), then we show
  549. # the output unconditionally. (But in this case we don't want to show
  550. # the output a second time if it turns out that there was an error.)
  551. #
  552. # stderr is always merged with stdout (even if show_stdout=True).
  553. if show_stdout:
  554. stdout = None
  555. else:
  556. stdout = subprocess.PIPE
  557. if command_desc is None:
  558. cmd_parts = []
  559. for part in cmd:
  560. if ' ' in part or '\n' in part or '"' in part or "'" in part:
  561. part = '"%s"' % part.replace('"', '\\"')
  562. cmd_parts.append(part)
  563. command_desc = ' '.join(cmd_parts)
  564. logger.debug("Running command %s", command_desc)
  565. env = os.environ.copy()
  566. if extra_environ:
  567. env.update(extra_environ)
  568. try:
  569. proc = subprocess.Popen(
  570. cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
  571. cwd=cwd, env=env)
  572. except Exception as exc:
  573. logger.critical(
  574. "Error %s while executing command %s", exc, command_desc,
  575. )
  576. raise
  577. if stdout is not None:
  578. all_output = []
  579. while True:
  580. line = console_to_str(proc.stdout.readline())
  581. if not line:
  582. break
  583. line = line.rstrip()
  584. all_output.append(line + '\n')
  585. if logger.getEffectiveLevel() <= std_logging.DEBUG:
  586. # Show the line immediately
  587. logger.debug(line)
  588. else:
  589. # Update the spinner
  590. if spinner is not None:
  591. spinner.spin()
  592. proc.wait()
  593. if spinner is not None:
  594. if proc.returncode:
  595. spinner.finish("error")
  596. else:
  597. spinner.finish("done")
  598. if proc.returncode:
  599. if on_returncode == 'raise':
  600. if (logger.getEffectiveLevel() > std_logging.DEBUG and
  601. not show_stdout):
  602. logger.info(
  603. 'Complete output from command %s:', command_desc,
  604. )
  605. logger.info(
  606. ''.join(all_output) +
  607. '\n----------------------------------------'
  608. )
  609. raise InstallationError(
  610. 'Command "%s" failed with error code %s in %s'
  611. % (command_desc, proc.returncode, cwd))
  612. elif on_returncode == 'warn':
  613. logger.warning(
  614. 'Command "%s" had error code %s in %s',
  615. command_desc, proc.returncode, cwd,
  616. )
  617. elif on_returncode == 'ignore':
  618. pass
  619. else:
  620. raise ValueError('Invalid value: on_returncode=%s' %
  621. repr(on_returncode))
  622. if not show_stdout:
  623. return ''.join(all_output)
  624. def read_text_file(filename):
  625. """Return the contents of *filename*.
  626. Try to decode the file contents with utf-8, the preferred system encoding
  627. (e.g., cp1252 on some Windows machines), and latin1, in that order.
  628. Decoding a byte string with latin1 will never raise an error. In the worst
  629. case, the returned string will contain some garbage characters.
  630. """
  631. with open(filename, 'rb') as fp:
  632. data = fp.read()
  633. encodings = ['utf-8', locale.getpreferredencoding(False), 'latin1']
  634. for enc in encodings:
  635. try:
  636. data = data.decode(enc)
  637. except UnicodeDecodeError:
  638. continue
  639. break
  640. assert type(data) != bytes # Latin1 should have worked.
  641. return data
  642. def _make_build_dir(build_dir):
  643. os.makedirs(build_dir)
  644. write_delete_marker_file(build_dir)
  645. class FakeFile(object):
  646. """Wrap a list of lines in an object with readline() to make
  647. ConfigParser happy."""
  648. def __init__(self, lines):
  649. self._gen = (l for l in lines)
  650. def readline(self):
  651. try:
  652. try:
  653. return next(self._gen)
  654. except NameError:
  655. return self._gen.next()
  656. except StopIteration:
  657. return ''
  658. def __iter__(self):
  659. return self._gen
  660. class StreamWrapper(StringIO):
  661. @classmethod
  662. def from_stream(cls, orig_stream):
  663. cls.orig_stream = orig_stream
  664. return cls()
  665. # compileall.compile_dir() needs stdout.encoding to print to stdout
  666. @property
  667. def encoding(self):
  668. return self.orig_stream.encoding
  669. @contextlib.contextmanager
  670. def captured_output(stream_name):
  671. """Return a context manager used by captured_stdout/stdin/stderr
  672. that temporarily replaces the sys stream *stream_name* with a StringIO.
  673. Taken from Lib/support/__init__.py in the CPython repo.
  674. """
  675. orig_stdout = getattr(sys, stream_name)
  676. setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout))
  677. try:
  678. yield getattr(sys, stream_name)
  679. finally:
  680. setattr(sys, stream_name, orig_stdout)
  681. def captured_stdout():
  682. """Capture the output of sys.stdout:
  683. with captured_stdout() as stdout:
  684. print('hello')
  685. self.assertEqual(stdout.getvalue(), 'hello\n')
  686. Taken from Lib/support/__init__.py in the CPython repo.
  687. """
  688. return captured_output('stdout')
  689. class cached_property(object):
  690. """A property that is only computed once per instance and then replaces
  691. itself with an ordinary attribute. Deleting the attribute resets the
  692. property.
  693. Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175
  694. """
  695. def __init__(self, func):
  696. self.__doc__ = getattr(func, '__doc__')
  697. self.func = func
  698. def __get__(self, obj, cls):
  699. if obj is None:
  700. # We're being accessed from the class itself, not from an object
  701. return self
  702. value = obj.__dict__[self.func.__name__] = self.func(obj)
  703. return value
  704. def get_installed_version(dist_name, lookup_dirs=None):
  705. """Get the installed version of dist_name avoiding pkg_resources cache"""
  706. # Create a requirement that we'll look for inside of setuptools.
  707. req = pkg_resources.Requirement.parse(dist_name)
  708. # We want to avoid having this cached, so we need to construct a new
  709. # working set each time.
  710. if lookup_dirs is None:
  711. working_set = pkg_resources.WorkingSet()
  712. else:
  713. working_set = pkg_resources.WorkingSet(lookup_dirs)
  714. # Get the installed distribution from our working set
  715. dist = working_set.find(req)
  716. # Check to see if we got an installed distribution or not, if we did
  717. # we want to return it's version.
  718. return dist.version if dist else None
  719. def consume(iterator):
  720. """Consume an iterable at C speed."""
  721. deque(iterator, maxlen=0)