a8138a0
a8138a0
# Version: 0.18
a8138a0
a8138a0
"""The Versioneer - like a rocketeer, but for versions.
a8138a0
a8138a0
The Versioneer
a8138a0
==============
a8138a0
a8138a0
* like a rocketeer, but for versions!
a8138a0
* https://github.com/warner/python-versioneer
a8138a0
* Brian Warner
a8138a0
* License: Public Domain
a8138a0
* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy
a8138a0
* [![Latest Version]
a8138a0
(https://pypip.in/version/versioneer/badge.svg?style=flat)
a8138a0
](https://pypi.python.org/pypi/versioneer/)
a8138a0
* [![Build Status]
a8138a0
(https://travis-ci.org/warner/python-versioneer.png?branch=master)
a8138a0
](https://travis-ci.org/warner/python-versioneer)
a8138a0
a8138a0
This is a tool for managing a recorded version number in distutils-based
a8138a0
python projects. The goal is to remove the tedious and error-prone "update
a8138a0
the embedded version string" step from your release process. Making a new
a8138a0
release should be as easy as recording a new tag in your version-control
a8138a0
system, and maybe making new tarballs.
a8138a0
a8138a0
a8138a0
## Quick Install
a8138a0
a8138a0
* `pip install versioneer` to somewhere to your $PATH
a8138a0
* add a `[versioneer]` section to your setup.cfg (see below)
a8138a0
* run `versioneer install` in your source tree, commit the results
a8138a0
a8138a0
## Version Identifiers
a8138a0
a8138a0
Source trees come from a variety of places:
a8138a0
a8138a0
* a version-control system checkout (mostly used by developers)
a8138a0
* a nightly tarball, produced by build automation
a8138a0
* a snapshot tarball, produced by a web-based VCS browser, like github's
a8138a0
  "tarball from tag" feature
a8138a0
* a release tarball, produced by "setup.py sdist", distributed through PyPI
a8138a0
a8138a0
Within each source tree, the version identifier (either a string or a number,
a8138a0
this tool is format-agnostic) can come from a variety of places:
a8138a0
a8138a0
* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
a8138a0
  about recent "tags" and an absolute revision-id
a8138a0
* the name of the directory into which the tarball was unpacked
a8138a0
* an expanded VCS keyword ($Id$, etc)
a8138a0
* a `_version.py` created by some earlier build step
a8138a0
a8138a0
For released software, the version identifier is closely related to a VCS
a8138a0
tag. Some projects use tag names that include more than just the version
a8138a0
string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
a8138a0
needs to strip the tag prefix to extract the version identifier. For
a8138a0
unreleased software (between tags), the version identifier should provide
a8138a0
enough information to help developers recreate the same tree, while also
a8138a0
giving them an idea of roughly how old the tree is (after version 1.2, before
a8138a0
version 1.3). Many VCS systems can report a description that captures this,
a8138a0
for example `git describe --tags --dirty --always` reports things like
a8138a0
"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
a8138a0
0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
a8138a0
uncommitted changes.
a8138a0
a8138a0
The version identifier is used for multiple purposes:
a8138a0
a8138a0
* to allow the module to self-identify its version: `myproject.__version__`
a8138a0
* to choose a name and prefix for a 'setup.py sdist' tarball
a8138a0
a8138a0
## Theory of Operation
a8138a0
a8138a0
Versioneer works by adding a special `_version.py` file into your source
a8138a0
tree, where your `__init__.py` can import it. This `_version.py` knows how to
a8138a0
dynamically ask the VCS tool for version information at import time.
a8138a0
a8138a0
`_version.py` also contains `$Revision$` markers, and the installation
a8138a0
process marks `_version.py` to have this marker rewritten with a tag name
a8138a0
during the `git archive` command. As a result, generated tarballs will
a8138a0
contain enough information to get the proper version.
a8138a0
a8138a0
To allow `setup.py` to compute a version too, a `versioneer.py` is added to
a8138a0
the top level of your source tree, next to `setup.py` and the `setup.cfg`
a8138a0
that configures it. This overrides several distutils/setuptools commands to
a8138a0
compute the version when invoked, and changes `setup.py build` and `setup.py
a8138a0
sdist` to replace `_version.py` with a small static file that contains just
a8138a0
the generated version data.
a8138a0
a8138a0
## Installation
a8138a0
a8138a0
See [INSTALL.md](./INSTALL.md) for detailed installation instructions.
a8138a0
a8138a0
## Version-String Flavors
a8138a0
a8138a0
Code which uses Versioneer can learn about its version string at runtime by
a8138a0
importing `_version` from your main `__init__.py` file and running the
a8138a0
`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
a8138a0
import the top-level `versioneer.py` and run `get_versions()`.
a8138a0
a8138a0
Both functions return a dictionary with different flavors of version
a8138a0
information:
a8138a0
a8138a0
* `['version']`: A condensed version string, rendered using the selected
a8138a0
  style. This is the most commonly used value for the project's version
a8138a0
  string. The default "pep440" style yields strings like `0.11`,
a8138a0
  `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section
a8138a0
  below for alternative styles.
a8138a0
a8138a0
* `['full-revisionid']`: detailed revision identifier. For Git, this is the
a8138a0
  full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
a8138a0
a8138a0
* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the
a8138a0
  commit date in ISO 8601 format. This will be None if the date is not
a8138a0
  available.
a8138a0
a8138a0
* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that
a8138a0
  this is only accurate if run in a VCS checkout, otherwise it is likely to
a8138a0
  be False or None
a8138a0
a8138a0
* `['error']`: if the version string could not be computed, this will be set
a8138a0
  to a string describing the problem, otherwise it will be None. It may be
a8138a0
  useful to throw an exception in setup.py if this is set, to avoid e.g.
a8138a0
  creating tarballs with a version string of "unknown".
a8138a0
a8138a0
Some variants are more useful than others. Including `full-revisionid` in a
a8138a0
bug report should allow developers to reconstruct the exact code being tested
a8138a0
(or indicate the presence of local changes that should be shared with the
a8138a0
developers). `version` is suitable for display in an "about" box or a CLI
a8138a0
`--version` output: it can be easily compared against release notes and lists
a8138a0
of bugs fixed in various releases.
a8138a0
a8138a0
The installer adds the following text to your `__init__.py` to place a basic
a8138a0
version in `YOURPROJECT.__version__`:
a8138a0
a8138a0
    from ._version import get_versions
a8138a0
    __version__ = get_versions()['version']
a8138a0
    del get_versions
a8138a0
a8138a0
## Styles
a8138a0
a8138a0
The setup.cfg `style=` configuration controls how the VCS information is
a8138a0
rendered into a version string.
a8138a0
a8138a0
The default style, "pep440", produces a PEP440-compliant string, equal to the
a8138a0
un-prefixed tag name for actual releases, and containing an additional "local
a8138a0
version" section with more detail for in-between builds. For Git, this is
a8138a0
TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags
a8138a0
--dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the
a8138a0
tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and
a8138a0
that this commit is two revisions ("+2") beyond the "0.11" tag. For released
a8138a0
software (exactly equal to a known tag), the identifier will only contain the
a8138a0
stripped tag, e.g. "0.11".
a8138a0
a8138a0
Other styles are available. See [details.md](details.md) in the Versioneer
a8138a0
source tree for descriptions.
a8138a0
a8138a0
## Debugging
a8138a0
a8138a0
Versioneer tries to avoid fatal errors: if something goes wrong, it will tend
a8138a0
to return a version of "0+unknown". To investigate the problem, run `setup.py
a8138a0
version`, which will run the version-lookup code in a verbose mode, and will
a8138a0
display the full contents of `get_versions()` (including the `error` string,
a8138a0
which may help identify what went wrong).
a8138a0
a8138a0
## Known Limitations
a8138a0
a8138a0
Some situations are known to cause problems for Versioneer. This details the
a8138a0
most significant ones. More can be found on Github
a8138a0
[issues page](https://github.com/warner/python-versioneer/issues).
a8138a0
a8138a0
### Subprojects
a8138a0
a8138a0
Versioneer has limited support for source trees in which `setup.py` is not in
a8138a0
the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are
a8138a0
two common reasons why `setup.py` might not be in the root:
a8138a0
a8138a0
* Source trees which contain multiple subprojects, such as
a8138a0
  [Buildbot](https://github.com/buildbot/buildbot), which contains both
a8138a0
  "master" and "slave" subprojects, each with their own `setup.py`,
a8138a0
  `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI
a8138a0
  distributions (and upload multiple independently-installable tarballs).
a8138a0
* Source trees whose main purpose is to contain a C library, but which also
a8138a0
  provide bindings to Python (and perhaps other langauges) in subdirectories.
a8138a0
a8138a0
Versioneer will look for `.git` in parent directories, and most operations
a8138a0
should get the right version string. However `pip` and `setuptools` have bugs
a8138a0
and implementation details which frequently cause `pip install .` from a
a8138a0
subproject directory to fail to find a correct version string (so it usually
a8138a0
defaults to `0+unknown`).
a8138a0
a8138a0
`pip install --editable .` should work correctly. `setup.py install` might
a8138a0
work too.
a8138a0
a8138a0
Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in
a8138a0
some later version.
a8138a0
a8138a0
[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking
a8138a0
this issue. The discussion in
a8138a0
[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the
a8138a0
issue from the Versioneer side in more detail.
a8138a0
[pip PR#3176](https://github.com/pypa/pip/pull/3176) and
a8138a0
[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve
a8138a0
pip to let Versioneer work correctly.
a8138a0
a8138a0
Versioneer-0.16 and earlier only looked for a `.git` directory next to the
a8138a0
`setup.cfg`, so subprojects were completely unsupported with those releases.
a8138a0
a8138a0
### Editable installs with setuptools <= 18.5
a8138a0
a8138a0
`setup.py develop` and `pip install --editable .` allow you to install a
a8138a0
project into a virtualenv once, then continue editing the source code (and
a8138a0
test) without re-installing after every change.
a8138a0
a8138a0
"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a
a8138a0
convenient way to specify executable scripts that should be installed along
a8138a0
with the python package.
a8138a0
a8138a0
These both work as expected when using modern setuptools. When using
a8138a0
setuptools-18.5 or earlier, however, certain operations will cause
a8138a0
`pkg_resources.DistributionNotFound` errors when running the entrypoint
a8138a0
script, which must be resolved by re-installing the package. This happens
a8138a0
when the install happens with one version, then the egg_info data is
a8138a0
regenerated while a different version is checked out. Many setup.py commands
a8138a0
cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into
a8138a0
a different virtualenv), so this can be surprising.
a8138a0
a8138a0
[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes
a8138a0
this one, but upgrading to a newer version of setuptools should probably
a8138a0
resolve it.
a8138a0
a8138a0
### Unicode version strings
a8138a0
a8138a0
While Versioneer works (and is continually tested) with both Python 2 and
a8138a0
Python 3, it is not entirely consistent with bytes-vs-unicode distinctions.
a8138a0
Newer releases probably generate unicode version strings on py2. It's not
a8138a0
clear that this is wrong, but it may be surprising for applications when then
a8138a0
write these strings to a network connection or include them in bytes-oriented
a8138a0
APIs like cryptographic checksums.
a8138a0
a8138a0
[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates
a8138a0
this question.
a8138a0
a8138a0
a8138a0
## Updating Versioneer
a8138a0
a8138a0
To upgrade your project to a new release of Versioneer, do the following:
a8138a0
a8138a0
* install the new Versioneer (`pip install -U versioneer` or equivalent)
a8138a0
* edit `setup.cfg`, if necessary, to include any new configuration settings
a8138a0
  indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details.
a8138a0
* re-run `versioneer install` in your source tree, to replace
a8138a0
  `SRC/_version.py`
a8138a0
* commit any changed files
a8138a0
a8138a0
## Future Directions
a8138a0
a8138a0
This tool is designed to make it easily extended to other version-control
a8138a0
systems: all VCS-specific components are in separate directories like
a8138a0
src/git/ . The top-level `versioneer.py` script is assembled from these
a8138a0
components by running make-versioneer.py . In the future, make-versioneer.py
a8138a0
will take a VCS name as an argument, and will construct a version of
a8138a0
`versioneer.py` that is specific to the given VCS. It might also take the
a8138a0
configuration arguments that are currently provided manually during
a8138a0
installation by editing setup.py . Alternatively, it might go the other
a8138a0
direction and include code from all supported VCS systems, reducing the
a8138a0
number of intermediate scripts.
a8138a0
a8138a0
a8138a0
## License
a8138a0
a8138a0
To make Versioneer easier to embed, all its code is dedicated to the public
a8138a0
domain. The `_version.py` that it creates is also in the public domain.
a8138a0
Specifically, both are released under the Creative Commons "Public Domain
a8138a0
Dedication" license (CC0-1.0), as described in
a8138a0
https://creativecommons.org/publicdomain/zero/1.0/ .
a8138a0
a8138a0
"""
a8138a0
a8138a0
from __future__ import print_function
a8138a0
try:
a8138a0
    import configparser
