]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - darcsver-1.7.2.egg/darcsver/darcsvermodule.py
aabd1c9e92b8c78af9684b3c53caf7513b748c43
[tahoe-lafs/tahoe-lafs.git] / darcsver-1.7.2.egg / darcsver / darcsvermodule.py
1 import os, string, sys, re
2 import xml.dom.minidom
3 import subprocess
4 PIPE=subprocess.PIPE
5 from distutils import log
6
7 def all(iterable):
8     for thing in iterable:
9         if not thing:
10             return False
11     return True
12
13 OUR_VERSION_BASE_RE_STR="(\d+)(\.(\d+)(\.(\d+))?)?((a|b|c)(\d+))?(\.dev(\d+))?"
14 try:
15     # If we can import pyutil.version_class then use its regex.
16     from pyutil import version_class
17     VERSION_BASE_RE_STR = version_class.VERSION_BASE_RE_STR
18 except (ImportError, AttributeError):
19     # Else (perhaps a bootstrapping problem),then we'll use this
20     # regex, which was copied from the pyutil source code on
21     # 2010-09-02.
22     VERSION_BASE_RE_STR=OUR_VERSION_BASE_RE_STR
23
24 def get_text(nodelist):
25     rc = ""
26     for node in nodelist:
27         if node.nodeType == node.TEXT_NODE:
28             rc = rc + node.data
29     return rc
30
31 VERSION_BODY = '''
32 # This is the version of this tree, as created by %(versiontool)s from the darcs patch
33 # information: the main version number is taken from the most recent release
34 # tag. If some patches have been added since the last release, this will have a
35 # -NN "build number" suffix, or else a -rNN "revision number" suffix. Please see
36 # pyutil.version_class for a description of what the different fields mean.
37
38 __pkgname__ = "%(pkgname)s"
39 verstr = "%(pkgversion)s"
40 try:
41     from pyutil.version_class import Version as pyutil_Version
42     __version__ = pyutil_Version(verstr)
43 except (ImportError, ValueError):
44     # Maybe there is no pyutil installed.
45     from distutils.version import LooseVersion as distutils_Version
46     __version__ = distutils_Version(verstr)
47 '''
48
49 def write_version_py(verstr, outfname, EXE_NAME, version_body, pkgname):
50     f = open(outfname, "wb+")
51     f.write(version_body % {
52             'versiontool': EXE_NAME,
53             'pkgversion': verstr,
54             'pkgname': pkgname,
55             })
56     f.close()
57
58 def read_version_py(infname):
59     try:
60         verstrline = open(infname, "rt").read()
61     except EnvironmentError:
62         return None
63     else:
64         VSRE = r"^verstr = ['\"]([^'\"]*)['\"]"
65         mo = re.search(VSRE, verstrline, re.M)
66         if mo:
67             return mo.group(1)
68
69 def update(pkgname, verfilename, revision_number=False, loud=False, abort_if_snapshot=False, EXE_NAME="darcsver", version_body=VERSION_BODY):
70     """
71     @param revision_number If true, count the total number of patches in all
72     history.  If false, count the total number of patches since the most recent
73     release tag.
74
75     Returns a tuple of (exit code, new version string).
76     """
77     if isinstance(verfilename, basestring):
78         verfilenames = [verfilename]
79     else:
80         verfilenames = verfilename
81         assert all([isinstance(vfn, basestring) for vfn in verfilenames]), [vfn for vfn in verfilenames if not isinstance(vfn, basestring)]
82     if isinstance(version_body, basestring):
83         verbodies = [version_body]
84     else:
85         verbodies = version_body
86     rc = -1
87
88     # First we try "darcs query repo" because if that fails then we
89     # won't try "darcs changes" at all, because "darcs changes" emits
90     # an ugly error message when run in not-a-repo.
91     try:
92         p = subprocess.Popen(["darcs", 'query', 'repo'], stdout=PIPE, stderr=PIPE, universal_newlines=True)
93     except OSError, ose:
94         if ose.errno == 2 and '~' in os.environ['PATH']:
95             expanded_path = os.environ['PATH'].replace('~', os.path.expanduser('~'))
96             msg = ("WARNING: 'darcs' was not found. However '~' was found in your PATH. \n"
97                    "Please note that bugs in python cause it to fail to traverse '~' in \n"
98                    "the user's PATH.  Please fix your path, e.g. \nPATH=%s" )
99             log.warn(msg % (expanded_path,))
100         pass
101     else:
102         (output, errput) = p.communicate()
103         rc = p.returncode
104
105     if rc == 0:
106         cmd = ["changes", "--xml-output"]
107         if not revision_number:
108             cmd.append("--from-tag=^%s" % (pkgname,))
109         try:
110             p = subprocess.Popen(["darcs"] + cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
111         except OSError:
112             pass
113         else:
114             (output, errput) = p.communicate()
115             rc = p.returncode
116             if rc != 0 and errput:
117                 log.info("%s: darcs wrote to stderr: '%s'" % (EXE_NAME, errput,))
118                 errput = None
119     else:
120         if all([os.path.exists(vfn) for vfn in verfilenames]):
121             log.info("%s: using extant version file %s" % (EXE_NAME, verfilenames))
122             return (0, read_version_py(verfilenames[0]))
123         else:
124             log.warn("%s: didn't find version tags with darcs, and %s don't exist." % (EXE_NAME, verfilenames))
125         return (rc, None)
126
127     # Filter out bad chars that can cause the XML parser to give up in despair.
128     # (Thanks to lelit of the tailor project and ndurner and warner for this hack.)
129     allbadchars = "".join([chr(i) for i in range(0x0a) + [0x0b, 0x0c] + range(0x0e, 0x20) + range(0x7f,0x100)])
130     tt = string.maketrans(allbadchars, "-"*len(allbadchars))
131     output = output.translate(tt)
132     regexstr = "^TAG %s-(%s)$" % (pkgname, VERSION_BASE_RE_STR)
133     last_tag = None
134
135     # strip off trailing warning messages that darcs 2.3.1 writes to stdout
136     endi = output.find("</changelog>")+len("</changelog>")
137     if endi != -1:
138         output = output[:endi]
139     try:
140         doc = xml.dom.minidom.parseString(output)
141     except xml.parsers.expat.ExpatError:
142         # Okay maybe this is an error message instead of an XML output.
143         pass
144     else:
145         changelog = doc.getElementsByTagName("changelog")[0]
146         patches = changelog.getElementsByTagName("patch")
147         version_re = re.compile(regexstr)
148         count_since_last_patch = 0
149         if abort_if_snapshot:
150             for patch in patches:
151                 name = get_text(patch.getElementsByTagName("name")[0].childNodes)
152                 m = version_re.match(name)
153                 if m:
154                     last_tag = m.group(1)
155                     last_tag = last_tag.encode("utf-8")
156                     break
157                 else:
158                     sys.exit(0) # because abort_if_snapshot
159         else:
160             for patch in patches:
161                 name = get_text(patch.getElementsByTagName("name")[0].childNodes)
162                 m = version_re.match(name)
163                 if m:
164                     last_tag = m.group(1)
165                     last_tag = last_tag.encode("utf-8")
166                     break
167                 else:
168                     count_since_last_patch += 1
169
170     if not last_tag:
171         if errput:
172             log.info("%s: darcs wrote to stderr: '%s'" % (EXE_NAME, errput,))
173             errput = None
174         assert all([isinstance(vfn, basestring) for vfn in verfilenames]), [vfn for vfn in verfilenames if not isinstance(vfn, basestring)]
175         if all([os.path.exists(vfn) for vfn in verfilenames]):
176             log.warn("%s: I'm unable to find a tag in the darcs history matching \"%s\", so I'm leaving %s alone." % (EXE_NAME, regexstr, verfilenames,))
177             return (0, read_version_py(verfilenames[0]))
178         else:
179             log.warn("%s: I'm unable to find a tag in the darcs history matching \"%s\", and %s don't exist." % (EXE_NAME, regexstr, verfilenames,))
180             return (-1, None)
181
182     if revision_number:
183         if count_since_last_patch:
184             # this is an interim version
185             verstr = "%s-r%d" % (last_tag, len(patches))
186         else:
187             # this is a release
188             verstr = last_tag
189     else:
190         if count_since_last_patch:
191             # this is an interim version
192             verstr = "%s-%d" % (last_tag, count_since_last_patch)
193         else:
194             # this is a release
195             verstr = last_tag
196
197     for verfn, verbod in zip(verfilenames, verbodies):
198         write_version_py(verstr, verfn, EXE_NAME, verbod, pkgname)
199         log.info("%s: wrote '%s' into %s" % (EXE_NAME, verstr, verfn,))
200     return (0, verstr)