]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - misc/make-version.py
make-version.py: use 'subprocess' module instead of 'commands', to improve windows...
[tahoe-lafs/tahoe-lafs.git] / misc / make-version.py
1 #! /usr/bin/python
2
3 """
4 Create src/allmydata/version.py, based upon the latest darcs release tag.
5
6 If your source tree is coming from darcs (i.e. there exists a _darcs
7 directory), this tool will determine the most recent release tag, count the
8 patches that have been applied since then, and compute a version number to be
9 written into version.py . This version number will be available by doing:
10
11  from allmydata import __version__
12
13 Source trees that do not come from darcs (release tarballs, nightly tarballs)
14 do not have a _darcs directory. Instead, they should have a version.py that
15 was generated before the tarball was produced. In this case, this script will
16 quietly exit without modifying the existing version.py .
17
18 FYI, src/allmydata/__init__.py will attempt to import version.py and use the
19 version number therein. If it cannot, it will announce a version of
20 'UNKNOWN'. This should only happen if someone manages to get hold of a
21 non-_darcs/ source tree.
22
23 'release tags' are tags in the tahoe source tree that match the following
24 regexp:
25
26  ^allmydata-tahoe-\d+\.\d+\.\d+\w*$
27
28 This excludes zfec tags (which start with 'zfec '). It also excludes
29 'developer convenience tags', which look like 'hoping to fix bug -warner'.
30 (the original goal was to use release tags that lacked the 'allmydata-tahoe-'
31 prefix, but it turns out to be more efficient to keep it in, because I can't
32 get 'darcs changes --from-tag=' to accept real regexps).
33
34 """
35
36 import os, sys, re
37 import xml.dom.minidom
38 from subprocess import Popen, PIPE
39
40 def get_text(nodelist):
41     rc = ""
42     for node in nodelist:
43         if node.nodeType == node.TEXT_NODE:
44             rc = rc + node.data
45     return rc
46
47 VERSION_BODY = '''
48 from util.version import Version
49
50 # This is the version of this tree, as created by misc/make-version.py from
51 # the Darcs patch information: the main version number is taken from the most
52 # recent release tag. If some patches have been added since the last release,
53 # this will have a -NN "build number" suffix. Please see
54 # allmydata.util.version for a description of what the different fields mean.
55
56 verstr = "%s"
57 __version__ = Version(verstr)
58 '''
59
60 def write_version_py(verstr):
61     f = open("src/allmydata/version.py", "wt")
62     f.write(VERSION_BODY % (verstr,))
63     f.close()
64
65 def update():
66     if not os.path.exists("_darcs") or not os.path.isdir("_darcs"):
67         if os.path.exists("src/allmydata/version.py"):
68             print "no _darcs/ and version.py exists, leaving it alone"
69             return 0
70         print "no _darcs/ but no version.py either: how did you get this tree?"
71         return 0
72     cmd = ["darcs", "changes", "--from-tag=^allmydata-tahoe", "--xml-output"]
73     p = Popen(cmd, stdout=PIPE)
74     output = p.communicate()[0]
75     rc = p.returncode
76     if rc != 0:
77         print "unable to run 'darcs changes':"
78         print output
79         print "so I'm leaving version.py alone"
80         return 0
81
82     # windows' weird ssh process prepends some 'plink: unknown option "-O"'
83     # junk to the beginning of the otput. To overcome this, manually scan for
84     # the opening <changelog> tag before giving anything to the xml parser.
85
86     output = output[output.find("<changelog>"):]
87
88     try:
89         doc = xml.dom.minidom.parseString(output)
90     except xml.parsers.expat.ExpatError:
91         print "unable to parse darcs XML output:"
92         print output
93         raise
94     changelog = doc.getElementsByTagName("changelog")[0]
95     patches = changelog.getElementsByTagName("patch")
96     count = 0
97     version_re = re.compile("^TAG allmydata-tahoe-(\d+\.\d+\.\d+\w*)$")
98     for patch in patches:
99         name = get_text(patch.getElementsByTagName("name")[0].childNodes)
100         m = version_re.match(name)
101         if m:
102             last_tag = m.group(1)
103             last_tag = last_tag.encode("ascii")
104             break
105         count += 1
106     else:
107         print "unable to find a matching tag"
108         print output
109         print "so I'm leaving version.py alone"
110         return 0
111
112     if count:
113         # this is an interim version
114         verstr = "%s-%d" % (last_tag, count)
115     else:
116         # this is a release
117         verstr = last_tag
118
119     write_version_py(verstr)
120     print "wrote '%s' into src/allmydata/version.py" % (verstr,)
121     return 0
122
123 if __name__ == '__main__':
124     rc = update()
125     sys.exit(rc)
126