Commit 5557c11a authored by Christoph Groth's avatar Christoph Groth
Browse files

setup.py: improve version determination, respect PEP 440

The motivation behind this change is to allow keeping Tinyarray
distributions in git repositories that have a different layout from the
canonical Tinyarray git repository.  This is useful for example for
packaging.

The static version is now kept in the file "version" and can take a
special value that signifies that the version should be determined using
git.  This file is rewritten upon creation of a source distribution.
parent 1f928990
......@@ -7,4 +7,6 @@ include TODO
include README_WINDOWS.txt
include test_tinyarray.py
include benchmark.py
include version
recursive-include src *.hh
exclude src/version.hh
#!/usr/bin/env python
# Copyright 2012-2013 Tinyarray authors.
# Copyright 2012-2015 Tinyarray authors.
#
# This file is part of Tinyarray. It is subject to the license terms in the
# LICENSE file found in the top-level directory of this distribution and at
......@@ -14,9 +14,12 @@ import sys
from distutils.core import setup, Extension, Command
from distutils.util import get_platform
from distutils.errors import DistutilsError, DistutilsModuleError
from distutils.command.build_ext import build_ext
from distutils.command.sdist import sdist
README_FILE = 'README'
STATIC_VERSION_FILE = 'src/version.hh'
SAVED_VERSION_FILE = 'version'
VERSION_HEADER = ['src', 'version.hh']
TEST_MODULE = 'test_tinyarray.py'
CLASSIFIERS = """\
......@@ -34,59 +37,75 @@ Operating System :: Unix
Operating System :: MacOS
Operating System :: Microsoft :: Windows"""
tinyarray_dir = os.path.dirname(os.path.abspath(__file__))
distr_root = os.path.dirname(os.path.abspath(__file__))
def get_version_from_git():
try:
p = subprocess.Popen(['git', 'describe'], cwd=tinyarray_dir,
p = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'],
cwd=distr_root,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
return
if p.wait() != 0:
return
version = p.communicate()[0].strip().decode()
if not os.path.samefile(p.communicate()[0].decode().rstrip('\n'), distr_root):
# The top-level directory of the current Git repository is not the same
# as the root directory of the source distribution: do not extract the
# version from Git.
return
if version[0] == 'v':
version = version[1:]
# git describe --first-parent does not take into account tags from branches
# that were merged-in.
for opts in [['--first-parent'], []]:
try:
p = subprocess.Popen(['git', 'describe', '--long'] + opts,
cwd=distr_root,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
return
if p.wait() == 0:
break
else:
return
description = p.communicate()[0].decode().strip('v').rstrip('\n')
release, dev, git = description.rsplit('-', 2)
version = [release]
labels = []
if dev != "0":
version.append(".dev{}".format(dev))
labels.append(git)
try:
p = subprocess.Popen(['git', 'diff', '--quiet'], cwd=tinyarray_dir)
p = subprocess.Popen(['git', 'diff', '--quiet'], cwd=distr_root)
except OSError:
version += '-confused' # This should never happen.
labels.append('confused') # This should never happen.
else:
if p.wait() == 1:
version += '-dirty'
return version
labels.append('dirty')
if labels:
version.append('+')
version.append(".".join(labels))
def get_static_version():
"""Return the version as recorded inside a file."""
try:
with open(STATIC_VERSION_FILE) as f:
contents = f.read()
assert contents[:17] == '#define VERSION "'
assert contents[-2:] == '"\n'
return contents[17:-2]
except:
return None
def version():
"""Determine the version of Tinyarray. Return it and save it in a file."""
git_version = get_version_from_git()
static_version = get_static_version()
if git_version is not None:
version = git_version
if static_version != git_version:
with open(STATIC_VERSION_FILE, 'w') as f:
f.write('#define VERSION "{}"\n'.format(version))
elif static_version is not None:
version = static_version
return "".join(version)
with open(os.path.join(SAVED_VERSION_FILE), 'r') as f:
for line in f:
line = line.strip()
if line.startswith('#'):
continue
else:
version = line
break
else:
version = 'unknown'
return version
raise RuntimeError("Saved version file does not contain version.")
version_is_from_git = (version == "__use_git__")
if version_is_from_git:
version = get_version_from_git()
if not version:
version = "unknown"
def long_description():
......@@ -110,6 +129,31 @@ def long_description():
return ''.join(text)
class our_build_ext(build_ext):
def run(self):
with open(os.path.join(*VERSION_HEADER), 'w') as f:
f.write("// This file has been generated by setup.py.\n")
f.write("// It is not included in source distributions.\n")
f.write('#define VERSION "{}"\n'.format(version))
build_ext.run(self)
class our_sdist(sdist):
def make_release_tree(self, base_dir, files):
sdist.make_release_tree(self, base_dir, files)
fname = os.path.join(base_dir, SAVED_VERSION_FILE)
# This could be a hard link, so try to delete it first. Is there any way
# to do this atomically together with opening?
try:
os.remove(fname)
except OSError:
pass
with open(fname, 'w') as f:
f.write("# This file has been generated by setup.py.\n{}\n"
.format(version))
class test(Command):
description = "run the unit tests"
user_options = []
......@@ -145,7 +189,7 @@ module = Extension('tinyarray',
def main():
setup(name='tinyarray',
version=version(),
version=version,
author='Christoph Groth (CEA) and others',
author_email='christoph.groth@cea.fr',
description="Arrays of numbers for Python, optimized for small sizes",
......@@ -155,7 +199,9 @@ def main():
license="Simplified BSD license",
platforms=["Unix", "Linux", "Mac OS-X", "Windows"],
classifiers=CLASSIFIERS.split('\n'),
cmdclass={'test': test},
cmdclass={'build_ext': our_build_ext,
'sdist': our_sdist,
'test': test},
ext_modules=[module])
......
# This file will be overwritten by setup.py when a source distribution is made.
__use_git__
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment