From 2fbec07bf3d97ef4a564ac8e5fe5cc98163935a8 Mon Sep 17 00:00:00 2001
From: Joseph Weston <joseph@weston.cloud>
Date: Fri, 23 Feb 2018 12:23:21 +0100
Subject: [PATCH] update versioning system to work with 'git archive'

Closes #188.
---
 .gitattributes          |  1 +
 kwant/_kwant_version.py |  4 ++++
 kwant/version.py        | 30 ++++++++++++++++++++++++++++++
 setup.py                |  9 ++++-----
 4 files changed, 39 insertions(+), 5 deletions(-)
 create mode 100644 .gitattributes

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..8ac2ef68
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+kwant/_kwant_version.py export-subst
diff --git a/kwant/_kwant_version.py b/kwant/_kwant_version.py
index 9530ac99..1507e6a4 100644
--- a/kwant/_kwant_version.py
+++ b/kwant/_kwant_version.py
@@ -2,3 +2,7 @@
 # distribution is made.  The magic value "__use_git__" is interpreted by
 # _common.py in this directory.
 version = "__use_git__"
+
+# These values are only set if the distribution was created with 'git archive'
+refnames = "$Format:%D$"
+git_hash = "$Format:%h$"
diff --git a/kwant/version.py b/kwant/version.py
index c7da0e29..48575383 100644
--- a/kwant/version.py
+++ b/kwant/version.py
@@ -83,6 +83,34 @@ def get_version_from_git():
     return "".join(version)
 
 
+# TODO: change this logic when there is a git pretty-format
+#       that gives the same output as 'git describe'.
+#       Currently we can only tell the tag the current commit is
+#       pointing to, or its hash (with no version info)
+#       if it is not tagged.
+def get_version_from_git_archive(version_info):
+    try:
+        refnames = version_info['refnames']
+        git_hash = version_info['git_hash']
+    except KeyError:
+        # These fields are not present if we are running from an sdist.
+        # Execution should never reach here, though
+        return None
+
+    if git_hash.startswith('$Format') or refnames.startswith('$Format'):
+        # variables not expanded during 'git archive'
+        return None
+
+    VTAG = 'tag: v'  # Our version tags always start with 'v'
+    refs = set(r.strip() for r in refnames.split(","))
+    version_tags = set(r[len(VTAG):] for r in refs if r.startswith(VTAG))
+    if version_tags:
+        release, *_ = sorted(version_tags)  # prefer e.g. "2.0" over "2.0rc1"
+        return release
+    else:
+        return ''.join(('unknown', '+g', git_hash))
+
+
 def init(version_file='_kwant_version.py'):
     global version, version_is_from_git
     version_info = {}
@@ -92,6 +120,8 @@ def init(version_file='_kwant_version.py'):
     version_is_from_git = (version == "__use_git__")
     if version_is_from_git:
         version = get_version_from_git()
+        if not version:
+            version = get_version_from_git_archive(version_info)
         if not version:
             version = "unknown"
 
diff --git a/setup.py b/setup.py
index 7165e486..00263e98 100755
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ import sys
 import re
 import os
 import glob
-import imp
+import importlib
 import subprocess
 import configparser
 import collections
@@ -123,10 +123,9 @@ def check_versions():
 
     # Let Kwant itself determine its own version.  We cannot simply import
     # kwant, as it is not built yet.
-    _dont_write_bytecode_saved = sys.dont_write_bytecode
-    sys.dont_write_bytecode = True
-    version_module = imp.load_source('version', 'kwant/version.py')
-    sys.dont_write_bytecode = _dont_write_bytecode_saved
+    spec = importlib.util.spec_from_file_location('version', 'kwant/version.py')
+    version_module = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(version_module)
 
     version_module.ensure_python()
     version = version_module.version
-- 
GitLab