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