a8138a0
except ImportError:
a8138a0
    import ConfigParser as configparser
a8138a0
import errno
a8138a0
import json
a8138a0
import os
a8138a0
import re
a8138a0
import subprocess
a8138a0
import sys
a8138a0
a8138a0
a8138a0
class VersioneerConfig:
a8138a0
    """Container for Versioneer configuration parameters."""
a8138a0
a8138a0
a8138a0
def get_root():
a8138a0
    """Get the project root directory.
a8138a0
a8138a0
    We require that all commands are run from the project root, i.e. the
a8138a0
    directory that contains setup.py, setup.cfg, and versioneer.py .
a8138a0
    """
a8138a0
    root = os.path.realpath(os.path.abspath(os.getcwd()))
a8138a0
    setup_py = os.path.join(root, "setup.py")
a8138a0
    versioneer_py = os.path.join(root, "versioneer.py")
a8138a0
    if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
a8138a0
        # allow 'python path/to/setup.py COMMAND'
a8138a0
        root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
a8138a0
        setup_py = os.path.join(root, "setup.py")
a8138a0
        versioneer_py = os.path.join(root, "versioneer.py")
a8138a0
    if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
a8138a0
        err = ("Versioneer was unable to run the project root directory. "
a8138a0
               "Versioneer requires setup.py to be executed from "
a8138a0
               "its immediate directory (like 'python setup.py COMMAND'), "
a8138a0
               "or in a way that lets it use sys.argv[0] to find the root "
a8138a0
               "(like 'python path/to/setup.py COMMAND').")
a8138a0
        raise VersioneerBadRootError(err)
a8138a0
    try:
a8138a0
        # Certain runtime workflows (setup.py install/develop in a setuptools
a8138a0
        # tree) execute all dependencies in a single python process, so
a8138a0
        # "versioneer" may be imported multiple times, and python's shared
a8138a0
        # module-import table will cache the first one. So we can't use
a8138a0
        # os.path.dirname(__file__), as that will find whichever
a8138a0
        # versioneer.py was first imported, even in later projects.
a8138a0
        me = os.path.realpath(os.path.abspath(__file__))
a8138a0
        me_dir = os.path.normcase(os.path.splitext(me)[0])
a8138a0
        vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0])
a8138a0
        if me_dir != vsr_dir:
a8138a0
            print("Warning: build in %s is using versioneer.py from %s"
a8138a0
                  % (os.path.dirname(me), versioneer_py))
a8138a0
    except NameError:
a8138a0
        pass
a8138a0
    return root
a8138a0
a8138a0
a8138a0
def get_config_from_root(root):
a8138a0
    """Read the project setup.cfg file to determine Versioneer config."""
a8138a0
    # This might raise EnvironmentError (if setup.cfg is missing), or
a8138a0
    # configparser.NoSectionError (if it lacks a [versioneer] section), or
a8138a0
    # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
a8138a0
    # the top of versioneer.py for instructions on writing your setup.cfg .
a8138a0
    setup_cfg = os.path.join(root, "setup.cfg")
a8138a0
    parser = configparser.SafeConfigParser()
a8138a0
    with open(setup_cfg, "r") as f:
a8138a0
        parser.readfp(f)
a8138a0
    VCS = parser.get("versioneer", "VCS")  # mandatory
a8138a0
a8138a0
    def get(parser, name):
a8138a0
        if parser.has_option("versioneer", name):
a8138a0
            return parser.get("versioneer", name)
a8138a0
        return None
a8138a0
    cfg = VersioneerConfig()
a8138a0
    cfg.VCS = VCS
a8138a0
    cfg.style = get(parser, "style") or ""
a8138a0
    cfg.versionfile_source = get(parser, "versionfile_source")
a8138a0
    cfg.versionfile_build = get(parser, "versionfile_build")
a8138a0
    cfg.tag_prefix = get(parser, "tag_prefix")
a8138a0
    if cfg.tag_prefix in ("''", '""'):
a8138a0
        cfg.tag_prefix = ""
a8138a0
    cfg.parentdir_prefix = get(parser, "parentdir_prefix")
a8138a0
    cfg.verbose = get(parser, "verbose")
a8138a0
    return cfg
a8138a0
a8138a0
a8138a0
class NotThisMethod(Exception):
a8138a0
    """Exception raised if a method is not valid for the current scenario."""
a8138a0
a8138a0
a8138a0
# these dictionaries contain VCS-specific tools
a8138a0
LONG_VERSION_PY = {}
a8138a0
HANDLERS = {}
a8138a0
a8138a0
a8138a0
def register_vcs_handler(vcs, method):  # decorator
a8138a0
    """Decorator to mark a method as the handler for a particular VCS."""
a8138a0
    def decorate(f):
a8138a0
        """Store f in HANDLERS[vcs][method]."""
a8138a0
        if vcs not in HANDLERS:
a8138a0
            HANDLERS[vcs] = {}
a8138a0
        HANDLERS[vcs][method] = f
a8138a0
        return f
a8138a0
    return decorate
a8138a0
a8138a0
a8138a0
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
a8138a0
                env=None):
a8138a0
    """Call the given command(s)."""
a8138a0
    assert isinstance(commands, list)
a8138a0
    p = None
a8138a0
    for c in commands:
a8138a0
        try:
a8138a0
            dispcmd = str([c] + args)
a8138a0
            # remember shell=False, so use git.cmd on windows, not just git
a8138a0
            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
a8138a0
                                 stdout=subprocess.PIPE,
a8138a0
                                 stderr=(subprocess.PIPE if hide_stderr
a8138a0
                                         else None))
a8138a0
            break
a8138a0
        except EnvironmentError:
a8138a0
            e = sys.exc_info()[1]
a8138a0
            if e.errno == errno.ENOENT:
a8138a0
                continue
a8138a0
            if verbose:
a8138a0
                print("unable to run %s" % dispcmd)
a8138a0
                print(e)
a8138a0
            return None, None
a8138a0
    else:
a8138a0
        if verbose:
