Completed
Pull Request — develop (#5)
by Kale
59s
created

auxlib.Tox   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 23
Duplicated Lines 0 %
Metric Value
dl 0
loc 23
rs 10
wmc 4

3 Methods

Rating   Name   Duplication   Size   Complexity  
A finalize_options() 0 4 1
A initialize_options() 0 3 1
A run_tests() 0 11 2
1
# -*- coding: utf-8 -*-
2
from __future__ import print_function, division, absolute_import
3
from logging import getLogger
4
from os.path import basename, dirname, join, isdir
5
from re import match
6
from setuptools.command.build_py import build_py
7
from setuptools.command.sdist import sdist
8
from setuptools.command.test import test as TestCommand
9
from subprocess import CalledProcessError, check_call, check_output
10
import sys
11
12
from .path import absdirname, PackageFile
13
14
log = getLogger(__name__)
15
16
17
def _get_version_from_pkg_info(package_name):
18
    with PackageFile('.version', package_name) as fh:
19
        return fh.read()
20
21
22
def _is_git_dirty():
23
    try:
24
        check_call(('git', 'diff', '--quiet'))
25
        check_call(('git', 'diff', '--cached', '--quiet'))
26
        return False
27
    except CalledProcessError:
28
        return True
29
30
31
def _get_most_recent_git_tag():
32
    try:
33
        return check_output(["git", "describe", "--tags"]).strip()
34
    except CalledProcessError as e:
35
        if e.returncode == 128:
36
            return "0.0.0.0"
37
        else:
38
            raise  # pragma: no cover
39
40
41
def _get_git_hash():
42
    try:
43
        return check_output(["git", "rev-parse", "HEAD"]).strip()[:7]
44
    except CalledProcessError:
45
        return 0
46
47
48
def _get_version_from_git_tag():
49
    """Return a PEP440-compliant version derived from the git status.
50
    If that fails for any reason, return the first 7 chars of the changeset hash.
51
    """
52
    tag = _get_most_recent_git_tag()
53
    m = match(b"(?P<xyz>\d+\.\d+\.\d+)(?:-(?P<dev>\d+)-(?P<hash>.+))?", tag)
54
    version = m.group('xyz').decode('utf-8')
55
    if m.group('dev') or _is_git_dirty():
56
        dev = (m.group('dev') or 0).decode('utf-8')
57
        hash_ = (m.group('hash') or _get_git_hash()).decode('utf-8')
58
        version += ".dev{dev}+{hash_}".format(dev=dev, hash_=hash_)
59
    return version
60
61
62
def is_git_repo(path, package):
63
    if path == '/' or dirname(basename(path)) == package:
64
        return False
65
    else:
66
        return isdir(join(path, '.git')) or is_git_repo(dirname(path), package)
67
68
69
def get_version(file, package):
70
    """Returns a version string for the current package, derived
71
    either from the SCM (git currently) or from PKG-INFO.
72
73
    This function is expected to run in two contexts. In a development
74
    context, where .git/ exists, the version is pulled from git tags
75
    and written into PKG-INFO to create an sdist or bdist.
76
77
    In an installation context, the PKG-INFO file written above is the
78
    source of version string.
79
80
    """
81
    here = absdirname(file)
82
    if is_git_repo(here, package):
83
        return _get_version_from_git_tag()
84
85
    # fall back to .version file
86
    version_from_pkg = _get_version_from_pkg_info(package)
87
    if version_from_pkg:
88
        return version_from_pkg.decode('utf-8')
89
90
    raise RuntimeError("Could not get package version (no .git or .version file)")
91
92
93
class BuildPyCommand(build_py):
94
    def run(self):
95
        build_py.run(self)
96
        # locate .version in the new build/ directory and replace it with an updated value
97
        target_version_file = join(self.build_lib, self.distribution.metadata.name, ".version")
98
        print("UPDATING %s" % target_version_file)
99
        with open(target_version_file, 'w') as f:
100
            f.write(self.distribution.metadata.version)
101
102
103
class SdistCommand(sdist):
104
    def run(self):
105
        return sdist.run(self)
106
107
    def make_release_tree(self, base_dir, files):
108
        sdist.make_release_tree(self, base_dir, files)
109
        target_version_file = join(base_dir, self.distribution.metadata.name, ".version")
110
        print("UPDATING {0}".format(target_version_file))
111
        with open(target_version_file, 'w') as f:
112
            f.write(self.distribution.metadata.version)
113
114
115
class Tox(TestCommand):
116
    user_options = [('tox-args=', 'a', "Arguments to pass to tox")]
117
118
    def initialize_options(self):
119
        TestCommand.initialize_options(self)
120
        self.tox_args = None
121
122
    def finalize_options(self):
123
        TestCommand.finalize_options(self)
124
        self.test_args = []
125
        self.test_suite = True
126
127
    def run_tests(self):
128
        # import here, cause outside the eggs aren't loaded
129
        import tox
130
        import shlex
131
        args = self.tox_args
132
        if args:
133
            args = shlex.split(self.tox_args)
134
        else:
135
            args = ''
136
        errno = tox.cmdline(args=args)
137
        sys.exit(errno)
138
139
140
if __name__ == "__main__":
141
    print(get_version(__file__, __package__))
142