PageRenderTime 105ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 1ms

/pip/req.py

https://github.com/ptthiem/pip
Python | 1840 lines | 1625 code | 109 blank | 106 comment | 288 complexity | 53b1f1efedcdef24ffa5a6732fd307b3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. from email.parser import FeedParser
  2. import os
  3. import imp
  4. import pkg_resources
  5. import re
  6. import sys
  7. import shutil
  8. import tempfile
  9. import textwrap
  10. import zipfile
  11. from distutils.util import change_root
  12. from pip.locations import (bin_py, running_under_virtualenv,PIP_DELETE_MARKER_FILENAME,
  13. write_delete_marker_file, bin_user)
  14. from pip.exceptions import (InstallationError, UninstallationError, UnsupportedWheel,
  15. BestVersionAlreadyInstalled, InvalidWheelFilename,
  16. DistributionNotFound, PreviousBuildDirError)
  17. from pip.vcs import vcs
  18. from pip.log import logger
  19. from pip.util import (display_path, rmtree, ask, ask_path_exists, backup_dir,
  20. is_installable_dir, is_local, dist_is_local,
  21. dist_in_usersite, dist_in_site_packages, renames,
  22. normalize_path, egg_link_path, make_path_relative,
  23. call_subprocess, is_prerelease, normalize_name)
  24. from pip.backwardcompat import (urlparse, urllib, uses_pycache,
  25. ConfigParser, string_types, HTTPError,
  26. get_python_version, b)
  27. from pip.index import Link
  28. from pip.locations import build_prefix
  29. from pip.download import (PipSession, get_file_content, is_url, url_to_path,
  30. path_to_url, is_archive_file,
  31. unpack_vcs_link, is_vcs_url, is_file_url,
  32. unpack_file_url, unpack_http_url)
  33. import pip.wheel
  34. from pip.wheel import move_wheel_files, Wheel, wheel_ext
  35. class InstallRequirement(object):
  36. def __init__(self, req, comes_from, source_dir=None, editable=False,
  37. url=None, as_egg=False, update=True, prereleases=None,
  38. editable_options=None, from_bundle=False, pycompile=True):
  39. self.extras = ()
  40. if isinstance(req, string_types):
  41. req = pkg_resources.Requirement.parse(req)
  42. self.extras = req.extras
  43. self.req = req
  44. self.comes_from = comes_from
  45. self.source_dir = source_dir
  46. self.editable = editable
  47. if editable_options is None:
  48. editable_options = {}
  49. self.editable_options = editable_options
  50. self.url = url
  51. self.as_egg = as_egg
  52. self._egg_info_path = None
  53. # This holds the pkg_resources.Distribution object if this requirement
  54. # is already available:
  55. self.satisfied_by = None
  56. # This hold the pkg_resources.Distribution object if this requirement
  57. # conflicts with another installed distribution:
  58. self.conflicts_with = None
  59. self._temp_build_dir = None
  60. self._is_bundle = None
  61. # True if the editable should be updated:
  62. self.update = update
  63. # Set to True after successful installation
  64. self.install_succeeded = None
  65. # UninstallPathSet of uninstalled distribution (for possible rollback)
  66. self.uninstalled = None
  67. self.use_user_site = False
  68. self.target_dir = None
  69. self.from_bundle = from_bundle
  70. self.pycompile = pycompile
  71. # True if pre-releases are acceptable
  72. if prereleases:
  73. self.prereleases = True
  74. elif self.req is not None:
  75. self.prereleases = any([is_prerelease(x[1]) and x[0] != "!=" for x in self.req.specs])
  76. else:
  77. self.prereleases = False
  78. @classmethod
  79. def from_editable(cls, editable_req, comes_from=None, default_vcs=None):
  80. name, url, extras_override = parse_editable(editable_req, default_vcs)
  81. if url.startswith('file:'):
  82. source_dir = url_to_path(url)
  83. else:
  84. source_dir = None
  85. res = cls(name, comes_from, source_dir=source_dir,
  86. editable=True,
  87. url=url,
  88. editable_options=extras_override,
  89. prereleases=True)
  90. if extras_override is not None:
  91. res.extras = extras_override
  92. return res
  93. @classmethod
  94. def from_line(cls, name, comes_from=None, prereleases=None):
  95. """Creates an InstallRequirement from a name, which might be a
  96. requirement, directory containing 'setup.py', filename, or URL.
  97. """
  98. url = None
  99. name = name.strip()
  100. req = None
  101. path = os.path.normpath(os.path.abspath(name))
  102. link = None
  103. if is_url(name):
  104. link = Link(name)
  105. elif os.path.isdir(path) and (os.path.sep in name or name.startswith('.')):
  106. if not is_installable_dir(path):
  107. raise InstallationError("Directory %r is not installable. File 'setup.py' not found." % name)
  108. link = Link(path_to_url(name))
  109. elif is_archive_file(path):
  110. if not os.path.isfile(path):
  111. logger.warn('Requirement %r looks like a filename, but the file does not exist', name)
  112. link = Link(path_to_url(name))
  113. # If the line has an egg= definition, but isn't editable, pull the requirement out.
  114. # Otherwise, assume the name is the req for the non URL/path/archive case.
  115. if link and req is None:
  116. url = link.url_without_fragment
  117. req = link.egg_fragment #when fragment is None, this will become an 'unnamed' requirement
  118. # Handle relative file URLs
  119. if link.scheme == 'file' and re.search(r'\.\./', url):
  120. url = path_to_url(os.path.normpath(os.path.abspath(link.path)))
  121. # fail early for invalid or unsupported wheels
  122. if link.ext == wheel_ext:
  123. wheel = Wheel(link.filename) # can raise InvalidWheelFilename
  124. if not wheel.supported():
  125. raise UnsupportedWheel("%s is not a supported wheel on this platform." % wheel.filename)
  126. else:
  127. req = name
  128. return cls(req, comes_from, url=url, prereleases=prereleases)
  129. def __str__(self):
  130. if self.req:
  131. s = str(self.req)
  132. if self.url:
  133. s += ' from %s' % self.url
  134. else:
  135. s = self.url
  136. if self.satisfied_by is not None:
  137. s += ' in %s' % display_path(self.satisfied_by.location)
  138. if self.comes_from:
  139. if isinstance(self.comes_from, string_types):
  140. comes_from = self.comes_from
  141. else:
  142. comes_from = self.comes_from.from_path()
  143. if comes_from:
  144. s += ' (from %s)' % comes_from
  145. return s
  146. def from_path(self):
  147. if self.req is None:
  148. return None
  149. s = str(self.req)
  150. if self.comes_from:
  151. if isinstance(self.comes_from, string_types):
  152. comes_from = self.comes_from
  153. else:
  154. comes_from = self.comes_from.from_path()
  155. if comes_from:
  156. s += '->' + comes_from
  157. return s
  158. def build_location(self, build_dir, unpack=True):
  159. if self._temp_build_dir is not None:
  160. return self._temp_build_dir
  161. if self.req is None:
  162. self._temp_build_dir = tempfile.mkdtemp('-build', 'pip-')
  163. self._ideal_build_dir = build_dir
  164. return self._temp_build_dir
  165. if self.editable:
  166. name = self.name.lower()
  167. else:
  168. name = self.name
  169. # FIXME: Is there a better place to create the build_dir? (hg and bzr need this)
  170. if not os.path.exists(build_dir):
  171. _make_build_dir(build_dir)
  172. return os.path.join(build_dir, name)
  173. def correct_build_location(self):
  174. """If the build location was a temporary directory, this will move it
  175. to a new more permanent location"""
  176. if self.source_dir is not None:
  177. return
  178. assert self.req is not None
  179. assert self._temp_build_dir
  180. old_location = self._temp_build_dir
  181. new_build_dir = self._ideal_build_dir
  182. del self._ideal_build_dir
  183. if self.editable:
  184. name = self.name.lower()
  185. else:
  186. name = self.name
  187. new_location = os.path.join(new_build_dir, name)
  188. if not os.path.exists(new_build_dir):
  189. logger.debug('Creating directory %s' % new_build_dir)
  190. _make_build_dir(new_build_dir)
  191. if os.path.exists(new_location):
  192. raise InstallationError(
  193. 'A package already exists in %s; please remove it to continue'
  194. % display_path(new_location))
  195. logger.debug('Moving package %s from %s to new location %s'
  196. % (self, display_path(old_location), display_path(new_location)))
  197. shutil.move(old_location, new_location)
  198. self._temp_build_dir = new_location
  199. self.source_dir = new_location
  200. self._egg_info_path = None
  201. @property
  202. def name(self):
  203. if self.req is None:
  204. return None
  205. return self.req.project_name
  206. @property
  207. def url_name(self):
  208. if self.req is None:
  209. return None
  210. return urllib.quote(self.req.unsafe_name)
  211. @property
  212. def setup_py(self):
  213. setup_file = 'setup.py'
  214. if self.editable_options and 'subdirectory' in self.editable_options:
  215. setup_py = os.path.join(self.source_dir,
  216. self.editable_options['subdirectory'],
  217. setup_file)
  218. else:
  219. setup_py = os.path.join(self.source_dir, setup_file)
  220. return setup_py
  221. def run_egg_info(self, force_root_egg_info=False):
  222. assert self.source_dir
  223. if self.name:
  224. logger.notify('Running setup.py (path:%s) egg_info for package %s' % (self.setup_py, self.name))
  225. else:
  226. logger.notify('Running setup.py (path:%s) egg_info for package from %s' % (self.setup_py, self.url))
  227. logger.indent += 2
  228. try:
  229. # if it's distribute>=0.7, it won't contain an importable
  230. # setuptools, and having an egg-info dir blocks the ability of
  231. # setup.py to find setuptools plugins, so delete the egg-info dir if
  232. # no setuptools. it will get recreated by the run of egg_info
  233. # NOTE: this self.name check only works when installing from a specifier
  234. # (not archive path/urls)
  235. # TODO: take this out later
  236. if self.name == 'distribute' and not os.path.isdir(os.path.join(self.source_dir, 'setuptools')):
  237. rmtree(os.path.join(self.source_dir, 'distribute.egg-info'))
  238. script = self._run_setup_py
  239. script = script.replace('__SETUP_PY__', repr(self.setup_py))
  240. script = script.replace('__PKG_NAME__', repr(self.name))
  241. egg_info_cmd = [sys.executable, '-c', script, 'egg_info']
  242. # We can't put the .egg-info files at the root, because then the source code will be mistaken
  243. # for an installed egg, causing problems
  244. if self.editable or force_root_egg_info:
  245. egg_base_option = []
  246. else:
  247. egg_info_dir = os.path.join(self.source_dir, 'pip-egg-info')
  248. if not os.path.exists(egg_info_dir):
  249. os.makedirs(egg_info_dir)
  250. egg_base_option = ['--egg-base', 'pip-egg-info']
  251. call_subprocess(
  252. egg_info_cmd + egg_base_option,
  253. cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False,
  254. command_level=logger.VERBOSE_DEBUG,
  255. command_desc='python setup.py egg_info')
  256. finally:
  257. logger.indent -= 2
  258. if not self.req:
  259. self.req = pkg_resources.Requirement.parse(
  260. "%(Name)s==%(Version)s" % self.pkg_info())
  261. self.correct_build_location()
  262. ## FIXME: This is a lame hack, entirely for PasteScript which has
  263. ## a self-provided entry point that causes this awkwardness
  264. _run_setup_py = """
  265. __file__ = __SETUP_PY__
  266. from setuptools.command import egg_info
  267. import pkg_resources
  268. import os
  269. def replacement_run(self):
  270. self.mkpath(self.egg_info)
  271. installer = self.distribution.fetch_build_egg
  272. for ep in pkg_resources.iter_entry_points('egg_info.writers'):
  273. # require=False is the change we're making:
  274. writer = ep.load(require=False)
  275. if writer:
  276. writer(self, ep.name, os.path.join(self.egg_info,ep.name))
  277. self.find_sources()
  278. egg_info.egg_info.run = replacement_run
  279. exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
  280. """
  281. def egg_info_data(self, filename):
  282. if self.satisfied_by is not None:
  283. if not self.satisfied_by.has_metadata(filename):
  284. return None
  285. return self.satisfied_by.get_metadata(filename)
  286. assert self.source_dir
  287. filename = self.egg_info_path(filename)
  288. if not os.path.exists(filename):
  289. return None
  290. fp = open(filename, 'r')
  291. data = fp.read()
  292. fp.close()
  293. return data
  294. def egg_info_path(self, filename):
  295. if self._egg_info_path is None:
  296. if self.editable:
  297. base = self.source_dir
  298. else:
  299. base = os.path.join(self.source_dir, 'pip-egg-info')
  300. filenames = os.listdir(base)
  301. if self.editable:
  302. filenames = []
  303. for root, dirs, files in os.walk(base):
  304. for dir in vcs.dirnames:
  305. if dir in dirs:
  306. dirs.remove(dir)
  307. # Iterate over a copy of ``dirs``, since mutating
  308. # a list while iterating over it can cause trouble.
  309. # (See https://github.com/pypa/pip/pull/462.)
  310. for dir in list(dirs):
  311. # Don't search in anything that looks like a virtualenv environment
  312. if (os.path.exists(os.path.join(root, dir, 'bin', 'python'))
  313. or os.path.exists(os.path.join(root, dir, 'Scripts', 'Python.exe'))):
  314. dirs.remove(dir)
  315. # Also don't search through tests
  316. if dir == 'test' or dir == 'tests':
  317. dirs.remove(dir)
  318. filenames.extend([os.path.join(root, dir)
  319. for dir in dirs])
  320. filenames = [f for f in filenames if f.endswith('.egg-info')]
  321. if not filenames:
  322. raise InstallationError('No files/directories in %s (from %s)' % (base, filename))
  323. assert filenames, "No files/directories in %s (from %s)" % (base, filename)
  324. # if we have more than one match, we pick the toplevel one. This can
  325. # easily be the case if there is a dist folder which contains an
  326. # extracted tarball for testing purposes.
  327. if len(filenames) > 1:
  328. filenames.sort(key=lambda x: x.count(os.path.sep) +
  329. (os.path.altsep and
  330. x.count(os.path.altsep) or 0))
  331. self._egg_info_path = os.path.join(base, filenames[0])
  332. return os.path.join(self._egg_info_path, filename)
  333. def egg_info_lines(self, filename):
  334. data = self.egg_info_data(filename)
  335. if not data:
  336. return []
  337. result = []
  338. for line in data.splitlines():
  339. line = line.strip()
  340. if not line or line.startswith('#'):
  341. continue
  342. result.append(line)
  343. return result
  344. def pkg_info(self):
  345. p = FeedParser()
  346. data = self.egg_info_data('PKG-INFO')
  347. if not data:
  348. logger.warn('No PKG-INFO file found in %s' % display_path(self.egg_info_path('PKG-INFO')))
  349. p.feed(data or '')
  350. return p.close()
  351. @property
  352. def dependency_links(self):
  353. return self.egg_info_lines('dependency_links.txt')
  354. _requirements_section_re = re.compile(r'\[(.*?)\]')
  355. def requirements(self, extras=()):
  356. in_extra = None
  357. for line in self.egg_info_lines('requires.txt'):
  358. match = self._requirements_section_re.match(line.lower())
  359. if match:
  360. in_extra = match.group(1)
  361. continue
  362. if in_extra and in_extra not in extras:
  363. logger.debug('skipping extra %s' % in_extra)
  364. # Skip requirement for an extra we aren't requiring
  365. continue
  366. yield line
  367. @property
  368. def absolute_versions(self):
  369. for qualifier, version in self.req.specs:
  370. if qualifier == '==':
  371. yield version
  372. @property
  373. def installed_version(self):
  374. return self.pkg_info()['version']
  375. def assert_source_matches_version(self):
  376. assert self.source_dir
  377. version = self.installed_version
  378. if version not in self.req:
  379. logger.warn('Requested %s, but installing version %s' % (self, self.installed_version))
  380. else:
  381. logger.debug('Source in %s has version %s, which satisfies requirement %s'
  382. % (display_path(self.source_dir), version, self))
  383. def update_editable(self, obtain=True):
  384. if not self.url:
  385. logger.info("Cannot update repository at %s; repository location is unknown" % self.source_dir)
  386. return
  387. assert self.editable
  388. assert self.source_dir
  389. if self.url.startswith('file:'):
  390. # Static paths don't get updated
  391. return
  392. assert '+' in self.url, "bad url: %r" % self.url
  393. if not self.update:
  394. return
  395. vc_type, url = self.url.split('+', 1)
  396. backend = vcs.get_backend(vc_type)
  397. if backend:
  398. vcs_backend = backend(self.url)
  399. if obtain:
  400. vcs_backend.obtain(self.source_dir)
  401. else:
  402. vcs_backend.export(self.source_dir)
  403. else:
  404. assert 0, (
  405. 'Unexpected version control type (in %s): %s'
  406. % (self.url, vc_type))
  407. def uninstall(self, auto_confirm=False):
  408. """
  409. Uninstall the distribution currently satisfying this requirement.
  410. Prompts before removing or modifying files unless
  411. ``auto_confirm`` is True.
  412. Refuses to delete or modify files outside of ``sys.prefix`` -
  413. thus uninstallation within a virtual environment can only
  414. modify that virtual environment, even if the virtualenv is
  415. linked to global site-packages.
  416. """
  417. if not self.check_if_exists():
  418. raise UninstallationError("Cannot uninstall requirement %s, not installed" % (self.name,))
  419. dist = self.satisfied_by or self.conflicts_with
  420. paths_to_remove = UninstallPathSet(dist)
  421. pip_egg_info_path = os.path.join(dist.location,
  422. dist.egg_name()) + '.egg-info'
  423. dist_info_path = os.path.join(dist.location,
  424. '-'.join(dist.egg_name().split('-')[:2])
  425. ) + '.dist-info'
  426. # workaround for http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=618367
  427. debian_egg_info_path = pip_egg_info_path.replace(
  428. '-py%s' % pkg_resources.PY_MAJOR, '')
  429. easy_install_egg = dist.egg_name() + '.egg'
  430. develop_egg_link = egg_link_path(dist)
  431. pip_egg_info_exists = os.path.exists(pip_egg_info_path)
  432. debian_egg_info_exists = os.path.exists(debian_egg_info_path)
  433. dist_info_exists = os.path.exists(dist_info_path)
  434. if pip_egg_info_exists or debian_egg_info_exists:
  435. # package installed by pip
  436. if pip_egg_info_exists:
  437. egg_info_path = pip_egg_info_path
  438. else:
  439. egg_info_path = debian_egg_info_path
  440. paths_to_remove.add(egg_info_path)
  441. if dist.has_metadata('installed-files.txt'):
  442. for installed_file in dist.get_metadata('installed-files.txt').splitlines():
  443. path = os.path.normpath(os.path.join(egg_info_path, installed_file))
  444. paths_to_remove.add(path)
  445. #FIXME: need a test for this elif block
  446. #occurs with --single-version-externally-managed/--record outside of pip
  447. elif dist.has_metadata('top_level.txt'):
  448. if dist.has_metadata('namespace_packages.txt'):
  449. namespaces = dist.get_metadata('namespace_packages.txt')
  450. else:
  451. namespaces = []
  452. for top_level_pkg in [p for p
  453. in dist.get_metadata('top_level.txt').splitlines()
  454. if p and p not in namespaces]:
  455. path = os.path.join(dist.location, top_level_pkg)
  456. paths_to_remove.add(path)
  457. paths_to_remove.add(path + '.py')
  458. paths_to_remove.add(path + '.pyc')
  459. elif dist.location.endswith(easy_install_egg):
  460. # package installed by easy_install
  461. paths_to_remove.add(dist.location)
  462. easy_install_pth = os.path.join(os.path.dirname(dist.location),
  463. 'easy-install.pth')
  464. paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg)
  465. elif develop_egg_link:
  466. # develop egg
  467. fh = open(develop_egg_link, 'r')
  468. link_pointer = os.path.normcase(fh.readline().strip())
  469. fh.close()
  470. assert (link_pointer == dist.location), 'Egg-link %s does not match installed location of %s (at %s)' % (link_pointer, self.name, dist.location)
  471. paths_to_remove.add(develop_egg_link)
  472. easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
  473. 'easy-install.pth')
  474. paths_to_remove.add_pth(easy_install_pth, dist.location)
  475. elif dist_info_exists:
  476. for path in pip.wheel.uninstallation_paths(dist):
  477. paths_to_remove.add(path)
  478. # find distutils scripts= scripts
  479. if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'):
  480. for script in dist.metadata_listdir('scripts'):
  481. if dist_in_usersite(dist):
  482. bin_dir = bin_user
  483. else:
  484. bin_dir = bin_py
  485. paths_to_remove.add(os.path.join(bin_dir, script))
  486. if sys.platform == 'win32':
  487. paths_to_remove.add(os.path.join(bin_dir, script) + '.bat')
  488. # find console_scripts
  489. if dist.has_metadata('entry_points.txt'):
  490. config = ConfigParser.SafeConfigParser()
  491. config.readfp(FakeFile(dist.get_metadata_lines('entry_points.txt')))
  492. if config.has_section('console_scripts'):
  493. for name, value in config.items('console_scripts'):
  494. if dist_in_usersite(dist):
  495. bin_dir = bin_user
  496. else:
  497. bin_dir = bin_py
  498. paths_to_remove.add(os.path.join(bin_dir, name))
  499. if sys.platform == 'win32':
  500. paths_to_remove.add(os.path.join(bin_dir, name) + '.exe')
  501. paths_to_remove.add(os.path.join(bin_dir, name) + '.exe.manifest')
  502. paths_to_remove.add(os.path.join(bin_dir, name) + '-script.py')
  503. paths_to_remove.remove(auto_confirm)
  504. self.uninstalled = paths_to_remove
  505. def rollback_uninstall(self):
  506. if self.uninstalled:
  507. self.uninstalled.rollback()
  508. else:
  509. logger.error("Can't rollback %s, nothing uninstalled."
  510. % (self.project_name,))
  511. def commit_uninstall(self):
  512. if self.uninstalled:
  513. self.uninstalled.commit()
  514. else:
  515. logger.error("Can't commit %s, nothing uninstalled."
  516. % (self.project_name,))
  517. def archive(self, build_dir):
  518. assert self.source_dir
  519. create_archive = True
  520. archive_name = '%s-%s.zip' % (self.name, self.installed_version)
  521. archive_path = os.path.join(build_dir, archive_name)
  522. if os.path.exists(archive_path):
  523. response = ask_path_exists(
  524. 'The file %s exists. (i)gnore, (w)ipe, (b)ackup ' %
  525. display_path(archive_path), ('i', 'w', 'b'))
  526. if response == 'i':
  527. create_archive = False
  528. elif response == 'w':
  529. logger.warn('Deleting %s' % display_path(archive_path))
  530. os.remove(archive_path)
  531. elif response == 'b':
  532. dest_file = backup_dir(archive_path)
  533. logger.warn('Backing up %s to %s'
  534. % (display_path(archive_path), display_path(dest_file)))
  535. shutil.move(archive_path, dest_file)
  536. if create_archive:
  537. zip = zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED)
  538. dir = os.path.normcase(os.path.abspath(self.source_dir))
  539. for dirpath, dirnames, filenames in os.walk(dir):
  540. if 'pip-egg-info' in dirnames:
  541. dirnames.remove('pip-egg-info')
  542. for dirname in dirnames:
  543. dirname = os.path.join(dirpath, dirname)
  544. name = self._clean_zip_name(dirname, dir)
  545. zipdir = zipfile.ZipInfo(self.name + '/' + name + '/')
  546. zipdir.external_attr = 0x1ED << 16 # 0o755
  547. zip.writestr(zipdir, '')
  548. for filename in filenames:
  549. if filename == PIP_DELETE_MARKER_FILENAME:
  550. continue
  551. filename = os.path.join(dirpath, filename)
  552. name = self._clean_zip_name(filename, dir)
  553. zip.write(filename, self.name + '/' + name)
  554. zip.close()
  555. logger.indent -= 2
  556. logger.notify('Saved %s' % display_path(archive_path))
  557. def _clean_zip_name(self, name, prefix):
  558. assert name.startswith(prefix+os.path.sep), (
  559. "name %r doesn't start with prefix %r" % (name, prefix))
  560. name = name[len(prefix)+1:]
  561. name = name.replace(os.path.sep, '/')
  562. return name
  563. def install(self, install_options, global_options=(), root=None):
  564. if self.editable:
  565. self.install_editable(install_options, global_options)
  566. return
  567. if self.is_wheel:
  568. self.move_wheel_files(self.source_dir, root=root)
  569. self.install_succeeded = True
  570. return
  571. temp_location = tempfile.mkdtemp('-record', 'pip-')
  572. record_filename = os.path.join(temp_location, 'install-record.txt')
  573. try:
  574. install_args = [sys.executable]
  575. install_args.append('-c')
  576. install_args.append(
  577. "import setuptools;__file__=%r;"\
  578. "exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py)
  579. install_args += list(global_options) + ['install','--record', record_filename]
  580. if not self.as_egg:
  581. install_args += ['--single-version-externally-managed']
  582. if root is not None:
  583. install_args += ['--root', root]
  584. if self.pycompile:
  585. install_args += ["--compile"]
  586. else:
  587. install_args += ["--no-compile"]
  588. if running_under_virtualenv():
  589. ## FIXME: I'm not sure if this is a reasonable location; probably not
  590. ## but we can't put it in the default location, as that is a virtualenv symlink that isn't writable
  591. install_args += ['--install-headers',
  592. os.path.join(sys.prefix, 'include', 'site',
  593. 'python' + get_python_version())]
  594. logger.notify('Running setup.py install for %s' % self.name)
  595. logger.indent += 2
  596. try:
  597. call_subprocess(install_args + install_options,
  598. cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False)
  599. finally:
  600. logger.indent -= 2
  601. if not os.path.exists(record_filename):
  602. logger.notify('Record file %s not found' % record_filename)
  603. return
  604. self.install_succeeded = True
  605. if self.as_egg:
  606. # there's no --always-unzip option we can pass to install command
  607. # so we unable to save the installed-files.txt
  608. return
  609. def prepend_root(path):
  610. if root is None or not os.path.isabs(path):
  611. return path
  612. else:
  613. return change_root(root, path)
  614. f = open(record_filename)
  615. for line in f:
  616. line = line.strip()
  617. if line.endswith('.egg-info'):
  618. egg_info_dir = prepend_root(line)
  619. break
  620. else:
  621. logger.warn('Could not find .egg-info directory in install record for %s' % self)
  622. f.close()
  623. ## FIXME: put the record somewhere
  624. ## FIXME: should this be an error?
  625. return
  626. f.close()
  627. new_lines = []
  628. f = open(record_filename)
  629. for line in f:
  630. filename = line.strip()
  631. if os.path.isdir(filename):
  632. filename += os.path.sep
  633. new_lines.append(make_path_relative(prepend_root(filename), egg_info_dir))
  634. f.close()
  635. f = open(os.path.join(egg_info_dir, 'installed-files.txt'), 'w')
  636. f.write('\n'.join(new_lines)+'\n')
  637. f.close()
  638. finally:
  639. if os.path.exists(record_filename):
  640. os.remove(record_filename)
  641. os.rmdir(temp_location)
  642. def remove_temporary_source(self):
  643. """Remove the source files from this requirement, if they are marked
  644. for deletion"""
  645. if self.is_bundle or os.path.exists(self.delete_marker_filename):
  646. logger.info('Removing source in %s' % self.source_dir)
  647. if self.source_dir:
  648. rmtree(self.source_dir)
  649. self.source_dir = None
  650. if self._temp_build_dir and os.path.exists(self._temp_build_dir):
  651. rmtree(self._temp_build_dir)
  652. self._temp_build_dir = None
  653. def install_editable(self, install_options, global_options=()):
  654. logger.notify('Running setup.py develop for %s' % self.name)
  655. logger.indent += 2
  656. try:
  657. ## FIXME: should we do --install-headers here too?
  658. call_subprocess(
  659. [sys.executable, '-c',
  660. "import setuptools; __file__=%r; exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))" % self.setup_py]
  661. + list(global_options) + ['develop', '--no-deps'] + list(install_options),
  662. cwd=self.source_dir, filter_stdout=self._filter_install,
  663. show_stdout=False)
  664. finally:
  665. logger.indent -= 2
  666. self.install_succeeded = True
  667. def _filter_install(self, line):
  668. level = logger.NOTIFY
  669. for regex in [r'^running .*', r'^writing .*', '^creating .*', '^[Cc]opying .*',
  670. r'^reading .*', r"^removing .*\.egg-info' \(and everything under it\)$",
  671. r'^byte-compiling ',
  672. # Not sure what this warning is, but it seems harmless:
  673. r"^warning: manifest_maker: standard file '-c' not found$"]:
  674. if re.search(regex, line.strip()):
  675. level = logger.INFO
  676. break
  677. return (level, line)
  678. def check_if_exists(self):
  679. """Find an installed distribution that satisfies or conflicts
  680. with this requirement, and set self.satisfied_by or
  681. self.conflicts_with appropriately."""
  682. if self.req is None:
  683. return False
  684. try:
  685. # DISTRIBUTE TO SETUPTOOLS UPGRADE HACK (1 of 3 parts)
  686. # if we've already set distribute as a conflict to setuptools
  687. # then this check has already run before. we don't want it to
  688. # run again, and return False, since it would block the uninstall
  689. # TODO: remove this later
  690. if (self.req.project_name == 'setuptools'
  691. and self.conflicts_with
  692. and self.conflicts_with.project_name == 'distribute'):
  693. return True
  694. else:
  695. self.satisfied_by = pkg_resources.get_distribution(self.req)
  696. except pkg_resources.DistributionNotFound:
  697. return False
  698. except pkg_resources.VersionConflict:
  699. existing_dist = pkg_resources.get_distribution(self.req.project_name)
  700. if self.use_user_site:
  701. if dist_in_usersite(existing_dist):
  702. self.conflicts_with = existing_dist
  703. elif running_under_virtualenv() and dist_in_site_packages(existing_dist):
  704. raise InstallationError("Will not install to the user site because it will lack sys.path precedence to %s in %s"
  705. %(existing_dist.project_name, existing_dist.location))
  706. else:
  707. self.conflicts_with = existing_dist
  708. return True
  709. @property
  710. def is_wheel(self):
  711. return self.url and '.whl' in self.url
  712. @property
  713. def is_bundle(self):
  714. if self._is_bundle is not None:
  715. return self._is_bundle
  716. base = self._temp_build_dir
  717. if not base:
  718. ## FIXME: this doesn't seem right:
  719. return False
  720. self._is_bundle = (os.path.exists(os.path.join(base, 'pip-manifest.txt'))
  721. or os.path.exists(os.path.join(base, 'pyinstall-manifest.txt')))
  722. return self._is_bundle
  723. def bundle_requirements(self):
  724. for dest_dir in self._bundle_editable_dirs:
  725. package = os.path.basename(dest_dir)
  726. ## FIXME: svnism:
  727. for vcs_backend in vcs.backends:
  728. url = rev = None
  729. vcs_bundle_file = os.path.join(
  730. dest_dir, vcs_backend.bundle_file)
  731. if os.path.exists(vcs_bundle_file):
  732. vc_type = vcs_backend.name
  733. fp = open(vcs_bundle_file)
  734. content = fp.read()
  735. fp.close()
  736. url, rev = vcs_backend().parse_vcs_bundle_file(content)
  737. break
  738. if url:
  739. url = '%s+%s@%s' % (vc_type, url, rev)
  740. else:
  741. url = None
  742. yield InstallRequirement(
  743. package, self, editable=True, url=url,
  744. update=False, source_dir=dest_dir, from_bundle=True)
  745. for dest_dir in self._bundle_build_dirs:
  746. package = os.path.basename(dest_dir)
  747. yield InstallRequirement(package, self,source_dir=dest_dir, from_bundle=True)
  748. def move_bundle_files(self, dest_build_dir, dest_src_dir):
  749. base = self._temp_build_dir
  750. assert base
  751. src_dir = os.path.join(base, 'src')
  752. build_dir = os.path.join(base, 'build')
  753. bundle_build_dirs = []
  754. bundle_editable_dirs = []
  755. for source_dir, dest_dir, dir_collection in [
  756. (src_dir, dest_src_dir, bundle_editable_dirs),
  757. (build_dir, dest_build_dir, bundle_build_dirs)]:
  758. if os.path.exists(source_dir):
  759. for dirname in os.listdir(source_dir):
  760. dest = os.path.join(dest_dir, dirname)
  761. dir_collection.append(dest)
  762. if os.path.exists(dest):
  763. logger.warn('The directory %s (containing package %s) already exists; cannot move source from bundle %s'
  764. % (dest, dirname, self))
  765. continue
  766. if not os.path.exists(dest_dir):
  767. logger.info('Creating directory %s' % dest_dir)
  768. os.makedirs(dest_dir)
  769. shutil.move(os.path.join(source_dir, dirname), dest)
  770. if not os.listdir(source_dir):
  771. os.rmdir(source_dir)
  772. self._temp_build_dir = None
  773. self._bundle_build_dirs = bundle_build_dirs
  774. self._bundle_editable_dirs = bundle_editable_dirs
  775. def move_wheel_files(self, wheeldir, root=None):
  776. move_wheel_files(
  777. self.name, self.req, wheeldir,
  778. user=self.use_user_site,
  779. home=self.target_dir,
  780. root=root,
  781. pycompile=self.pycompile,
  782. )
  783. @property
  784. def delete_marker_filename(self):
  785. assert self.source_dir
  786. return os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)
  787. class Requirements(object):
  788. def __init__(self):
  789. self._keys = []
  790. self._dict = {}
  791. def keys(self):
  792. return self._keys
  793. def values(self):
  794. return [self._dict[key] for key in self._keys]
  795. def __contains__(self, item):
  796. return item in self._keys
  797. def __setitem__(self, key, value):
  798. if key not in self._keys:
  799. self._keys.append(key)
  800. self._dict[key] = value
  801. def __getitem__(self, key):
  802. return self._dict[key]
  803. def __repr__(self):
  804. values = ['%s: %s' % (repr(k), repr(self[k])) for k in self.keys()]
  805. return 'Requirements({%s})' % ', '.join(values)
  806. class RequirementSet(object):
  807. def __init__(self, build_dir, src_dir, download_dir, download_cache=None,
  808. upgrade=False, ignore_installed=False, as_egg=False, target_dir=None,
  809. ignore_dependencies=False, force_reinstall=False, use_user_site=False,
  810. session=None, pycompile=True):
  811. self.build_dir = build_dir
  812. self.src_dir = src_dir
  813. self.download_dir = download_dir
  814. self.download_cache = download_cache
  815. self.upgrade = upgrade
  816. self.ignore_installed = ignore_installed
  817. self.force_reinstall = force_reinstall
  818. self.requirements = Requirements()
  819. # Mapping of alias: real_name
  820. self.requirement_aliases = {}
  821. self.unnamed_requirements = []
  822. self.ignore_dependencies = ignore_dependencies
  823. self.successfully_downloaded = []
  824. self.successfully_installed = []
  825. self.reqs_to_cleanup = []
  826. self.as_egg = as_egg
  827. self.use_user_site = use_user_site
  828. self.target_dir = target_dir #set from --target option
  829. self.session = session or PipSession()
  830. self.pycompile = pycompile
  831. def __str__(self):
  832. reqs = [req for req in self.requirements.values()
  833. if not req.comes_from]
  834. reqs.sort(key=lambda req: req.name.lower())
  835. return ' '.join([str(req.req) for req in reqs])
  836. def add_requirement(self, install_req):
  837. name = install_req.name
  838. install_req.as_egg = self.as_egg
  839. install_req.use_user_site = self.use_user_site
  840. install_req.target_dir = self.target_dir
  841. install_req.pycompile = self.pycompile
  842. if not name:
  843. #url or path requirement w/o an egg fragment
  844. self.unnamed_requirements.append(install_req)
  845. else:
  846. if self.has_requirement(name):
  847. raise InstallationError(
  848. 'Double requirement given: %s (already in %s, name=%r)'
  849. % (install_req, self.get_requirement(name), name))
  850. self.requirements[name] = install_req
  851. ## FIXME: what about other normalizations? E.g., _ vs. -?
  852. if name.lower() != name:
  853. self.requirement_aliases[name.lower()] = name
  854. def has_requirement(self, project_name):
  855. for name in project_name, project_name.lower():
  856. if name in self.requirements or name in self.requirement_aliases:
  857. return True
  858. return False
  859. @property
  860. def has_requirements(self):
  861. return list(self.requirements.values()) or self.unnamed_requirements
  862. @property
  863. def has_editables(self):
  864. if any(req.editable for req in self.requirements.values()):
  865. return True
  866. if any(req.editable for req in self.unnamed_requirements):
  867. return True
  868. return False
  869. @property
  870. def is_download(self):
  871. if self.download_dir:
  872. self.download_dir = os.path.expanduser(self.download_dir)
  873. if os.path.exists(self.download_dir):
  874. return True
  875. else:
  876. logger.fatal('Could not find download directory')
  877. raise InstallationError(
  878. "Could not find or access download directory '%s'"
  879. % display_path(self.download_dir))
  880. return False
  881. def get_requirement(self, project_name):
  882. for name in project_name, project_name.lower():
  883. if name in self.requirements:
  884. return self.requirements[name]
  885. if name in self.requirement_aliases:
  886. return self.requirements[self.requirement_aliases[name]]
  887. raise KeyError("No project with the name %r" % project_name)
  888. def uninstall(self, auto_confirm=False):
  889. for req in self.requirements.values():
  890. req.uninstall(auto_confirm=auto_confirm)
  891. req.commit_uninstall()
  892. def locate_files(self):
  893. ## FIXME: duplicates code from prepare_files; relevant code should
  894. ## probably be factored out into a separate method
  895. unnamed = list(self.unnamed_requirements)
  896. reqs = list(self.requirements.values())
  897. while reqs or unnamed:
  898. if unnamed:
  899. req_to_install = unnamed.pop(0)
  900. else:
  901. req_to_install = reqs.pop(0)
  902. install_needed = True
  903. if not self.ignore_installed and not req_to_install.editable:
  904. req_to_install.check_if_exists()
  905. if req_to_install.satisfied_by:
  906. if self.upgrade:
  907. #don't uninstall conflict if user install and and conflict is not user install
  908. if not (self.use_user_site and not dist_in_usersite(req_to_install.satisfied_by)):
  909. req_to_install.conflicts_with = req_to_install.satisfied_by
  910. req_to_install.satisfied_by = None
  911. else:
  912. install_needed = False
  913. if req_to_install.satisfied_by:
  914. logger.notify('Requirement already satisfied '
  915. '(use --upgrade to upgrade): %s'
  916. % req_to_install)
  917. if req_to_install.editable:
  918. if req_to_install.source_dir is None:
  919. req_to_install.source_dir = req_to_install.build_location(self.src_dir)
  920. elif install_needed:
  921. req_to_install.source_dir = req_to_install.build_location(self.build_dir, not self.is_download)
  922. if req_to_install.source_dir is not None and not os.path.isdir(req_to_install.source_dir):
  923. raise InstallationError('Could not install requirement %s '
  924. 'because source folder %s does not exist '
  925. '(perhaps --no-download was used without first running '
  926. 'an equivalent install with --no-install?)'
  927. % (req_to_install, req_to_install.source_dir))
  928. def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
  929. """Prepare process. Create temp directories, download and/or unpack files."""
  930. unnamed = list(self.unnamed_requirements)
  931. reqs = list(self.requirements.values())
  932. while reqs or unnamed:
  933. if unnamed:
  934. req_to_install = unnamed.pop(0)
  935. else:
  936. req_to_install = reqs.pop(0)
  937. install = True
  938. best_installed = False
  939. not_found = None
  940. if not self.ignore_installed and not req_to_install.editable:
  941. req_to_install.check_if_exists()
  942. if req_to_install.satisfied_by:
  943. if self.upgrade:
  944. if not self.force_reinstall and not req_to_install.url:
  945. try:
  946. url = finder.find_requirement(
  947. req_to_install, self.upgrade)
  948. except BestVersionAlreadyInstalled:
  949. best_installed = True
  950. install = False
  951. except DistributionNotFound:
  952. not_found = sys.exc_info()[1]
  953. else:
  954. # Avoid the need to call find_requirement again
  955. req_to_install.url = url.url
  956. if not best_installed:
  957. #don't uninstall conflict if user install and conflict is not user install
  958. if not (self.use_user_site and not dist_in_usersite(req_to_install.satisfied_by)):
  959. req_to_install.conflicts_with = req_to_install.satisfied_by
  960. req_to_install.satisfied_by = None
  961. else:
  962. install = False
  963. if req_to_install.satisfied_by:
  964. if best_installed:
  965. logger.notify('Requirement already up-to-date: %s'
  966. % req_to_install)
  967. else:
  968. logger.notify('Requirement already satisfied '
  969. '(use --upgrade to upgrade): %s'
  970. % req_to_install)
  971. if req_to_install.editable:
  972. logger.notify('Obtaining %s' % req_to_install)
  973. elif install:
  974. if req_to_install.url and req_to_install.url.lower().startswith('file:'):
  975. logger.notify('Unpacking %s' % display_path(url_to_path(req_to_install.url)))
  976. else:
  977. logger.notify('Downloading/unpacking %s' % req_to_install)
  978. logger.indent += 2
  979. try:
  980. is_bundle = False
  981. is_wheel = False
  982. if req_to_install.editable:
  983. if req_to_install.source_dir is None:
  984. location = req_to_install.build_location(self.src_dir)
  985. req_to_install.source_dir = location
  986. else:
  987. location = req_to_install.source_dir
  988. if not os.path.exists(self.build_dir):
  989. _make_build_dir(self.build_dir)
  990. req_to_install.update_editable(not self.is_download)
  991. if self.is_download:
  992. req_to_install.run_egg_info()
  993. req_to_install.archive(self.download_dir)
  994. else:
  995. req_to_install.run_egg_info()
  996. elif install:
  997. ##@@ if filesystem packages are not marked
  998. ##editable in a req, a non deterministic error
  999. ##occurs when the script attempts to unpack the
  1000. ##build directory
  1001. # NB: This call can result in the creation of a temporary build directory
  1002. location = req_to_install.build_location(self.build_dir, not self.is_download)
  1003. unpack = True
  1004. url = None
  1005. # In the case where the req comes from a bundle, we should
  1006. # assume a build dir exists and move on
  1007. if req_to_install.from_bundle:
  1008. pass
  1009. # If a checkout exists, it's unwise to keep going. version
  1010. # inconsistencies are logged later, but do not fail the
  1011. # installation.
  1012. elif os.path.exists(os.path.join(location, 'setup.py')):
  1013. raise PreviousBuildDirError(textwrap.dedent("""
  1014. pip can't proceed with requirement '%s' due to a pre-existing build directory.
  1015. location: %s
  1016. This is likely due to a previous installation that failed.
  1017. pip is being responsible and not assuming it can delete this.
  1018. Please delete it and try again.
  1019. """ % (req_to_install, location)))
  1020. else:
  1021. ## FIXME: this won't upgrade when there's an existing package unpacked in `location`
  1022. if req_to_install.url is None:
  1023. if not_found:
  1024. raise not_found
  1025. url = finder.find_requirement(req_to_install, upgrade=self.upgrade)
  1026. else:
  1027. ## FIXME: should req_to_install.url already be a link?
  1028. url = Link(req_to_install.url)
  1029. assert url
  1030. if url:
  1031. try:
  1032. self.unpack_url(url, location, self.is_download)
  1033. except HTTPError:

Large files files are truncated, but you can click here to view the full file