a8138a0
            print("unable to find command, tried %s" % (commands,))
a8138a0
        return None, None
a8138a0
    stdout = p.communicate()[0].strip()
a8138a0
    if sys.version_info[0] >= 3:
a8138a0
        stdout = stdout.decode()
a8138a0
    if p.returncode != 0:
a8138a0
        if verbose:
a8138a0
            print("unable to run %s (error)" % dispcmd)
a8138a0
            print("stdout was %s" % stdout)
a8138a0
        return None, p.returncode
a8138a0
    return stdout, p.returncode
a8138a0
a8138a0
a8138a0
LONG_VERSION_PY['git'] = '''
a8138a0
# This file helps to compute a version number in source trees obtained from
a8138a0
# git-archive tarball (such as those provided by githubs download-from-tag
a8138a0
# feature). Distribution tarballs (built by setup.py sdist) and build
a8138a0
# directories (produced by setup.py build) will contain a much shorter file
a8138a0
# that just contains the computed version number.
a8138a0
a8138a0
# This file is released into the public domain. Generated by
a8138a0
# versioneer-0.18 (https://github.com/warner/python-versioneer)
a8138a0
a8138a0
"""Git implementation of _version.py."""
a8138a0
a8138a0
import errno
a8138a0
import os
a8138a0
import re
a8138a0
import subprocess
a8138a0
import sys
a8138a0
a8138a0
a8138a0
def get_keywords():
a8138a0
    """Get the keywords needed to look up the version information."""
a8138a0
    # these strings will be replaced by git during git-archive.
a8138a0
    # setup.py/versioneer.py will grep for the variable names, so they must
a8138a0
    # each be defined on a line of their own. _version.py will just call
a8138a0
    # get_keywords().
a8138a0
    git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
a8138a0
    git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
a8138a0
    git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s"
a8138a0
    keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
a8138a0
    return keywords
a8138a0
a8138a0
a8138a0
class VersioneerConfig:
a8138a0
    """Container for Versioneer configuration parameters."""
a8138a0
a8138a0
a8138a0
def get_config():
a8138a0
    """Create, populate and return the VersioneerConfig() object."""
a8138a0
    # these strings are filled in when 'setup.py versioneer' creates
a8138a0
    # _version.py
a8138a0
    cfg = VersioneerConfig()
a8138a0
    cfg.VCS = "git"
a8138a0
    cfg.style = "%(STYLE)s"
a8138a0
    cfg.tag_prefix = "%(TAG_PREFIX)s"
a8138a0
    cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s"
a8138a0
    cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s"
a8138a0
    cfg.verbose = False
a8138a0
    return cfg
a8138a0
a8138a0
a8138a0
class NotThisMethod(Exception):
a8138a0
    """Exception raised if a method is not valid for the current scenario."""
a8138a0
a8138a0
a8138a0
LONG_VERSION_PY = {}
a8138a0
HANDLERS = {}
a8138a0
a8138a0
a8138a0
def register_vcs_handler(vcs, method):  # decorator
a8138a0
    """Decorator to mark a method as the handler for a particular VCS."""
a8138a0
    def decorate(f):
a8138a0
        """Store f in HANDLERS[vcs][method]."""
a8138a0
        if vcs not in HANDLERS:
a8138a0
            HANDLERS[vcs] = {}
a8138a0
        HANDLERS[vcs][method] = f
a8138a0
        return f
a8138a0
    return decorate
a8138a0
a8138a0
a8138a0
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
a8138a0
                env=None):
a8138a0
    """Call the given command(s)."""
a8138a0
    assert isinstance(commands, list)
a8138a0
    p = None
a8138a0
    for c in commands:
a8138a0
        try:
a8138a0
            dispcmd = str([c] + args)
a8138a0
            # remember shell=False, so use git.cmd on windows, not just git
a8138a0
            p = subprocess.Popen([c] + args, cwd=cwd, env=env,
a8138a0
                                 stdout=subprocess.PIPE,
a8138a0
                                 stderr=(subprocess.PIPE if hide_stderr
a8138a0
                                         else None))
a8138a0
            break
a8138a0
        except EnvironmentError:
a8138a0
            e = sys.exc_info()[1]
a8138a0
            if e.errno == errno.ENOENT:
a8138a0
                continue
a8138a0
            if verbose:
a8138a0
                print("unable to run %%s" %% dispcmd)
a8138a0
                print(e)
a8138a0
            return None, None
a8138a0
    else:
a8138a0
        if verbose:
a8138a0
            print("unable to find command, tried %%s" %% (commands,))
a8138a0
        return None, None
a8138a0
    stdout = p.communicate()[0].strip()
a8138a0
    if sys.version_info[0] >= 3:
a8138a0
        stdout = stdout.decode()
a8138a0
    if p.returncode != 0:
a8138a0
        if verbose:
a8138a0
            print("unable to run %%s (error)" %% dispcmd)
a8138a0
            print("stdout was %%s" %% stdout)
a8138a0
        return None, p.returncode
a8138a0
    return stdout, p.returncode
a8138a0
a8138a0
a8138a0
def versions_from_parentdir(parentdir_prefix, root, verbose):
a8138a0
    """Try to determine the version from the parent directory name.
a8138a0
a8138a0
    Source tarballs conventionally unpack into a directory that includes both
a8138a0
    the project name and a version string. We will also support searching up
a8138a0
    two directory levels for an appropriately named parent directory
a8138a0
    """
a8138a0
    rootdirs = []
a8138a0
a8138a0
    for i in range(3):
a8138a0
        dirname = os.path.basename(root)
a8138a0
        if dirname.startswith(parentdir_prefix):
a8138a0
            return {"version": dirname[len(parentdir_prefix):],
a8138a0
                    "full-revisionid": None,
a8138a0
                    "dirty": False, "error": None, "date": None}
a8138a0
        else:
a8138a0
            rootdirs.append(root)
a8138a0
            root = os.path.dirname(root)  # up a level
a8138a0
a8138a0
    if verbose:
a8138a0
        print("Tried directories %%s but none started with prefix %%s" %%
a8138a0
              (str(rootdirs), parentdir_prefix))
a8138a0
    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "get_keywords")
a8138a0
def git_get_keywords(versionfile_abs):
a8138a0
    """Extract version information from the given file."""
a8138a0
    # the code embedded in _version.py can just fetch the value of these
a8138a0
    # keywords. When used from setup.py, we don't want to import _version.py,
a8138a0
    # so we do it with a regexp instead. This function is not used from
a8138a0
    # _version.py.
a8138a0
    keywords = {}
a8138a0
    try:
a8138a0
        f = open(versionfile_abs, "r")
a8138a0
        for line in f.readlines():
a8138a0
            if line.strip().startswith("git_refnames ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["refnames"] = mo.group(1)
a8138a0
            if line.strip().startswith("git_full ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["full"] = mo.group(1)
a8138a0
            if line.strip().startswith("git_date ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["date"] = mo.group(1)
a8138a0
        f.close()
a8138a0
    except EnvironmentError:
a8138a0
        pass
a8138a0
    return keywords
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "keywords")
a8138a0
def git_versions_from_keywords(keywords, tag_prefix, verbose):
a8138a0
    """Get version information from git keywords."""
a8138a0
    if not keywords:
a8138a0
        raise NotThisMethod("no keywords at all, weird")
a8138a0
    date = keywords.get("date")
a8138a0
    if date is not None:
a8138a0
        # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant
a8138a0
        # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601
a8138a0
        # -like" string, which we must then edit to make compliant), because
a8138a0
        # it's been around since git-1.5.3, and it's too difficult to
a8138a0
        # discover which version we're using, or to work around using an
a8138a0
        # older one.
a8138a0
        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
a8138a0
    refnames = keywords["refnames"].strip()
a8138a0
    if refnames.startswith("$Format"):
a8138a0
        if verbose:
a8138a0
            print("keywords are unexpanded, not using")
a8138a0
        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
a8138a0
    refs = set([r.strip() for r in refnames.strip("()").split(",")])
a8138a0
    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
a8138a0
    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
a8138a0
    TAG = "tag: "
a8138a0
    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
a8138a0
    if not tags:
a8138a0
        # Either we're using git < 1.8.3, or there really are no tags. We use
a8138a0
        # a heuristic: assume all version tags have a digit. The old git %%d
a8138a0
        # expansion behaves like git log --decorate=short and strips out the
a8138a0
        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
a8138a0
        # between branches and tags. By ignoring refnames without digits, we
a8138a0
        # filter out many common branch names like "release" and
a8138a0
        # "stabilization", as well as "HEAD" and "master".
a8138a0
        tags = set([r for r in refs if re.search(r'\d', r)])
a8138a0
        if verbose:
a8138a0
            print("discarding '%%s', no digits" %% ",".join(refs - tags))
a8138a0
    if verbose:
a8138a0
        print("likely tags: %%s" %% ",".join(sorted(tags)))
a8138a0
    for ref in sorted(tags):
a8138a0
        # sorting will prefer e.g. "2.0" over "2.0rc1"
a8138a0
        if ref.startswith(tag_prefix):
a8138a0
            r = ref[len(tag_prefix):]
a8138a0
            if verbose:
a8138a0
                print("picking %%s" %% r)
a8138a0
            return {"version": r,
a8138a0
                    "full-revisionid": keywords["full"].strip(),
a8138a0
                    "dirty": False, "error": None,
a8138a0
                    "date": date}
a8138a0
    # no suitable tags, so version is "0+unknown", but full hex is still there
a8138a0
    if verbose:
a8138a0
        print("no suitable tags, using unknown + full revision id")
a8138a0
    return {"version": "0+unknown",
a8138a0
            "full-revisionid": keywords["full"].strip(),
a8138a0
            "dirty": False, "error": "no suitable tags", "date": None}
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "pieces_from_vcs")
a8138a0
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
a8138a0
    """Get version from 'git describe' in the root of the source tree.
a8138a0
a8138a0
    This only gets called if the git-archive 'subst' keywords were *not*
a8138a0
    expanded, and _version.py hasn't already been rewritten with a short
a8138a0
    version string, meaning we're inside a checked out source tree.
a8138a0
    """
a8138a0
    GITS = ["git"]
a8138a0
    if sys.platform == "win32":
a8138a0
        GITS = ["git.cmd", "git.exe"]
a8138a0
a8138a0
    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
a8138a0
                          hide_stderr=True)
a8138a0
    if rc != 0:
a8138a0
        if verbose:
a8138a0
            print("Directory %%s not under git control" %% root)
a8138a0
        raise NotThisMethod("'git rev-parse --git-dir' returned error")
a8138a0
a8138a0
    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
a8138a0
    # if there isn't one, this yields HEX[-dirty] (no NUM)
a8138a0
    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
a8138a0
                                          "--always", "--long",
a8138a0
                                          "--match", "%%s*" %% tag_prefix],
a8138a0
                                   cwd=root)
a8138a0
    # --long was added in git-1.5.5
a8138a0
    if describe_out is None:
a8138a0
        raise NotThisMethod("'git describe' failed")
a8138a0
    describe_out = describe_out.strip()
a8138a0
    full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
a8138a0
    if full_out is None:
a8138a0
        raise NotThisMethod("'git rev-parse' failed")
a8138a0
    full_out = full_out.strip()
a8138a0
a8138a0
    pieces = {}
a8138a0
    pieces["long"] = full_out
a8138a0
    pieces["short"] = full_out[:7]  # maybe improved later
a8138a0
    pieces["error"] = None
a8138a0
a8138a0
    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
a8138a0
    # TAG might have hyphens.
a8138a0
    git_describe = describe_out
a8138a0
a8138a0
    # look for -dirty suffix
a8138a0
    dirty = git_describe.endswith("-dirty")
a8138a0
    pieces["dirty"] = dirty
a8138a0
    if dirty:
a8138a0
        git_describe = git_describe[:git_describe.rindex("-dirty")]
a8138a0
a8138a0
    # now we have TAG-NUM-gHEX or HEX
a8138a0
a8138a0
    if "-" in git_describe:
a8138a0
        # TAG-NUM-gHEX
a8138a0
        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
a8138a0
        if not mo:
a8138a0
            # unparseable. Maybe git-describe is misbehaving?
a8138a0
            pieces["error"] = ("unable to parse git-describe output: '%%s'"
a8138a0
                               %% describe_out)
a8138a0
            return pieces
a8138a0
a8138a0
        # tag
a8138a0
        full_tag = mo.group(1)
a8138a0
        if not full_tag.startswith(tag_prefix):
a8138a0
            if verbose:
a8138a0
                fmt = "tag '%%s' doesn't start with prefix '%%s'"
a8138a0
                print(fmt %% (full_tag, tag_prefix))
a8138a0
            pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'"
a8138a0
                               %% (full_tag, tag_prefix))
a8138a0
            return pieces
a8138a0
        pieces["closest-tag"] = full_tag[len(tag_prefix):]
a8138a0
a8138a0
        # distance: number of commits since tag
a8138a0
        pieces["distance"] = int(mo.group(2))
a8138a0
a8138a0
        # commit: short hex revision ID
a8138a0
        pieces["short"] = mo.group(3)
a8138a0
a8138a0
    else:
a8138a0
        # HEX: no tags
a8138a0
        pieces["closest-tag"] = None
a8138a0
        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
a8138a0
                                    cwd=root)
a8138a0
        pieces["distance"] = int(count_out)  # total number of commits
a8138a0
a8138a0
    # commit date: see ISO-8601 comment in git_versions_from_keywords()
a8138a0
    date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"],
a8138a0
                       cwd=root)[0].strip()
a8138a0
    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
a8138a0
a8138a0
    return pieces
a8138a0
a8138a0
a8138a0
def plus_or_dot(pieces):
a8138a0
    """Return a + if we don't already have one, else return a ."""
a8138a0
    if "+" in pieces.get("closest-tag", ""):
a8138a0
        return "."
a8138a0
    return "+"
a8138a0
a8138a0
a8138a0
def render_pep440(pieces):
a8138a0
    """Build up version string, with post-release "local version identifier".
a8138a0
a8138a0
    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
a8138a0
    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += plus_or_dot(pieces)
a8138a0
            rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"])
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dirty"
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"],
a8138a0
                                          pieces["short"])
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_pre(pieces):
a8138a0
    """TAG[.post.devDISTANCE] -- No -dirty.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. 0.post.devDISTANCE
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"]:
a8138a0
            rendered += ".post.dev%%d" %% pieces["distance"]
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post.dev%%d" %% pieces["distance"]
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_post(pieces):
a8138a0
    """TAG[.postDISTANCE[.dev0]+gHEX] .
a8138a0
a8138a0
    The ".dev0" means dirty. Note that .dev0 sorts backwards
a8138a0
    (a dirty tree will appear "older" than the corresponding clean one),
a8138a0
    but you shouldn't be releasing software with -dirty anyways.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. 0.postDISTANCE[.dev0]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += ".post%%d" %% pieces["distance"]
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dev0"
a8138a0
            rendered += plus_or_dot(pieces)
a8138a0
            rendered += "g%%s" %% pieces["short"]
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post%%d" %% pieces["distance"]
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dev0"
a8138a0
        rendered += "+g%%s" %% pieces["short"]
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_old(pieces):
a8138a0
    """TAG[.postDISTANCE[.dev0]] .
a8138a0
a8138a0
    The ".dev0" means dirty.
a8138a0
a8138a0
    Eexceptions:
a8138a0
    1: no tags. 0.postDISTANCE[.dev0]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += ".post%%d" %% pieces["distance"]
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dev0"
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post%%d" %% pieces["distance"]
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dev0"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_git_describe(pieces):
a8138a0
    """TAG[-DISTANCE-gHEX][-dirty].
a8138a0
a8138a0
    Like 'git describe --tags --dirty --always'.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"]:
a8138a0
            rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = pieces["short"]
a8138a0
    if pieces["dirty"]:
a8138a0
        rendered += "-dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_git_describe_long(pieces):
a8138a0
    """TAG-DISTANCE-gHEX[-dirty].
a8138a0
a8138a0
    Like 'git describe --tags --dirty --always -long'.
a8138a0
    The distance/hash is unconditional.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = pieces["short"]
a8138a0
    if pieces["dirty"]:
a8138a0
        rendered += "-dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render(pieces, style):
a8138a0
    """Render the given version pieces into the requested style."""
a8138a0
    if pieces["error"]:
a8138a0
        return {"version": "unknown",
a8138a0
                "full-revisionid": pieces.get("long"),
a8138a0
                "dirty": None,
a8138a0
                "error": pieces["error"],
a8138a0
                "date": None}
a8138a0
a8138a0
    if not style or style == "default":
a8138a0
        style = "pep440"  # the default
a8138a0
a8138a0
    if style == "pep440":
a8138a0
        rendered = render_pep440(pieces)
a8138a0
    elif style == "pep440-pre":
a8138a0
        rendered = render_pep440_pre(pieces)
a8138a0
    elif style == "pep440-post":
a8138a0
        rendered = render_pep440_post(pieces)
a8138a0
    elif style == "pep440-old":
a8138a0
        rendered = render_pep440_old(pieces)
a8138a0
    elif style == "git-describe":
a8138a0
        rendered = render_git_describe(pieces)
a8138a0
    elif style == "git-describe-long":
a8138a0
        rendered = render_git_describe_long(pieces)
a8138a0
    else:
a8138a0
        raise ValueError("unknown style '%%s'" %% style)
a8138a0
a8138a0
    return {"version": rendered, "full-revisionid": pieces["long"],
a8138a0
            "dirty": pieces["dirty"], "error": None,
a8138a0
            "date": pieces.get("date")}
a8138a0
a8138a0
a8138a0
def get_versions():
a8138a0
    """Get version information or return default if unable to do so."""
a8138a0
    # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
a8138a0
    # __file__, we can work backwards from there to the root. Some
a8138a0
    # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
a8138a0
    # case we can only use expanded keywords.
a8138a0
a8138a0
    cfg = get_config()
a8138a0
    verbose = cfg.verbose
a8138a0
a8138a0
    try:
a8138a0
        return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
a8138a0
                                          verbose)
a8138a0
    except NotThisMethod:
a8138a0
        pass
a8138a0
a8138a0
    try:
a8138a0
        root = os.path.realpath(__file__)
a8138a0
        # versionfile_source is the relative path from the top of the source
a8138a0
        # tree (where the .git directory might live) to this file. Invert
a8138a0
        # this to find the root from __file__.
a8138a0
        for i in cfg.versionfile_source.split('/'):
a8138a0
            root = os.path.dirname(root)
a8138a0
    except NameError:
a8138a0
        return {"version": "0+unknown", "full-revisionid": None,
a8138a0
                "dirty": None,
a8138a0
                "error": "unable to find root of source tree",
a8138a0
                "date": None}
a8138a0
a8138a0
    try:
a8138a0
        pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
a8138a0
        return render(pieces, cfg.style)
a8138a0
    except NotThisMethod:
a8138a0
        pass
a8138a0
a8138a0
    try:
a8138a0
        if cfg.parentdir_prefix:
a8138a0
            return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
a8138a0
    except NotThisMethod:
a8138a0
        pass
a8138a0
a8138a0
    return {"version": "0+unknown", "full-revisionid": None,
a8138a0
            "dirty": None,
a8138a0
            "error": "unable to compute version", "date": None}
a8138a0
'''
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "get_keywords")
a8138a0
def git_get_keywords(versionfile_abs):
a8138a0
    """Extract version information from the given file."""
