]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
import version class and make-version script from pyutil -- fixes win32 build, improv...
authorZooko O'Whielacronx <zooko@zooko.com>
Thu, 16 Aug 2007 21:09:30 +0000 (14:09 -0700)
committerZooko O'Whielacronx <zooko@zooko.com>
Thu, 16 Aug 2007 21:09:30 +0000 (14:09 -0700)
Makefile
misc/make-version.py
src/allmydata/__init__.py
src/allmydata/test/test_client.py
src/allmydata/util/version.py [deleted file]
src/allmydata/util/version_class.py [new file with mode: 0644]

index f984f87d34d095b91c34d1ceb034c58acb8fc5d4..e73293fb65ad35c0db7a58bf1826a6d0491a2533 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -59,7 +59,7 @@ PP=PYTHONPATH=$(PYTHONPATH)
 
 .PHONY: make-version build
 make-version:
-       $(PYTHON) misc/make-version.py
+       $(PYTHON) misc/make-version.py "allmydata-tahoe" "src/allmydata/_version.py"
 
 build: make-version build-zfec build-Crypto build-foolscap build-simplejson
        $(PP) $(PYTHON) ./setup.py $(EXTRA_SETUP_ARGS) install --prefix="$(INSTDIR)" --install-lib="$(INSTDIR)/lib" --install-scripts="$(INSTDIR)/bin"
index 36da171786837c85d0b1b4cd5ecf8bc80c434066..5dc0af014cae4a9fe7cdd4137c64aaebe46674b5 100644 (file)
@@ -1,35 +1,26 @@
 #! /usr/bin/env python
 
-"""
-Create src/allmydata/version.py, based upon the latest darcs release tag.
+import os, sys
 
-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:
+"""
+Create _version.py, based upon the latest darcs release tag.
 
- from allmydata import __version__
+If your source tree is coming from darcs (i.e. it is in a darcs repository),
+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:
 
-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 .
+ from your_package_name import __version__
 
-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.
+Source trees that do not come from darcs (e.g. release tarballs, nightly
+tarballs) and are not within a darcs repository should instead, come with 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 .
 
