versioneer.py 39 KB

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