a8138a0
    # the code embedded in _version.py can just fetch the value of these
a8138a0
    # keywords. When used from setup.py, we don't want to import _version.py,
a8138a0
    # so we do it with a regexp instead. This function is not used from
a8138a0
    # _version.py.
a8138a0
    keywords = {}
a8138a0
    try:
a8138a0
        f = open(versionfile_abs, "r")
a8138a0
        for line in f.readlines():
a8138a0
            if line.strip().startswith("git_refnames ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["refnames"] = mo.group(1)
a8138a0
            if line.strip().startswith("git_full ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["full"] = mo.group(1)
a8138a0
            if line.strip().startswith("git_date ="):
a8138a0
                mo = re.search(r'=\s*"(.*)"', line)
a8138a0
                if mo:
a8138a0
                    keywords["date"] = mo.group(1)
a8138a0
        f.close()
a8138a0
    except EnvironmentError:
a8138a0
        pass
a8138a0
    return keywords
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "keywords")
a8138a0
def git_versions_from_keywords(keywords, tag_prefix, verbose):
a8138a0
    """Get version information from git keywords."""
a8138a0
    if not keywords:
a8138a0
        raise NotThisMethod("no keywords at all, weird")
a8138a0
    date = keywords.get("date")
a8138a0
    if date is not None:
a8138a0
        # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
a8138a0
        # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
a8138a0
        # -like" string, which we must then edit to make compliant), because
a8138a0
        # it's been around since git-1.5.3, and it's too difficult to
a8138a0
        # discover which version we're using, or to work around using an
a8138a0
        # older one.
a8138a0
        date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
a8138a0
    refnames = keywords["refnames"].strip()
a8138a0
    if refnames.startswith("$Format"):
a8138a0
        if verbose:
a8138a0
            print("keywords are unexpanded, not using")
a8138a0
        raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
a8138a0
    refs = set([r.strip() for r in refnames.strip("()").split(",")])
a8138a0
    # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
a8138a0
    # just "foo-1.0". If we see a "tag: " prefix, prefer those.
a8138a0
    TAG = "tag: "
a8138a0
    tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
a8138a0
    if not tags:
a8138a0
        # Either we're using git < 1.8.3, or there really are no tags. We use
a8138a0
        # a heuristic: assume all version tags have a digit. The old git %d
a8138a0
        # expansion behaves like git log --decorate=short and strips out the
a8138a0
        # refs/heads/ and refs/tags/ prefixes that would let us distinguish
a8138a0
        # between branches and tags. By ignoring refnames without digits, we
a8138a0
        # filter out many common branch names like "release" and
a8138a0
        # "stabilization", as well as "HEAD" and "master".
a8138a0
        tags = set([r for r in refs if re.search(r'\d', r)])
a8138a0
        if verbose:
a8138a0
            print("discarding '%s', no digits" % ",".join(refs - tags))
a8138a0
    if verbose:
a8138a0
        print("likely tags: %s" % ",".join(sorted(tags)))
a8138a0
    for ref in sorted(tags):
a8138a0
        # sorting will prefer e.g. "2.0" over "2.0rc1"
a8138a0
        if ref.startswith(tag_prefix):
a8138a0
            r = ref[len(tag_prefix):]
a8138a0
            if verbose:
a8138a0
                print("picking %s" % r)
a8138a0
            return {"version": r,
a8138a0
                    "full-revisionid": keywords["full"].strip(),
a8138a0
                    "dirty": False, "error": None,
a8138a0
                    "date": date}
a8138a0
    # no suitable tags, so version is "0+unknown", but full hex is still there
a8138a0
    if verbose:
a8138a0
        print("no suitable tags, using unknown + full revision id")
a8138a0
    return {"version": "0+unknown",
a8138a0
            "full-revisionid": keywords["full"].strip(),
a8138a0
            "dirty": False, "error": "no suitable tags", "date": None}
a8138a0
a8138a0
a8138a0
@register_vcs_handler("git", "pieces_from_vcs")
a8138a0
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
a8138a0
    """Get version from 'git describe' in the root of the source tree.
a8138a0
a8138a0
    This only gets called if the git-archive 'subst' keywords were *not*
a8138a0
    expanded, and _version.py hasn't already been rewritten with a short
a8138a0
    version string, meaning we're inside a checked out source tree.
a8138a0
    """
a8138a0
    GITS = ["git"]
a8138a0
    if sys.platform == "win32":
a8138a0
        GITS = ["git.cmd", "git.exe"]
a8138a0
a8138a0
    out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
a8138a0
                          hide_stderr=True)
