/ octoprint_GPX / _version.py
_version.py
1 2 # This file helps to compute a version number in source trees obtained from 3 # git-archive tarball (such as those provided by githubs download-from-tag 4 # feature). Distribution tarballs (built by setup.py sdist) and build 5 # directories (produced by setup.py build) will contain a much shorter file 6 # that just contains the computed version number. 7 8 # This file is released into the public domain. Generated by 9 # versioneer-0.14 (https://github.com/warner/python-versioneer) 10 11 import errno 12 import os 13 import re 14 import subprocess 15 import sys 16 17 # these strings will be replaced by git during git-archive 18 git_refnames = "$Format:%d$" 19 git_full = "$Format:%H$" 20 21 # these strings are filled in when 'setup.py versioneer' creates _version.py 22 tag_prefix = "" 23 parentdir_prefix = "" 24 versionfile_source = "octoprint_GPX/_version.py" 25 26 27 def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False): 28 assert isinstance(commands, list) 29 p = None 30 for c in commands: 31 try: 32 # remember shell=False, so use git.cmd on windows, not just git 33 p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE, 34 stderr=(subprocess.PIPE if hide_stderr 35 else None)) 36 break 37 except EnvironmentError: 38 e = sys.exc_info()[1] 39 if e.errno == errno.ENOENT: 40 continue 41 if verbose: 42 print("unable to run %s" % args[0]) 43 print(e) 44 return None 45 else: 46 if verbose: 47 print("unable to find command, tried %s" % (commands,)) 48 return None 49 stdout = p.communicate()[0].strip() 50 if sys.version_info[0] >= 3: 51 stdout = stdout.decode() 52 if p.returncode != 0: 53 if verbose: 54 print("unable to run %s (error)" % args[0]) 55 return None 56 return stdout 57 58 59 def versions_from_parentdir(parentdir_prefix, root, verbose=False): 60 # Source tarballs conventionally unpack into a directory that includes 61 # both the project name and a version string. 62 dirname = os.path.basename(root) 63 if not dirname.startswith(parentdir_prefix): 64 if verbose: 65 print("guessing rootdir is '%s', but '%s' doesn't start with " 66 "prefix '%s'" % (root, dirname, parentdir_prefix)) 67 return None 68 return {"version": dirname[len(parentdir_prefix):], "full": ""} 69 70 71 def git_get_keywords(versionfile_abs): 72 # the code embedded in _version.py can just fetch the value of these 73 # keywords. When used from setup.py, we don't want to import _version.py, 74 # so we do it with a regexp instead. This function is not used from 75 # _version.py. 76 keywords = {} 77 try: 78 f = open(versionfile_abs, "r") 79 for line in f.readlines(): 80 if line.strip().startswith("git_refnames ="): 81 mo = re.search(r'=\s*"(.*)"', line) 82 if mo: 83 keywords["refnames"] = mo.group(1) 84 if line.strip().startswith("git_full ="): 85 mo = re.search(r'=\s*"(.*)"', line) 86 if mo: 87 keywords["full"] = mo.group(1) 88 f.close() 89 except EnvironmentError: 90 pass 91 return keywords 92 93 94 def git_versions_from_keywords(keywords, tag_prefix, verbose=False): 95 if not keywords: 96 return {} # keyword-finding function failed to find keywords 97 refnames = keywords["refnames"].strip() 98 if refnames.startswith("$Format"): 99 if verbose: 100 print("keywords are unexpanded, not using") 101 return {} # unexpanded, so not in an unpacked git-archive tarball 102 refs = set([r.strip() for r in refnames.strip("()").split(",")]) 103 # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of 104 # just "foo-1.0". If we see a "tag: " prefix, prefer those. 105 TAG = "tag: " 106 tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) 107 if not tags: 108 # Either we're using git < 1.8.3, or there really are no tags. We use 109 # a heuristic: assume all version tags have a digit. The old git %d 110 # expansion behaves like git log --decorate=short and strips out the 111 # refs/heads/ and refs/tags/ prefixes that would let us distinguish 112 # between branches and tags. By ignoring refnames without digits, we 113 # filter out many common branch names like "release" and 114 # "stabilization", as well as "HEAD" and "master". 115 tags = set([r for r in refs if re.search(r'\d', r)]) 116 if verbose: 117 print("discarding '%s', no digits" % ",".join(refs-tags)) 118 if verbose: 119 print("likely tags: %s" % ",".join(sorted(tags))) 120 for ref in sorted(tags): 121 # sorting will prefer e.g. "2.0" over "2.0rc1" 122 if ref.startswith(tag_prefix): 123 r = ref[len(tag_prefix):] 124 if verbose: 125 print("picking %s" % r) 126 return {"version": r, 127 "full": keywords["full"].strip()} 128 # no suitable tags, so version is "0+unknown", but full hex is still there 129 if verbose: 130 print("no suitable tags, using unknown + full revision id") 131 return {"version": "0+unknown", 132 "full": keywords["full"].strip()} 133 134 135 def git_parse_vcs_describe(git_describe, tag_prefix, verbose=False): 136 # TAG-NUM-gHEX[-dirty] or HEX[-dirty] . TAG might have hyphens. 137 138 # dirty 139 dirty = git_describe.endswith("-dirty") 140 if dirty: 141 git_describe = git_describe[:git_describe.rindex("-dirty")] 142 dirty_suffix = ".dirty" if dirty else "" 143 144 # now we have TAG-NUM-gHEX or HEX 145 146 if "-" not in git_describe: # just HEX 147 return "0+untagged.g"+git_describe+dirty_suffix, dirty 148 149 # just TAG-NUM-gHEX 150 mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) 151 if not mo: 152 # unparseable. Maybe git-describe is misbehaving? 153 return "0+unparseable"+dirty_suffix, dirty 154 155 # tag 156 full_tag = mo.group(1) 157 if not full_tag.startswith(tag_prefix): 158 if verbose: 159 fmt = "tag '%s' doesn't start with prefix '%s'" 160 print(fmt % (full_tag, tag_prefix)) 161 return None, dirty 162 tag = full_tag[len(tag_prefix):] 163 164 # distance: number of commits since tag 165 distance = int(mo.group(2)) 166 167 # commit: short hex revision ID 168 commit = mo.group(3) 169 170 # now build up version string, with post-release "local version 171 # identifier". Our goal: TAG[+NUM.gHEX[.dirty]] . Note that if you get a 172 # tagged build and then dirty it, you'll get TAG+0.gHEX.dirty . So you 173 # can always test version.endswith(".dirty"). 174 version = tag 175 if distance or dirty: 176 version += "+%d.g%s" % (distance, commit) + dirty_suffix 177 178 return version, dirty 179 180 181 def git_versions_from_vcs(tag_prefix, root, verbose=False): 182 # this runs 'git' from the root of the source tree. This only gets called 183 # if the git-archive 'subst' keywords were *not* expanded, and 184 # _version.py hasn't already been rewritten with a short version string, 185 # meaning we're inside a checked out source tree. 186 187 if not os.path.exists(os.path.join(root, ".git")): 188 if verbose: 189 print("no .git in %s" % root) 190 return {} # get_versions() will try next method 191 192 GITS = ["git"] 193 if sys.platform == "win32": 194 GITS = ["git.cmd", "git.exe"] 195 # if there is a tag, this yields TAG-NUM-gHEX[-dirty] 196 # if there are no tags, this yields HEX[-dirty] (no NUM) 197 stdout = run_command(GITS, ["describe", "--tags", "--dirty", 198 "--always", "--long"], 199 cwd=root) 200 # --long was added in git-1.5.5 201 if stdout is None: 202 return {} # try next method 203 version, dirty = git_parse_vcs_describe(stdout, tag_prefix, verbose) 204 205 # build "full", which is FULLHEX[.dirty] 206 stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) 207 if stdout is None: 208 return {} 209 full = stdout.strip() 210 if dirty: 211 full += ".dirty" 212 213 return {"version": version, "full": full} 214 215 216 def get_versions(default={"version": "0+unknown", "full": ""}, verbose=False): 217 # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have 218 # __file__, we can work backwards from there to the root. Some 219 # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which 220 # case we can only use expanded keywords. 221 222 keywords = {"refnames": git_refnames, "full": git_full} 223 ver = git_versions_from_keywords(keywords, tag_prefix, verbose) 224 if ver: 225 return ver 226 227 try: 228 root = os.path.realpath(__file__) 229 # versionfile_source is the relative path from the top of the source 230 # tree (where the .git directory might live) to this file. Invert 231 # this to find the root from __file__. 232 for i in versionfile_source.split('/'): 233 root = os.path.dirname(root) 234 except NameError: 235 return default 236 237 return (git_versions_from_vcs(tag_prefix, root, verbose) 238 or versions_from_parentdir(parentdir_prefix, root, verbose) 239 or default)