summaryrefslogtreecommitdiff
path: root/darcsver-1.6.3.egg/darcsver/darcsvermodule.py
blob: 4f03572ec79e3da6f44d1c8427a98cb808e35d66 (plain)
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)