Add support for sdists and git-archive to _get_version() (#5814)

Co-authored-by: Jakub Kuczys <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
Jakub Kuczys 2022-12-30 03:52:49 +01:00 committed by GitHub
parent fa6b2f8c10
commit 88a348210c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 33 deletions

2
.git_archive_info.txt Normal file
View File

@ -0,0 +1,2 @@
$Format:%h$
$Format:%(describe:tags=true)$

3
.gitattributes vendored
View File

@ -2,3 +2,6 @@
# binary file excludsions # binary file excludsions
*.png binary *.png binary
# include commit/tag information in `.git_archive_info.txt` when packing with git-archive
.git_archive_info.txt export-subst

View File

@ -1,3 +1,4 @@
import os as _os
import re as _re import re as _re
import sys as _sys import sys as _sys
import warnings as _warnings import warnings as _warnings
@ -209,45 +210,86 @@ class VersionInfo:
def _get_version(cls, *, ignore_installed: bool = False) -> _Tuple[str, "VersionInfo"]: def _get_version(cls, *, ignore_installed: bool = False) -> _Tuple[str, "VersionInfo"]:
if not _VERSION.endswith(".dev1"): if not _VERSION.endswith(".dev1"):
return _VERSION, cls.from_str(_VERSION) return _VERSION, cls.from_str(_VERSION)
try:
import os
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) project_root = _os.path.abspath(_os.path.dirname(_os.path.dirname(__file__)))
# we only want to do this for editable installs
if not os.path.exists(os.path.join(path, ".git")):
raise RuntimeError("not a git repository")
import subprocess methods = [
cls._get_version_from_git_repo,
output = subprocess.check_output( ]
("git", "describe", "--tags", "--long", "--dirty"), # `ignore_installed` is `True` when building with setuptools.
stderr=subprocess.DEVNULL, if ignore_installed:
cwd=path, methods.append(cls._get_version_from_sdist_pkg_info)
) methods.append(cls._get_version_from_git_archive)
_, count, commit, *dirty = output.decode("utf-8").strip().split("-", 3) else:
dirty_suffix = f".{dirty[0]}" if dirty else "" methods.append(cls._get_version_from_package_metadata)
ver = f"{_VERSION[:-1]}{count}+{commit}{dirty_suffix}" exceptions = []
return ver, cls.from_str(ver) for method in methods:
except Exception: try:
# `ignore_installed` is `True` when building with setuptools. version = method(project_root)
if ignore_installed: except Exception as exc:
# we don't want any failure to raise here but we should print it exceptions.append(exc)
import traceback
traceback.print_exc()
else: else:
try: break
from importlib.metadata import version else:
import traceback
ver = version("Red-DiscordBot") for exc in exceptions:
return ver, cls.from_str(ver) traceback.print_exception(None, exc, exc.__traceback__)
except Exception: exc.__traceback__ = None
# we don't want any failure to raise here but we should print it
import traceback
traceback.print_exc() version = _VERSION
return _VERSION, cls.from_str(_VERSION) return version, cls.from_str(version)
@classmethod
def _get_version_from_git_repo(cls, project_root: str) -> str:
# we only want to do this for editable installs
if not _os.path.exists(_os.path.join(project_root, ".git")):
raise RuntimeError("not a git repository")
import subprocess
output = subprocess.check_output(
("git", "describe", "--tags", "--long", "--dirty"),
stderr=subprocess.DEVNULL,
cwd=project_root,
)
_, count, commit, *dirty = output.decode("utf-8").strip().split("-", 3)
dirty_suffix = f".{dirty[0]}" if dirty else ""
return f"{_VERSION[:-1]}{count}+{commit}{dirty_suffix}"
@classmethod
def _get_version_from_git_archive(cls, project_root: str) -> str:
with open(_os.path.join(project_root, ".git_archive_info.txt"), encoding="utf-8") as fp:
commit, describe_name = fp.read().splitlines()
if not describe_name:
raise RuntimeError("git archive's describe didn't output anything")
if "%(describe" in describe_name:
# either git-archive was generated with Git < 2.35 or this is not a git-archive
raise RuntimeError("git archive did not support describe output")
_, _, suffix = describe_name.partition("-")
if suffix:
count, _, _ = suffix.partition("-")
else:
count = "0"
return f"{_VERSION[:-1]}{count}+g{commit}"
@classmethod
def _get_version_from_sdist_pkg_info(cls, project_root: str) -> str:
pkg_info_path = _os.path.join(project_root, "PKG-INFO")
if not _os.path.exists(pkg_info_path):
raise RuntimeError("not an sdist")
import email
with open(pkg_info_path, encoding="utf-8") as fp:
return email.message_from_file(fp)["Version"]
@classmethod
def _get_version_from_package_metadata(cls, project_root: str) -> str:
from importlib.metadata import version
return version("Red-DiscordBot")
def _update_event_loop_policy(): def _update_event_loop_policy():