a8138a0
    if rc != 0:
a8138a0
        if verbose:
a8138a0
            print("Directory %s not under git control" % root)
a8138a0
        raise NotThisMethod("'git rev-parse --git-dir' returned error")
a8138a0
a8138a0
    # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
a8138a0
    # if there isn't one, this yields HEX[-dirty] (no NUM)
a8138a0
    describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
a8138a0
                                          "--always", "--long",
a8138a0
                                          "--match", "%s*" % tag_prefix],
a8138a0
                                   cwd=root)
a8138a0
    # --long was added in git-1.5.5
a8138a0
    if describe_out is None:
a8138a0
        raise NotThisMethod("'git describe' failed")
a8138a0
    describe_out = describe_out.strip()
a8138a0
    full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
a8138a0
    if full_out is None:
a8138a0
        raise NotThisMethod("'git rev-parse' failed")
a8138a0
    full_out = full_out.strip()
a8138a0
a8138a0
    pieces = {}
a8138a0
    pieces["long"] = full_out
a8138a0
    pieces["short"] = full_out[:7]  # maybe improved later
a8138a0
    pieces["error"] = None
a8138a0
a8138a0
    # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
a8138a0
    # TAG might have hyphens.
a8138a0
    git_describe = describe_out
a8138a0
a8138a0
    # look for -dirty suffix
a8138a0
    dirty = git_describe.endswith("-dirty")
a8138a0
    pieces["dirty"] = dirty
a8138a0
    if dirty:
a8138a0
        git_describe = git_describe[:git_describe.rindex("-dirty")]
a8138a0
a8138a0
    # now we have TAG-NUM-gHEX or HEX
a8138a0
a8138a0
    if "-" in git_describe:
a8138a0
        # TAG-NUM-gHEX
a8138a0
        mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
a8138a0
        if not mo:
a8138a0
            # unparseable. Maybe git-describe is misbehaving?
a8138a0
            pieces["error"] = ("unable to parse git-describe output: '%s'"
a8138a0
                               % describe_out)
a8138a0
            return pieces
a8138a0
a8138a0
        # tag
a8138a0
        full_tag = mo.group(1)
a8138a0
        if not full_tag.startswith(tag_prefix):
a8138a0
            if verbose:
a8138a0
                fmt = "tag '%s' doesn't start with prefix '%s'"
a8138a0
                print(fmt % (full_tag, tag_prefix))
a8138a0
            pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
a8138a0
                               % (full_tag, tag_prefix))
a8138a0
            return pieces
a8138a0
        pieces["closest-tag"] = full_tag[len(tag_prefix):]
a8138a0
a8138a0
        # distance: number of commits since tag
a8138a0
        pieces["distance"] = int(mo.group(2))
a8138a0
a8138a0
        # commit: short hex revision ID
a8138a0
        pieces["short"] = mo.group(3)
a8138a0
a8138a0
    else:
a8138a0
        # HEX: no tags
a8138a0
        pieces["closest-tag"] = None
a8138a0
        count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
a8138a0
                                    cwd=root)
a8138a0
        pieces["distance"] = int(count_out)  # total number of commits
a8138a0
a8138a0
    # commit date: see ISO-8601 comment in git_versions_from_keywords()
a8138a0
    date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
a8138a0
                       cwd=root)[0].strip()
a8138a0
    pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
a8138a0
a8138a0
    return pieces
a8138a0
a8138a0
a8138a0
def do_vcs_install(manifest_in, versionfile_source, ipy):
a8138a0
    """Git-specific installation logic for Versioneer.
a8138a0
a8138a0
    For Git, this means creating/changing .gitattributes to mark _version.py
a8138a0
    for export-subst keyword substitution.
a8138a0
    """
a8138a0
    GITS = ["git"]
a8138a0
    if sys.platform == "win32":
a8138a0
        GITS = ["git.cmd", "git.exe"]
a8138a0
    files = [manifest_in, versionfile_source]
a8138a0
    if ipy:
a8138a0
        files.append(ipy)
a8138a0
    try:
a8138a0
        me = __file__
a8138a0
        if me.endswith(".pyc") or me.endswith(".pyo"):
a8138a0
            me = os.path.splitext(me)[0] + ".py"
a8138a0
        versioneer_file = os.path.relpath(me)
a8138a0
    except NameError:
a8138a0
        versioneer_file = "versioneer.py"
a8138a0
    files.append(versioneer_file)
a8138a0
    present = False
a8138a0
    try:
a8138a0
        f = open(".gitattributes", "r")
