diff options
Diffstat (limited to 'src/snakeoil/version.py')
-rw-r--r-- | src/snakeoil/version.py | 78 |
1 files changed, 44 insertions, 34 deletions
diff --git a/src/snakeoil/version.py b/src/snakeoil/version.py index 7b9a500..0e88dbf 100644 --- a/src/snakeoil/version.py +++ b/src/snakeoil/version.py @@ -3,12 +3,14 @@ import errno import os import subprocess +from datetime import datetime from importlib import import_module +from typing import NamedTuple, Optional _ver = None -def get_version(project, repo_file, api_version=None): +def get_version(project, repo_file, api_version=None) -> str: """Determine a project's version information. Standardized version retrieval for git-based projects. In summary, if the @@ -40,74 +42,82 @@ def get_version(project, repo_file, api_version=None): version_info = get_git_version(path) if version_info is None: - s = '' - elif version_info['tag'] == api_version: - s = f" -- released {version_info['date']}" + suffix = '' + elif version_info.tag == api_version: + suffix = f' -- released {version_info.date_rfc2822}' else: - rev = version_info['rev'][:7] - date = version_info['date'] - commits = version_info.get('commits', None) - commits = f'-{commits}' if commits is not None else '' - s = f'{commits}-g{rev} -- {date}' + rev = version_info.short_revision + date = version_info.date_rfc2822 + commits = f'-{version_info.commits}' if version_info.commits is not None else '' + suffix = f'{commits}-g{rev} -- {date}' - _ver = f'{project} {api_version}{s}' + _ver = f'{project} {api_version}{suffix}' return _ver -def _run_git(path, cmd): +def _run_git(path: str, *cmd: str): env = dict(os.environ) for key in env.copy(): # pragma: no cover if key.startswith("LC_"): del env[key] env["LC_CTYPE"] = "C" env["LC_ALL"] = "C" + r = subprocess.Popen(('git', ) + cmd, env=env, cwd=path, + stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) - r = subprocess.Popen( - ['git'] + list(cmd), stdout=subprocess.PIPE, env=env, - stderr=subprocess.DEVNULL, cwd=path) - - stdout = r.communicate()[0] + stdout, _ = r.communicate() return stdout, r.returncode -def get_git_version(path): +class GitVersion(NamedTuple): + revision: str + date: datetime + tag: Optional[str] = None + commits: Optional[int] = None + + @property + def date_rfc2822(self): + return self.date.strftime('%a, %d %b %Y %H:%M:%S %z') + + @property + def short_revision(self): + return self.revision[:7] + + +def get_git_version(path: str) -> Optional[GitVersion]: """Return git related revision data.""" path = os.path.abspath(path) try: - stdout, ret = _run_git(path, ["log", "--format=%H\n%aD", "HEAD^..HEAD"]) - + stdout, ret = _run_git(path, "log", "--format=%H\n%aI", "HEAD^..HEAD") if ret != 0: return None - data = stdout.decode().splitlines() - tag = _get_git_tag(path, data[0]) + revision, date = stdout.decode().splitlines() + tag = _get_git_tag(path, revision) # get number of commits since most recent tag - stdout, ret = _run_git(path, ['describe', '--tags', '--abbrev=0']) - prev_tag = None + stdout, ret = _run_git(path, 'describe', '--tags', '--abbrev=0') commits = None if ret == 0: prev_tag = stdout.decode().strip() - stgbdout, ret = _run_git( - path, ['log', '--oneline', f'{prev_tag}..HEAD']) + stdout, ret = _run_git( + path, 'log', '--oneline', f'{prev_tag}..HEAD') if ret == 0: commits = len(stdout.decode().splitlines()) - return { - 'rev': data[0], - 'date': data[1], - 'tag': tag, - 'commits': commits, - } - except EnvironmentError as e: + return GitVersion( + revision=revision, date=datetime.fromisoformat(date), + tag=tag, commits=commits, + ) + except EnvironmentError as exc: # ENOENT is thrown when the git binary can't be found. - if e.errno != errno.ENOENT: + if exc.errno != errno.ENOENT: raise return None def _get_git_tag(path, rev): - stdout, _ = _run_git(path, ['name-rev', '--tag', rev]) + stdout, _ = _run_git(path, 'name-rev', '--tag', rev) tag = stdout.decode().split() if len(tag) != 2: return None |