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