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