Completed
Push — master ( 17f08d...6c508a )
by Charles
01:14
created

get_versions()   C

Complexity

Conditions 7

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
cc 7
c 2
b 0
f 2
dl 0
loc 51
rs 5.7838

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# This file helps to compute a version number in source trees obtained from
2
# git-archive tarball (such as those provided by githubs download-from-tag
3
# feature). Distribution tarballs (built by setup.py sdist) and build
4
# directories (produced by setup.py build) will contain a much shorter file
5
# that just contains the computed version number.
6
7
# This file is released into the public domain. Generated by
8
# versioneer-0.18 (https://github.com/warner/python-versioneer)
9
"""Git implementation of _version.py."""
10
11
import errno
12
import os
13
import re
14
import subprocess
15
import sys
16
17
18
def get_keywords():
19
    """Get the keywords needed to look up the version information."""
20
    # these strings will be replaced by git during git-archive.
21
    # setup.py/versioneer.py will grep for the variable names, so they must
22
    # each be defined on a line of their own. _version.py will just call
23
    # get_keywords().
24
    git_refnames = "$Format:%d$"
25
    git_full = "$Format:%H$"
26
    git_date = "$Format:%ci$"
27
    keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
28
    return keywords
29
30
31
class VersioneerConfig:
0 ignored issues
show
introduced by
Old-style class defined.
Loading history...
Coding Style introduced by
This class has no __init__ method.
Loading history...
32
    """Container for Versioneer configuration parameters."""
33
34
35
def get_config():
36
    """Create, populate and return the VersioneerConfig() object."""
37
    # these strings are filled in when 'setup.py versioneer' creates
38
    # _version.py
39
    cfg = VersioneerConfig()
40
    cfg.VCS = "git"
0 ignored issues
show
Coding Style Naming introduced by
The name VCS does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
The attribute VCS was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
41
    cfg.style = "git-describe"
0 ignored issues
show
Coding Style introduced by
The attribute style was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
42
    cfg.tag_prefix = ""
0 ignored issues
show
Coding Style introduced by
The attribute tag_prefix was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
43
    cfg.parentdir_prefix = "None"
0 ignored issues
show
Coding Style introduced by
The attribute parentdir_prefix was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
44
    cfg.versionfile_source = "git_app_version/_version.py"
0 ignored issues
show
Coding Style introduced by
The attribute versionfile_source was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
45
    cfg.verbose = False
0 ignored issues
show
Coding Style introduced by
The attribute verbose was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
46
    return cfg
47
48
49
class NotThisMethod(Exception):
50
    """Exception raised if a method is not valid for the current scenario."""
51
52
53
LONG_VERSION_PY = {}
54
HANDLERS = {}
55
56
57
def register_vcs_handler(vcs, method):  # decorator
58
    """Decorator to mark a method as the handler for a particular VCS."""
59
60
    def decorate(f):
0 ignored issues
show
Coding Style Naming introduced by
The name f does not conform to the argument naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
61
        """Store f in HANDLERS[vcs][method]."""
62
        if vcs not in HANDLERS:
63
            HANDLERS[vcs] = {}
64
        HANDLERS[vcs][method] = f
65
        return f
66
67
    return decorate
68
69
70 View Code Duplication
def run_command(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
best-practice introduced by
Too many arguments (6/5)
Loading history...
71
    commands, args, cwd=None, verbose=False, hide_stderr=False, env=None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block.
commands, args, cwd=None, verbose=False, hide_stderr=False, env=None
^ |
Loading history...
72
):
73
    """Call the given command(s)."""
74
    assert isinstance(commands, list)
75
    p = None
0 ignored issues
show
Coding Style Naming introduced by
The name p does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
76
    for c in commands:
0 ignored issues
show
Coding Style Naming introduced by
The name c does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
77
        try:
78
            dispcmd = str([c] + args)
79
            # remember shell=False, so use git.cmd on windows, not just git
80
            p = subprocess.Popen(
0 ignored issues
show
Coding Style Naming introduced by
The name p does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
81
                [c] + args,
82
                cwd=cwd,
83
                env=env,
84
                stdout=subprocess.PIPE,
85
                stderr=(subprocess.PIPE if hide_stderr else None)
86
            )
87
            break
88
        except EnvironmentError:
89
            e = sys.exc_info()[1]
