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.
 
 
 
 

117 lines
3.9 KiB

  1. from distutils import log, dir_util
  2. import os
  3. from setuptools import Command
  4. from setuptools.archive_util import unpack_archive
  5. import pkg_resources
  6. class install_egg_info(Command):
  7. """Install an .egg-info directory for the package"""
  8. description = "Install an .egg-info directory for the package"
  9. user_options = [
  10. ('install-dir=', 'd', "directory to install to"),
  11. ]
  12. def initialize_options(self):
  13. self.install_dir = None
  14. def finalize_options(self):
  15. self.set_undefined_options('install_lib',
  16. ('install_dir', 'install_dir'))
  17. ei_cmd = self.get_finalized_command("egg_info")
  18. basename = pkg_resources.Distribution(
  19. None, None, ei_cmd.egg_name, ei_cmd.egg_version
  20. ).egg_name() + '.egg-info'
  21. self.source = ei_cmd.egg_info
  22. self.target = os.path.join(self.install_dir, basename)
  23. self.outputs = [self.target]
  24. def run(self):
  25. self.run_command('egg_info')
  26. if os.path.isdir(self.target) and not os.path.islink(self.target):
  27. dir_util.remove_tree(self.target, dry_run=self.dry_run)
  28. elif os.path.exists(self.target):
  29. self.execute(os.unlink, (self.target,), "Removing " + self.target)
  30. if not self.dry_run:
  31. pkg_resources.ensure_directory(self.target)
  32. self.execute(
  33. self.copytree, (), "Copying %s to %s" % (self.source, self.target)
  34. )
  35. self.install_namespaces()
  36. def get_outputs(self):
  37. return self.outputs
  38. def copytree(self):
  39. # Copy the .egg-info tree to site-packages
  40. def skimmer(src, dst):
  41. # filter out source-control directories; note that 'src' is always
  42. # a '/'-separated path, regardless of platform. 'dst' is a
  43. # platform-specific path.
  44. for skip in '.svn/', 'CVS/':
  45. if src.startswith(skip) or '/' + skip in src:
  46. return None
  47. self.outputs.append(dst)
  48. log.debug("Copying %s to %s", src, dst)
  49. return dst
  50. unpack_archive(self.source, self.target, skimmer)
  51. def install_namespaces(self):
  52. nsp = self._get_all_ns_packages()
  53. if not nsp:
  54. return
  55. filename, ext = os.path.splitext(self.target)
  56. filename += '-nspkg.pth'
  57. self.outputs.append(filename)
  58. log.info("Installing %s", filename)
  59. lines = map(self._gen_nspkg_line, nsp)
  60. if self.dry_run:
  61. # always generate the lines, even in dry run
  62. list(lines)
  63. return
  64. with open(filename, 'wt') as f:
  65. f.writelines(lines)
  66. _nspkg_tmpl = (
  67. "import sys, types, os",
  68. "p = os.path.join(sys._getframe(1).f_locals['sitedir'], *%(pth)r)",
  69. "ie = os.path.exists(os.path.join(p,'__init__.py'))",
  70. "m = not ie and "
  71. "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
  72. "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
  73. "(p not in mp) and mp.append(p)",
  74. )
  75. "lines for the namespace installer"
  76. _nspkg_tmpl_multi = (
  77. 'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
  78. )
  79. "additional line(s) when a parent package is indicated"
  80. @classmethod
  81. def _gen_nspkg_line(cls, pkg):
  82. # ensure pkg is not a unicode string under Python 2.7
  83. pkg = str(pkg)
  84. pth = tuple(pkg.split('.'))
  85. tmpl_lines = cls._nspkg_tmpl
  86. parent, sep, child = pkg.rpartition('.')
  87. if parent:
  88. tmpl_lines += cls._nspkg_tmpl_multi
  89. return ';'.join(tmpl_lines) % locals() + '\n'
  90. def _get_all_ns_packages(self):
  91. """Return sorted list of all package namespaces"""
  92. nsp = set()
  93. for pkg in self.distribution.namespace_packages or []:
  94. pkg = pkg.split('.')
  95. while pkg:
  96. nsp.add('.'.join(pkg))
  97. pkg.pop()
  98. return sorted(nsp)