Add CHANGELOG entry for #33299.
[tor-bridgedb.git] / versioneer.py
blobc010f63e3ead851cb35e4d4cc8bc958b8be76ab0
2 # Version: 0.15
4 """
5 The Versioneer
6 ==============
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)
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.
27 ## Quick Install
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
33 ## Version Identifiers
35 Source trees come from a variety of places:
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
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:
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
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.
65 The version identifier is used for multiple purposes:
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
70 ## Theory of Operation
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.
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.
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.
88 ## Installation
90 First, decide on values for the following configuration variables:
92 * `VCS`: the version control system you use. Currently accepts "git".
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]]`.
98 * `versionfile_source`:
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.
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.
117 * `versionfile_build`:
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'`.
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.
132 * `tag_prefix`:
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.
139 * `parentdir_prefix`:
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`.
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.
150 To versioneer-enable your project:
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):
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 ````
166 * 2: Run `versioneer install`. This will do the following:
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
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.
179 * 3: add a `import versioneer` to your setup.py, and add the following
180 arguments to the setup() call:
182 version=versioneer.get_version(),
183 cmdclass=versioneer.get_cmdclass(),
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.
189 ## Post-Installation Usage
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).
195 If you distribute your project through PyPI, then the release process should
196 boil down to two steps:
198 * 1: git tag 1.0
199 * 2: python setup.py register sdist upload
201 If you distribute it through github (i.e. users use github to generate
202 tarballs with `git archive`), the process is:
204 * 1: git tag 1.0
205 * 2: git push; git push --tags
207 Versioneer will report "0+untagged.NUMCOMMITS.gHASH" until your tree has at
208 least one tag in its history.
210 ## Version-String Flavors
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()`.
217 Both functions return a dictionary with different flavors of version
218 information:
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.
226 * `['full-revisionid']`: detailed revision identifier. For Git, this is the
227 full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
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
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".
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.
245 The installer adds the following text to your `__init__.py` to place a basic
246 version in `YOURPROJECT.__version__`:
248 from ._version import get_versions
249 __version__ = get_versions()['version']
250 del get_versions
252 ## Styles
254 The setup.cfg `style=` configuration controls how the VCS information is
255 rendered into a version string.
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".
267 Other styles are available. See details.md in the Versioneer source tree for
268 descriptions.
270 ## Debugging
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).
278 ## Updating Versioneer
280 To upgrade your project to a new release of Versioneer, do the following:
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
289 ### Upgrading to 0.15
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.
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.
302 ### Upgrading to 0.14
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.
310 ### Upgrading from 0.11 to 0.12
312 Nothing special.
314 ### Upgrading from 0.10 to 0.11
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.
320 ## Future Directions
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.
334 ## License
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.
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
355 class VersioneerConfig:
356 pass
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
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
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
419 class NotThisMethod(Exception):
420 pass
422 # these dictionaries contain VCS-specific tools
423 LONG_VERSION_PY = {}
424 HANDLERS = {}
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
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.
474 # This file is released into the public domain. Generated by
475 # versioneer-0.15 (https://github.com/warner/python-versioneer)
477 import errno
478 import os
479 import re
480 import subprocess
481 import sys
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
495 class VersioneerConfig:
496 pass
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
512 class NotThisMethod(Exception):
513 pass
516 LONG_VERSION_PY = {}
517 HANDLERS = {}
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
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
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}
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
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
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"}
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.
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")
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()
674 pieces = {}
675 pieces["long"] = full_out
676 pieces["short"] = full_out[:7] # maybe improved later
677 pieces["error"] = None
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
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")]
689 # now we have TAG-NUM-gHEX or HEX
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
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):]
711 # distance: number of commits since tag
712 pieces["distance"] = int(mo.group(2))
714 # commit: short hex revision ID
715 pieces["short"] = mo.group(3)
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
724 return pieces
727 def plus_or_dot(pieces):
728 if "+" in pieces.get("closest-tag", ""):
729 return "."
730 return "+"
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
738 # exceptions:
739 # 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
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
757 def render_pep440_pre(pieces):
758 # TAG[.post.devDISTANCE] . No -dirty
760 # exceptions:
761 # 1: no tags. 0.post.devDISTANCE
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
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.
779 # exceptions:
780 # 1: no tags. 0.postDISTANCE[.dev0]
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
799 def render_pep440_old(pieces):
800 # TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty.
802 # exceptions:
803 # 1: no tags. 0.postDISTANCE[.dev0]
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
819 def render_git_describe(pieces):
820 # TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty
821 # --always'
823 # exceptions:
824 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
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
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.
842 # exceptions:
843 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
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
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"]}
863 if not style or style == "default":
864 style = "pep440" # the default
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)
881 return {"version": rendered, "full-revisionid": pieces["long"],
882 "dirty": pieces["dirty"], "error": None}
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.
891 cfg = get_config()
892 verbose = cfg.verbose
894 try:
895 return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
896 verbose)
897 except NotThisMethod:
898 pass
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"}
912 try:
913 pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
914 return render(pieces, cfg.style)
915 except NotThisMethod:
916 pass
918 try:
919 if cfg.parentdir_prefix:
920 return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
921 except NotThisMethod:
922 pass
924 return {"version": "0+unknown", "full-revisionid": None,
925 "dirty": None,
926 "error": "unable to compute version"}
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
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
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"}
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.
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")
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()
1028 pieces = {}
1029 pieces["long"] = full_out
1030 pieces["short"] = full_out[:7] # maybe improved later
1031 pieces["error"] = None
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
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")]
1043 # now we have TAG-NUM-gHEX or HEX
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
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):]
1065 # distance: number of commits since tag
1066 pieces["distance"] = int(mo.group(2))
1068 # commit: short hex revision ID
1069 pieces["short"] = mo.group(3)
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
1078 return pieces
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)
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}
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.
1133 import json
1134 import sys
1136 version_json = '''
1138 ''' # END VERSION_JSON
1141 def get_versions():
1142 return json.loads(version_json)
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))
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)
1166 print("set %s to '%s'" % (filename, versions["version"]))
1169 def plus_or_dot(pieces):
1170 if "+" in pieces.get("closest-tag", ""):
1171 return "."
1172 return "+"
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
1180 # exceptions:
1181 # 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
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
1199 def render_pep440_pre(pieces):
1200 # TAG[.post.devDISTANCE] . No -dirty
1202 # exceptions:
1203 # 1: no tags. 0.post.devDISTANCE
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
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.
1221 # exceptions:
1222 # 1: no tags. 0.postDISTANCE[.dev0]
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
1241 def render_pep440_old(pieces):
1242 # TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty.
1244 # exceptions:
1245 # 1: no tags. 0.postDISTANCE[.dev0]
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
1261 def render_git_describe(pieces):
1262 # TAG[-DISTANCE-gHEX][-dirty], like 'git describe --tags --dirty
1263 # --always'
1265 # exceptions:
1266 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
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
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.
1284 # exceptions:
1285 # 1: no tags. HEX[-dirty] (note: no 'g' prefix)
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
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"]}
1305 if not style or style == "default":
1306 style = "pep440" # the default
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)
1323 return {"version": rendered, "full-revisionid": pieces["long"],
1324 "dirty": pieces["dirty"], "error": None}
1327 class VersioneerBadRootError(Exception):
1328 pass
1331 def get_versions(verbose=False):
1332 # returns dict with two keys: 'version' and 'full'
1334 if "versioneer" in sys.modules:
1335 # see the discussion in cmdclass.py:get_cmdclass()
1336 del sys.modules["versioneer"]
1338 root = get_root()
1339 cfg = get_config_from_root(root)
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"
1349 versionfile_abs = os.path.join(root, cfg.versionfile_source)
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.
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
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
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
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
1397 if verbose:
1398 print("unable to compute version")
1400 return {"version": "0+unknown", "full-revisionid": None,
1401 "dirty": None, "error": "unable to compute version"}
1404 def get_version():
1405 return get_versions()["version"]
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
1424 cmds = {}
1426 # we add "version" to both distutils and setuptools
1427 from distutils.core import Command
1429 class cmd_version(Command):
1430 description = "report generated version string"
1431 user_options = []
1432 boolean_options = []
1434 def initialize_options(self):
1435 pass
1437 def finalize_options(self):
1438 pass
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
1449 # we override "build_py" in both distutils and setuptools
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 -> ?
1459 from distutils.command.build_py import build_py as _build_py
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
1476 if "cx_Freeze" in sys.modules: # cx_freeze enabled?
1477 from cx_Freeze.dist import build_exe as _build_exe
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)
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,
1499 cmds["build_exe"] = cmd_build_exe
1500 del cmds["build_py"]
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
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)
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
1530 return cmds
1533 CONFIG_ERROR = """
1534 setup.cfg is missing the necessary Versioneer configuration. You need
1535 a section like:
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-
1545 You will also need to edit your setup.py to use the results:
1547 import versioneer
1548 setup(version=versioneer.get_version(),
1549 cmdclass=versioneer.get_cmdclass(), ...)
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'.
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.
1560 [versioneer]
1561 #VCS = git
1562 #style = pep440
1563 #versionfile_source =
1564 #versionfile_build =
1565 #tag_prefix =
1566 #parentdir_prefix =
1570 INIT_PY_SNIPPET = """
1571 from ._version import get_versions
1572 __version__ = get_versions()['version']
1573 del get_versions
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
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,
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
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")
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
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
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)