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