From 3f6b66027201f5ee41866b278f67f6e28d852a54 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Thu, 3 May 2007 20:14:07 -0700 Subject: [PATCH] update version-number handling, pull release tags from darcs history --- .darcs-boringfile | 3 + GNUmakefile | 9 ++- misc/get-version.py | 38 +++++++++++++ misc/make-version.py | 117 ++++++++++++++++++++++++++++++++++++++ setup.py | 18 ++++-- src/allmydata/__init__.py | 19 +++---- 6 files changed, 184 insertions(+), 20 deletions(-) create mode 100644 misc/get-version.py create mode 100644 misc/make-version.py diff --git a/.darcs-boringfile b/.darcs-boringfile index 39fd8d2c..bc032565 100644 --- a/.darcs-boringfile +++ b/.darcs-boringfile @@ -56,3 +56,6 @@ ^src/Crypto/build($|/) ^_test_memory($|/) +# version.py is generated at build time, and never checked in +^src/allmydata/version\.py$ + diff --git a/GNUmakefile b/GNUmakefile index b72bc4b0..9f15ce0b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -56,6 +56,7 @@ PP=PYTHONPATH=$(PYTHONPATH) .PHONY: build build: build-zfec build-Crypto build-foolscap + $(PYTHON) misc/make-version.py $(PP) $(PYTHON) ./setup.py $(EXTRA_SETUP_ARGS) install --prefix="." --root="$(INSTDIR)" --install-lib="lib" --install-scripts="bin" build-zfec: @@ -178,13 +179,11 @@ clean: clean-zfec clean-Crypto clean-foolscap # DEBIAN PACKAGING -VER=$(shell python -c "import os,re;print re.search(\"verstr=['\\\"](.*?)['\\\"]\", open(os.path.join('src', 'allmydata', '__init__.py')).readline()).group(1)") -DEBSTRING=$(VER)-T`date +%s` +VER=$(shell $(PYTHON) misc/get-version.py) DEBCOMMENTS="'make deb' build" -show: +show-version: @echo $(VER) - @echo $(DEBSTRING) .PHONY: setup-dapper setup-sid setup-edgy setup-feisty .PHONY: deb-dapper deb-sid deb-edgy deb-feisty @@ -242,7 +241,7 @@ deb-feisty: setup-feisty echo "The newly built .deb packages are in the parent directory from here." increment-deb-version: - debchange --newversion $(DEBSTRING) $(DEBCOMMENTS) + debchange --newversion $(VER) $(DEBCOMMENTS) deb-dapper-head: setup-dapper increment-deb-version fakeroot debian/rules binary deb-sid-head: setup-sid increment-deb-version diff --git a/misc/get-version.py b/misc/get-version.py new file mode 100644 index 00000000..9281a9df --- /dev/null +++ b/misc/get-version.py @@ -0,0 +1,38 @@ +#! /usr/bin/python + +"""Determine the version number of the current tree. + +This should be run *after* make-version.py . It will emit a single line of +text to stdout, either of the form '0.2.0' if this is a release tree (i.e. no +patches have been added since the last release tag), or '0.2.0-34' (if 34 +patches have been added since the last release tag). If the tree does not +have a well-formed version number, this will emit 'unknown'. + +The version string thus calculated should exactly match the version string +determined by setup.py (when it creates eggs and source tarballs) and also +the version available in the code image when you do: + + from allmydata import __version__ + +""" + +import os.path, re + +def get_version(): + VERSIONFILE = "src/allmydata/version.py" + verstr = "unknown" + if os.path.exists(VERSIONFILE): + VSRE = re.compile("^verstr = ['\"]([^'\"]*)['\"]", re.M) + verstrline = open(VERSIONFILE, "rt").read() + mo = VSRE.search(verstrline) + if mo: + verstr = mo.group(1) + else: + raise RuntimeError("if version.py exists, it must be well-formed") + + return verstr + +if __name__ == '__main__': + verstr = get_version() + print verstr + diff --git a/misc/make-version.py b/misc/make-version.py new file mode 100644 index 00000000..466240e0 --- /dev/null +++ b/misc/make-version.py @@ -0,0 +1,117 @@ +#! /usr/bin/python + +""" +Create src/allmydata/version.py, based upon the latest darcs release tag. + +If your source tree is coming from darcs (i.e. there exists a _darcs +directory), this tool will determine the most recent release tag, count the +patches that have been applied since then, and compute a version number to be +written into version.py . This version number will be available by doing: + + from allmydata import __version__ + +Source trees that do not come from darcs (release tarballs, nightly tarballs) +do not have a _darcs directory. Instead, they should have a version.py that +was generated before the tarball was produced. In this case, this script will +quietly exit without modifying the existing version.py . + +FYI, src/allmydata/__init__.py will attempt to import version.py and use the +version number therein. If it cannot, it will announce a version of +'UNKNOWN'. This should only happen if someone manages to get hold of a +non-_darcs/ source tree. + +'release tags' are tags in the tahoe source tree that match the following +regexp: + + ^allmydata-tahoe-\d+\.\d+\.\d+\w*$ + +This excludes zfec tags (which start with 'zfec '). It also excludes +'developer convenience tags', which look like 'hoping to fix bug -warner'. +(the original goal was to use release tags that lacked the 'allmydata-tahoe-' +prefix, but it turns out to be more efficient to keep it in, because I can't +get 'darcs changes --from-tag=' to accept real regexps). + +""" + +import os, sys, commands, re +import xml.dom.minidom + +def get_text(nodelist): + rc = "" + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + +VERSION_BODY = ''' +from util.version import Version + +# This is the version of this tree, as created by misc/make-version.py from +# the Darcs patch information: the main version number is taken from the most +# recent release tag. If some patches have been added since the last release, +# this will have a -NN "build number" suffix. Please see +# allmydata.util.version for a description of what the different fields mean. + +verstr = "%s" +__version__ = Version(verstr) +''' + +def write_version_py(verstr): + f = open("src/allmydata/version.py", "wt") + f.write(VERSION_BODY % (verstr,)) + f.close() + +def update(): + if not os.path.exists("_darcs") or not os.path.isdir("_darcs"): + if os.path.exists("src/allmydata/version.py"): + print "no _darcs/ and version.py exists, leaving it alone" + return 0 + print "no _darcs/ but no version.py either: how did you get this tree?" + return 0 + cmd = "darcs changes --from-tag=^allmydata-tahoe --xml-output" + (rc, output) = commands.getstatusoutput(cmd) + if rc != 0: + print "unable to run 'darcs changes':" + print output + print "so I'm leaving version.py alone" + return 0 + + try: + doc = xml.dom.minidom.parseString(output) + except xml.parsers.expat.ExpatError: + print "unable to parse darcs XML output:" + print output + raise + changelog = doc.getElementsByTagName("changelog")[0] + patches = changelog.getElementsByTagName("patch") + count = 0 + version_re = re.compile("^TAG allmydata-tahoe-(\d+\.\d+\.\d+\w*)$") + for patch in patches: + name = get_text(patch.getElementsByTagName("name")[0].childNodes) + m = version_re.match(name) + if m: + last_tag = m.group(1) + last_tag = last_tag.encode("ascii") + break + count += 1 + else: + print "unable to find a matching tag" + print output + print "so I'm leaving version.py alone" + return 0 + + if count: + # this is an interim version + verstr = "%s-%d" % (last_tag, count) + else: + # this is a release + verstr = last_tag + + write_version_py(verstr) + print "wrote '%s' into src/allmydata/version.py" % (verstr,) + return 0 + +if __name__ == '__main__': + rc = update() + sys.exit(rc) + diff --git a/setup.py b/setup.py index f2ab1913..15eda54e 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. +import re, os.path from distutils.core import Extension, setup trove_classifiers=[ @@ -56,11 +57,18 @@ trove_classifiers=[ "Topic :: System :: Archiving", ] -import re -VSRE=re.compile("verstr=['\"]([^'\"]*)['\"]") -verstrline=open("src/allmydata/__init__.py").readline() -mo = VSRE.search(verstrline) -verstr = mo.group(1) + +VERSIONFILE = "src/allmydata/version.py" +verstr = "unknown" +if os.path.exists(VERSIONFILE): + VSRE = re.compile("^verstr = ['\"]([^'\"]*)['\"]", re.M) + verstrline = open(VERSIONFILE, "rt").read() + mo = VSRE.search(verstrline) + if mo: + verstr = mo.group(1) + else: + print "unable to find version in version.py" + raise RuntimeError("if version.py exists, it must be well-formed") setup(name='allmydata-tahoe', version=verstr, diff --git a/src/allmydata/__init__.py b/src/allmydata/__init__.py index 415dff45..0ad8d293 100644 --- a/src/allmydata/__init__.py +++ b/src/allmydata/__init__.py @@ -1,5 +1,3 @@ -verstr="0.2.0-0-UNSTABLE" -# The line is placed above so that it can be easily read by build scripts. """ Decentralized storage grid. @@ -9,13 +7,14 @@ maintainer web site: U{http://allmydata.com/} community web site: U{http://allmydata.org/} """ -from util.version import Version +__version__ = "unknown" +try: + from allmydata.version import __version__ +except ImportError: + # we're running in a tree that hasn't run misc/make-version.py, so we + # don't know what our version is. This should not happen very often. + pass -# For an explanation of what the parts of the version string mean, -# please see pyutil.version. -__version__ = Version(verstr) - -# Please put a URL or other note here which shows where to get the branch of -# development from which this version grew. -__sources__ = ["http://allmydata.org/source/tahoe",] +hush_pyflakes = __version__ +del hush_pyflakes -- 2.45.2