1
2# Version: 0.18
3
4"""The Versioneer - like a rocketeer, but for versions.
5
6The Versioneer
7==============
8
9* like a rocketeer, but for versions!
10* https://github.com/warner/python-versioneer
11* Brian Warner
12* License: Public Domain
13* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy
14* [![Latest Version]
15(https://pypip.in/version/versioneer/badge.svg?style=flat)
16](https://pypi.python.org/pypi/versioneer/)
17* [![Build Status]
18(https://travis-ci.org/warner/python-versioneer.png?branch=master)
19](https://travis-ci.org/warner/python-versioneer)
20
21This is a tool for managing a recorded version number in distutils-based
22python projects. The goal is to remove the tedious and error-prone "update
23the embedded version string" step from your release process. Making a new
24release should be as easy as recording a new tag in your version-control
25system, and maybe making new tarballs.
26
27
28## Quick Install
29
30* `pip install versioneer` to somewhere to your $PATH
31* add a `[versioneer]` section to your setup.cfg (see below)
32* run `versioneer install` in your source tree, commit the results
33
34## Version Identifiers
35
36Source trees come from a variety of places:
37
38* a version-control system checkout (mostly used by developers)
39* a nightly tarball, produced by build automation
40* a snapshot tarball, produced by a web-based VCS browser, like github's
41  "tarball from tag" feature
42* a release tarball, produced by "setup.py sdist", distributed through PyPI
43
44Within each source tree, the version identifier (either a string or a number,
45this tool is format-agnostic) can come from a variety of places:
46
47* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
48  about recent "tags" and an absolute revision-id
49* the name of the directory into which the tarball was unpacked
50* an expanded VCS keyword ($Id$, etc)
51* a `_version.py` created by some earlier build step
52
53For released software, the version identifier is closely related to a VCS
54tag. Some projects use tag names that include more than just the version
55string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
56needs to strip the tag prefix to extract the version identifier. For
57unreleased software (between tags), the version identifier should provide
58enough information to help developers recreate the same tree, while also
59giving them an idea of roughly how old the tree is (after version 1.2, before
60version 1.3). Many VCS systems can report a description that captures this,
61for example `git describe --tags --dirty --always` reports things like
62"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
630.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
64uncommitted changes.
65
66The version identifier is used for multiple purposes:
67
68* to allow the module to self-identify its version: `myproject.__version__`
69* to choose a name and prefix for a 'setup.py sdist' tarball
70
71## Theory of Operation
72
73Versioneer works by adding a special `_version.py` file into your source
74tree, where your `__init__.py` can import it. This `_version.py` knows how to
75dynamically ask the VCS tool for version information at import time.
76
77`_version.py` also contains `$Revision$` markers, and the installation
78process marks `_version.py` to have this marker rewritten with a tag name
79during the `git archive` command. As a result, generated tarballs will
80contain enough information to get the proper version.
81
82To allow `setup.py` to compute a version too, a `versioneer.py` is added to
83the top level of your source tree, next to `setup.py` and the `setup.cfg`
84that configures it. This overrides several distutils/setuptools commands to
85compute the version when invoked, and changes `setup.py build` and `setup.py
86sdist` to replace `_version.py` with a small static file that contains just
87the generated version data.
88
89## Installation
90
91See [INSTALL.md](./INSTALL.md) for detailed installation instructions.
92
93## Version-String Flavors
94
95Code which uses Versioneer can learn about its version string at runtime by
96importing `_version` from your main `__init__.py` file and running the
97`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
98import the top-level `versioneer.py` and run `get_versions()`.
99
100Both functions return a dictionary with different flavors of version
101information:
102
103* `['version']`: A condensed version string, rendered using the selected
104  style. This is the most commonly used value for the project's version
105  string. The default "pep440" style yields strings like `0.11`,
106  `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section
107  below for alternative styles.
108
109* `['full-revisionid']`: detailed revision identifier. For Git, this is the
110  full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
111
112* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the
113  commit date in ISO 8601 format. This will be None if the date is not
114  available.
115
116* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that
117  this is only accurate if run in a VCS checkout, otherwise it is likely to
118  be False or None
119
120* `['error']`: if the version string could not be computed, this will be set
121  to a string describing the problem, otherwise it will be None. It may be
122  useful to throw an exception in setup.py if this is set, to avoid e.g.
123  creating tarballs with a version string of "unknown".
124
125Some variants are more useful than others. Including `full-revisionid` in a
126bug report should allow developers to reconstruct the exact code being tested
127(or indicate the presence of local changes that should be shared with the
128developers). `version` is suitable for display in an "about" box or a CLI
129`--version` output: it can be easily compared against release notes and lists
130of bugs fixed in various releases.
131
132The installer adds the following text to your `__init__.py` to place a basic
133version in `YOURPROJECT.__version__`:
134
135    from ._version import get_versions
136    __version__ = get_versions()['version']
137    del get_versions
138
139## Styles
140
141The setup.cfg `style=` configuration controls how the VCS information is
142rendered into a version string.
143
144The default style, "pep440", produces a PEP440-compliant string, equal to the
145un-prefixed tag name for actual releases, and containing an additional "local
146version" section with more detail for in-between builds. For Git, this is
147TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags
148--dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the
149tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and
150that this commit is two revisions ("+2") beyond the "0.11" tag. For released
151software (exactly equal to a known tag), the identifier will only contain the
152stripped tag, e.g. "0.11".
153
154Other styles are available. See [details.md](details.md) in the Versioneer
155source tree for descriptions.
156
157## Debugging
158
159Versioneer tries to avoid fatal errors: if something goes wrong, it will tend
160to return a version of "0+unknown". To investigate the problem, run `setup.py
161version`, which will run the version-lookup code in a verbose mode, and will
162display the full contents of `get_versions()` (including the `error` string,
163which may help identify what went wrong).
164
165## Known Limitations
166
167Some situations are known to cause problems for Versioneer. This details the
168most significant ones. More can be found on Github
169[issues page](https://github.com/warner/python-versioneer/issues).
170
171### Subprojects
172
173Versioneer has limited support for source trees in which `setup.py` is not in
174the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are
175two common reasons why `setup.py` might not be in the root:
176
177* Source trees which contain multiple subprojects, such as
178  [Buildbot](https://github.com/buildbot/buildbot), which contains both
179  "master" and "slave" subprojects, each with their own `setup.py`,
180  `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI
181  distributions (and upload multiple independently-installable tarballs).
182* Source trees whose main purpose is to contain a C library, but which also
183  provide bindings to Python (and perhaps other langauges) in subdirectories.
184
185Versioneer will look for `.git` in parent directories, and most operations
186should get the right version string. However `pip` and `setuptools` have bugs
187and implementation details which frequently cause `pip install .` from a
188subproject directory to fail to find a correct version string (so it usually
189defaults to `0+unknown`).
190
191`pip install --editable .` should work correctly. `setup.py install` might
192work too.
193
194Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in
195some later version.
196
197[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking
198this issue. The discussion in
199[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the
200issue from the Versioneer side in more detail.
201[pip PR#3176](https://github.com/pypa/pip/pull/3176) and
202[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve
203pip to let Versioneer work correctly.
204
205Versioneer-0.16 and earlier only looked for a `.git` directory next to the
206`setup.cfg`, so subprojects were completely unsupported with those releases.
207
208### Editable installs with setuptools <= 18.5
209
210`setup.py develop` and `pip install --editable .` allow you to install a
211project into a virtualenv once, then continue editing the source code (and
212test) without re-installing after every change.
213
214"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a
215convenient way to specify executable scripts that should be installed along
216with the python package.
217
218These both work as expected when using modern setuptools. When using
219setuptools-18.5 or earlier, however, certain operations will cause
220`pkg_resources.DistributionNotFound` errors when running the entrypoint
221script, which must be resolved by re-installing the package. This happens
222when the install happens with one version, then the egg_info data is
223regenerated while a different version is checked out. Many setup.py commands
224cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into
225a different virtualenv), so this can be surprising.
226
227[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes
228this one, but upgrading to a newer version of setuptools should probably
229resolve it.
230
231### Unicode version strings
232
233While Versioneer works (and is continually tested) with both Python 2 and
234Python 3, it is not entirely consistent with bytes-vs-unicode distinctions.
235Newer releases probably generate unicode version strings on py2. It's not
236clear that this is wrong, but it may be surprising for applications when then
237write these strings to a network connection or include them in bytes-oriented
238APIs like cryptographic checksums.
239
240[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates
241this question.
242
243
244## Updating Versioneer
245
246To upgrade your project to a new release of Versioneer, do the following:
247
248* install the new Versioneer (`pip install -U versioneer` or equivalent)
249* edit `setup.cfg`, if necessary, to include any new configuration settings
250  indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details.
251* re-run `versioneer install` in your source tree, to replace
252  `SRC/_version.py`
253* commit any changed files
254
255## Future Directions
256
257This tool is designed to make it easily extended to other version-control
258systems: all VCS-specific components are in separate directories like
259src/git/ . The top-level `versioneer.py` script is assembled from these
260components by running make-versioneer.py . In the future, make-versioneer.py
261will take a VCS name as an argument, and will construct a version of
262`versioneer.py` that is specific to the given VCS. It might also take the
263configuration arguments that are currently provided manually during
264installation by editing setup.py . Alternatively, it might go the other
265direction and include code from all supported VCS systems, reducing the
266number of intermediate scripts.
267
268
269## License
270
271To make Versioneer easier to embed, all its code is dedicated to the public
272domain. The `_version.py` that it creates is also in the public domain.
273Specifically, both are released under the Creative Commons "Public Domain
274Dedication" license (CC0-1.0), as described in
275https://creativecommons.org/publicdomain/zero/1.0/ .
276
277"""
278
279from __future__ import print_function
280try:
281    import configparser
282except ImportError:
283    import ConfigParser as configparser
284import errno
285import json
286import os
287import re
288import subprocess
289import sys
290
291
292class VersioneerConfig:
293    """Container for Versioneer configuration parameters."""
294
295
296def get_root():
297    """Get the project root directory.
298
299    We require that all commands are run from the project root, i.e. the
300    directory that contains setup.py, setup.cfg, and versioneer.py .
301    """
302    root = os.path.realpath(os.path.abspath(os.getcwd()))
303    setup_py = os.path.join(root, "setup.py")
304    versioneer_py = os.path.join(root, "versioneer.py")
305    if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
306        # allow 'python path/to/setup.py COMMAND'
307        root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
308        setup_py = os.path.join(root, "setup.py")
309        versioneer_py = os.path.join(root, "versioneer.py")
310    if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
311        err = ("Versioneer was unable to run the project root directory. "
312               "Versioneer requires setup.py to be executed from "
313               "its immediate directory (like 'python setup.py COMMAND'), "
314               "or in a way that lets it use sys.argv[0] to find the root "
315               "(like 'python path/to/setup.py COMMAND').")
316        raise VersioneerBadRootError(err)
317    try:
318        # Certain runtime workflows (setup.py install/develop in a setuptools
319        # tree) execute all dependencies in a single python process, so
320        # "versioneer" may be imported multiple times, and python's shared
321        # module-import table will cache the first one. So we can't use
322        # os.path.dirname(__file__), as that will find whichever
323        # versioneer.py was first imported, even in later projects.
324        me = os.path.realpath(os.path.abspath(__file__))
325        me_dir = os.path.normcase(os.path.splitext(me)[0])
326        vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0])
327        if me_dir != vsr_dir:
328            print("Warning: build in %s is using versioneer.py from %s"
329                  % (os.path.dirname(me), versioneer_py))
330    except NameError:
331        pass
332    return root
333
334
335def get_config_from_root(root):
336    """Read the project setup.cfg file to determine Versioneer config."""
337    # This might raise EnvironmentError (if setup.cfg is missing), or
338    # configparser.NoSectionError (if it lacks a [versioneer] section), or
339    # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
340    # the top of versioneer.py for instructions on writing your setup.cfg .
341    setup_cfg = os.path.join(root, "setup.cfg")
342    parser = configparser.SafeConfigParser()
343    with open(setup_cfg, "r") as f:
344        parser.readfp(f)
345    VCS = parser.get("versioneer", "VCS")  # mandatory
346
347    def get(parser, name):
348        if parser.has_option("versioneer", name):
349            return parser.get("versioneer", name)
350        return None
351    cfg = VersioneerConfig()
352    cfg.VCS = VCS
353    cfg.style = get(parser, "style") or ""
354    cfg.versionfile_source = get(parser, "versionfile_source")
355    cfg.versionfile_build = get(parser, "versionfile_build")
356    cfg.tag_prefix = get(parser, "tag_prefix")
357    if cfg.tag_prefix in ("''", '""'):
358        cfg.tag_prefix = ""
359    cfg.parentdir_prefix = get(parser, "parentdir_prefix")
360    cfg.verbose = get(parser, "verbose")
361    return cfg
362
363
364class NotThisMethod(Exception):
365    """Exception raised if a method is not valid for the current scenario."""
366
367
368# these dictionaries contain VCS-specific tools
369LONG_VERSION_PY = {}
370HANDLERS = {}
371
372
373def register_vcs_handler(vcs, method):  # decorator
374    """Decorator to mark a method as the handler for a particular VCS."""
375    def decorate(f):
376        """Store f in HANDLERS[vcs][method]."""
377        if vcs not in HANDLERS:
378            HANDLERS[vcs] = {}
379        HANDLERS[vcs][method] = f
380        return f
381    return decorate
382
383
384def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
385                env=None):
386    """Call the given command(s)."""
387    assert isinstance(commands, list)
388    p = None
389    for c in commands:
390        try:
391            dispcmd = str([c] + args)
392            # remember shell=False, so use git.cmd on windows, not just git
393            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
394                                 stdout=subprocess.PIPE,
395                                 stderr=(subprocess.PIPE if hide_stderr
396                                         else None))
397            break
398        except EnvironmentError:
399            e = sys.exc_info()[1]
400            if e.errno == errno.ENOENT:
401                continue
402            if verbose:
403                print("unable to run %s" % dispcmd)
404                print(e)
405            return None, None
406    else:
407        if verbose:
408            print("unable to find command, tried %s" % (commands,))
409        return None, None
410    stdout = p.communicate()[0].strip()
411    if sys.version_info[0] >= 3:
412        stdout = stdout.decode()
413    if p.returncode != 0:
414        if verbose:
415            print("unable to run %s (error)" % dispcmd)
416            print("stdout was %s" % stdout)
417        return None, p.returncode
418    return stdout, p.returncode
419
420
421LONG_VERSION_PY['git'] = '''
422# This file helps to compute a version number in source trees obtained from
423# git-archive tarball (such as those provided by githubs download-from-tag
424# feature). Distribution tarballs (built by setup.py sdist) and build
425# directories (produced by setup.py build) will contain a much shorter file
426# that just contains the computed version number.
427
428# This file is released into the public domain. Generated by
429# versioneer-0.18 (https://github.com/warner/python-versioneer)
430
431"""Git implementation of _version.py."""
432
433import errno
434import os
435import re
436import subprocess
437import sys
438
439
440def get_keywords():
441    """Get the keywords needed to look up the version information."""
442    # these strings will be replaced by git during git-archive.
443    # setup.py/versioneer.py will grep for the variable names, so they must
444    # each be defined on a line of their own. _version.py will just call
445    # get_keywords().
446    git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
447    git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
448    git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s"
449    keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
450    return keywords
451
452
453class VersioneerConfig:
454    """Container for Versioneer configuration parameters."""
455
456
457def get_config():
458    """Create, populate and return the VersioneerConfig() object."""
459    # these strings are filled in when 'setup.py versioneer' creates
460    # _version.py
461    cfg = VersioneerConfig()
462    cfg.VCS = "git"
463    cfg.style = "%(STYLE)s"
464    cfg.tag_prefix = "%(TAG_PREFIX)s"
465    cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s"
466    cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s"
467    cfg.verbose = False
468    return cfg
469
470
471class NotThisMethod(Exception):
472    """Exception raised if a method is not valid for the current scenario."""
473
474
475LONG_VERSION_PY = {}
476HANDLERS = {}
477
478
479def register_vcs_handler(vcs, method):  # decorator
480    """Decorator to mark a method as the handler for a particular VCS."""
481    def decorate(f):
482        """Store f in HANDLERS[vcs][method]."""
483        if vcs not in HANDLERS:
484            HANDLERS[vcs] = {}
485        HANDLERS[vcs][method] = f
486        return f
487    return decorate
488
489
490def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
491                env=None):
492    """Call the given command(s)."""
493    assert isinstance(commands, list)
494    p = None
495    for c in commands:
496        try:
497            dispcmd = str([c] + args)
498            # remember shell=False, so use git.cmd on windows, not just git
499            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
500                                 stdout=subprocess.PIPE,
501                                 stderr=(subprocess.PIPE if hide_stderr
502                                         else None))
503            break
504        except EnvironmentError:
505            e = sys.exc_info()[1]
506            if e.errno == errno.ENOENT:
507                continue
508            if verbose:
509                print("unable to run %%s" %% dispcmd)
510                print(e)
511            return None, None
512    else:
513        if verbose:
514            print("unable to find command, tried %%s" %% (commands,))
515        return None, None
516    stdout = p.communicate()[0].strip()
517    if sys.version_info[0] >= 3:
518        stdout = stdout.decode()
519    if p.returncode != 0:
520        if verbose:
521            print("unable to run %%s (error)" %% dispcmd)
522            print("stdout was %%s" %% stdout)
523        return None, p.returncode
524    return stdout, p.returncode
525
526
527def versions_from_parentdir(parentdir_prefix, root, verbose):
528    """Try to determine the version from the parent directory name.
529
530    Source tarballs conventionally unpack into a directory that includes both
531    the project name and a version string. We will also support searching up
532    two directory levels for an appropriately named parent directory
533    """
534    rootdirs = []
535
536    for i in range(3):
537        dirname = os.path.basename(root)
538        if dirname.startswith(parentdir_prefix):
539            return {"version": dirname[len(parentdir_prefix):],
540                    "full-revisionid": None,
541                    "dirty": False, "error": None, "date": None}
542        else:
543            rootdirs.append(root)
544            root = os.path.dirname(root)  # up a level
545
546    if verbose:
547        print("Tried directories %%s but none started with prefix %%s" %%
548              (str(rootdirs), parentdir_prefix))
549    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
550
551
552@register_vcs_handler("git", "get_keywords")
553def git_get_keywords(versionfile_abs):
554    """Extract version information from the given file."""
555    # the code embedded in _version.py can just fetch the value of these
556    # keywords. When used from setup.py, we don't want to import _version.py,
557    # so we do it with a regexp instead. This function is not used from
558    # _version.py.
559    keywords = {}
560    try:
561        f = open(versionfile_abs, "r")
562        for line in f.readlines():
563            if line.strip().startswith("git_refnames ="):
564                mo = re.search(r'=\s*"(.*)"', line)
565                if mo:
566                    keywords["refnames"] = mo.group(1)
567            if line.strip().startswith("git_full ="):
568                mo = re.search(r'=\s*"(.*)"', line)
569                if mo:
570                    keywords["full"] = mo.group(1)
571            if line.strip().startswith("git_date ="):
572                mo = re.search(r'=\s*"(.*)"', line)
573                if mo:
574                    keywords["date"] = mo.group(1)
575        f.close()
576    except EnvironmentError:
577        pass
578    return keywords
579
580
581@register_vcs_handler("git", "keywords")
582def git_versions_from_keywords(keywords, tag_prefix, verbose):
583    """Get version information from git keywords."""
584    if not keywords:
585        raise NotThisMethod("no keywords at all, weird")
586    date = keywords.get("date")
587    if date is not None:
588        # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant
589        # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601
590        # -like" string, which we must then edit to make compliant), because
591        # it's been around since git-1.5.3, and it's too difficult to
592        # discover which version we're using, or to work around using an
593        # older one.
594        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
595    refnames = keywords["refnames"].strip()
596    if refnames.startswith("$Format"):
597        if verbose:
598            print("keywords are unexpanded, not using")
599        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
600    refs = set([r.strip() for r in refnames.strip("()").split(",")])
601    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
602    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
603    TAG = "tag: "
604    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
605    if not tags:
606        # Either we're using git < 1.8.3, or there really are no tags. We use
607        # a heuristic: assume all version tags have a digit. The old git %%d
608        # expansion behaves like git log --decorate=short and strips out the
609        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
610        # between branches and tags. By ignoring refnames without digits, we
611        # filter out many common branch names like "release" and
612        # "stabilization", as well as "HEAD" and "master".
613        tags = set([r for r in refs if re.search(r'\d', r)])
614        if verbose:
615            print("discarding '%%s', no digits" %% ",".join(refs - tags))
616    if verbose:
617        print("likely tags: %%s" %% ",".join(sorted(tags)))
618    for ref in sorted(tags):
619        # sorting will prefer e.g. "2.0" over "2.0rc1"
620        if ref.startswith(tag_prefix):
621            r = ref[len(tag_prefix):]
622            if verbose:
623                print("picking %%s" %% r)
624            return {"version": r,
625                    "full-revisionid": keywords["full"].strip(),
626                    "dirty": False, "error": None,
627                    "date": date}
628    # no suitable tags, so version is "0+unknown", but full hex is still there
629    if verbose:
630        print("no suitable tags, using unknown + full revision id")
631    return {"version": "0+unknown",
632            "full-revisionid": keywords["full"].strip(),
633            "dirty": False, "error": "no suitable tags", "date": None}
634
635
636@register_vcs_handler("git", "pieces_from_vcs")
637def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
638    """Get version from 'git describe' in the root of the source tree.
639
640    This only gets called if the git-archive 'subst' keywords were *not*
641    expanded, and _version.py hasn't already been rewritten with a short
642    version string, meaning we're inside a checked out source tree.
643    """
644    GITS = ["git"]
645    if sys.platform == "win32":
646        GITS = ["git.cmd", "git.exe"]
647
648    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
649                          hide_stderr=True)
650    if rc != 0:
651        if verbose:
652            print("Directory %%s not under git control" %% root)
653        raise NotThisMethod("'git rev-parse --git-dir' returned error")
654
655    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
656    # if there isn't one, this yields HEX[-dirty] (no NUM)
657    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
658                                          "--always", "--long",
659                                          "--match", "%%s*" %% tag_prefix],
660                                   cwd=root)
661    # --long was added in git-1.5.5
662    if describe_out is None:
663        raise NotThisMethod("'git describe' failed")
664    describe_out = describe_out.strip()
665    full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
666    if full_out is None:
667        raise NotThisMethod("'git rev-parse' failed")
668    full_out = full_out.strip()
669
670    pieces = {}
671    pieces["long"] = full_out
672    pieces["short"] = full_out[:7]  # maybe improved later
673    pieces["error"] = None
674
675    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
676    # TAG might have hyphens.
677    git_describe = describe_out
678
679    # look for -dirty suffix
680    dirty = git_describe.endswith("-dirty")
681    pieces["dirty"] = dirty
682    if dirty:
683        git_describe = git_describe[:git_describe.rindex("-dirty")]
684
685    # now we have TAG-NUM-gHEX or HEX
686
687    if "-" in git_describe:
688        # TAG-NUM-gHEX
689        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
690        if not mo:
691            # unparseable. Maybe git-describe is misbehaving?
692            pieces["error"] = ("unable to parse git-describe output: '%%s'"
693                               %% describe_out)
694            return pieces
695
696        # tag
697        full_tag = mo.group(1)
698        if not full_tag.startswith(tag_prefix):
699            if verbose:
700                fmt = "tag '%%s' doesn't start with prefix '%%s'"
701                print(fmt %% (full_tag, tag_prefix))
702            pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'"
703                               %% (full_tag, tag_prefix))
704            return pieces
705        pieces["closest-tag"] = full_tag[len(tag_prefix):]
706
707        # distance: number of commits since tag
708        pieces["distance"] = int(mo.group(2))
709
710        # commit: short hex revision ID
711        pieces["short"] = mo.group(3)
712
713    else:
714        # HEX: no tags
715        pieces["closest-tag"] = None
716        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
717                                    cwd=root)
718        pieces["distance"] = int(count_out)  # total number of commits
719
720    # commit date: see ISO-8601 comment in git_versions_from_keywords()
721    date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"],
722                       cwd=root)[0].strip()
723    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
724
725    return pieces
726
727
728def plus_or_dot(pieces):
729    """Return a + if we don't already have one, else return a ."""
730    if "+" in pieces.get("closest-tag", ""):
731        return "."
732    return "+"
733
734
735def render_pep440(pieces):
736    """Build up version string, with post-release "local version identifier".
737
738    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
739    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
740
741    Exceptions:
742    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
743    """
744    if pieces["closest-tag"]:
745        rendered = pieces["closest-tag"]
746        if pieces["distance"] or pieces["dirty"]:
747            rendered += plus_or_dot(pieces)
748            rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"])
749            if pieces["dirty"]:
750                rendered += ".dirty"
751    else:
752        # exception #1
753        rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"],
754                                          pieces["short"])
755        if pieces["dirty"]:
756            rendered += ".dirty"
757    return rendered
758
759
760def render_pep440_pre(pieces):
761    """TAG[.post.devDISTANCE] -- No -dirty.
762
763    Exceptions:
764    1: no tags. 0.post.devDISTANCE
765    """
766    if pieces["closest-tag"]:
767        rendered = pieces["closest-tag"]
768        if pieces["distance"]:
769            rendered += ".post.dev%%d" %% pieces["distance"]
770    else:
771        # exception #1
772        rendered = "0.post.dev%%d" %% pieces["distance"]
773    return rendered
774
775
776def render_pep440_post(pieces):
777    """TAG[.postDISTANCE[.dev0]+gHEX] .
778
779    The ".dev0" means dirty. Note that .dev0 sorts backwards
780    (a dirty tree will appear "older" than the corresponding clean one),
781    but you shouldn't be releasing software with -dirty anyways.
782
783    Exceptions:
784    1: no tags. 0.postDISTANCE[.dev0]
785    """
786    if pieces["closest-tag"]:
787        rendered = pieces["closest-tag"]
788        if pieces["distance"] or pieces["dirty"]:
789            rendered += ".post%%d" %% pieces["distance"]
790            if pieces["dirty"]:
791                rendered += ".dev0"
792            rendered += plus_or_dot(pieces)
793            rendered += "g%%s" %% pieces["short"]
794    else:
795        # exception #1
796        rendered = "0.post%%d" %% pieces["distance"]
797        if pieces["dirty"]:
798            rendered += ".dev0"
799        rendered += "+g%%s" %% pieces["short"]
800    return rendered
801
802
803def render_pep440_old(pieces):
804    """TAG[.postDISTANCE[.dev0]] .
805
806    The ".dev0" means dirty.
807
808    Eexceptions:
809    1: no tags. 0.postDISTANCE[.dev0]
810    """
811    if pieces["closest-tag"]:
812        rendered = pieces["closest-tag"]
813        if pieces["distance"] or pieces["dirty"]:
814            rendered += ".post%%d" %% pieces["distance"]
815            if pieces["dirty"]:
816                rendered += ".dev0"
817    else:
818        # exception #1
819        rendered = "0.post%%d" %% pieces["distance"]
820        if pieces["dirty"]:
821            rendered += ".dev0"
822    return rendered
823
824
825def render_git_describe(pieces):
826    """TAG[-DISTANCE-gHEX][-dirty].
827
828    Like 'git describe --tags --dirty --always'.
829
830    Exceptions:
831    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
832    """
833    if pieces["closest-tag"]:
834        rendered = pieces["closest-tag"]
835        if pieces["distance"]:
836            rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
837    else:
838        # exception #1
839        rendered = pieces["short"]
840    if pieces["dirty"]:
841        rendered += "-dirty"
842    return rendered
843
844
845def render_git_describe_long(pieces):
846    """TAG-DISTANCE-gHEX[-dirty].
847
848    Like 'git describe --tags --dirty --always -long'.
849    The distance/hash is unconditional.
850
851    Exceptions:
852    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
853    """
854    if pieces["closest-tag"]:
855        rendered = pieces["closest-tag"]
856        rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
857    else:
858        # exception #1
859        rendered = pieces["short"]
860    if pieces["dirty"]:
861        rendered += "-dirty"
862    return rendered
863
864
865def render(pieces, style):
866    """Render the given version pieces into the requested style."""
867    if pieces["error"]:
868        return {"version": "unknown",
869                "full-revisionid": pieces.get("long"),
870                "dirty": None,
871                "error": pieces["error"],
872                "date": None}
873
874    if not style or style == "default":
875        style = "pep440"  # the default
876
877    if style == "pep440":
878        rendered = render_pep440(pieces)
879    elif style == "pep440-pre":
880        rendered = render_pep440_pre(pieces)
881    elif style == "pep440-post":
882        rendered = render_pep440_post(pieces)
883    elif style == "pep440-old":
884        rendered = render_pep440_old(pieces)
885    elif style == "git-describe":
886        rendered = render_git_describe(pieces)
887    elif style == "git-describe-long":
888        rendered = render_git_describe_long(pieces)
889    else:
890        raise ValueError("unknown style '%%s'" %% style)
891
892    return {"version": rendered, "full-revisionid": pieces["long"],
893            "dirty": pieces["dirty"], "error": None,
894            "date": pieces.get("date")}
895
896
897def get_versions():
898    """Get version information or return default if unable to do so."""
899    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
900    # __file__, we can work backwards from there to the root. Some
901    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
902    # case we can only use expanded keywords.
903
904    cfg = get_config()
905    verbose = cfg.verbose
906
907    try:
908        return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
909                                          verbose)
910    except NotThisMethod:
911        pass
912
913    try:
914        root = os.path.realpath(__file__)
915        # versionfile_source is the relative path from the top of the source
916        # tree (where the .git directory might live) to this file. Invert
917        # this to find the root from __file__.
918        for i in cfg.versionfile_source.split('/'):
919            root = os.path.dirname(root)
920    except NameError:
921        return {"version": "0+unknown", "full-revisionid": None,
922                "dirty": None,
923                "error": "unable to find root of source tree",
924                "date": None}
925
926    try:
927        pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
928        return render(pieces, cfg.style)
929    except NotThisMethod:
930        pass
931
932    try:
933        if cfg.parentdir_prefix:
934            return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
935    except NotThisMethod:
936        pass
937
938    return {"version": "0+unknown", "full-revisionid": None,
939            "dirty": None,
940            "error": "unable to compute version", "date": None}
941'''
942
943
944@register_vcs_handler("git", "get_keywords")
945def git_get_keywords(versionfile_abs):
946    """Extract version information from the given file."""
947    # the code embedded in _version.py can just fetch the value of these
948    # keywords. When used from setup.py, we don't want to import _version.py,
949    # so we do it with a regexp instead. This function is not used from
950    # _version.py.
951    keywords = {}
952    try:
953        f = open(versionfile_abs, "r")
954        for line in f.readlines():
955            if line.strip().startswith("git_refnames ="):
956                mo = re.search(r'=\s*"(.*)"', line)
957                if mo:
958                    keywords["refnames"] = mo.group(1)
959            if line.strip().startswith("git_full ="):
960                mo = re.search(r'=\s*"(.*)"', line)
961                if mo:
962                    keywords["full"] = mo.group(1)
963            if line.strip().startswith("git_date ="):
964                mo = re.search(r'=\s*"(.*)"', line)
965                if mo:
966                    keywords["date"] = mo.group(1)
967        f.close()
968    except EnvironmentError:
969        pass
970    return keywords
971
972
973@register_vcs_handler("git", "keywords")
974def git_versions_from_keywords(keywords, tag_prefix, verbose):
975    """Get version information from git keywords."""
976    if not keywords:
977        raise NotThisMethod("no keywords at all, weird")
978    date = keywords.get("date")
979    if date is not None:
980        # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
981        # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
982        # -like" string, which we must then edit to make compliant), because
983        # it's been around since git-1.5.3, and it's too difficult to
984        # discover which version we're using, or to work around using an
985        # older one.
986        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
987    refnames = keywords["refnames"].strip()
988    if refnames.startswith("$Format"):
989        if verbose:
990            print("keywords are unexpanded, not using")
991        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
992    refs = set([r.strip() for r in refnames.strip("()").split(",")])
993    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
994    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
995    TAG = "tag: "
996    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
997    if not tags:
998        # Either we're using git < 1.8.3, or there really are no tags. We use
999        # a heuristic: assume all version tags have a digit. The old git %d
1000        # expansion behaves like git log --decorate=short and strips out the
1001        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
1002        # between branches and tags. By ignoring refnames without digits, we
1003        # filter out many common branch names like "release" and
1004        # "stabilization", as well as "HEAD" and "master".
1005        tags = set([r for r in refs if re.search(r'\d', r)])
1006        if verbose:
1007            print("discarding '%s', no digits" % ",".join(refs - tags))
1008    if verbose:
1009        print("likely tags: %s" % ",".join(sorted(tags)))
1010    for ref in sorted(tags):
1011        # sorting will prefer e.g. "2.0" over "2.0rc1"
1012        if ref.startswith(tag_prefix):
1013            r = ref[len(tag_prefix):]
1014            if verbose:
1015                print("picking %s" % r)
1016            return {"version": r,
1017                    "full-revisionid": keywords["full"].strip(),
1018                    "dirty": False, "error": None,
1019                    "date": date}
1020    # no suitable tags, so version is "0+unknown", but full hex is still there
1021    if verbose:
1022        print("no suitable tags, using unknown + full revision id")
1023    return {"version": "0+unknown",
1024            "full-revisionid": keywords["full"].strip(),
1025            "dirty": False, "error": "no suitable tags", "date": None}
1026
1027
1028@register_vcs_handler("git", "pieces_from_vcs")
1029def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1030    """Get version from 'git describe' in the root of the source tree.
1031
1032    This only gets called if the git-archive 'subst' keywords were *not*
1033    expanded, and _version.py hasn't already been rewritten with a short
1034    version string, meaning we're inside a checked out source tree.
1035    """
1036    GITS = ["git"]
1037    if sys.platform == "win32":
1038        GITS = ["git.cmd", "git.exe"]
1039
1040    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
1041                          hide_stderr=True)
1042    if rc != 0:
1043        if verbose:
1044            print("Directory %s not under git control" % root)
1045        raise NotThisMethod("'git rev-parse --git-dir' returned error")
1046
1047    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
1048    # if there isn't one, this yields HEX[-dirty] (no NUM)
1049    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
1050                                          "--always", "--long",
1051                                          "--match", "%s*" % tag_prefix],
1052                                   cwd=root)
1053    # --long was added in git-1.5.5
1054    if describe_out is None:
1055        raise NotThisMethod("'git describe' failed")
1056    describe_out = describe_out.strip()
1057    full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
1058    if full_out is None:
1059        raise NotThisMethod("'git rev-parse' failed")
1060    full_out = full_out.strip()
1061
1062    pieces = {}
1063    pieces["long"] = full_out
1064    pieces["short"] = full_out[:7]  # maybe improved later
1065    pieces["error"] = None
1066
1067    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
1068    # TAG might have hyphens.
1069    git_describe = describe_out
1070
1071    # look for -dirty suffix
1072    dirty = git_describe.endswith("-dirty")
1073    pieces["dirty"] = dirty
1074    if dirty:
1075        git_describe = git_describe[:git_describe.rindex("-dirty")]
1076
1077    # now we have TAG-NUM-gHEX or HEX
1078
1079    if "-" in git_describe:
1080        # TAG-NUM-gHEX
1081        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
1082        if not mo:
1083            # unparseable. Maybe git-describe is misbehaving?
1084            pieces["error"] = ("unable to parse git-describe output: '%s'"
1085                               % describe_out)
1086            return pieces
1087
1088        # tag
1089        full_tag = mo.group(1)
1090        if not full_tag.startswith(tag_prefix):
1091            if verbose:
1092                fmt = "tag '%s' doesn't start with prefix '%s'"
1093                print(fmt % (full_tag, tag_prefix))
1094            pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
1095                               % (full_tag, tag_prefix))
1096            return pieces
1097        pieces["closest-tag"] = full_tag[len(tag_prefix):]
1098
1099        # distance: number of commits since tag
1100        pieces["distance"] = int(mo.group(2))
1101
1102        # commit: short hex revision ID
1103        pieces["short"] = mo.group(3)
1104
1105    else:
1106        # HEX: no tags
1107        pieces["closest-tag"] = None
1108        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
1109                                    cwd=root)
1110        pieces["distance"] = int(count_out)  # total number of commits
1111
1112    # commit date: see ISO-8601 comment in git_versions_from_keywords()
1113    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
1114                       cwd=root)[0].strip()
1115    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
1116
1117    return pieces
1118
1119
1120def do_vcs_install(manifest_in, versionfile_source, ipy):
1121    """Git-specific installation logic for Versioneer.
1122
1123    For Git, this means creating/changing .gitattributes to mark _version.py
1124    for export-subst keyword substitution.
1125    """
1126    GITS = ["git"]
1127    if sys.platform == "win32":
1128        GITS = ["git.cmd", "git.exe"]
1129    files = [manifest_in, versionfile_source]
1130    if ipy:
1131        files.append(ipy)
1132    try:
1133        me = __file__
1134        if me.endswith(".pyc") or me.endswith(".pyo"):
1135            me = os.path.splitext(me)[0] + ".py"
1136        versioneer_file = os.path.relpath(me)
1137    except NameError:
1138        versioneer_file = "versioneer.py"
1139    files.append(versioneer_file)
1140    present = False
1141    try:
1142        f = open(".gitattributes", "r")
1143        for line in f.readlines():
1144            if line.strip().startswith(versionfile_source):
1145                if "export-subst" in line.strip().split()[1:]:
1146                    present = True
1147        f.close()
1148    except EnvironmentError:
1149        pass
1150    if not present:
1151        f = open(".gitattributes", "a+")
1152        f.write("%s export-subst\n" % versionfile_source)
1153        f.close()
1154        files.append(".gitattributes")
1155    run_command(GITS, ["add", "--"] + files)
1156
1157
1158def versions_from_parentdir(parentdir_prefix, root, verbose):
1159    """Try to determine the version from the parent directory name.
1160
1161    Source tarballs conventionally unpack into a directory that includes both
1162    the project name and a version string. We will also support searching up
1163    two directory levels for an appropriately named parent directory
1164    """
1165    rootdirs = []
1166
1167    for i in range(3):
1168        dirname = os.path.basename(root)
1169        if dirname.startswith(parentdir_prefix):
1170            return {"version": dirname[len(parentdir_prefix):],
1171                    "full-revisionid": None,
1172                    "dirty": False, "error": None, "date": None}
1173        else:
1174            rootdirs.append(root)
1175            root = os.path.dirname(root)  # up a level
1176
1177    if verbose:
1178        print("Tried directories %s but none started with prefix %s" %
1179              (str(rootdirs), parentdir_prefix))
1180    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
1181
1182
1183SHORT_VERSION_PY = """
1184# This file was generated by 'versioneer.py' (0.18) from
1185# revision-control system data, or from the parent directory name of an
1186# unpacked source archive. Distribution tarballs contain a pre-generated copy
1187# of this file.
1188
1189import json
1190
1191version_json = '''
1192%s
1193'''  # END VERSION_JSON
1194
1195
1196def get_versions():
1197    return json.loads(version_json)
1198"""
1199
1200
1201def versions_from_file(filename):
1202    """Try to determine the version from _version.py if present."""
1203    try:
1204        with open(filename) as f:
1205            contents = f.read()
1206    except EnvironmentError:
1207        raise NotThisMethod("unable to read _version.py")
1208    mo = re.search(r"version_json = '''\n(.*)'''  # END VERSION_JSON",
1209                   contents, re.M | re.S)
1210    if not mo:
1211        mo = re.search(r"version_json = '''\r\n(.*)'''  # END VERSION_JSON",
1212                       contents, re.M | re.S)
1213    if not mo:
1214        raise NotThisMethod("no version_json in _version.py")
1215    return json.loads(mo.group(1))
1216
1217
1218def write_to_version_file(filename, versions):
1219    """Write the given version number to the given _version.py file."""
1220    os.unlink(filename)
1221    contents = json.dumps(versions, sort_keys=True,
1222                          indent=1, separators=(",", ": "))
1223    with open(filename, "w") as f:
1224        f.write(SHORT_VERSION_PY % contents)
1225
1226    print("set %s to '%s'" % (filename, versions["version"]))
1227
1228
1229def plus_or_dot(pieces):
1230    """Return a + if we don't already have one, else return a ."""
1231    if "+" in pieces.get("closest-tag", ""):
1232        return "."
1233    return "+"
1234
1235
1236def render_pep440(pieces):
1237    """Build up version string, with post-release "local version identifier".
1238
1239    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
1240    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
1241
1242    Exceptions:
1243    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
1244    """
1245    if pieces["closest-tag"]:
1246        rendered = pieces["closest-tag"]
1247        if pieces["distance"] or pieces["dirty"]:
1248            rendered += plus_or_dot(pieces)
1249            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
1250            if pieces["dirty"]:
1251                rendered += ".dirty"
1252    else:
1253        # exception #1
1254        rendered = "0+untagged.%d.g%s" % (pieces["distance"],
1255                                          pieces["short"])
1256        if pieces["dirty"]:
1257            rendered += ".dirty"
1258    return rendered
1259
1260
1261def render_pep440_pre(pieces):
1262    """TAG[.post.devDISTANCE] -- No -dirty.
1263
1264    Exceptions:
1265    1: no tags. 0.post.devDISTANCE
1266    """
1267    if pieces["closest-tag"]:
1268        rendered = pieces["closest-tag"]
1269        if pieces["distance"]:
1270            rendered += ".post.dev%d" % pieces["distance"]
1271    else:
1272        # exception #1
1273        rendered = "0.post.dev%d" % pieces["distance"]
1274    return rendered
1275
1276
1277def render_pep440_post(pieces):
1278    """TAG[.postDISTANCE[.dev0]+gHEX] .
1279
1280    The ".dev0" means dirty. Note that .dev0 sorts backwards
1281    (a dirty tree will appear "older" than the corresponding clean one),
1282    but you shouldn't be releasing software with -dirty anyways.
1283
1284    Exceptions:
1285    1: no tags. 0.postDISTANCE[.dev0]
1286    """
1287    if pieces["closest-tag"]:
1288        rendered = pieces["closest-tag"]
1289        if pieces["distance"] or pieces["dirty"]:
1290            rendered += ".post%d" % pieces["distance"]
1291            if pieces["dirty"]:
1292                rendered += ".dev0"
1293            rendered += plus_or_dot(pieces)
1294            rendered += "g%s" % pieces["short"]
1295    else:
1296        # exception #1
1297        rendered = "0.post%d" % pieces["distance"]
1298        if pieces["dirty"]:
1299            rendered += ".dev0"
1300        rendered += "+g%s" % pieces["short"]
1301    return rendered
1302
1303
1304def render_pep440_old(pieces):
1305    """TAG[.postDISTANCE[.dev0]] .
1306
1307    The ".dev0" means dirty.
1308
1309    Eexceptions:
1310    1: no tags. 0.postDISTANCE[.dev0]
1311    """
1312    if pieces["closest-tag"]:
1313        rendered = pieces["closest-tag"]
1314        if pieces["distance"] or pieces["dirty"]:
1315            rendered += ".post%d" % pieces["distance"]
1316            if pieces["dirty"]:
1317                rendered += ".dev0"
1318    else:
1319        # exception #1
1320        rendered = "0.post%d" % pieces["distance"]
1321        if pieces["dirty"]:
1322            rendered += ".dev0"
1323    return rendered
1324
1325
1326def render_git_describe(pieces):
1327    """TAG[-DISTANCE-gHEX][-dirty].
1328
1329    Like 'git describe --tags --dirty --always'.
1330
1331    Exceptions:
1332    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
1333    """
1334    if pieces["closest-tag"]:
1335        rendered = pieces["closest-tag"]
1336        if pieces["distance"]:
1337            rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
1338    else:
1339        # exception #1
1340        rendered = pieces["short"]
1341    if pieces["dirty"]:
1342        rendered += "-dirty"
1343    return rendered
1344
1345
1346def render_git_describe_long(pieces):
1347    """TAG-DISTANCE-gHEX[-dirty].
1348
1349    Like 'git describe --tags --dirty --always -long'.
1350    The distance/hash is unconditional.
1351
1352    Exceptions:
1353    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
1354    """
1355    if pieces["closest-tag"]:
1356        rendered = pieces["closest-tag"]
1357        rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
1358    else:
1359        # exception #1
1360        rendered = pieces["short"]
1361    if pieces["dirty"]:
1362        rendered += "-dirty"
1363    return rendered
1364
1365
1366def render(pieces, style):
1367    """Render the given version pieces into the requested style."""
1368    if pieces["error"]:
1369        return {"version": "unknown",
1370                "full-revisionid": pieces.get("long"),
1371                "dirty": None,
1372                "error": pieces["error"],
1373                "date": None}
1374
1375    if not style or style == "default":
1376        style = "pep440"  # the default
1377
1378    if style == "pep440":
1379        rendered = render_pep440(pieces)
1380    elif style == "pep440-pre":
1381        rendered = render_pep440_pre(pieces)
1382    elif style == "pep440-post":
1383        rendered = render_pep440_post(pieces)
1384    elif style == "pep440-old":
1385        rendered = render_pep440_old(pieces)
1386    elif style == "git-describe":
1387        rendered = render_git_describe(pieces)
1388    elif style == "git-describe-long":
1389        rendered = render_git_describe_long(pieces)
1390    else:
1391        raise ValueError("unknown style '%s'" % style)
1392
1393    return {"version": rendered, "full-revisionid": pieces["long"],
1394            "dirty": pieces["dirty"], "error": None,
1395            "date": pieces.get("date")}
1396
1397
1398class VersioneerBadRootError(Exception):
1399    """The project root directory is unknown or missing key files."""
1400
1401
1402def get_versions(verbose=False):
1403    """Get the project version from whatever source is available.
1404
1405    Returns dict with two keys: 'version' and 'full'.
1406    """
1407    if "versioneer" in sys.modules:
1408        # see the discussion in cmdclass.py:get_cmdclass()
1409        del sys.modules["versioneer"]
1410
1411    root = get_root()
1412    cfg = get_config_from_root(root)
1413
1414    assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg"
1415    handlers = HANDLERS.get(cfg.VCS)
1416    assert handlers, "unrecognized VCS '%s'" % cfg.VCS
1417    verbose = verbose or cfg.verbose
1418    assert cfg.versionfile_source is not None, \
1419        "please set versioneer.versionfile_source"
1420    assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
1421
1422    versionfile_abs = os.path.join(root, cfg.versionfile_source)
1423
1424    # extract version from first of: _version.py, VCS command (e.g. 'git
1425    # describe'), parentdir. This is meant to work for developers using a
1426    # source checkout, for users of a tarball created by 'setup.py sdist',
1427    # and for users of a tarball/zipball created by 'git archive' or github's
1428    # download-from-tag feature or the equivalent in other VCSes.
1429
1430    get_keywords_f = handlers.get("get_keywords")
1431    from_keywords_f = handlers.get("keywords")
1432    if get_keywords_f and from_keywords_f:
1433        try:
1434            keywords = get_keywords_f(versionfile_abs)
1435            ver = from_keywords_f(keywords, cfg.tag_prefix, verbose)
1436            if verbose:
1437                print("got version from expanded keyword %s" % ver)
1438            return ver
1439        except NotThisMethod:
1440            pass
1441
1442    try:
1443        ver = versions_from_file(versionfile_abs)
1444        if verbose:
1445            print("got version from file %s %s" % (versionfile_abs, ver))
1446        return ver
1447    except NotThisMethod:
1448        pass
1449
1450    from_vcs_f = handlers.get("pieces_from_vcs")
1451    if from_vcs_f:
1452        try:
1453            pieces = from_vcs_f(cfg.tag_prefix, root, verbose)
1454            ver = render(pieces, cfg.style)
1455            if verbose:
1456                print("got version from VCS %s" % ver)
1457            return ver
1458        except NotThisMethod:
1459            pass
1460
1461    try:
1462        if cfg.parentdir_prefix:
1463            ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
1464            if verbose:
1465                print("got version from parentdir %s" % ver)
1466            return ver
1467    except NotThisMethod:
1468        pass
1469
1470    if verbose:
1471        print("unable to compute version")
1472
1473    return {"version": "0+unknown", "full-revisionid": None,
1474            "dirty": None, "error": "unable to compute version",
1475            "date": None}
1476
1477
1478def get_version():
1479    """Get the short version string for this project."""
1480    return get_versions()["version"]
1481
1482
1483def get_cmdclass():
1484    """Get the custom setuptools/distutils subclasses used by Versioneer."""
1485    if "versioneer" in sys.modules:
1486        del sys.modules["versioneer"]
1487        # this fixes the "python setup.py develop" case (also 'install' and
1488        # 'easy_install .'), in which subdependencies of the main project are
1489        # built (using setup.py bdist_egg) in the same python process. Assume
1490        # a main project A and a dependency B, which use different versions
1491        # of Versioneer. A's setup.py imports A's Versioneer, leaving it in
1492        # sys.modules by the time B's setup.py is executed, causing B to run
1493        # with the wrong versioneer. Setuptools wraps the sub-dep builds in a
1494        # sandbox that restores sys.modules to it's pre-build state, so the
1495        # parent is protected against the child's "import versioneer". By
1496        # removing ourselves from sys.modules here, before the child build
1497        # happens, we protect the child from the parent's versioneer too.
1498        # Also see https://github.com/warner/python-versioneer/issues/52
1499
1500    cmds = {}
1501
1502    # we add "version" to both distutils and setuptools
1503    from distutils.core import Command
1504
1505    class cmd_version(Command):
1506        description = "report generated version string"
1507        user_options = []
1508        boolean_options = []
1509
1510        def initialize_options(self):
1511            pass
1512
1513        def finalize_options(self):
1514            pass
1515
1516        def run(self):
1517            vers = get_versions(verbose=True)
1518            print("Version: %s" % vers["version"])
1519            print(" full-revisionid: %s" % vers.get("full-revisionid"))
1520            print(" dirty: %s" % vers.get("dirty"))
1521            print(" date: %s" % vers.get("date"))
1522            if vers["error"]:
1523                print(" error: %s" % vers["error"])
1524    cmds["version"] = cmd_version
1525
1526    # we override "build_py" in both distutils and setuptools
1527    #
1528    # most invocation pathways end up running build_py:
1529    #  distutils/build -> build_py
1530    #  distutils/install -> distutils/build ->..
1531    #  setuptools/bdist_wheel -> distutils/install ->..
1532    #  setuptools/bdist_egg -> distutils/install_lib -> build_py
1533    #  setuptools/install -> bdist_egg ->..
1534    #  setuptools/develop -> ?
1535    #  pip install:
1536    #   copies source tree to a tempdir before running egg_info/etc
1537    #   if .git isn't copied too, 'git describe' will fail
1538    #   then does setup.py bdist_wheel, or sometimes setup.py install
1539    #  setup.py egg_info -> ?
1540
1541    # we override different "build_py" commands for both environments
1542    if "setuptools" in sys.modules:
1543        from setuptools.command.build_py import build_py as _build_py
1544    else:
1545        from distutils.command.build_py import build_py as _build_py
1546
1547    class cmd_build_py(_build_py):
1548        def run(self):
1549            root = get_root()
1550            cfg = get_config_from_root(root)
1551            versions = get_versions()
1552            _build_py.run(self)
1553            # now locate _version.py in the new build/ directory and replace
1554            # it with an updated value
1555            if cfg.versionfile_build:
1556                target_versionfile = os.path.join(self.build_lib,
1557                                                  cfg.versionfile_build)
1558                print("UPDATING %s" % target_versionfile)
1559                write_to_version_file(target_versionfile, versions)
1560    cmds["build_py"] = cmd_build_py
1561
1562    if "cx_Freeze" in sys.modules:  # cx_freeze enabled?
1563        from cx_Freeze.dist import build_exe as _build_exe
1564        # nczeczulin reports that py2exe won't like the pep440-style string
1565        # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g.
1566        # setup(console=[{
1567        #   "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION
1568        #   "product_version": versioneer.get_version(),
1569        #   ...
1570
1571        class cmd_build_exe(_build_exe):
1572            def run(self):
1573                root = get_root()
1574                cfg = get_config_from_root(root)
1575                versions = get_versions()
1576                target_versionfile = cfg.versionfile_source
1577                print("UPDATING %s" % target_versionfile)
1578                write_to_version_file(target_versionfile, versions)
1579
1580                _build_exe.run(self)
1581                os.unlink(target_versionfile)
1582                with open(cfg.versionfile_source, "w") as f:
1583                    LONG = LONG_VERSION_PY[cfg.VCS]
1584                    f.write(LONG %
1585                            {"DOLLAR": "$",
1586                             "STYLE": cfg.style,
1587                             "TAG_PREFIX": cfg.tag_prefix,
1588                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1589                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
1590                             })
1591        cmds["build_exe"] = cmd_build_exe
1592        del cmds["build_py"]
1593
1594    if 'py2exe' in sys.modules:  # py2exe enabled?
1595        try:
1596            from py2exe.distutils_buildexe import py2exe as _py2exe  # py3
1597        except ImportError:
1598            from py2exe.build_exe import py2exe as _py2exe  # py2
1599
1600        class cmd_py2exe(_py2exe):
1601            def run(self):
1602                root = get_root()
1603                cfg = get_config_from_root(root)
1604                versions = get_versions()
1605                target_versionfile = cfg.versionfile_source
1606                print("UPDATING %s" % target_versionfile)
1607                write_to_version_file(target_versionfile, versions)
1608
1609                _py2exe.run(self)
1610                os.unlink(target_versionfile)
1611                with open(cfg.versionfile_source, "w") as f:
1612                    LONG = LONG_VERSION_PY[cfg.VCS]
1613                    f.write(LONG %
1614                            {"DOLLAR": "$",
1615                             "STYLE": cfg.style,
1616                             "TAG_PREFIX": cfg.tag_prefix,
1617                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1618                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
1619                             })
1620        cmds["py2exe"] = cmd_py2exe
1621
1622    # we override different "sdist" commands for both environments
1623    if "setuptools" in sys.modules:
1624        from setuptools.command.sdist import sdist as _sdist
1625    else:
1626        from distutils.command.sdist import sdist as _sdist
1627
1628    class cmd_sdist(_sdist):
1629        def run(self):
1630            versions = get_versions()
1631            self._versioneer_generated_versions = versions
1632            # unless we update this, the command will keep using the old
1633            # version
1634            self.distribution.metadata.version = versions["version"]
1635            return _sdist.run(self)
1636
1637        def make_release_tree(self, base_dir, files):
1638            root = get_root()
1639            cfg = get_config_from_root(root)
1640            _sdist.make_release_tree(self, base_dir, files)
1641            # now locate _version.py in the new base_dir directory
1642            # (remembering that it may be a hardlink) and replace it with an
1643            # updated value
1644            target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
1645            print("UPDATING %s" % target_versionfile)
1646            write_to_version_file(target_versionfile,
1647                                  self._versioneer_generated_versions)
1648    cmds["sdist"] = cmd_sdist
1649
1650    return cmds
1651
1652
1653CONFIG_ERROR = """
1654setup.cfg is missing the necessary Versioneer configuration. You need
1655a section like:
1656
1657 [versioneer]
1658 VCS = git
1659 style = pep440
1660 versionfile_source = src/myproject/_version.py
1661 versionfile_build = myproject/_version.py
1662 tag_prefix =
1663 parentdir_prefix = myproject-
1664
1665You will also need to edit your setup.py to use the results:
1666
1667 import versioneer
1668 setup(version=versioneer.get_version(),
1669       cmdclass=versioneer.get_cmdclass(), ...)
1670
1671Please read the docstring in ./versioneer.py for configuration instructions,
1672edit setup.cfg, and re-run the installer or 'python versioneer.py setup'.
1673"""
1674
1675SAMPLE_CONFIG = """
1676# See the docstring in versioneer.py for instructions. Note that you must
1677# re-run 'versioneer.py setup' after changing this section, and commit the
1678# resulting files.
1679
1680[versioneer]
1681#VCS = git
1682#style = pep440
1683#versionfile_source =
1684#versionfile_build =
1685#tag_prefix =
1686#parentdir_prefix =
1687
1688"""
1689
1690INIT_PY_SNIPPET = """
1691from ._version import get_versions
1692__version__ = get_versions()['version']
1693del get_versions
1694"""
1695
1696
1697def do_setup():
1698    """Main VCS-independent setup function for installing Versioneer."""
1699    root = get_root()
1700    try:
1701        cfg = get_config_from_root(root)
1702    except (EnvironmentError, configparser.NoSectionError,
1703            configparser.NoOptionError) as e:
1704        if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
1705            print("Adding sample versioneer config to setup.cfg",
1706                  file=sys.stderr)
1707            with open(os.path.join(root, "setup.cfg"), "a") as f:
1708                f.write(SAMPLE_CONFIG)
1709        print(CONFIG_ERROR, file=sys.stderr)
1710        return 1
1711
1712    print(" creating %s" % cfg.versionfile_source)
1713    with open(cfg.versionfile_source, "w") as f:
1714        LONG = LONG_VERSION_PY[cfg.VCS]
1715        f.write(LONG % {"DOLLAR": "$",
1716                        "STYLE": cfg.style,
1717                        "TAG_PREFIX": cfg.tag_prefix,
1718                        "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1719                        "VERSIONFILE_SOURCE": cfg.versionfile_source,
1720                        })
1721
1722    ipy = os.path.join(os.path.dirname(cfg.versionfile_source),
1723                       "__init__.py")
1724    if os.path.exists(ipy):
1725        try:
1726            with open(ipy, "r") as f:
1727                old = f.read()
1728        except EnvironmentError:
1729            old = ""
1730        if INIT_PY_SNIPPET not in old:
1731            print(" appending to %s" % ipy)
1732            with open(ipy, "a") as f:
1733                f.write(INIT_PY_SNIPPET)
1734        else:
1735            print(" %s unmodified" % ipy)
1736    else:
1737        print(" %s doesn't exist, ok" % ipy)
1738        ipy = None
1739
1740    # Make sure both the top-level "versioneer.py" and versionfile_source
1741    # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
1742    # they'll be copied into source distributions. Pip won't be able to
1743    # install the package without this.
1744    manifest_in = os.path.join(root, "MANIFEST.in")
1745    simple_includes = set()
1746    try:
1747        with open(manifest_in, "r") as f:
1748            for line in f:
1749                if line.startswith("include "):
1750                    for include in line.split()[1:]:
1751                        simple_includes.add(include)
1752    except EnvironmentError:
1753        pass
1754    # That doesn't cover everything MANIFEST.in can do
1755    # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
1756    # it might give some false negatives. Appending redundant 'include'
1757    # lines is safe, though.
1758    if "versioneer.py" not in simple_includes:
1759        print(" appending 'versioneer.py' to MANIFEST.in")
1760        with open(manifest_in, "a") as f:
1761            f.write("include versioneer.py\n")
1762    else:
1763        print(" 'versioneer.py' already in MANIFEST.in")
1764    if cfg.versionfile_source not in simple_includes:
1765        print(" appending versionfile_source ('%s') to MANIFEST.in" %
1766              cfg.versionfile_source)
1767        with open(manifest_in, "a") as f:
1768            f.write("include %s\n" % cfg.versionfile_source)
1769    else:
1770        print(" versionfile_source already in MANIFEST.in")
1771
1772    # Make VCS-specific changes. For git, this means creating/changing
1773    # .gitattributes to mark _version.py for export-subst keyword
1774    # substitution.
1775    do_vcs_install(manifest_in, cfg.versionfile_source, ipy)
1776    return 0
1777
1778
1779def scan_setup_py():
1780    """Validate the contents of setup.py against Versioneer's expectations."""
1781    found = set()
1782    setters = False
1783    errors = 0
1784    with open("setup.py", "r") as f:
1785        for line in f.readlines():
1786            if "import versioneer" in line:
1787                found.add("import")
1788            if "versioneer.get_cmdclass()" in line:
1789                found.add("cmdclass")
1790            if "versioneer.get_version()" in line:
1791                found.add("get_version")
1792            if "versioneer.VCS" in line:
1793                setters = True
1794            if "versioneer.versionfile_source" in line:
1795                setters = True
1796    if len(found) != 3:
1797        print("")
1798        print("Your setup.py appears to be missing some important items")
1799        print("(but I might be wrong). Please make sure it has something")
1800        print("roughly like the following:")
1801        print("")
1802        print(" import versioneer")
1803        print(" setup( version=versioneer.get_version(),")
1804        print("        cmdclass=versioneer.get_cmdclass(),  ...)")
1805        print("")
1806        errors += 1
1807    if setters:
1808        print("You should remove lines like 'versioneer.VCS = ' and")
1809        print("'versioneer.versionfile_source = ' . This configuration")
1810        print("now lives in setup.cfg, and should be removed from setup.py")
1811        print("")
1812        errors += 1
1813    return errors
1814
1815
1816if __name__ == "__main__":
1817    cmd = sys.argv[1]
1818    if cmd == "setup":
1819        errors = do_setup()
1820        errors += scan_setup_py()
1821        if errors:
1822            sys.exit(1)
1823