/ versioneer.py
versioneer.py
   1  
   2  # Version: 0.14
   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  * run `versioneer-installer` in your source tree: this installs `versioneer.py`
  31  * follow the instructions below (also in the `versioneer.py` docstring)
  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. However,
  75  when you use "setup.py build" or "setup.py sdist", `_version.py` in the new
  76  copy is replaced by a small static file that contains just the generated
  77  version data.
  78  
  79  `_version.py` also contains `$Revision$` markers, and the installation
  80  process marks `_version.py` to have this marker rewritten with a tag name
  81  during the "git archive" command. As a result, generated tarballs will
  82  contain enough information to get the proper version.
  83  
  84  
  85  ## Installation
  86  
  87  First, decide on values for the following configuration variables:
  88  
  89  * `VCS`: the version control system you use. Currently accepts "git".
  90  
  91  * `versionfile_source`:
  92  
  93    A project-relative pathname into which the generated version strings should
  94    be written. This is usually a `_version.py` next to your project's main
  95    `__init__.py` file, so it can be imported at runtime. If your project uses
  96    `src/myproject/__init__.py`, this should be `src/myproject/_version.py`.
  97    This file should be checked in to your VCS as usual: the copy created below
  98    by `setup.py versioneer` will include code that parses expanded VCS
  99    keywords in generated tarballs. The 'build' and 'sdist' commands will
 100    replace it with a copy that has just the calculated version string.
 101  
 102    This must be set even if your project does not have any modules (and will
 103    therefore never import `_version.py`), since "setup.py sdist" -based trees
 104    still need somewhere to record the pre-calculated version strings. Anywhere
 105    in the source tree should do. If there is a `__init__.py` next to your
 106    `_version.py`, the `setup.py versioneer` command (described below) will
 107    append some `__version__`-setting assignments, if they aren't already
 108    present.
 109  
 110  * `versionfile_build`:
 111  
 112    Like `versionfile_source`, but relative to the build directory instead of
 113    the source directory. These will differ when your setup.py uses
 114    'package_dir='. If you have `package_dir={'myproject': 'src/myproject'}`,
 115    then you will probably have `versionfile_build='myproject/_version.py'` and
 116    `versionfile_source='src/myproject/_version.py'`.
 117  
 118    If this is set to None, then `setup.py build` will not attempt to rewrite
 119    any `_version.py` in the built tree. If your project does not have any
 120    libraries (e.g. if it only builds a script), then you should use
 121    `versionfile_build = None` and override `distutils.command.build_scripts`
 122    to explicitly insert a copy of `versioneer.get_version()` into your
 123    generated script.
 124  
 125  * `tag_prefix`:
 126  
 127    a string, like 'PROJECTNAME-', which appears at the start of all VCS tags.
 128    If your tags look like 'myproject-1.2.0', then you should use
 129    tag_prefix='myproject-'. If you use unprefixed tags like '1.2.0', this
 130    should be an empty string.
 131  
 132  * `parentdir_prefix`:
 133  
 134    a string, frequently the same as tag_prefix, which appears at the start of
 135    all unpacked tarball filenames. If your tarball unpacks into
 136    'myproject-1.2.0', this should be 'myproject-'.
 137  
 138  This tool provides one script, named `versioneer-installer`. That script does
 139  one thing: write a copy of `versioneer.py` into the current directory.
 140  
 141  To versioneer-enable your project:
 142  
 143  * 1: Run `versioneer-installer` to copy `versioneer.py` into the top of your
 144    source tree.
 145  
 146  * 2: add the following lines to the top of your `setup.py`, with the
 147    configuration values you decided earlier:
 148  
 149    ````
 150    import versioneer
 151    versioneer.VCS = 'git'
 152    versioneer.versionfile_source = 'src/myproject/_version.py'
 153    versioneer.versionfile_build = 'myproject/_version.py'
 154    versioneer.tag_prefix = '' # tags are like 1.2.0
 155    versioneer.parentdir_prefix = 'myproject-' # dirname like 'myproject-1.2.0'
 156    ````
 157  
 158  * 3: add the following arguments to the setup() call in your setup.py:
 159  
 160          version=versioneer.get_version(),
 161          cmdclass=versioneer.get_cmdclass(),
 162  
 163  * 4: now run `setup.py versioneer`, which will create `_version.py`, and will
 164    modify your `__init__.py` (if one exists next to `_version.py`) to define
 165    `__version__` (by calling a function from `_version.py`). It will also
 166    modify your `MANIFEST.in` to include both `versioneer.py` and the generated
 167    `_version.py` in sdist tarballs.
 168  
 169  * 5: commit these changes to your VCS. To make sure you won't forget,
 170    `setup.py versioneer` will mark everything it touched for addition.
 171  
 172  ## Post-Installation Usage
 173  
 174  Once established, all uses of your tree from a VCS checkout should get the
 175  current version string. All generated tarballs should include an embedded
 176  version string (so users who unpack them will not need a VCS tool installed).
 177  
 178  If you distribute your project through PyPI, then the release process should
 179  boil down to two steps:
 180  
 181  * 1: git tag 1.0
 182  * 2: python setup.py register sdist upload
 183  
 184  If you distribute it through github (i.e. users use github to generate
 185  tarballs with `git archive`), the process is:
 186  
 187  * 1: git tag 1.0
 188  * 2: git push; git push --tags
 189  
 190  Currently, all version strings must be based upon a tag. Versioneer will
 191  report "unknown" until your tree has at least one tag in its history. This
 192  restriction will be fixed eventually (see issue #12).
 193  
 194  ## Version-String Flavors
 195  
 196  Code which uses Versioneer can learn about its version string at runtime by
 197  importing `_version` from your main `__init__.py` file and running the
 198  `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
 199  import the top-level `versioneer.py` and run `get_versions()`.
 200  
 201  Both functions return a dictionary with different keys for different flavors
 202  of the version string:
 203  
 204  * `['version']`: A condensed PEP440-compliant string, equal to the
 205    un-prefixed tag name for actual releases, and containing an additional
 206    "local version" section with more detail for in-between builds. For Git,
 207    this is TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe
 208    --tags --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates
 209    that the tree is like the "1076c97" commit but has uncommitted changes
 210    (".dirty"), and that this commit is two revisions ("+2") beyond the "0.11"
 211    tag. For released software (exactly equal to a known tag), the identifier
 212    will only contain the stripped tag, e.g. "0.11".
 213  
 214  * `['full']`: detailed revision identifier. For Git, this is the full SHA1
 215    commit id, followed by ".dirty" if the tree contains uncommitted changes,
 216    e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac.dirty".
 217  
 218  Some variants are more useful than others. Including `full` in a bug report
 219  should allow developers to reconstruct the exact code being tested (or
 220  indicate the presence of local changes that should be shared with the
 221  developers). `version` is suitable for display in an "about" box or a CLI
 222  `--version` output: it can be easily compared against release notes and lists
 223  of bugs fixed in various releases.
 224  
 225  The `setup.py versioneer` command adds the following text to your
 226  `__init__.py` to place a basic version in `YOURPROJECT.__version__`:
 227  
 228      from ._version import get_versions
 229      __version__ = get_versions()['version']
 230      del get_versions
 231  
 232  ## Updating Versioneer
 233  
 234  To upgrade your project to a new release of Versioneer, do the following:
 235  
 236  * install the new Versioneer (`pip install -U versioneer` or equivalent)
 237  * re-run `versioneer-installer` in your source tree to replace your copy of
 238    `versioneer.py`
 239  * edit `setup.py`, if necessary, to include any new configuration settings
 240    indicated by the release notes
 241  * re-run `setup.py versioneer` to replace `SRC/_version.py`
 242  * commit any changed files
 243  
 244  ### Upgrading from 0.10 to 0.11
 245  
 246  You must add a `versioneer.VCS = "git"` to your `setup.py` before re-running
 247  `setup.py versioneer`. This will enable the use of additional version-control
 248  systems (SVN, etc) in the future.
 249  
 250  ### Upgrading from 0.11 to 0.12
 251  
 252  Nothing special.
 253  
 254  ## Upgrading to 0.14
 255  
 256  0.14 changes the format of the version string. 0.13 and earlier used
 257  hyphen-separated strings like "0.11-2-g1076c97-dirty". 0.14 and beyond use a
 258  plus-separated "local version" section strings, with dot-separated
 259  components, like "0.11+2.g1076c97". PEP440-strict tools did not like the old
 260  format, but should be ok with the new one.
 261  
 262  ## Future Directions
 263  
 264  This tool is designed to make it easily extended to other version-control
 265  systems: all VCS-specific components are in separate directories like
 266  src/git/ . The top-level `versioneer.py` script is assembled from these
 267  components by running make-versioneer.py . In the future, make-versioneer.py
 268  will take a VCS name as an argument, and will construct a version of
 269  `versioneer.py` that is specific to the given VCS. It might also take the
 270  configuration arguments that are currently provided manually during
 271  installation by editing setup.py . Alternatively, it might go the other
 272  direction and include code from all supported VCS systems, reducing the
 273  number of intermediate scripts.
 274  
 275  
 276  ## License
 277  
 278  To make Versioneer easier to embed, all its code is hereby released into the
 279  public domain. The `_version.py` that it creates is also in the public
 280  domain.
 281  
 282  """
 283  
 284  import errno
 285  import os
 286  import re
 287  import subprocess
 288  import sys
 289  from distutils.command.build import build as _build
 290  from distutils.command.sdist import sdist as _sdist
 291  from distutils.core import Command
 292  
 293  # these configuration settings will be overridden by setup.py after it
 294  # imports us
 295  versionfile_source = None
 296  versionfile_build = None
 297  tag_prefix = None
 298  parentdir_prefix = None
 299  VCS = None
 300  
 301  # these dictionaries contain VCS-specific tools
 302  LONG_VERSION_PY = {}
 303  
 304  
 305  def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
 306      assert isinstance(commands, list)
 307      p = None
 308      for c in commands:
 309          try:
 310              # remember shell=False, so use git.cmd on windows, not just git
 311              p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
 312                                   stderr=(subprocess.PIPE if hide_stderr
 313                                           else None))
 314              break
 315          except EnvironmentError:
 316              e = sys.exc_info()[1]
 317              if e.errno == errno.ENOENT:
 318                  continue
 319              if verbose:
 320                  print("unable to run %s" % args[0])
 321                  print(e)
 322              return None
 323      else:
 324          if verbose:
 325              print("unable to find command, tried %s" % (commands,))
 326          return None
 327      stdout = p.communicate()[0].strip()
 328      if sys.version_info[0] >= 3:
 329          stdout = stdout.decode()
 330      if p.returncode != 0:
 331          if verbose:
 332              print("unable to run %s (error)" % args[0])
 333          return None
 334      return stdout
 335  LONG_VERSION_PY['git'] = '''
 336  # This file helps to compute a version number in source trees obtained from
 337  # git-archive tarball (such as those provided by githubs download-from-tag
 338  # feature). Distribution tarballs (built by setup.py sdist) and build
 339  # directories (produced by setup.py build) will contain a much shorter file
 340  # that just contains the computed version number.
 341  
 342  # This file is released into the public domain. Generated by
 343  # versioneer-0.14 (https://github.com/warner/python-versioneer)
 344  
 345  import errno
 346  import os
 347  import re
 348  import subprocess
 349  import sys
 350  
 351  # these strings will be replaced by git during git-archive
 352  git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
 353  git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
 354  
 355  # these strings are filled in when 'setup.py versioneer' creates _version.py
 356  tag_prefix = "%(TAG_PREFIX)s"
 357  parentdir_prefix = "%(PARENTDIR_PREFIX)s"
 358  versionfile_source = "%(VERSIONFILE_SOURCE)s"
 359  
 360  
 361  def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
 362      assert isinstance(commands, list)
 363      p = None
 364      for c in commands:
 365          try:
 366              # remember shell=False, so use git.cmd on windows, not just git
 367              p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
 368                                   stderr=(subprocess.PIPE if hide_stderr
 369                                           else None))
 370              break
 371          except EnvironmentError:
 372              e = sys.exc_info()[1]
 373              if e.errno == errno.ENOENT:
 374                  continue
 375              if verbose:
 376                  print("unable to run %%s" %% args[0])
 377                  print(e)
 378              return None
 379      else:
 380          if verbose:
 381              print("unable to find command, tried %%s" %% (commands,))
 382          return None
 383      stdout = p.communicate()[0].strip()
 384      if sys.version_info[0] >= 3:
 385          stdout = stdout.decode()
 386      if p.returncode != 0:
 387          if verbose:
 388              print("unable to run %%s (error)" %% args[0])
 389          return None
 390      return stdout
 391  
 392  
 393  def versions_from_parentdir(parentdir_prefix, root, verbose=False):
 394      # Source tarballs conventionally unpack into a directory that includes
 395      # both the project name and a version string.
 396      dirname = os.path.basename(root)
 397      if not dirname.startswith(parentdir_prefix):
 398          if verbose:
 399              print("guessing rootdir is '%%s', but '%%s' doesn't start with "
 400                    "prefix '%%s'" %% (root, dirname, parentdir_prefix))
 401          return None
 402      return {"version": dirname[len(parentdir_prefix):], "full": ""}
 403  
 404  
 405  def git_get_keywords(versionfile_abs):
 406      # the code embedded in _version.py can just fetch the value of these
 407      # keywords. When used from setup.py, we don't want to import _version.py,
 408      # so we do it with a regexp instead. This function is not used from
 409      # _version.py.
 410      keywords = {}
 411      try:
 412          f = open(versionfile_abs, "r")
 413          for line in f.readlines():
 414              if line.strip().startswith("git_refnames ="):
 415                  mo = re.search(r'=\s*"(.*)"', line)
 416                  if mo:
 417                      keywords["refnames"] = mo.group(1)
 418              if line.strip().startswith("git_full ="):
 419                  mo = re.search(r'=\s*"(.*)"', line)
 420                  if mo:
 421                      keywords["full"] = mo.group(1)
 422          f.close()
 423      except EnvironmentError:
 424          pass
 425      return keywords
 426  
 427  
 428  def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
 429      if not keywords:
 430          return {}  # keyword-finding function failed to find keywords
 431      refnames = keywords["refnames"].strip()
 432      if refnames.startswith("$Format"):
 433          if verbose:
 434              print("keywords are unexpanded, not using")
 435          return {}  # unexpanded, so not in an unpacked git-archive tarball
 436      refs = set([r.strip() for r in refnames.strip("()").split(",")])
 437      # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
 438      # just "foo-1.0". If we see a "tag: " prefix, prefer those.
 439      TAG = "tag: "
 440      tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
 441      if not tags:
 442          # Either we're using git < 1.8.3, or there really are no tags. We use
 443          # a heuristic: assume all version tags have a digit. The old git %%d
 444          # expansion behaves like git log --decorate=short and strips out the
 445          # refs/heads/ and refs/tags/ prefixes that would let us distinguish
 446          # between branches and tags. By ignoring refnames without digits, we
 447          # filter out many common branch names like "release" and
 448          # "stabilization", as well as "HEAD" and "master".
 449          tags = set([r for r in refs if re.search(r'\d', r)])
 450          if verbose:
 451              print("discarding '%%s', no digits" %% ",".join(refs-tags))
 452      if verbose:
 453          print("likely tags: %%s" %% ",".join(sorted(tags)))
 454      for ref in sorted(tags):
 455          # sorting will prefer e.g. "2.0" over "2.0rc1"
 456          if ref.startswith(tag_prefix):
 457              r = ref[len(tag_prefix):]
 458              if verbose:
 459                  print("picking %%s" %% r)
 460              return {"version": r,
 461                      "full": keywords["full"].strip()}
 462      # no suitable tags, so version is "0+unknown", but full hex is still there
 463      if verbose:
 464          print("no suitable tags, using unknown + full revision id")
 465      return {"version": "0+unknown",
 466              "full": keywords["full"].strip()}
 467  
 468  
 469  def git_parse_vcs_describe(git_describe, tag_prefix, verbose=False):
 470      # TAG-NUM-gHEX[-dirty] or HEX[-dirty] . TAG might have hyphens.
 471  
 472      # dirty
 473      dirty = git_describe.endswith("-dirty")
 474      if dirty:
 475          git_describe = git_describe[:git_describe.rindex("-dirty")]
 476      dirty_suffix = ".dirty" if dirty else ""
 477  
 478      # now we have TAG-NUM-gHEX or HEX
 479  
 480      if "-" not in git_describe:  # just HEX
 481          return "0+untagged.g"+git_describe+dirty_suffix, dirty
 482  
 483      # just TAG-NUM-gHEX
 484      mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
 485      if not mo:
 486          # unparseable. Maybe git-describe is misbehaving?
 487          return "0+unparseable"+dirty_suffix, dirty
 488  
 489      # tag
 490      full_tag = mo.group(1)
 491      if not full_tag.startswith(tag_prefix):
 492          if verbose:
 493              fmt = "tag '%%s' doesn't start with prefix '%%s'"
 494              print(fmt %% (full_tag, tag_prefix))
 495          return None, dirty
 496      tag = full_tag[len(tag_prefix):]
 497  
 498      # distance: number of commits since tag
 499      distance = int(mo.group(2))
 500  
 501      # commit: short hex revision ID
 502      commit = mo.group(3)
 503  
 504      # now build up version string, with post-release "local version
 505      # identifier". Our goal: TAG[+NUM.gHEX[.dirty]] . Note that if you get a
 506      # tagged build and then dirty it, you'll get TAG+0.gHEX.dirty . So you
 507      # can always test version.endswith(".dirty").
 508      version = tag
 509      if distance or dirty:
 510          version += "+%%d.g%%s" %% (distance, commit) + dirty_suffix
 511  
 512      return version, dirty
 513  
 514  
 515  def git_versions_from_vcs(tag_prefix, root, verbose=False):
 516      # this runs 'git' from the root of the source tree. This only gets called
 517      # if the git-archive 'subst' keywords were *not* expanded, and
 518      # _version.py hasn't already been rewritten with a short version string,
 519      # meaning we're inside a checked out source tree.
 520  
 521      if not os.path.exists(os.path.join(root, ".git")):
 522          if verbose:
 523              print("no .git in %%s" %% root)
 524          return {}  # get_versions() will try next method
 525  
 526      GITS = ["git"]
 527      if sys.platform == "win32":
 528          GITS = ["git.cmd", "git.exe"]
 529      # if there is a tag, this yields TAG-NUM-gHEX[-dirty]
 530      # if there are no tags, this yields HEX[-dirty] (no NUM)
 531      stdout = run_command(GITS, ["describe", "--tags", "--dirty",
 532                                  "--always", "--long"],
 533                           cwd=root)
 534      # --long was added in git-1.5.5
 535      if stdout is None:
 536          return {}  # try next method
 537      version, dirty = git_parse_vcs_describe(stdout, tag_prefix, verbose)
 538  
 539      # build "full", which is FULLHEX[.dirty]
 540      stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
 541      if stdout is None:
 542          return {}
 543      full = stdout.strip()
 544      if dirty:
 545          full += ".dirty"
 546  
 547      return {"version": version, "full": full}
 548  
 549  
 550  def get_versions(default={"version": "0+unknown", "full": ""}, verbose=False):
 551      # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
 552      # __file__, we can work backwards from there to the root. Some
 553      # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
 554      # case we can only use expanded keywords.
 555  
 556      keywords = {"refnames": git_refnames, "full": git_full}
 557      ver = git_versions_from_keywords(keywords, tag_prefix, verbose)
 558      if ver:
 559          return ver
 560  
 561      try:
 562          root = os.path.realpath(__file__)
 563          # versionfile_source is the relative path from the top of the source
 564          # tree (where the .git directory might live) to this file. Invert
 565          # this to find the root from __file__.
 566          for i in versionfile_source.split('/'):
 567              root = os.path.dirname(root)
 568      except NameError:
 569          return default
 570  
 571      return (git_versions_from_vcs(tag_prefix, root, verbose)
 572              or versions_from_parentdir(parentdir_prefix, root, verbose)
 573              or default)
 574  '''
 575  
 576  
 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  def git_versions_from_keywords(keywords, tag_prefix, verbose=False):
 601      if not keywords:
 602          return {}  # keyword-finding function failed to find keywords
 603      refnames = keywords["refnames"].strip()
 604      if refnames.startswith("$Format"):
 605          if verbose:
 606              print("keywords are unexpanded, not using")
 607          return {}  # unexpanded, so not in an unpacked git-archive tarball
 608      refs = set([r.strip() for r in refnames.strip("()").split(",")])
 609      # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
 610      # just "foo-1.0". If we see a "tag: " prefix, prefer those.
 611      TAG = "tag: "
 612      tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
 613      if not tags:
 614          # Either we're using git < 1.8.3, or there really are no tags. We use
 615          # a heuristic: assume all version tags have a digit. The old git %d
 616          # expansion behaves like git log --decorate=short and strips out the
 617          # refs/heads/ and refs/tags/ prefixes that would let us distinguish
 618          # between branches and tags. By ignoring refnames without digits, we
 619          # filter out many common branch names like "release" and
 620          # "stabilization", as well as "HEAD" and "master".
 621          tags = set([r for r in refs if re.search(r'\d', r)])
 622          if verbose:
 623              print("discarding '%s', no digits" % ",".join(refs-tags))
 624      if verbose:
 625          print("likely tags: %s" % ",".join(sorted(tags)))
 626      for ref in sorted(tags):
 627          # sorting will prefer e.g. "2.0" over "2.0rc1"
 628          if ref.startswith(tag_prefix):
 629              r = ref[len(tag_prefix):]
 630              if verbose:
 631                  print("picking %s" % r)
 632              return {"version": r,
 633                      "full": keywords["full"].strip()}
 634      # no suitable tags, so version is "0+unknown", but full hex is still there
 635      if verbose:
 636          print("no suitable tags, using unknown + full revision id")
 637      return {"version": "0+unknown",
 638              "full": keywords["full"].strip()}
 639  
 640  
 641  def git_parse_vcs_describe(git_describe, tag_prefix, verbose=False):
 642      # TAG-NUM-gHEX[-dirty] or HEX[-dirty] . TAG might have hyphens.
 643  
 644      # dirty
 645      dirty = git_describe.endswith("-dirty")
 646      if dirty:
 647          git_describe = git_describe[:git_describe.rindex("-dirty")]
 648      dirty_suffix = ".dirty" if dirty else ""
 649  
 650      # now we have TAG-NUM-gHEX or HEX
 651  
 652      if "-" not in git_describe:  # just HEX
 653          return "0+untagged.g"+git_describe+dirty_suffix, dirty
 654  
 655      # just TAG-NUM-gHEX
 656      mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
 657      if not mo:
 658          # unparseable. Maybe git-describe is misbehaving?
 659          return "0+unparseable"+dirty_suffix, dirty
 660  
 661      # tag
 662      full_tag = mo.group(1)
 663      if not full_tag.startswith(tag_prefix):
 664          if verbose:
 665              fmt = "tag '%s' doesn't start with prefix '%s'"
 666              print(fmt % (full_tag, tag_prefix))
 667          return None, dirty
 668      tag = full_tag[len(tag_prefix):]
 669  
 670      # distance: number of commits since tag
 671      distance = int(mo.group(2))
 672  
 673      # commit: short hex revision ID
 674      commit = mo.group(3)
 675  
 676      # now build up version string, with post-release "local version
 677      # identifier". Our goal: TAG[+NUM.gHEX[.dirty]] . Note that if you get a
 678      # tagged build and then dirty it, you'll get TAG+0.gHEX.dirty . So you
 679      # can always test version.endswith(".dirty").
 680      version = tag
 681      if distance or dirty:
 682          version += "+%d.g%s" % (distance, commit) + dirty_suffix
 683  
 684      return version, dirty
 685  
 686  
 687  def git_versions_from_vcs(tag_prefix, root, verbose=False):
 688      # this runs 'git' from the root of the source tree. This only gets called
 689      # if the git-archive 'subst' keywords were *not* expanded, and
 690      # _version.py hasn't already been rewritten with a short version string,
 691      # meaning we're inside a checked out source tree.
 692  
 693      if not os.path.exists(os.path.join(root, ".git")):
 694          if verbose:
 695              print("no .git in %s" % root)
 696          return {}  # get_versions() will try next method
 697  
 698      GITS = ["git"]
 699      if sys.platform == "win32":
 700          GITS = ["git.cmd", "git.exe"]
 701      # if there is a tag, this yields TAG-NUM-gHEX[-dirty]
 702      # if there are no tags, this yields HEX[-dirty] (no NUM)
 703      stdout = run_command(GITS, ["describe", "--tags", "--dirty",
 704                                  "--always", "--long"],
 705                           cwd=root)
 706      # --long was added in git-1.5.5
 707      if stdout is None:
 708          return {}  # try next method
 709      version, dirty = git_parse_vcs_describe(stdout, tag_prefix, verbose)
 710  
 711      # build "full", which is FULLHEX[.dirty]
 712      stdout = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
 713      if stdout is None:
 714          return {}
 715      full = stdout.strip()
 716      if dirty:
 717          full += ".dirty"
 718  
 719      return {"version": version, "full": full}
 720  
 721  
 722  def do_vcs_install(manifest_in, versionfile_source, ipy):
 723      GITS = ["git"]
 724      if sys.platform == "win32":
 725          GITS = ["git.cmd", "git.exe"]
 726      files = [manifest_in, versionfile_source]
 727      if ipy:
 728          files.append(ipy)
 729      try:
 730          me = __file__
 731          if me.endswith(".pyc") or me.endswith(".pyo"):
 732              me = os.path.splitext(me)[0] + ".py"
 733          versioneer_file = os.path.relpath(me)
 734      except NameError:
 735          versioneer_file = "versioneer.py"
 736      files.append(versioneer_file)
 737      present = False
 738      try:
 739          f = open(".gitattributes", "r")
 740          for line in f.readlines():
 741              if line.strip().startswith(versionfile_source):
 742                  if "export-subst" in line.strip().split()[1:]:
 743                      present = True
 744          f.close()
 745      except EnvironmentError:
 746          pass
 747      if not present:
 748          f = open(".gitattributes", "a+")
 749          f.write("%s export-subst\n" % versionfile_source)
 750          f.close()
 751          files.append(".gitattributes")
 752      run_command(GITS, ["add", "--"] + files)
 753  
 754  
 755  def versions_from_parentdir(parentdir_prefix, root, verbose=False):
 756      # Source tarballs conventionally unpack into a directory that includes
 757      # both the project name and a version string.
 758      dirname = os.path.basename(root)
 759      if not dirname.startswith(parentdir_prefix):
 760          if verbose:
 761              print("guessing rootdir is '%s', but '%s' doesn't start with "
 762                    "prefix '%s'" % (root, dirname, parentdir_prefix))
 763          return None
 764      return {"version": dirname[len(parentdir_prefix):], "full": ""}
 765  
 766  SHORT_VERSION_PY = """
 767  # This file was generated by 'versioneer.py' (0.14) from
 768  # revision-control system data, or from the parent directory name of an
 769  # unpacked source archive. Distribution tarballs contain a pre-generated copy
 770  # of this file.
 771  
 772  version_version = '%(version)s'
 773  version_full = '%(full)s'
 774  def get_versions(default={}, verbose=False):
 775      return {'version': version_version, 'full': version_full}
 776  
 777  """
 778  
 779  DEFAULT = {"version": "0+unknown", "full": "unknown"}
 780  
 781  
 782  def versions_from_file(filename):
 783      versions = {}
 784      try:
 785          with open(filename) as f:
 786              for line in f.readlines():
 787                  mo = re.match("version_version = '([^']+)'", line)
 788                  if mo:
 789                      versions["version"] = mo.group(1)
 790                  mo = re.match("version_full = '([^']+)'", line)
 791                  if mo:
 792                      versions["full"] = mo.group(1)
 793      except EnvironmentError:
 794          return {}
 795  
 796      return versions
 797  
 798  
 799  def write_to_version_file(filename, versions):
 800      with open(filename, "w") as f:
 801          f.write(SHORT_VERSION_PY % versions)
 802  
 803      print("set %s to '%s'" % (filename, versions["version"]))
 804  
 805  
 806  def get_root():
 807      try:
 808          return os.path.dirname(os.path.abspath(__file__))
 809      except NameError:
 810          return os.path.dirname(os.path.abspath(sys.argv[0]))
 811  
 812  
 813  def vcs_function(vcs, suffix):
 814      return getattr(sys.modules[__name__], '%s_%s' % (vcs, suffix), None)
 815  
 816  
 817  def get_versions(default=DEFAULT, verbose=False):
 818      # returns dict with two keys: 'version' and 'full'
 819      assert versionfile_source is not None, \
 820          "please set versioneer.versionfile_source"
 821      assert tag_prefix is not None, "please set versioneer.tag_prefix"
 822      assert parentdir_prefix is not None, \
 823          "please set versioneer.parentdir_prefix"
 824      assert VCS is not None, "please set versioneer.VCS"
 825  
 826      # I am in versioneer.py, which must live at the top of the source tree,
 827      # which we use to compute the root directory. py2exe/bbfreeze/non-CPython
 828      # don't have __file__, in which case we fall back to sys.argv[0] (which
 829      # ought to be the setup.py script). We prefer __file__ since that's more
 830      # robust in cases where setup.py was invoked in some weird way (e.g. pip)
 831      root = get_root()
 832      versionfile_abs = os.path.join(root, versionfile_source)
 833  
 834      # extract version from first of _version.py, VCS command (e.g. 'git
 835      # describe'), parentdir. This is meant to work for developers using a
 836      # source checkout, for users of a tarball created by 'setup.py sdist',
 837      # and for users of a tarball/zipball created by 'git archive' or github's
 838      # download-from-tag feature or the equivalent in other VCSes.
 839  
 840      get_keywords_f = vcs_function(VCS, "get_keywords")
 841      versions_from_keywords_f = vcs_function(VCS, "versions_from_keywords")
 842      if get_keywords_f and versions_from_keywords_f:
 843          vcs_keywords = get_keywords_f(versionfile_abs)
 844          ver = versions_from_keywords_f(vcs_keywords, tag_prefix)
 845          if ver:
 846              if verbose:
 847                  print("got version from expanded keyword %s" % ver)
 848              return ver
 849  
 850      ver = versions_from_file(versionfile_abs)
 851      if ver:
 852          if verbose:
 853              print("got version from file %s %s" % (versionfile_abs, ver))
 854          return ver
 855  
 856      versions_from_vcs_f = vcs_function(VCS, "versions_from_vcs")
 857      if versions_from_vcs_f:
 858          ver = versions_from_vcs_f(tag_prefix, root, verbose)
 859          if ver:
 860              if verbose:
 861                  print("got version from VCS %s" % ver)
 862              return ver
 863  
 864      ver = versions_from_parentdir(parentdir_prefix, root, verbose)
 865      if ver:
 866          if verbose:
 867              print("got version from parentdir %s" % ver)
 868          return ver
 869  
 870      if verbose:
 871          print("got version from default %s" % default)
 872      return default
 873  
 874  
 875  def get_version(verbose=False):
 876      return get_versions(verbose=verbose)["version"]
 877  
 878  
 879  class cmd_version(Command):
 880      description = "report generated version string"
 881      user_options = []
 882      boolean_options = []
 883  
 884      def initialize_options(self):
 885          pass
 886  
 887      def finalize_options(self):
 888          pass
 889  
 890      def run(self):
 891          ver = get_version(verbose=True)
 892          print("Version is currently: %s" % ver)
 893  
 894  
 895  class cmd_build(_build):
 896      def run(self):
 897          versions = get_versions(verbose=True)
 898          _build.run(self)
 899          # now locate _version.py in the new build/ directory and replace it
 900          # with an updated value
 901          if versionfile_build:
 902              target_versionfile = os.path.join(self.build_lib,
 903                                                versionfile_build)
 904              print("UPDATING %s" % target_versionfile)
 905              os.unlink(target_versionfile)
 906              with open(target_versionfile, "w") as f:
 907                  f.write(SHORT_VERSION_PY % versions)
 908  
 909  if 'cx_Freeze' in sys.modules:  # cx_freeze enabled?
 910      from cx_Freeze.dist import build_exe as _build_exe
 911  
 912      class cmd_build_exe(_build_exe):
 913          def run(self):
 914              versions = get_versions(verbose=True)
 915              target_versionfile = versionfile_source
 916              print("UPDATING %s" % target_versionfile)
 917              os.unlink(target_versionfile)
 918              with open(target_versionfile, "w") as f:
 919                  f.write(SHORT_VERSION_PY % versions)
 920  
 921              _build_exe.run(self)
 922              os.unlink(target_versionfile)
 923              with open(versionfile_source, "w") as f:
 924                  assert VCS is not None, "please set versioneer.VCS"
 925                  LONG = LONG_VERSION_PY[VCS]
 926                  f.write(LONG % {"DOLLAR": "$",
 927                                  "TAG_PREFIX": tag_prefix,
 928                                  "PARENTDIR_PREFIX": parentdir_prefix,
 929                                  "VERSIONFILE_SOURCE": versionfile_source,
 930                                  })
 931  
 932  
 933  class cmd_sdist(_sdist):
 934      def run(self):
 935          versions = get_versions(verbose=True)
 936          self._versioneer_generated_versions = versions
 937          # unless we update this, the command will keep using the old version
 938          self.distribution.metadata.version = versions["version"]
 939          return _sdist.run(self)
 940  
 941      def make_release_tree(self, base_dir, files):
 942          _sdist.make_release_tree(self, base_dir, files)
 943          # now locate _version.py in the new base_dir directory (remembering
 944          # that it may be a hardlink) and replace it with an updated value
 945          target_versionfile = os.path.join(base_dir, versionfile_source)
 946          print("UPDATING %s" % target_versionfile)
 947          os.unlink(target_versionfile)
 948          with open(target_versionfile, "w") as f:
 949              f.write(SHORT_VERSION_PY % self._versioneer_generated_versions)
 950  
 951  INIT_PY_SNIPPET = """
 952  from ._version import get_versions
 953  __version__ = get_versions()['version']
 954  del get_versions
 955  """
 956  
 957  
 958  class cmd_update_files(Command):
 959      description = ("install/upgrade Versioneer files: "
 960                     "__init__.py SRC/_version.py")
 961      user_options = []
 962      boolean_options = []
 963  
 964      def initialize_options(self):
 965          pass
 966  
 967      def finalize_options(self):
 968          pass
 969  
 970      def run(self):
 971          print(" creating %s" % versionfile_source)
 972          with open(versionfile_source, "w") as f:
 973              assert VCS is not None, "please set versioneer.VCS"
 974              LONG = LONG_VERSION_PY[VCS]
 975              f.write(LONG % {"DOLLAR": "$",
 976                              "TAG_PREFIX": tag_prefix,
 977                              "PARENTDIR_PREFIX": parentdir_prefix,
 978                              "VERSIONFILE_SOURCE": versionfile_source,
 979                              })
 980  
 981          ipy = os.path.join(os.path.dirname(versionfile_source), "__init__.py")
 982          if os.path.exists(ipy):
 983              try:
 984                  with open(ipy, "r") as f:
 985                      old = f.read()
 986              except EnvironmentError:
 987                  old = ""
 988              if INIT_PY_SNIPPET not in old:
 989                  print(" appending to %s" % ipy)
 990                  with open(ipy, "a") as f:
 991                      f.write(INIT_PY_SNIPPET)
 992              else:
 993                  print(" %s unmodified" % ipy)
 994          else:
 995              print(" %s doesn't exist, ok" % ipy)
 996              ipy = None
 997  
 998          # Make sure both the top-level "versioneer.py" and versionfile_source
 999          # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
1000          # they'll be copied into source distributions. Pip won't be able to
1001          # install the package without this.
1002          manifest_in = os.path.join(get_root(), "MANIFEST.in")
1003          simple_includes = set()
1004          try:
1005              with open(manifest_in, "r") as f:
1006                  for line in f:
1007                      if line.startswith("include "):
1008                          for include in line.split()[1:]:
1009                              simple_includes.add(include)
1010          except EnvironmentError:
1011              pass
1012          # That doesn't cover everything MANIFEST.in can do
1013          # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
1014          # it might give some false negatives. Appending redundant 'include'
1015          # lines is safe, though.
1016          if "versioneer.py" not in simple_includes:
1017              print(" appending 'versioneer.py' to MANIFEST.in")
1018              with open(manifest_in, "a") as f:
1019                  f.write("include versioneer.py\n")
1020          else:
1021              print(" 'versioneer.py' already in MANIFEST.in")
1022          if versionfile_source not in simple_includes:
1023              print(" appending versionfile_source ('%s') to MANIFEST.in" %
1024                    versionfile_source)
1025              with open(manifest_in, "a") as f:
1026                  f.write("include %s\n" % versionfile_source)
1027          else:
1028              print(" versionfile_source already in MANIFEST.in")
1029  
1030          # Make VCS-specific changes. For git, this means creating/changing
1031          # .gitattributes to mark _version.py for export-time keyword
1032          # substitution.
1033          do_vcs_install(manifest_in, versionfile_source, ipy)
1034  
1035  
1036  def get_cmdclass():
1037      cmds = {'version': cmd_version,
1038              'versioneer': cmd_update_files,
1039              'build': cmd_build,
1040              'sdist': cmd_sdist,
1041              }
1042      if 'cx_Freeze' in sys.modules:  # cx_freeze enabled?
1043          cmds['build_exe'] = cmd_build_exe
1044          del cmds['build']
1045  
1046      return cmds