dist_info.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. """
  2. Create a dist_info directory
  3. As defined in the wheel specification
  4. """
  5. import os
  6. import shutil
  7. import sys
  8. from contextlib import contextmanager
  9. from distutils import log
  10. from distutils.core import Command
  11. from pathlib import Path
  12. from .. import _normalization
  13. class dist_info(Command):
  14. """
  15. This command is private and reserved for internal use of setuptools,
  16. users should rely on ``setuptools.build_meta`` APIs.
  17. """
  18. description = "DO NOT CALL DIRECTLY, INTERNAL ONLY: create .dist-info directory"
  19. user_options = [
  20. (
  21. 'output-dir=',
  22. 'o',
  23. "directory inside of which the .dist-info will be"
  24. "created (default: top of the source tree)",
  25. ),
  26. ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
  27. ('tag-build=', 'b', "Specify explicit tag to add to version number"),
  28. ('no-date', 'D', "Don't include date stamp [default]"),
  29. ('keep-egg-info', None, "*TRANSITIONAL* will be removed in the future"),
  30. ]
  31. boolean_options = ['tag-date', 'keep-egg-info']
  32. negative_opt = {'no-date': 'tag-date'}
  33. def initialize_options(self):
  34. self.output_dir = None
  35. self.name = None
  36. self.dist_info_dir = None
  37. self.tag_date = None
  38. self.tag_build = None
  39. self.keep_egg_info = False
  40. def finalize_options(self):
  41. dist = self.distribution
  42. project_dir = dist.src_root or os.curdir
  43. self.output_dir = Path(self.output_dir or project_dir)
  44. egg_info = self.reinitialize_command("egg_info")
  45. egg_info.egg_base = str(self.output_dir)
  46. if self.tag_date:
  47. egg_info.tag_date = self.tag_date
  48. else:
  49. self.tag_date = egg_info.tag_date
  50. if self.tag_build:
  51. egg_info.tag_build = self.tag_build
  52. else:
  53. self.tag_build = egg_info.tag_build
  54. egg_info.finalize_options()
  55. self.egg_info = egg_info
  56. name = _normalization.safer_name(dist.get_name())
  57. version = _normalization.safer_best_effort_version(dist.get_version())
  58. self.name = f"{name}-{version}"
  59. self.dist_info_dir = os.path.join(self.output_dir, f"{self.name}.dist-info")
  60. @contextmanager
  61. def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool):
  62. if requires_bkp:
  63. bkp_name = f"{dir_path}.__bkp__"
  64. _rm(bkp_name, ignore_errors=True)
  65. _copy(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True)
  66. try:
  67. yield
  68. finally:
  69. _rm(dir_path, ignore_errors=True)
  70. shutil.move(bkp_name, dir_path)
  71. else:
  72. yield
  73. def run(self):
  74. self.output_dir.mkdir(parents=True, exist_ok=True)
  75. self.egg_info.run()
  76. egg_info_dir = self.egg_info.egg_info
  77. assert os.path.isdir(egg_info_dir), ".egg-info dir should have been created"
  78. log.info("creating '{}'".format(os.path.abspath(self.dist_info_dir)))
  79. bdist_wheel = self.get_finalized_command('bdist_wheel')
  80. # TODO: if bdist_wheel if merged into setuptools, just add "keep_egg_info" there
  81. with self._maybe_bkp_dir(egg_info_dir, self.keep_egg_info):
  82. bdist_wheel.egg2dist(egg_info_dir, self.dist_info_dir)
  83. def _rm(dir_name, **opts):
  84. if os.path.isdir(dir_name):
  85. shutil.rmtree(dir_name, **opts)
  86. def _copy(src, dst, **opts):
  87. if sys.version_info < (3, 8):
  88. opts.pop("dirs_exist_ok", None)
  89. shutil.copytree(src, dst, **opts)