-'release tags' are tags in the tahoe source tree that match the following
+'release tags' are tags in the source repository 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).
+ ^your_package_name-\d+\.\d+(\.\d+)?((a|b|c)(\d+)?)?\w*$
 
 """
 
@@ -37,6 +28,16 @@ import os, sys, re
 import xml.dom.minidom
 from subprocess import Popen, PIPE
 
+try:
+    # If we can import allmydata.util.version_class then use its regex.
+    from allmydata.util import version_class
+    VERSION_BASE_RE_STR = version_class.VERSION_BASE_RE_STR
+except ImportError:
+    # Else (perhaps a bootstrapping problem),then we'll use this
+    # regex, which was copied from the pyutil source code on
+    # 2007-08-11.
+    VERSION_BASE_RE_STR="(\d+)\.(\d+)(\.(\d+))?((a|b|c)(\d+))?"
+
 def get_text(nodelist):
     rc = ""
     for node in nodelist:
@@ -45,55 +46,53 @@ def get_text(nodelist):
     return rc
 
 VERSION_BODY = '''
-from util.version import Version
+from allmydata.util.version_class import Version
 
-# This is the version of this tree, as created by misc/make-version.py from
+# This is the version of this tree, as created by scripts/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.
+# allmydata.util.version_class 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")
+def write_version_py(verstr, outfname):
+    f = open(outfname, "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"]
+def update(pkgname, verfilename):
+    rc = -1
+    cmd = ["darcs", "changes", "--from-tag=^%s" % (pkgname,), "--xml-output"]
     try:
         p = Popen(cmd, stdout=PIPE)
+    except:
+        pass
+    else:
         output = p.communicate()[0]
         rc = p.returncode
-    except EnvironmentError, le:
-        output = "There was an environment error: %s" % (le,)
-        rc = -1
-
     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
+        cmd = ["realdarcs.exe", "changes", "--from-tag=^%s" % (pkgname,), "--xml-output"]
+        p = Popen(cmd, stdout=PIPE)
+        output = p.communicate()[0]
+        rc = p.returncode
+        if rc != 0:
+            if os.path.exists(verfilename):
+                print "Failure from attempt to find version tags with 'darcs changes', and %s already exists, so leaving it alone." % (verfilename,)
+                return 0
+            else:
+                print "Failure from attempt to find version tags with 'darcs changes', and %s doesn't exist." % (verfilename,)
+                return rc
+
+    doc = xml.dom.minidom.parseString(output)
     changelog = doc.getElementsByTagName("changelog")[0]
     patches = changelog.getElementsByTagName("patch")
     count = 0
-    version_re = re.compile("^TAG allmydata-tahoe-(\d+\.\d+\.\d+\w*)$")
+    regexstr = "^TAG %s-(%s)" % (pkgname, VERSION_BASE_RE_STR,)
+    version_re = re.compile(regexstr)
     for patch in patches:
         name = get_text(patch.getElementsByTagName("name")[0].childNodes)
         m = version_re.match(name)
@@ -103,23 +102,33 @@ def update():
             break
         count += 1
     else:
-        print "unable to find a matching tag"
-        print output
-        print "so I'm leaving version.py alone"
+        print "I'm unable to find a tag in the darcs history matching \"%s\", so I'm leaving %s alone." % (regexstr, verfilename,)
         return 0
 
     if count:
         # this is an interim version
-        verstr = "%s-%d" % (last_tag, count)
+        verstr = "%s-dev-r%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,)
+    write_version_py(verstr, verfilename)
+    print "wrote '%s' into %s" % (verstr, verfilename,)
     return 0
 
 if __name__ == '__main__':
-    rc = update()
+    if len(sys.argv) >= 2:
+        pkgname = sys.argv[1]
+    else:
+        pkgname = os.path.basename(os.getcwd())
+        print "You didn't pass a pkg-name on the command-line, so I'm going to take the name of the current working directory: \"%s\"" % (pkgname,)
+
+    if len(sys.argv) >= 3:
+        verfilename = sys.argv[2]
+    else:
+        verfilename = os.path.join(pkgname, "_version.py")
+        print "You didn't pass a verfilename on the command-line, so I'm going to build one from the name of the package: \"%s\"" % (verfilename,)
+
+    rc = update(pkgname=pkgname, verfilename=verfilename)
     sys.exit(rc)
 
index 0ad8d29399ee947a463afa01d8061a21bc5b625d..349c7e2e82e69dedf94ce41a109a2bb767deb7a1 100644 (file)
@@ -9,7 +9,7 @@ community web site: U{http://allmydata.org/}
 
 __version__ = "unknown"
 try:
-    from allmydata.version import __version__
+    from _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.
index 016be9bdecbe222572bedb8069d173de0b3dc031..f5cec18447c9c04ea2c136ff17890ec44ec5eac8 100644 (file)
@@ -6,7 +6,7 @@ from twisted.internet import reactor, defer
 
 import allmydata
 from allmydata import client, introducer
-from allmydata.util import version
+from allmydata.util import version_class
 from foolscap.eventual import flushEventualQueue
 
 class MyIntroducerClient(introducer.IntroducerClient):
@@ -107,7 +107,7 @@ class Basic(unittest.TestCase):
         open(os.path.join(basedir, "vdrive.furl"), "w").write("")
         c = client.Client(basedir)
         mine, oldest = c.remote_get_versions()
-        self.failUnlessEqual(version.Version(mine), allmydata.__version__)
+        self.failUnlessEqual(version_class.Version(mine), allmydata.__version__)
 
 def flush_but_dont_ignore(res):
     d = flushEventualQueue()
diff --git a/src/allmydata/util/version.py b/src/allmydata/util/version.py
deleted file mode 100644 (file)
index e495ff6..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright (c) 2004-2007 Bryce "Zooko" Wilcox-O'Hearn
-# mailto:zooko@zooko.com
-# http://zooko.com/repos/pyutil
-# Permission is hereby granted, free of charge, to any person obtaining a copy 
-# of this work to deal in this work without restriction (including the rights 
-# to use, modify, distribute, sublicense, and/or sell copies).
-
-"""
-extended version number class
-"""
-
-from distutils import version
-
-# End users see version strings like this:
-
-# "1.0.0"
-#  ^ ^ ^
-#  | | |
-#  | | '- micro version number
-#  | '- minor version number
-#  '- major version number
-
-# The first number is "major version number".  The second number is the "minor
-# version number" -- it gets bumped whenever we make a new release that adds or
-# changes functionality.  The third version is the "micro version number" -- it
-# gets bumped whenever we make a new release that doesn't add or change
-# functionality, but just fixes bugs (including performance issues).
-
-# Early-adopter end users see version strings like this:
-
-# "1.0.0a1"
-#  ^ ^ ^^^
-#  | | |||
-#  | | ||'- release number
-#  | | |'- alpha or beta (or none)
-#  | | '- micro version number
-#  | '- minor version number
-#  '- major version number
-
-# The optional "a" or "b" stands for "alpha release" or "beta release"
-# respectively.  The number after "a" or "b" gets bumped every time we
-# make a new alpha or beta release. This has the same form and the same
-# meaning as version numbers of releases of Python.
-
-# Developers see "full version strings", like this:
-
-# "1.0.0a1-55"
-#  ^ ^ ^^^  ^
-#  | | |||  |
-#  | | |||  |
-#  | | |||  '- nano version number
-#  | | ||'- release number
-#  | | |'- alpha or beta (or none)
-#  | | '- micro version number
-#  | '- minor version number
-#  '- major version number
-
-# The next number is the "nano version number".  It is meaningful only to
-# developers.  It gets bumped whenever a developer changes anything that another
-# developer might care about.
-
-class Tag(str):
-    def __cmp__(t1, t2):
-        if t1 == t2:
-            return 0
-        if t1 == "UNSTABLE" and t2 == "STABLE":
-            return 1
-        if t1 == "STABLE" and t2 == "UNSTABLE":
-            return -1
-        return -2 # who knows
-
-class Version:
-    def __init__(self, vstring=None):
-        self.major = None
-        self.minor = None
-        self.micro = None
-        self.prereleasetag = None
-        self.nano = None
-        self.tags = None
-        if vstring:
-            self.parse(vstring)
-
-    def parse(self, vstring):
-        i = vstring.find('-')
-        if i != -1:
-            svstring = vstring[:i]
-            estring = vstring[i+1:]
-        else:
-            svstring = vstring
-            estring = None
-
-        self.strictversion = version.StrictVersion(svstring)
-
-        self.nanovernum = None
-        self.tags = []
-        if estring:
-            if '-' in estring:
-                (self.nano, tags,) = estring.split('-')
-            else:
-                self.nano = estring
-
-        self.fullstr = str(self.strictversion)
-        if self.nano is not None:
-            self.fullstr += "-" + str(self.nano)
-        if self.tags:
-            self.fullstr += '_'.join(self.tags)
-
-    def tags(self):
-        return self.tags
-
-    def user_str(self):
-        return self.strictversion.__str__()
-
-    def full_str(self):
-        return self.fullstr
-
-    def __str__(self):
-        return self.full_str()
-
-    def __repr__(self):
-        return self.__str__()
-
-    def __cmp__ (self, other):
-        if isinstance(other, basestring):
-            other = Version(other)
-
-        res = cmp(self.strictversion, other.strictversion)
-        if res != 0:
-            return res
-
-        res = cmp(self.nano, other.nano)
-        if res != 0:
-            return res
-
-        return cmp(self.tags, other.tags)
diff --git a/src/allmydata/util/version_class.py b/src/allmydata/util/version_class.py
new file mode 100644 (file)
index 0000000..dbab3b8
--- /dev/null
@@ -0,0 +1,133 @@
+# Copyright (c) 2004-2007 Bryce "Zooko" Wilcox-O'Hearn
+# mailto:zooko@zooko.com
+# http://zooko.com/repos/pyutil
+# Permission is hereby granted, free of charge, to any person obtaining a copy 
+# of this work to deal in this work without restriction (including the rights 
+# to use, modify, distribute, sublicense, and/or sell copies).
+
+"""
+extended version number class
+"""
+
+# from setuptools, but intended to be included in future version of Python Standard Library (PEP 365)
+import pkg_resources
+
+# bindann, by Nathan Wilcox (needed only for debugging)
+try:
+    import bindann
+    bindann.install_exception_handler()
+except ImportError:
+    pass
+
+# Python Standard Library
+import re
+
+# End users see version strings like this:
+
+# "1.0.0"
+#  ^ ^ ^
+#  | | |
+#  | | '- micro version number
+#  | '- minor version number
+#  '- major version number
+
+# The first number is "major version number".  The second number is the "minor
+# version number" -- it gets bumped whenever we make a new release that adds or
+# changes functionality.  The third version is the "micro version number" -- it
+# gets bumped whenever we make a new release that doesn't add or change
+# functionality, but just fixes bugs (including performance issues).
+
+# Early-adopter end users see version strings like this:
+
+# "1.0.0a1"
+#  ^ ^ ^^^
+#  | | |||
+#  | | ||'- release number
+#  | | |'- a=alpha, b=beta, c=release candidate, or none
+#  | | '- micro version number
+#  | '- minor version number
+#  '- major version number
+
+# The optional "a" or "b" stands for "alpha release" or "beta release"
+# respectively.  The number after "a" or "b" gets bumped every time we
+# make a new alpha or beta release. This has the same form and the same
+# meaning as version numbers of releases of Python.
+
+# Developers see "full version strings", like this:
+
+# "1.0.0a1-dev-r55"
+#  ^ ^ ^^^  ^    ^
+#  | | |||  |    |
+#  | | |||  |    '- nano version number
+#  | | |||  '- "dev" if this is a development version (not a release version)
+#  | | ||'- release number
+#  | | |'- a=alpha, b=beta, c=release candidate or none
+#  | | '- micro version number
+#  | '- minor version number
+#  '- major version number
+
+# The presence of "-dev" means that this is a development version.  There are
+# no guarantees about compatibility, etc.  This version is considered to be
+# more recent than the version without this field (e.g. "1.0.0a1").
+
+# The next number is the "nano version number".  It is meaningful only to
+# developers.  It gets generated automatically from darcs revision control
+# history by "make-version-from-darcs-history.py".  It is the count of patches
+# that have been applied since the last version number tag was applied.
+
+VERSION_BASE_RE_STR="(\d+)\.(\d+)(\.(\d+))?((a|b|c)(\d+))?"
+VERSION_RE_STR=VERSION_BASE_RE_STR + "(-dev-r(\d+))?"
+VERSION_RE=re.compile("^" + VERSION_RE_STR + "$")
+
+class Version(object):
+    def __init__(self, vstring=None):
+        self.major = None
+        self.minor = None
+        self.micro = None
+        self.prereleasetag = None
+        self.prerelease = None
+        self.nano = None
+        self.leftovers = ''
+        if vstring:
+            try:
+                self.parse(vstring)
+            except ValueError, le:
+                le.args = tuple(le.args + ('vstring:', vstring,))
+                raise
+
+    def parse(self, vstring):
+        mo = VERSION_RE.search(vstring)
+        if not mo:
+            raise ValueError, "Not a valid version string for allmydata.util.version_class.Version(): %r" % (vstring,)
+
+        self.major = int(mo.group(1))
+        self.minor = int(mo.group(2))
+        self.micro = int(mo.group(4))
+        reltag = mo.group(5)
+        if reltag:
+            reltagnum = int(mo.group(6))
+            self.prereleasetag = reltag
+            self.prerelease = reltagnum
+
+        if mo.group(7):
+            self.nano = int(mo.group(8))
+
+        self.fullstr = "%d.%d.%d%s%s" % (self.major, self.minor, self.micro, self.prereleasetag and "%s%d" % (self.prereleasetag, self.prerelease,) or "", self.nano and "-dev-r%d" % (self.nano,) or "",)
+
+    def user_str(self):
+        return self.strictversion.__str__()
+
+    def full_str(self):
+        if hasattr(self, 'fullstr'):
+            return self.fullstr
+        else:
+            return 'None'
+
+    def __str__(self):
+        return self.full_str()
+
+    def __repr__(self):
+        return self.__str__()
+
+    def __cmp__ (self, other):
+        return cmp(pkg_resources.parse_version(str(self)), pkg_resources.parse_version(str(other)))