0 ignored issues
show
Coding Style Naming introduced by
The name e does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
90
            if e.errno == errno.ENOENT:
91
                continue
92
            if verbose:
93
                print("unable to run %s" % dispcmd)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
94
                print(e)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
95
            return None, None
96
    else:
97
        if verbose:
98
            print("unable to find command, tried %s" % (commands, ))
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
99
        return None, None
100
    stdout = p.communicate()[0].strip()
101
    if sys.version_info[0] >= 3:
102
        stdout = stdout.decode()
103
    if p.returncode != 0:
104
        if verbose:
105
            print("unable to run %s (error)" % dispcmd)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
106
            print("stdout was %s" % stdout)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
107
        return None, p.returncode
108
    return stdout, p.returncode
109
110
111 View Code Duplication
def versions_from_parentdir(parentdir_prefix, root, verbose):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
112
    """Try to determine the version from the parent directory name.
113
114
    Source tarballs conventionally unpack into a directory that includes both
115
    the project name and a version string. We will also support searching up
116
    two directory levels for an appropriately named parent directory
117
    """
118
    rootdirs = []
119
120
    for i in range(3):
0 ignored issues
show
Unused Code introduced by
The variable i seems to be unused.
Loading history...
121
        dirname = os.path.basename(root)
122
        if dirname.startswith(parentdir_prefix):
123
            return {
124
                "version": dirname[len(parentdir_prefix):],
125
                "full-revisionid": None,
126
                "dirty": False,
127
                "error": None,
128
                "date": None
129
            }
130
        else:
131
            rootdirs.append(root)
132
            root = os.path.dirname(root)  # up a level
133
134
    if verbose:
135
        print(
136
            "Tried directories %s but none started with prefix %s" %
137
            (str(rootdirs), parentdir_prefix)
138
        )
139
    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
140
141
142 View Code Duplication
@register_vcs_handler("git", "get_keywords")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
143
def git_get_keywords(versionfile_abs):
144
    """Extract version information from the given file."""
145
    # the code embedded in _version.py can just fetch the value of these
146
    # keywords. When used from setup.py, we don't want to import _version.py,
147
    # so we do it with a regexp instead. This function is not used from
148
    # _version.py.
149
    keywords = {}
150
    try:
151
        f = open(versionfile_abs, "r")
0 ignored issues
show
Coding Style Naming introduced by
The name f does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
152
        for line in f.readlines():
153
            if line.strip().startswith("git_refnames ="):
154
                mo = re.search(r'=\s*"(.*)"', line)
0 ignored issues
show
Coding Style Naming introduced by
The name mo does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
155
                if mo:
156
                    keywords["refnames"] = mo.group(1)
157
            if line.strip().startswith("git_full ="):
158
                mo = re.search(r'=\s*"(.*)"', line)
0 ignored issues
show
Coding Style Naming introduced by
The name mo does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
159
                if mo:
160
                    keywords["full"] = mo.group(1)
161
            if line.strip().startswith("git_date ="):
162
                mo = re.search(r'=\s*"(.*)"', line)
0 ignored issues
show
Coding Style Naming introduced by
The name mo does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
163
                if mo:
164
                    keywords["date"] = mo.group(1)
165
        f.close()
166
    except EnvironmentError:
167
        pass
168
    return keywords
169
170
171 View Code Duplication
@register_vcs_handler("git", "keywords")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
172
def git_versions_from_keywords(keywords, tag_prefix, verbose):
173
    """Get version information from git keywords."""
174
    if not keywords:
175
        raise NotThisMethod("no keywords at all, weird")
176
    date = keywords.get("date")
177
    if date is not None:
178
        # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
179
        # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
180
        # -like" string, which we must then edit to make compliant), because
181
        # it's been around since git-1.5.3, and it's too difficult to
182
        # discover which version we're using, or to work around using an
183
        # older one.
184
        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
185
    refnames = keywords["refnames"].strip()
186
    if refnames.startswith("$Format"):
187
        if verbose:
188
            print("keywords are unexpanded, not using")
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
189
        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
190
    refs = set([r.strip() for r in refnames.strip("()").split(",")])
191
    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
192
    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
193
    TAG = "tag: "
0 ignored issues
show
Coding Style Naming introduced by
The name TAG does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
194
    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
