diff --git a/.versioneer-lookup b/.versioneer-lookup new file mode 100644 index 0000000000..8e1218d797 --- /dev/null +++ b/.versioneer-lookup @@ -0,0 +1,18 @@ +# Configuration file for the versioneer lookup, manually mapping tags based on branches +# +# Format is +# +# +# +# The file is processed from top to bottom, the first matching line wins. If or are left out, +# the lookup table does not apply to the matched branches + +# master and staging shall not use the lookup table +master +staging + +# fix/ branches are fixes for master, so we don't handle those either +fix/.* + +# every other branch is a development branch and thus gets resolved to 1.2.0-dev for now +.* 1.2.0-dev 50cf776e70b9 diff --git a/setup.py b/setup.py index 471e546f35..d06296ea24 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ versioneer.versionfile_build = 'octoprint/_version.py' versioneer.tag_prefix = '' versioneer.parentdir_prefix = '' +versioneer.lookupfile = '.versioneer-lookup' from setuptools import setup, find_packages, Command import os diff --git a/src/octoprint/_version.py b/src/octoprint/_version.py index f9a41364b8..52aefd4943 100644 --- a/src/octoprint/_version.py +++ b/src/octoprint/_version.py @@ -54,6 +54,18 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): import re import os.path +def get_gits(root, verbose=False): + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return None + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + return GITS + + def get_expanded_variables(versionfile_abs): # the code embedded in _version.py can just fetch the value of these # variables. When used from setup.py, we don't want to import @@ -114,20 +126,60 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False): return { "version": variables["full"].strip(), "full": variables["full"].strip() } +def versions_from_lookup(lookup, root, verbose=False): + GITS = get_gits(root, verbose=verbose) + if GITS is None: + return {} + + stdout = run_command(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], + cwd=root) + if stdout is None: + return {} + + current_branch = stdout.strip() + for matcher, tag, ref_commit in lookup: + if matcher.match(current_branch): + if tag is None or ref_commit is None: + return {} + + stdout = run_command(GITS, ["rev-list", "%s..HEAD" % ref_commit, "--count"], cwd=root) + if stdout is None: + return {} + num_commits = stdout.strip() + + stdout =run_command(GITS, ["rev-parse", "--short", "HEAD"], cwd=root) + if stdout is None: + return {} + short_hash = stdout.strip() + + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) + if stdout is None: + return {} + dirty = stdout.strip().endswith("-dirty") + + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + + version = "%s-%s-g%s" % (tag, num_commits, short_hash) + if dirty: + version += "-dirty" + full += "-dirty" + return {"version": version, "full": full} + + return {} + def versions_from_vcs(tag_prefix, root, verbose=False): # this runs 'git' from the root of the source tree. This only gets called # if the git-archive 'subst' variables were *not* expanded, and # _version.py hasn't already been rewritten with a short version string, # meaning we're inside a checked out source tree. - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %s" % root) + GITS = get_gits(root, verbose=verbose) + if GITS is None: return {} - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) if stdout is None: @@ -158,10 +210,39 @@ def versions_from_parentdir(parentdir_prefix, root, verbose=False): return {"version": dirname[len(parentdir_prefix):], "full": ""} tag_prefix = "" -parentdir_prefix = "octoprint-" +parentdir_prefix = "" versionfile_source = "src/octoprint/_version.py" +lookupfile = ".versioneer-lookup" + +def parse_lookup_file(root, lookup_path=None): + if not lookup_path: + lookup_path = lookupfile + if not lookup_path: + return [] + + path = os.path.join(root, lookup_path) + if not os.path.exists(path): + return [] + + import re + lookup = [] + with open(os.path.join(root, lookup_path), "r") as f: + for line in f: + if '#' in line: + line = line[:line.rindex('#')] + line = line.strip() + try: + split_line = line.split() + if len(split_line) == 3: + pattern, tag, ref_commit = split_line + lookup.append([re.compile(pattern), tag, ref_commit]) + elif len(split_line) >= 1: + lookup.append([re.compile(split_line[0]), None, None]) + except: + break + return lookup -def get_versions(default={"version": "unknown", "full": ""}, verbose=False): +def get_versions(default={"version": "unknown", "full": ""}, lookup_path=None, verbose=False): # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which @@ -182,7 +263,9 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False): except NameError: return default - return (versions_from_vcs(tag_prefix, root, verbose) + lookup = parse_lookup_file(root, lookup_path=lookup_path) + return (versions_from_lookup(lookup, root, verbose) + or versions_from_vcs(tag_prefix, root, verbose) or versions_from_parentdir(parentdir_prefix, root, verbose) or default) diff --git a/versioneer.py b/versioneer.py index a01ab1cefe..237968f19d 100644 --- a/versioneer.py +++ b/versioneer.py @@ -252,6 +252,7 @@ versionfile_build = None tag_prefix = None parentdir_prefix = None +lookupfile = None VCS = "git" @@ -312,6 +313,18 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): import re import os.path +def get_gits(root, verbose=False): + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %%s" %% root) + return None + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + return GITS + + def get_expanded_variables(versionfile_abs): # the code embedded in _version.py can just fetch the value of these # variables. When used from setup.py, we don't want to import @@ -372,20 +385,60 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False): return { "version": variables["full"].strip(), "full": variables["full"].strip() } +def versions_from_lookup(lookup, root, verbose=False): + GITS = get_gits(root, verbose=verbose) + if GITS is None: + return {} + + stdout = run_command(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], + cwd=root) + if stdout is None: + return {} + + current_branch = stdout.strip() + for matcher, tag, ref_commit in lookup: + if matcher.match(current_branch): + if tag is None or ref_commit is None: + return {} + + stdout = run_command(GITS, ["rev-list", "%%s..HEAD" %% ref_commit, "--count"], cwd=root) + if stdout is None: + return {} + num_commits = stdout.strip() + + stdout =run_command(GITS, ["rev-parse", "--short", "HEAD"], cwd=root) + if stdout is None: + return {} + short_hash = stdout.strip() + + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) + if stdout is None: + return {} + dirty = stdout.strip().endswith("-dirty") + + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + + version = "%%s-%%s-g%%s" %% (tag, num_commits, short_hash) + if dirty: + version += "-dirty" + full += "-dirty" + return {"version": version, "full": full} + + return {} + def versions_from_vcs(tag_prefix, root, verbose=False): # this runs 'git' from the root of the source tree. This only gets called # if the git-archive 'subst' variables were *not* expanded, and # _version.py hasn't already been rewritten with a short version string, # meaning we're inside a checked out source tree. - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %%s" %% root) + GITS = get_gits(root, verbose=verbose) + if GITS is None: return {} - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) if stdout is None: @@ -418,8 +471,37 @@ def versions_from_parentdir(parentdir_prefix, root, verbose=False): tag_prefix = "%(TAG_PREFIX)s" parentdir_prefix = "%(PARENTDIR_PREFIX)s" versionfile_source = "%(VERSIONFILE_SOURCE)s" - -def get_versions(default={"version": "unknown", "full": ""}, verbose=False): +lookupfile = %(LOOKUPFILE)s + +def parse_lookup_file(root, lookup_path=None): + if not lookup_path: + lookup_path = lookupfile + if not lookup_path: + return [] + + path = os.path.join(root, lookup_path) + if not os.path.exists(path): + return [] + + import re + lookup = [] + with open(os.path.join(root, lookup_path), "r") as f: + for line in f: + if '#' in line: + line = line[:line.rindex('#')] + line = line.strip() + try: + split_line = line.split() + if len(split_line) == 3: + pattern, tag, ref_commit = split_line + lookup.append([re.compile(pattern), tag, ref_commit]) + elif len(split_line) >= 1: + lookup.append([re.compile(split_line[0]), None, None]) + except: + break + return lookup + +def get_versions(default={"version": "unknown", "full": ""}, lookup_path=None, verbose=False): # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which @@ -440,7 +522,9 @@ def get_versions(default={"version": "unknown", "full": ""}, verbose=False): except NameError: return default - return (versions_from_vcs(tag_prefix, root, verbose) + lookup = parse_lookup_file(root, lookup_path=lookup_path) + return (versions_from_lookup(lookup, root, verbose) + or versions_from_vcs(tag_prefix, root, verbose) or versions_from_parentdir(parentdir_prefix, root, verbose) or default) @@ -488,6 +572,18 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): import re import os.path +def get_gits(root, verbose=False): + if not os.path.exists(os.path.join(root, ".git")): + if verbose: + print("no .git in %s" % root) + return None + + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + return GITS + + def get_expanded_variables(versionfile_abs): # the code embedded in _version.py can just fetch the value of these # variables. When used from setup.py, we don't want to import @@ -548,20 +644,62 @@ def versions_from_expanded_variables(variables, tag_prefix, verbose=False): return { "version": variables["full"].strip(), "full": variables["full"].strip() } + +def versions_from_lookup(lookup, root, verbose=False): + GITS = get_gits(root, verbose=verbose) + if GITS is None: + return {} + + stdout = run_command(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], + cwd=root) + if stdout is None: + return {} + + current_branch = stdout.strip() + for matcher, tag, ref_commit in lookup: + if matcher.match(current_branch): + if tag is None or ref_commit is None: + return {} + + stdout = run_command(GITS, ["rev-list", "%s..HEAD" % ref_commit, "--count"], cwd=root) + if stdout is None: + return {} + num_commits = stdout.strip() + + stdout =run_command(GITS, ["rev-parse", "--short", "HEAD"], cwd=root) + if stdout is None: + return {} + short_hash = stdout.strip() + + stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) + if stdout is None: + return {} + dirty = stdout.strip().endswith("-dirty") + + stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if stdout is None: + return {} + full = stdout.strip() + + version = "%s-%s-g%s" % (tag, num_commits, short_hash) + if dirty: + version += "-dirty" + full += "-dirty" + return {"version": version, "full": full} + + return {} + + def versions_from_vcs(tag_prefix, root, verbose=False): # this runs 'git' from the root of the source tree. This only gets called # if the git-archive 'subst' variables were *not* expanded, and # _version.py hasn't already been rewritten with a short version string, # meaning we're inside a checked out source tree. - if not os.path.exists(os.path.join(root, ".git")): - if verbose: - print("no .git in %s" % root) + GITS = get_gits(root, verbose=verbose) + if GITS is None: return {} - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] stdout = run_command(GITS, ["describe", "--tags", "--dirty", "--always"], cwd=root) if stdout is None: @@ -684,11 +822,38 @@ def get_root(): except NameError: return os.path.dirname(os.path.abspath(sys.argv[0])) +def parse_lookup_file(root, lookup_path=None): + if not lookup_path: + lookup_path = lookupfile + + path = os.path.join(root, lookup_path) + if not os.path.exists(path): + return [] + + import re + lookup = [] + with open(os.path.join(root, lookup_path), "r") as f: + for line in f: + if '#' in line: + line = line[:line.rindex("#")] + line = line.strip() + try: + split_line = line.split() + if len(split_line) == 3: + pattern, tag, ref_commit = split_line + lookup.append([re.compile(pattern), tag, ref_commit]) + elif len(split_line) >= 1: + lookup.append([re.compile(split_line[0]), None, None]) + except: + break + return lookup + def get_versions(default=DEFAULT, verbose=False): # returns dict with two keys: 'version' and 'full' assert versionfile_source is not None, "please set versioneer.versionfile_source" assert tag_prefix is not None, "please set versioneer.tag_prefix" assert parentdir_prefix is not None, "please set versioneer.parentdir_prefix" + # I am in versioneer.py, which must live at the top of the source tree, # which we use to compute the root directory. py2exe/bbfreeze/non-CPython # don't have __file__, in which case we fall back to sys.argv[0] (which @@ -697,6 +862,11 @@ def get_versions(default=DEFAULT, verbose=False): root = get_root() versionfile_abs = os.path.join(root, versionfile_source) + if lookupfile: + lookup = parse_lookup_file(root, lookup_path = lookupfile) + else: + lookup = None + # extract version from first of _version.py, 'git describe', parentdir. # This is meant to work for developers using a source checkout, for users # of a tarball created by 'setup.py sdist', and for users of a @@ -715,6 +885,12 @@ def get_versions(default=DEFAULT, verbose=False): if verbose: print("got version from file %s %s" % (versionfile_abs,ver)) return ver + if lookup: + ver = versions_from_lookup(lookup, root, verbose=verbose) + if ver: + if verbose: print("got version from lookup %s" % ver) + return ver + ver = versions_from_vcs(tag_prefix, root, verbose) if ver: if verbose: print("got version from git %s" % ver) @@ -792,6 +968,7 @@ def run(self): "TAG_PREFIX": tag_prefix, "PARENTDIR_PREFIX": parentdir_prefix, "VERSIONFILE_SOURCE": versionfile_source, + "LOOKUPFILE": '"%s"' % lookupfile if lookupfile is not None else "None", }) f.close() @@ -835,6 +1012,7 @@ def run(self): "TAG_PREFIX": tag_prefix, "PARENTDIR_PREFIX": parentdir_prefix, "VERSIONFILE_SOURCE": versionfile_source, + "LOOKUPFILE": '"%s"' % lookupfile if lookupfile is not None else "None", }) f.close()