a8138a0
        for line in f.readlines():
a8138a0
            if line.strip().startswith(versionfile_source):
a8138a0
                if "export-subst" in line.strip().split()[1:]:
a8138a0
                    present = True
a8138a0
        f.close()
a8138a0
    except EnvironmentError:
a8138a0
        pass
a8138a0
    if not present:
a8138a0
        f = open(".gitattributes", "a+")
a8138a0
        f.write("%s export-subst\n" % versionfile_source)
a8138a0
        f.close()
a8138a0
        files.append(".gitattributes")
a8138a0
    run_command(GITS, ["add", "--"] + files)
a8138a0
a8138a0
a8138a0
def versions_from_parentdir(parentdir_prefix, root, verbose):
a8138a0
    """Try to determine the version from the parent directory name.
a8138a0
a8138a0
    Source tarballs conventionally unpack into a directory that includes both
a8138a0
    the project name and a version string. We will also support searching up
a8138a0
    two directory levels for an appropriately named parent directory
a8138a0
    """
a8138a0
    rootdirs = []
a8138a0
a8138a0
    for i in range(3):
a8138a0
        dirname = os.path.basename(root)
a8138a0
        if dirname.startswith(parentdir_prefix):
a8138a0
            return {"version": dirname[len(parentdir_prefix):],
a8138a0
                    "full-revisionid": None,
a8138a0
                    "dirty": False, "error": None, "date": None}
a8138a0
        else:
a8138a0
            rootdirs.append(root)
a8138a0
            root = os.path.dirname(root)  # up a level
a8138a0
a8138a0
    if verbose:
a8138a0
        print("Tried directories %s but none started with prefix %s" %
a8138a0
              (str(rootdirs), parentdir_prefix))
a8138a0
    raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
a8138a0
a8138a0
a8138a0
SHORT_VERSION_PY = """
a8138a0
# This file was generated by 'versioneer.py' (0.18) from
a8138a0
# revision-control system data, or from the parent directory name of an
a8138a0
# unpacked source archive. Distribution tarballs contain a pre-generated copy
a8138a0
# of this file.
a8138a0
a8138a0
import json
a8138a0
a8138a0
version_json = '''
a8138a0
%s
a8138a0
'''  # END VERSION_JSON
a8138a0
a8138a0
a8138a0
def get_versions():
a8138a0
    return json.loads(version_json)
a8138a0
"""
a8138a0
a8138a0
a8138a0
def versions_from_file(filename):
a8138a0
    """Try to determine the version from _version.py if present."""
a8138a0
    try:
a8138a0
        with open(filename) as f:
a8138a0
            contents = f.read()
a8138a0
    except EnvironmentError:
a8138a0
        raise NotThisMethod("unable to read _version.py")
a8138a0
    mo = re.search(r"version_json = '''\n(.*)'''  # END VERSION_JSON",
a8138a0
                   contents, re.M | re.S)
a8138a0
    if not mo:
a8138a0
        mo = re.search(r"version_json = '''\r\n(.*)'''  # END VERSION_JSON",
a8138a0
                       contents, re.M | re.S)
a8138a0
    if not mo:
a8138a0
        raise NotThisMethod("no version_json in _version.py")
a8138a0
    return json.loads(mo.group(1))
a8138a0
a8138a0
a8138a0
def write_to_version_file(filename, versions):
a8138a0
    """Write the given version number to the given _version.py file."""
a8138a0
    os.unlink(filename)
a8138a0
    contents = json.dumps(versions, sort_keys=True,
a8138a0
                          indent=1, separators=(",", ": "))
a8138a0
    with open(filename, "w") as f:
a8138a0
        f.write(SHORT_VERSION_PY % contents)
a8138a0
a8138a0
    print("set %s to '%s'" % (filename, versions["version"]))
a8138a0
a8138a0
a8138a0
def plus_or_dot(pieces):
a8138a0
    """Return a + if we don't already have one, else return a ."""
a8138a0
    if "+" in pieces.get("closest-tag", ""):
a8138a0
        return "."
a8138a0
    return "+"
a8138a0
a8138a0
a8138a0
def render_pep440(pieces):
a8138a0
    """Build up version string, with post-release "local version identifier".
a8138a0
a8138a0
    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
a8138a0
    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += plus_or_dot(pieces)
a8138a0
            rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dirty"
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0+untagged.%d.g%s" % (pieces["distance"],
a8138a0
                                          pieces["short"])
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_pre(pieces):
a8138a0
    """TAG[.post.devDISTANCE] -- No -dirty.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. 0.post.devDISTANCE
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"]:
a8138a0
            rendered += ".post.dev%d" % pieces["distance"]
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post.dev%d" % pieces["distance"]
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_post(pieces):
a8138a0
    """TAG[.postDISTANCE[.dev0]+gHEX] .
a8138a0
a8138a0
    The ".dev0" means dirty. Note that .dev0 sorts backwards
a8138a0
    (a dirty tree will appear "older" than the corresponding clean one),
a8138a0
    but you shouldn't be releasing software with -dirty anyways.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. 0.postDISTANCE[.dev0]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += ".post%d" % pieces["distance"]
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dev0"
a8138a0
            rendered += plus_or_dot(pieces)
a8138a0
            rendered += "g%s" % pieces["short"]
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post%d" % pieces["distance"]
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dev0"
a8138a0
        rendered += "+g%s" % pieces["short"]
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_pep440_old(pieces):
a8138a0
    """TAG[.postDISTANCE[.dev0]] .
a8138a0
a8138a0
    The ".dev0" means dirty.
a8138a0
a8138a0
    Eexceptions:
a8138a0
    1: no tags. 0.postDISTANCE[.dev0]
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"] or pieces["dirty"]:
a8138a0
            rendered += ".post%d" % pieces["distance"]
a8138a0
            if pieces["dirty"]:
a8138a0
                rendered += ".dev0"
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = "0.post%d" % pieces["distance"]
a8138a0
        if pieces["dirty"]:
a8138a0
            rendered += ".dev0"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_git_describe(pieces):
a8138a0
    """TAG[-DISTANCE-gHEX][-dirty].
a8138a0
a8138a0
    Like 'git describe --tags --dirty --always'.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        if pieces["distance"]:
a8138a0
            rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = pieces["short"]
a8138a0
    if pieces["dirty"]:
a8138a0
        rendered += "-dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render_git_describe_long(pieces):
a8138a0
    """TAG-DISTANCE-gHEX[-dirty].
a8138a0
a8138a0
    Like 'git describe --tags --dirty --always -long'.
a8138a0
    The distance/hash is unconditional.
a8138a0
a8138a0
    Exceptions:
a8138a0
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
a8138a0
    """
a8138a0
    if pieces["closest-tag"]:
a8138a0
        rendered = pieces["closest-tag"]
a8138a0
        rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
a8138a0
    else:
a8138a0
        # exception #1
a8138a0
        rendered = pieces["short"]
a8138a0
    if pieces["dirty"]:
a8138a0
        rendered += "-dirty"
a8138a0
    return rendered
a8138a0
a8138a0
a8138a0
def render(pieces, style):
a8138a0
    """Render the given version pieces into the requested style."""
a8138a0
    if pieces["error"]:
a8138a0
        return {"version": "unknown",
a8138a0
                "full-revisionid": pieces.get("long"),
a8138a0
                "dirty": None,
a8138a0
                "error": pieces["error"],
a8138a0
                "date": None}
a8138a0
a8138a0
    if not style or style == "default":
a8138a0
        style = "pep440"  # the default
a8138a0
a8138a0
    if style == "pep440":
a8138a0
        rendered = render_pep440(pieces)
a8138a0
    elif style == "pep440-pre":
a8138a0
        rendered = render_pep440_pre(pieces)
a8138a0
    elif style == "pep440-post":
a8138a0
        rendered = render_pep440_post(pieces)
a8138a0
    elif style == "pep440-old":
a8138a0
        rendered = render_pep440_old(pieces)
a8138a0
    elif style == "git-describe":
a8138a0
        rendered = render_git_describe(pieces)
a8138a0
    elif style == "git-describe-long":
a8138a0
        rendered = render_git_describe_long(pieces)
a8138a0
    else:
a8138a0
        raise ValueError("unknown style '%s'" % style)
a8138a0
a8138a0
    return {"version": rendered, "full-revisionid": pieces["long"],
a8138a0
            "dirty": pieces["dirty"], "error": None,
a8138a0
            "date": pieces.get("date")}
a8138a0
a8138a0
a8138a0
class VersioneerBadRootError(Exception):
a8138a0
    """The project root directory is unknown or missing key files."""
a8138a0
a8138a0
a8138a0
def get_versions(verbose=False):
a8138a0
    """Get the project version from whatever source is available.
a8138a0
a8138a0
    Returns dict with two keys: 'version' and 'full'.
