Skip to content

Commit

Permalink
Update setup.py to allow prerelease version (#1366)
Browse files Browse the repository at this point in the history
* Update setup.py to allow prerelease version

* Add the missing .gitattributes
  • Loading branch information
kitchoi authored Oct 15, 2020
1 parent 7b53731 commit 1bb2142
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 54 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# For archives, substitute the commit hash in the setup.py file.
/setup.py export-subst
263 changes: 209 additions & 54 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,64 @@

import os
import re
import runpy
import subprocess

from setuptools import setup, find_packages
from io import open

# Version information; update this by hand when making a new bugfix or feature
# release. The actual package version is autogenerated from this information
# together with information from the version control system, and then injected
# into the package source.
MAJOR = 7
MINOR = 2
MICRO = 0

PRERELEASE = ""
IS_RELEASED = False

VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
# If this file is part of a Git export (for example created with "git archive",
# or downloaded from GitHub), ARCHIVE_COMMIT_HASH gives the full hash of the
# commit that was exported.
ARCHIVE_COMMIT_HASH = "$Format:%H$"

# Templates for version strings.
RELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}"
UNRELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}.dev{dev}"

# Paths to the autogenerated version file and the Git directory.
HERE = os.path.abspath(os.path.dirname(__file__))
VERSION_FILE = os.path.join(HERE, "traitsui", "_version.py")
GIT_DIRECTORY = os.path.join(HERE, ".git")

# Template for the autogenerated version file.
VERSION_FILE_TEMPLATE = """\
# (C) Copyright 2005-2020 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
# THIS FILE IS GENERATED FROM SETUP.PY
#: The full version of the package, including a development suffix
#: for unreleased versions of the package.
version = '{version}'
#: The full version of the package, same as 'version'
#: Kept for backward compatibility
full_version = version
#: The Git revision from which this release was made.
git_revision = '{git_revision}'
#: Flag whether this is a final release
is_released = {is_released}
"""


def read_module(module, package='traitsui'):
Expand All @@ -37,7 +83,25 @@ def read_module(module, package='traitsui'):


# Return the git revision as a string
def git_version():
def _git_info():
"""
Get information about the given commit from Git.
Returns
-------
git_count : int
Number of revisions from this commit to the initial commit.
git_revision : str
Commit hash for HEAD.
Raises
------
EnvironmentError
If Git is not available.
subprocess.CalledProcessError
If Git is available, but the version command fails (most likely
because there's no Git repository here).
"""
def _minimal_ext_cmd(cmd):
# construct minimal environment
env = {}
Expand Down Expand Up @@ -67,66 +131,157 @@ def _minimal_ext_cmd(cmd):
else:
git_revision, git_count = match.group('hash'), match.group('count')

return git_revision, git_count
return git_count, git_revision


def write_version_py(filename=None):
template = """\
# THIS FILE IS GENERATED FROM TRAITS SETUP.PY
version = '{version}'
full_version = '{full_version}'
git_revision = '{git_revision}'
is_released = {is_released}
def git_version():
"""
Construct version information from local variables and Git.
if not is_released:
version = full_version
"""
if filename is None:
# correctly generate relative path
base_dir = os.path.dirname(__file__)
filename = os.path.join(base_dir, 'traitsui', '_version.py')

# Adding the git rev number needs to be done inside
# write_version_py(), otherwise the import of traits._version messes
# up the build under Python 3.
fullversion = VERSION
if os.path.exists('.git'):
git_rev, dev_num = git_version()
elif os.path.exists(filename):
# must be a source distribution, use existing version file
try:
data = read_module('_version')
git_rev = data['git_revision']
fullversion_source = data['full_version']
except Exception:
print("Unable to read git_revision. Try removing "
"traitsui/_version.py and the build directory "
"before building.")
raise

match = re.match(r'.*?\.dev(?P<dev_num>\d+)', fullversion_source)
if match is None:
dev_num = '0'
else:
dev_num = match.group('dev_num')
else:
git_rev = 'Unknown'
dev_num = '0'
Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
if not IS_RELEASED:
fullversion += '.dev{0}'.format(dev_num)
Raises
------
EnvironmentError
If Git is not available.
subprocess.CalledProcessError
If Git is available, but the version command fails (most likely
because there's no Git repository here).
"""
git_count, git_revision = _git_info()
version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION
version = version_template.format(
major=MAJOR,
minor=MINOR,
micro=MICRO,
prerelease=PRERELEASE,
dev=git_count,
)
return version, git_revision


def archive_version():
"""
Construct version information for an archive.
Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
Raises
------
ValueError
If this does not appear to be an archive.
"""
if "$" in ARCHIVE_COMMIT_HASH:
raise ValueError("This does not appear to be an archive.")

version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION
version = version_template.format(
major=MAJOR,
minor=MINOR,
micro=MICRO,
prerelease=PRERELEASE,
dev="-unknown",
)
return version, ARCHIVE_COMMIT_HASH


def write_version_file(version, git_revision, filename=VERSION_FILE):
"""
Write version information to the version file.
Overwrites any existing version file.
with open(filename, "w", encoding='ascii') as fp:
fp.write(template.format(version=VERSION,
full_version=fullversion,
git_revision=git_rev,
is_released=IS_RELEASED))
Parameters
----------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
filename : str
Path to the version file.
"""
with open(filename, "w", encoding="utf-8") as version_file:
version_file.write(
VERSION_FILE_TEMPLATE.format(
version=version,
git_revision=git_revision,
is_released=IS_RELEASED,
)
)


def read_version_file():
"""
Read version information from the version file, if it exists.
Returns
-------
version : str
The full version, including any development suffix.
git_revision : str
The full commit hash for the current Git revision.
Raises
------
EnvironmentError
If the version file does not exist.
"""
version_info = runpy.run_path(VERSION_FILE)
return (version_info["version"], version_info["git_revision"])


def resolve_version():
"""
Process version information and write a version file if necessary.
Returns the current version information.
Returns
-------
version : str
Package version.
git_revision : str
The full commit hash for the current Git revision.
"""
if os.path.isdir(GIT_DIRECTORY):
# This is a local clone; compute version information and write
# it to the version file, overwriting any existing information.
version = git_version()
print("Computed package version: {}".format(version))
print("Writing version to version file {}.".format(VERSION_FILE))
write_version_file(*version)
elif "$" not in ARCHIVE_COMMIT_HASH:
# This is a source archive.
version = archive_version()
print("Archive package version: {}".format(version))
print("Writing version to version file {}.".format(VERSION_FILE))
write_version_file(*version)
elif os.path.isfile(VERSION_FILE):
# This is a source distribution. Read the version information.
print("Reading version file {}".format(VERSION_FILE))
version = read_version_file()
print("Package version from version file: {}".format(version))
else:
raise RuntimeError(
"Unable to determine package version. No local Git clone "
"detected, and no version file found at {}.".format(VERSION_FILE)
)

return fullversion
return version


if __name__ == "__main__":
__version__ = write_version_py()
__version__, _ = resolve_version()
data = read_module('__init__')
__requires__ = data['__requires__']
__extras_require__ = data['__extras_require__']
Expand Down

0 comments on commit 1bb2142

Please sign in to comment.