195
    if not tags:
196
        # Either we're using git < 1.8.3, or there really are no tags. We use
197
        # a heuristic: assume all version tags have a digit. The old git %d
198
        # expansion behaves like git log --decorate=short and strips out the
199
        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
200
        # between branches and tags. By ignoring refnames without digits, we
201
        # filter out many common branch names like "release" and
202
        # "stabilization", as well as "HEAD" and "master".
203
        tags = set([r for r in refs if re.search(r'\d', r)])
204
        if verbose:
205
            print("discarding '%s', no digits" % ",".join(refs - tags))
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
206
    if verbose:
207
        print("likely tags: %s" % ",".join(sorted(tags)))
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
208
    for ref in sorted(tags):
209
        # sorting will prefer e.g. "2.0" over "2.0rc1"
210
        if ref.startswith(tag_prefix):
211
            r = ref[len(tag_prefix):]
0 ignored issues
show
Coding Style Naming introduced by
The name r does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
212
            if verbose:
213
                print("picking %s" % r)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
214
            return {
215
                "version": r,
216
                "full-revisionid": keywords["full"].strip(),
217
                "dirty": False,
218
                "error": None,
219
                "date": date
220
            }
221
    # no suitable tags, so version is "0+unknown", but full hex is still there
222
    if verbose:
223
        print("no suitable tags, using unknown + full revision id")
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
224
    return {
225
        "version": "0+unknown",
226
        "full-revisionid": keywords["full"].strip(),
227
        "dirty": False,
228
        "error": "no suitable tags",
229
        "date": None
230
    }
231
232
233 View Code Duplication
@register_vcs_handler("git", "pieces_from_vcs")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
234
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
0 ignored issues
show
Comprehensibility Bug introduced by
run_command is re-defining a name which is already available in the outer-scope (previously defined on line 70).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (17/15).
Loading history...
235
    """Get version from 'git describe' in the root of the source tree.
236
237
    This only gets called if the git-archive 'subst' keywords were *not*
238
    expanded, and _version.py hasn't already been rewritten with a short
239
    version string, meaning we're inside a checked out source tree.
240
    """
241
    GITS = ["git"]
0 ignored issues
show
Coding Style Naming introduced by
The name GITS does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
242
    if sys.platform == "win32":
243
        GITS = ["git.cmd", "git.exe"]
0 ignored issues
show
Coding Style Naming introduced by
The name GITS does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
244
245
    out, rc = run_command(
0 ignored issues
show
Coding Style Naming introduced by
The name rc does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Unused Code introduced by
The variable out seems to be unused.
Loading history...
246
        GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True
247
    )
248
    if rc != 0:
249
        if verbose:
250
            print("Directory %s not under git control" % root)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
251
        raise NotThisMethod("'git rev-parse --git-dir' returned error")
252
253
    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
254
    # if there isn't one, this yields HEX[-dirty] (no NUM)
255
    describe_out, rc = run_command(
0 ignored issues
show
Coding Style Naming introduced by
The name rc does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
256
        GITS, [
257
            "describe", "--tags", "--dirty", "--always", "--long", "--match",
258
            "%s*" % tag_prefix
259
        ],
260
        cwd=root
261
    )
262
    # --long was added in git-1.5.5
263
    if describe_out is None:
264
        raise NotThisMethod("'git describe' failed")
265
    describe_out = describe_out.strip()
266
    full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
0 ignored issues
show
Coding Style Naming introduced by
The name rc does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
267
    if full_out is None:
268
        raise NotThisMethod("'git rev-parse' failed")
269
    full_out = full_out.strip()
270
271
    pieces = {}
272
    pieces["long"] = full_out
273
    pieces["short"] = full_out[:7]  # maybe improved later
274
    pieces["error"] = None
275
276
    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
277
    # TAG might have hyphens.
278
    git_describe = describe_out
279
280
    # look for -dirty suffix
281
    dirty = git_describe.endswith("-dirty")
282
    pieces["dirty"] = dirty
283
    if dirty:
284
        git_describe = git_describe[:git_describe.rindex("-dirty")]
285
286
    # now we have TAG-NUM-gHEX or HEX
287
288
    if "-" in git_describe:
289
        # TAG-NUM-gHEX
290
        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
0 ignored issues
show
Coding Style Naming introduced by
The name mo does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
291
        if not mo:
292
            # unparseable. Maybe git-describe is misbehaving?
293
            pieces["error"] = (
294
                "unable to parse git-describe output: '%s'" % describe_out
295
            )
296
            return pieces
297
298
        # tag
299
        full_tag = mo.group(1)
300
        if not full_tag.startswith(tag_prefix):
301
            if verbose:
302
                fmt = "tag '%s' doesn't start with prefix '%s'"
303
                print(fmt % (full_tag, tag_prefix))
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after print.
Loading history...
304
            pieces["error"] = (
305
                "tag '%s' doesn't start with prefix '%s'" %
306
                (full_tag, tag_prefix)
307
            )
308
            return pieces
309
        pieces["closest-tag"] = full_tag[len(tag_prefix):]
310
311
        # distance: number of commits since tag
312
        pieces["distance"] = int(mo.group(2))
313
314
        # commit: short hex revision ID
315
        pieces["short"] = mo.group(3)
316
317
    else:
318
        # HEX: no tags
319
        pieces["closest-tag"] = None
320
        count_out, rc = run_command(
0 ignored issues
show
Coding Style Naming introduced by
The name rc does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
321
            GITS, ["rev-list", "HEAD", "--count"], cwd=root
322
        )
323
        pieces["distance"] = int(count_out)  # total number of commits
324
325
    # commit date: see ISO-8601 comment in git_versions_from_keywords()
326
    date = run_command(
327
        GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root
328
    )[0].strip()
329
    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
330
331
    return pieces
332
333
334
def plus_or_dot(pieces):
335
    """Return a + if we don't already have one, else return a ."""
336
    if "+" in pieces.get("closest-tag", ""):
337
        return "."
338
    return "+"
339
340
341
def render_pep440(pieces):
342
    """Build up version string, with post-release "local version identifier".
343
344
    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
345
    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
346
347
    Exceptions:
348
    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
349
    """
350
    if pieces["closest-tag"]:
351
        rendered = pieces["closest-tag"]
352
        if pieces["distance"] or pieces["dirty"]:
353
            rendered += plus_or_dot(pieces)
354
            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
355
            if pieces["dirty"]:
356
                rendered += ".dirty"
357
    else:
358
        # exception #1
359
        rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
360
        if pieces["dirty"]:
361
            rendered += ".dirty"
362
    return rendered
363
364
365
def render_pep440_pre(pieces):
366
    """TAG[.post.devDISTANCE] -- No -dirty.
367
368
    Exceptions:
369
    1: no tags. 0.post.devDISTANCE
370
    """
371
    if pieces["closest-tag"]:
372
        rendered = pieces["closest-tag"]
373
        if pieces["distance"]:
374
            rendered += ".post.dev%d" % pieces["distance"]
375
    else:
376
        # exception #1
377
        rendered = "0.post.dev%d" % pieces["distance"]
378
    return rendered
379
380
381
def render_pep440_post(pieces):
382
    """TAG[.postDISTANCE[.dev0]+gHEX] .
383
384
    The ".dev0" means dirty. Note that .dev0 sorts backwards
385
    (a dirty tree will appear "older" than the corresponding clean one),
386
    but you shouldn't be releasing software with -dirty anyways.
387
388
    Exceptions:
389
    1: no tags. 0.postDISTANCE[.dev0]
390
    """
391
    if pieces["closest-tag"]:
392
        rendered = pieces["closest-tag"]
393
        if pieces["distance"] or pieces["dirty"]:
394
            rendered += ".post%d" % pieces["distance"]
395
            if pieces["dirty"]:
396
                rendered += ".dev0"
397
            rendered += plus_or_dot(pieces)
398
            rendered += "g%s" % pieces["short"]
399
    else:
400
        # exception #1
401
        rendered = "0.post%d" % pieces["distance"]
402
        if pieces["dirty"]:
403
            rendered += ".dev0"
404
        rendered += "+g%s" % pieces["short"]
405
    return rendered
406
407
408 View Code Duplication
def render_pep440_old(pieces):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
409
    """TAG[.postDISTANCE[.dev0]] .
410
411
    The ".dev0" means dirty.
412
413
    Eexceptions:
414
    1: no tags. 0.postDISTANCE[.dev0]
415
    """
416
    if pieces["closest-tag"]:
417
        rendered = pieces["closest-tag"]
418
        if pieces["distance"] or pieces["dirty"]:
419
            rendered += ".post%d" % pieces["distance"]
420
            if pieces["dirty"]:
421
                rendered += ".dev0"
422
    else:
423
        # exception #1
424
        rendered = "0.post%d" % pieces["distance"]
425
        if pieces["dirty"]:
426
            rendered += ".dev0"
427
    return rendered
428
429
430
def render_git_describe(pieces):
431
    """TAG[-DISTANCE-gHEX][-dirty].
432
433
    Like 'git describe --tags --dirty --always'.
434
435
    Exceptions:
436
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
437
    """
438
    if pieces["closest-tag"]:
439
        rendered = pieces["closest-tag"]
440
        if pieces["distance"]:
441
            rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
442
    else:
443
        # exception #1
444
        rendered = pieces["short"]
445
    if pieces["dirty"]:
446
        rendered += "-dirty"
447
    return rendered
448
449
450
def render_git_describe_long(pieces):
451
    """TAG-DISTANCE-gHEX[-dirty].
452
453
    Like 'git describe --tags --dirty --always -long'.
454
    The distance/hash is unconditional.
455
456
    Exceptions:
457
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
458
    """
459
    if pieces["closest-tag"]:
460
        rendered = pieces["closest-tag"]
461
        rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
462
    else:
463
        # exception #1
464
        rendered = pieces["short"]
465
    if pieces["dirty"]:
466
        rendered += "-dirty"
467
    return rendered
468
469
470 View Code Duplication
def render(pieces, style):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
471
    """Render the given version pieces into the requested style."""
472
    if pieces["error"]:
473
        return {
474
            "version": "unknown",
475
            "full-revisionid": pieces.get("long"),
476
            "dirty": None,
477
            "error": pieces["error"],
478
            "date": None
479
        }
480
481
    if not style or style == "default":
482
        style = "pep440"  # the default
483
484
    if style == "pep440":
485
        rendered = render_pep440(pieces)
486
    elif style == "pep440-pre":
487
        rendered = render_pep440_pre(pieces)
488
    elif style == "pep440-post":
489
        rendered = render_pep440_post(pieces)
490
    elif style == "pep440-old":
491
        rendered = render_pep440_old(pieces)
492
    elif style == "git-describe":
493
        rendered = render_git_describe(pieces)
494
    elif style == "git-describe-long":
495
        rendered = render_git_describe_long(pieces)
496
    else:
497
        raise ValueError("unknown style '%s'" % style)
498
499
    return {
500
        "version": rendered,
501
        "full-revisionid": pieces["long"],
502
        "dirty": pieces["dirty"],
503
        "error": None,
504
        "date": pieces.get("date")
505
    }
506
507
508
def get_versions():
509
    """Get version information or return default if unable to do so."""
510
    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
511
    # __file__, we can work backwards from there to the root. Some
512
    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
513
    # case we can only use expanded keywords.
514
515
    cfg = get_config()
516
    verbose = cfg.verbose
517
518
    try:
519
        return git_versions_from_keywords(
520
            get_keywords(), cfg.tag_prefix, verbose
521
        )
522
    except NotThisMethod:
523
        pass
524
525
    try:
526
        root = os.path.realpath(__file__)
527
        # versionfile_source is the relative path from the top of the source
528
        # tree (where the .git directory might live) to this file. Invert
529
        # this to find the root from __file__.
530
        for i in cfg.versionfile_source.split('/'):
0 ignored issues
show
Unused Code introduced by
The variable i seems to be unused.
Loading history...
531
            root = os.path.dirname(root)
532
    except NameError:
533
        return {
534
            "version": "0+unknown",
535
            "full-revisionid": None,
536
            "dirty": None,
537
            "error": "unable to find root of source tree",
538
            "date": None
539
        }
540
541
    try:
542
        pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
543
        return render(pieces, cfg.style)
544
    except NotThisMethod:
545
        pass
546
547
    try:
548
        if cfg.parentdir_prefix:
549
            return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
550
    except NotThisMethod:
551
        pass
552
553
    return {
554
        "version": "0+unknown",
555
        "full-revisionid": None,
556
        "dirty": None,
557
        "error": "unable to compute version",
558
        "date": None
559
    }
560