a8138a0
    """
a8138a0
    if "versioneer" in sys.modules:
a8138a0
        # see the discussion in cmdclass.py:get_cmdclass()
a8138a0
        del sys.modules["versioneer"]
a8138a0
a8138a0
    root = get_root()
a8138a0
    cfg = get_config_from_root(root)
a8138a0
a8138a0
    assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg"
a8138a0
    handlers = HANDLERS.get(cfg.VCS)
a8138a0
    assert handlers, "unrecognized VCS '%s'" % cfg.VCS
a8138a0
    verbose = verbose or cfg.verbose
a8138a0
    assert cfg.versionfile_source is not None, \
a8138a0
        "please set versioneer.versionfile_source"
a8138a0
    assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
a8138a0
a8138a0
    versionfile_abs = os.path.join(root, cfg.versionfile_source)
a8138a0
a8138a0
    # extract version from first of: _version.py, VCS command (e.g. 'git
a8138a0
    # describe'), parentdir. This is meant to work for developers using a
a8138a0
    # source checkout, for users of a tarball created by 'setup.py sdist',
a8138a0
    # and for users of a tarball/zipball created by 'git archive' or github's
a8138a0
    # download-from-tag feature or the equivalent in other VCSes.
a8138a0
a8138a0
    get_keywords_f = handlers.get("get_keywords")
a8138a0
    from_keywords_f = handlers.get("keywords")
a8138a0
    if get_keywords_f and from_keywords_f:
a8138a0
        try:
a8138a0
            keywords = get_keywords_f(versionfile_abs)
a8138a0
            ver = from_keywords_f(keywords, cfg.tag_prefix, verbose)
a8138a0
            if verbose:
a8138a0
                print("got version from expanded keyword %s" % ver)
a8138a0
            return ver
a8138a0
        except NotThisMethod:
a8138a0
            pass
a8138a0
a8138a0
    try:
a8138a0
        ver = versions_from_file(versionfile_abs)
a8138a0
        if verbose:
a8138a0
            print("got version from file %s %s" % (versionfile_abs, ver))
a8138a0
        return ver
a8138a0
    except NotThisMethod:
a8138a0
        pass
a8138a0
a8138a0
    from_vcs_f = handlers.get("pieces_from_vcs")
a8138a0
    if from_vcs_f:
a8138a0
        try:
a8138a0
            pieces = from_vcs_f(cfg.tag_prefix, root, verbose)
a8138a0
            ver = render(pieces, cfg.style)
a8138a0
            if verbose:
a8138a0
                print("got version from VCS %s" % ver)
a8138a0
            return ver
a8138a0
        except NotThisMethod:
a8138a0
            pass
a8138a0
a8138a0
    try:
a8138a0
        if cfg.parentdir_prefix:
a8138a0
            ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
a8138a0
            if verbose:
a8138a0
                print("got version from parentdir %s" % ver)
a8138a0
            return ver
a8138a0
    except NotThisMethod:
a8138a0
        pass
a8138a0
a8138a0
    if verbose:
a8138a0
        print("unable to compute version")
a8138a0
a8138a0
    return {"version": "0+unknown", "full-revisionid": None,
a8138a0
            "dirty": None, "error": "unable to compute version",
a8138a0
            "date": None}
a8138a0
a8138a0
a8138a0
def get_version():
a8138a0
    """Get the short version string for this project."""
a8138a0
    return get_versions()["version"]
a8138a0
a8138a0
a8138a0
def get_cmdclass():
a8138a0
    """Get the custom setuptools/distutils subclasses used by Versioneer."""
a8138a0
    if "versioneer" in sys.modules:
a8138a0
        del sys.modules["versioneer"]
a8138a0
        # this fixes the "python setup.py develop" case (also 'install' and
a8138a0
        # 'easy_install .'), in which subdependencies of the main project are
a8138a0
        # built (using setup.py bdist_egg) in the same python process. Assume
a8138a0
        # a main project A and a dependency B, which use different versions
a8138a0
        # of Versioneer. A's setup.py imports A's Versioneer, leaving it in
a8138a0
        # sys.modules by the time B's setup.py is executed, causing B to run
a8138a0
        # with the wrong versioneer. Setuptools wraps the sub-dep builds in a
a8138a0
        # sandbox that restores sys.modules to it's pre-build state, so the
a8138a0
        # parent is protected against the child's "import versioneer". By
a8138a0
        # removing ourselves from sys.modules here, before the child build
a8138a0
        # happens, we protect the child from the parent's versioneer too.
a8138a0
        # Also see https://github.com/warner/python-versioneer/issues/52
a8138a0
a8138a0
    cmds = {}
a8138a0
a8138a0
    # we add "version" to both distutils and setuptools
a8138a0
    from distutils.core import Command
a8138a0
a8138a0
    class cmd_version(Command):
a8138a0
        description = "report generated version string"
a8138a0
        user_options = []
a8138a0
        boolean_options = []
a8138a0
a8138a0
        def initialize_options(self):
a8138a0
            pass
a8138a0
a8138a0
        def finalize_options(self):
a8138a0
            pass
a8138a0
a8138a0
        def run(self):
a8138a0
            vers = get_versions(verbose=True)
a8138a0
            print("Version: %s" % vers["version"])
a8138a0
            print(" full-revisionid: %s" % vers.get("full-revisionid"))
a8138a0
            print(" dirty: %s" % vers.get("dirty"))
a8138a0
            print(" date: %s" % vers.get("date"))
a8138a0
            if vers["error"]:
a8138a0
                print(" error: %s" % vers["error"])
a8138a0
    cmds["version"] = cmd_version
a8138a0
a8138a0
    # we override "build_py" in both distutils and setuptools
a8138a0
    #
a8138a0
    # most invocation pathways end up running build_py:
a8138a0
    #  distutils/build -> build_py
a8138a0
    #  distutils/install -> distutils/build ->..
a8138a0
    #  setuptools/bdist_wheel -> distutils/install ->..
a8138a0
    #  setuptools/bdist_egg -> distutils/install_lib -> build_py
a8138a0
    #  setuptools/install -> bdist_egg ->..
a8138a0
    #  setuptools/develop -> ?
a8138a0
    #  pip install:
a8138a0
    #   copies source tree to a tempdir before running egg_info/etc
a8138a0
    #   if .git isn't copied too, 'git describe' will fail
a8138a0
    #   then does setup.py bdist_wheel, or sometimes setup.py install
a8138a0
    #  setup.py egg_info -> ?
a8138a0
a8138a0
    # we override different "build_py" commands for both environments
a8138a0
    if "setuptools" in sys.modules:
a8138a0
        from setuptools.command.build_py import build_py as _build_py
a8138a0
    else:
a8138a0
        from distutils.command.build_py import build_py as _build_py
a8138a0
a8138a0
    class cmd_build_py(_build_py):
a8138a0
        def run(self):
a8138a0
            root = get_root()
a8138a0
            cfg = get_config_from_root(root)
a8138a0
            versions = get_versions()
a8138a0
            _build_py.run(self)
a8138a0
            # now locate _version.py in the new build/ directory and replace
a8138a0
            # it with an updated value
a8138a0
            if cfg.versionfile_build:
a8138a0
                target_versionfile = os.path.join(self.build_lib,
a8138a0
                                                  cfg.versionfile_build)
a8138a0
                print("UPDATING %s" % target_versionfile)
a8138a0
                write_to_version_file(target_versionfile, versions)
a8138a0
    cmds["build_py"] = cmd_build_py
a8138a0
a8138a0
    if "cx_Freeze" in sys.modules:  # cx_freeze enabled?
a8138a0
        from cx_Freeze.dist import build_exe as _build_exe
a8138a0
        # nczeczulin reports that py2exe won't like the pep440-style string
a8138a0
        # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g.
a8138a0
        # setup(console=[{
a8138a0
        #   "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION
a8138a0
        #   "product_version": versioneer.get_version(),
a8138a0
        #   ...
a8138a0
a8138a0
        class cmd_build_exe(_build_exe):
a8138a0
            def run(self):
a8138a0
                root = get_root()
a8138a0
                cfg = get_config_from_root(root)
a8138a0
                versions = get_versions()
a8138a0
                target_versionfile = cfg.versionfile_source
a8138a0
                print("UPDATING %s" % target_versionfile)
a8138a0
                write_to_version_file(target_versionfile, versions)
a8138a0
a8138a0
                _build_exe.run(self)
a8138a0
                os.unlink(target_versionfile)
a8138a0
                with open(cfg.versionfile_source, "w") as f:
a8138a0
                    LONG = LONG_VERSION_PY[cfg.VCS]
a8138a0
                    f.write(LONG %
a8138a0
                            {"DOLLAR": "$",
a8138a0
                             "STYLE": cfg.style,
a8138a0
                             "TAG_PREFIX": cfg.tag_prefix,
a8138a0
                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
a8138a0
                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
a8138a0
                             })
a8138a0
        cmds["build_exe"] = cmd_build_exe
a8138a0
        del cmds["build_py"]
a8138a0
a8138a0
    if 'py2exe' in sys.modules:  # py2exe enabled?
a8138a0
        try:
a8138a0
            from py2exe.distutils_buildexe import py2exe as _py2exe  # py3
a8138a0
        except ImportError:
a8138a0
            from py2exe.build_exe import py2exe as _py2exe  # py2
a8138a0
a8138a0
        class cmd_py2exe(_py2exe):
a8138a0
            def run(self):
a8138a0
                root = get_root()
a8138a0
                cfg = get_config_from_root(root)
a8138a0
                versions = get_versions()
a8138a0
                target_versionfile = cfg.versionfile_source
a8138a0
                print("UPDATING %s" % target_versionfile)
a8138a0
                write_to_version_file(target_versionfile, versions)
a8138a0
a8138a0
                _py2exe.run(self)
a8138a0
                os.unlink(target_versionfile)
a8138a0
                with open(cfg.versionfile_source, "w") as f:
a8138a0
                    LONG = LONG_VERSION_PY[cfg.VCS]
a8138a0
                    f.write(LONG %
a8138a0
                            {"DOLLAR": "$",
a8138a0
                             "STYLE": cfg.style,
a8138a0
                             "TAG_PREFIX": cfg.tag_prefix,
a8138a0
                             "PARENTDIR_PREFIX": cfg.parentdir_prefix,
a8138a0
                             "VERSIONFILE_SOURCE": cfg.versionfile_source,
a8138a0
                             })
a8138a0
        cmds["py2exe"] = cmd_py2exe
a8138a0
a8138a0
    # we override different "sdist" commands for both environments
a8138a0
    if "setuptools" in sys.modules:
a8138a0
        from setuptools.command.sdist import sdist as _sdist
a8138a0
    else:
a8138a0
        from distutils.command.sdist import sdist as _sdist
a8138a0
a8138a0
    class cmd_sdist(_sdist):
a8138a0
        def run(self):
a8138a0
            versions = get_versions()
a8138a0
            self._versioneer_generated_versions = versions
a8138a0
            # unless we update this, the command will keep using the old
a8138a0
            # version
a8138a0
            self.distribution.metadata.version = versions["version"]
a8138a0
            return _sdist.run(self)
a8138a0
a8138a0
        def make_release_tree(self, base_dir, files):
a8138a0
            root = get_root()
a8138a0
            cfg = get_config_from_root(root)
a8138a0
            _sdist.make_release_tree(self, base_dir, files)
a8138a0
            # now locate _version.py in the new base_dir directory
a8138a0
            # (remembering that it may be a hardlink) and replace it with an
a8138a0
            # updated value
a8138a0
            target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
a8138a0
            print("UPDATING %s" % target_versionfile)
a8138a0
            write_to_version_file(target_versionfile,
a8138a0
                                  self._versioneer_generated_versions)
a8138a0
    cmds["sdist"] = cmd_sdist
a8138a0
a8138a0
    return cmds
a8138a0
a8138a0
a8138a0
CONFIG_ERROR = """
a8138a0
setup.cfg is missing the necessary Versioneer configuration. You need
a8138a0
a section like:
a8138a0
a8138a0
 [versioneer]
