From 40067dce0abda1b073836c223a774d50ad12d217 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Wed, 8 Jun 2022 07:06:45 +0200 Subject: [PATCH] Auto-generate git versions compatible with PEP 440 `git archive` is configured to set osc version according to the git tag via .gitattributes/export-subst --- .gitattributes | 2 ++ osc/core.py | 5 ++- osc/util/git_version.py | 75 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 osc/util/git_version.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..75a90df0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +osc/util/git_version.py export-subst + diff --git a/osc/core.py b/osc/core.py index c6e251f7..adac010b 100644 --- a/osc/core.py +++ b/osc/core.py @@ -5,7 +5,10 @@ from __future__ import print_function -__version__ = '0.179' + +from .util import git_version +__version__ = git_version.get_version('0.179.0') + # __store_version__ is to be incremented when the format of the working copy # "store" changes in an incompatible way. Please add any needed migration diff --git a/osc/util/git_version.py b/osc/util/git_version.py new file mode 100644 index 00000000..7002b9c6 --- /dev/null +++ b/osc/util/git_version.py @@ -0,0 +1,75 @@ +import os +import subprocess + + +def get_git_archive_version(): + """ + Return version that is set by git during `git archive`. + The returned format is equal to what `git describe --tags` returns. + """ + # the `version` variable contents get substituted during `git archive` + # it requires adding this to .gitattributes: export-subst + version = "$Format:%(describe:tags=true)$" + if version.startswith("$"): + # version hasn't been substituted during `git archive` + return None + return version + + +def get_git_version(): + """ + Determine version from git repo by calling `git describe --tags`. + """ + cmd = ["git", "describe", "--tags"] + # run the command from the place where this file is placed + # to ensure that we're in a git repo + cwd = os.path.dirname(__file__) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) + stdout, _ = proc.communicate() + + if proc.returncode != 0: + return None + + version = stdout.strip().decode("utf-8") + return version + + +def get_version(version): + """ + Get the most relevant version of the software: + 1. the version set during `git archive` + 2. the version from the git tags by calling `git describe --tags` + 3. the version explicitly specified in the source code + + The version conforms PEP 440. + """ + # use version from the archive + git_version = get_git_archive_version() + + # use version from the git repo + if not git_version: + git_version = get_git_version() + + # unable to determine version from git + if not git_version: + return version + + if "-" not in git_version: + git_tag = git_version + git_commits = None + git_hash = None + else: + git_tag, git_commits, git_hash = git_version.rsplit("-", 2) + git_commits = int(git_commits) + # remove the 'g' prefix from hash + git_hash = git_hash[1:] + + if version and git_tag != version: + msg = "Git tag '{}' doesn't correspond with version '{}' specified in the source code".format(git_tag, version) + raise ValueError(msg) + + result = git_tag + if git_hash: + result += "+{}.git.{}".format(git_commits, git_hash) + + return result