a8138a0
 VCS = git
a8138a0
 style = pep440
a8138a0
 versionfile_source = src/myproject/_version.py
a8138a0
 versionfile_build = myproject/_version.py
a8138a0
 tag_prefix =
a8138a0
 parentdir_prefix = myproject-
a8138a0
a8138a0
You will also need to edit your setup.py to use the results:
a8138a0
a8138a0
 import versioneer
a8138a0
 setup(version=versioneer.get_version(),
a8138a0
       cmdclass=versioneer.get_cmdclass(), ...)
a8138a0
a8138a0
Please read the docstring in ./versioneer.py for configuration instructions,
a8138a0
edit setup.cfg, and re-run the installer or 'python versioneer.py setup'.
a8138a0
"""
a8138a0
a8138a0
SAMPLE_CONFIG = """
a8138a0
# See the docstring in versioneer.py for instructions. Note that you must
a8138a0
# re-run 'versioneer.py setup' after changing this section, and commit the
a8138a0
# resulting files.
a8138a0
a8138a0
[versioneer]
a8138a0
#VCS = git
a8138a0
#style = pep440
a8138a0
#versionfile_source =
a8138a0
#versionfile_build =
a8138a0
#tag_prefix =
a8138a0
#parentdir_prefix =
a8138a0
a8138a0
"""
a8138a0
a8138a0
INIT_PY_SNIPPET = """
a8138a0
from ._version import get_versions
a8138a0
__version__ = get_versions()['version']
a8138a0
del get_versions
a8138a0
"""
a8138a0
a8138a0
a8138a0
def do_setup():
a8138a0
    """Main VCS-independent setup function for installing Versioneer."""
a8138a0
    root = get_root()
a8138a0
    try:
a8138a0
        cfg = get_config_from_root(root)
a8138a0
    except (EnvironmentError, configparser.NoSectionError,
a8138a0
            configparser.NoOptionError) as e:
a8138a0
        if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
a8138a0
            print("Adding sample versioneer config to setup.cfg",
a8138a0
                  file=sys.stderr)
a8138a0
            with open(os.path.join(root, "setup.cfg"), "a") as f:
a8138a0
                f.write(SAMPLE_CONFIG)
a8138a0
        print(CONFIG_ERROR, file=sys.stderr)
a8138a0
        return 1
a8138a0
a8138a0
    print(" creating %s" % cfg.versionfile_source)
a8138a0
    with open(cfg.versionfile_source, "w") as f:
a8138a0
        LONG = LONG_VERSION_PY[cfg.VCS]
a8138a0
        f.write(LONG % {"DOLLAR": "$",
a8138a0
                        "STYLE": cfg.style,
a8138a0
                        "TAG_PREFIX": cfg.tag_prefix,
a8138a0
                        "PARENTDIR_PREFIX": cfg.parentdir_prefix,
a8138a0
                        "VERSIONFILE_SOURCE": cfg.versionfile_source,
a8138a0
                        })
a8138a0
a8138a0
    ipy = os.path.join(os.path.dirname(cfg.versionfile_source),
a8138a0
                       "__init__.py")
a8138a0
    if os.path.exists(ipy):
a8138a0
        try:
a8138a0
            with open(ipy, "r") as f:
a8138a0
                old = f.read()
a8138a0
        except EnvironmentError:
a8138a0
            old = ""
a8138a0
        if INIT_PY_SNIPPET not in old:
a8138a0
            print(" appending to %s" % ipy)
a8138a0
            with open(ipy, "a") as f:
a8138a0
                f.write(INIT_PY_SNIPPET)
a8138a0
        else:
a8138a0
            print(" %s unmodified" % ipy)
a8138a0
    else:
a8138a0
        print(" %s doesn't exist, ok" % ipy)
a8138a0
        ipy = None
a8138a0
a8138a0
    # Make sure both the top-level "versioneer.py" and versionfile_source
a8138a0
    # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
a8138a0
    # they'll be copied into source distributions. Pip won't be able to
a8138a0
    # install the package without this.
a8138a0
    manifest_in = os.path.join(root, "MANIFEST.in")
a8138a0
    simple_includes = set()
a8138a0
    try:
a8138a0
        with open(manifest_in, "r") as f:
a8138a0
            for line in f:
a8138a0
                if line.startswith("include "):
a8138a0
                    for include in line.split()[1:]:
a8138a0
                        simple_includes.add(include)
a8138a0
    except EnvironmentError:
a8138a0
        pass
a8138a0
    # That doesn't cover everything MANIFEST.in can do
a8138a0
    # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
a8138a0
    # it might give some false negatives. Appending redundant 'include'
a8138a0
    # lines is safe, though.
a8138a0
    if "versioneer.py" not in simple_includes:
a8138a0
        print(" appending 'versioneer.py' to MANIFEST.in")
a8138a0
        with open(manifest_in, "a") as f:
a8138a0
            f.write("include versioneer.py\n")
a8138a0
    else:
a8138a0
        print(" 'versioneer.py' already in MANIFEST.in")
a8138a0
    if cfg.versionfile_source not in simple_includes:
a8138a0
        print(" appending versionfile_source ('%s') to MANIFEST.in" %
a8138a0
              cfg.versionfile_source)
a8138a0
        with open(manifest_in, "a") as f:
a8138a0
            f.write("include %s\n" % cfg.versionfile_source)
a8138a0
    else:
a8138a0
        print(" versionfile_source already in MANIFEST.in")
a8138a0
a8138a0
    # Make VCS-specific changes. For git, this means creating/changing
a8138a0
    # .gitattributes to mark _version.py for export-subst keyword
a8138a0
    # substitution.
a8138a0
    do_vcs_install(manifest_in, cfg.versionfile_source, ipy)
a8138a0
    return 0
a8138a0
a8138a0
a8138a0
def scan_setup_py():
a8138a0
    """Validate the contents of setup.py against Versioneer's expectations."""
a8138a0
    found = set()
a8138a0
    setters = False
a8138a0
    errors = 0
a8138a0
    with open("setup.py", "r") as f:
a8138a0
        for line in f.readlines():
a8138a0
            if "import versioneer" in line:
a8138a0
                found.add("import")
a8138a0
            if "versioneer.get_cmdclass()" in line:
a8138a0
                found.add("cmdclass")
a8138a0
            if "versioneer.get_version()" in line:
a8138a0
                found.add("get_version")
a8138a0
            if "versioneer.VCS" in line:
a8138a0
                setters = True
a8138a0
            if "versioneer.versionfile_source" in line:
a8138a0
                setters = True
a8138a0
    if len(found) != 3:
a8138a0
        print("")
a8138a0
        print("Your setup.py appears to be missing some important items")
a8138a0
        print("(but I might be wrong). Please make sure it has something")
a8138a0
        print("roughly like the following:")
a8138a0
        print("")
a8138a0
        print(" import versioneer")
a8138a0
        print(" setup( version=versioneer.get_version(),")
a8138a0
        print("        cmdclass=versioneer.get_cmdclass(),  ...)")
a8138a0
        print("")
a8138a0
        errors += 1
a8138a0
    if setters:
a8138a0
        print("You should remove lines like 'versioneer.VCS = ' and")
a8138a0
        print("'versioneer.versionfile_source = ' . This configuration")
a8138a0
        print("now lives in setup.cfg, and should be removed from setup.py")
a8138a0
        print("")
a8138a0
        errors += 1
a8138a0
    return errors
a8138a0
a8138a0
a8138a0
if __name__ == "__main__":
a8138a0
    cmd = sys.argv[1]
a8138a0
    if cmd == "setup":
a8138a0
        errors = do_setup()
a8138a0
        errors += scan_setup_py()
a8138a0
        if errors:
a8138a0
            sys.exit(1)