source: soft/build_system/build_system/repsys/tags/V1_6_17_1/RepSys/svn.py @ 1

Last change on this file since 1 was 1, checked in by fasma, 13 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 13.9 KB
Line 
1from RepSys import Error, config, pexpect
2from RepSys.util import execcmd, get_auth
3import sys
4import re
5import time
6
7__all__ = ["SVN", "SVNLook", "SVNLogEntry"]
8
9class SVNLogEntry:
10    def __init__(self, revision, author, date):
11        self.revision = revision
12        self.author = author
13        self.date = date
14        self.changed = []
15        self.lines = []
16
17    def __cmp__(self, other):
18        return cmp(self.date, other.date)
19
20class SVN:
21    def __init__(self, username=None, password=None, noauth=0, baseurl=None):
22        self.noauth = noauth or (
23            baseurl and (
24                baseurl.startswith("file:") or
25                baseurl.startswith("svn+ssh:")))
26        if not self.noauth: # argh
27            self.username, self.password = get_auth()
28
29
30    def _execsvn(self, *args, **kwargs):
31        cmdstr = "svn "+" ".join(args)
32        if kwargs.get("local") or kwargs.get("noauth") or self.noauth:
33            return execcmd(cmdstr, **kwargs)
34        show = kwargs.get("show")
35        noerror = kwargs.get("noerror")
36        p = pexpect.spawn(cmdstr, timeout=1)
37        p.setmaxread(1024)
38        p.setecho(False)
39        outlist = []
40        while True:
41            i = p.expect_exact([pexpect.EOF, pexpect.TIMEOUT,
42                    "username:", "password:",
43                    "(p)ermanently?",
44                    "Authorization failed"])
45            if i == 0:
46                if show and p.before:
47                    print p.before,
48                outlist.append(p.before)
49                break
50            elif i == 1:
51                if show and p.before:
52                    print p.before,
53                outlist.append(p.before)
54            elif i == 2:
55                p.sendline(self.username)
56                outlist = []
57            elif i == 3:
58                p.sendline(self.password)
59                outlist = []
60            elif i == 4:
61                p.sendline("p")
62                outlist = []
63            elif i == 5:
64                if not noerror:
65                    raise Error, "authorization failed"
66                else:
67                    break
68        while p.isalive():
69            try:
70                time.sleep(1)
71            except (pexpect.TIMEOUT, pexpect.EOF):
72                # Continue until the child dies
73                pass
74        status, output = p.exitstatus, "".join(outlist).strip()
75        if status != 0 and not kwargs.get("noerror"):
76            sys.stderr.write(cmdstr)
77            sys.stderr.write("\n")
78            sys.stderr.write(output)
79            sys.stderr.write("\n")
80            raise Error, "command failed: "+cmdstr
81        return status, output
82
83    def _execsvn_success(self, *args, **kwargs):
84        status, output = self._execsvn(*args, **kwargs)
85        return status == 0
86
87    def _add_log(self, cmd_args, received_kwargs, optional=0):
88        if (not optional or
89            received_kwargs.has_key("log") or
90            received_kwargs.has_key("logfile")):
91            ret = received_kwargs.get("log")
92            if ret is not None:
93                cmd_args.append("-m '%s'" % ret)
94            ret = received_kwargs.get("logfile")
95            if ret is not None:
96                cmd_args.append("-F '%s'" % ret)
97
98    def _add_revision(self, cmd_args, received_kwargs, optional=0):
99        if not optional or received_kwargs.has_key("rev"):
100            ret = received_kwargs.get("rev")
101            if isinstance(ret, basestring):
102                try:
103                    ret = int(ret)
104                except ValueError:
105                    raise Error, "invalid revision provided"
106            if ret:
107                cmd_args.append("-r %d" % ret)
108       
109    def add(self, path, **kwargs):
110        cmd = ["add", path]
111        return self._execsvn_success(noauth=1, *cmd, **kwargs)
112
113    def copy(self, pathfrom, pathto, **kwargs):
114        cmd = ["copy", pathfrom, pathto]
115        self._add_revision(cmd, kwargs, optional=1)
116        self._add_log(cmd, kwargs)
117        return self._execsvn_success(*cmd, **kwargs)
118
119    def remove(self, path, force=0, **kwargs):
120        cmd = ["remove", path]
121        self._add_log(cmd, kwargs)
122        if force:
123            cmd.append("--force")
124        return self._execsvn_success(*cmd, **kwargs)
125
126    def mkdir(self, path, **kwargs):
127        cmd = ["mkdir", path]
128        self._add_log(cmd, kwargs)
129        return self._execsvn_success(*cmd, **kwargs)
130
131    def commit(self, path, **kwargs):
132        cmd = ["commit", path]
133        self._add_log(cmd, kwargs)
134        return self._execsvn_success(*cmd, **kwargs)
135
136    def export(self, url, targetpath, **kwargs):
137        cmd = ["export", "'%s'" % url, targetpath]
138        self._add_revision(cmd, kwargs, optional=1)
139        return self._execsvn_success(*cmd, **kwargs)
140
141    def checkout(self, url, targetpath, **kwargs):
142        cmd = ["checkout", "'%s'" % url, targetpath]
143        self._add_revision(cmd, kwargs, optional=1)
144        return self._execsvn_success(*cmd, **kwargs)
145 
146    def propset(self, propname, value, targets, **kwargs):
147        cmd = ["propset", propname, "'%s'" % value, targets]
148        return self._execsvn_success(*cmd, **kwargs)
149
150    def propedit(self, propname, target, **kwargs):
151        cmd = ["propedit", propname, target]
152        if kwargs.get("rev"):
153            cmd.append("--revprop")
154            self._add_revision(cmd, kwargs)
155        return self._execsvn_success(local=True, show=True, *cmd, **kwargs)
156
157    def revision(self, path, **kwargs):
158        cmd = ["info", path]
159        status, output = self._execsvn(local=True, *cmd, **kwargs)
160        if status == 0:
161            for line in output.splitlines():
162                if line.startswith("Revision: "):
163                    return int(line.split()[1])
164        return None
165         
166    def info(self, path, **kwargs):
167        cmd = ["info", path]
168        status, output = self._execsvn(local=True, *cmd, **kwargs)
169        if status == 0:
170            return output.splitlines()
171        return None
172
173    def info2(self, *args, **kwargs):
174        lines = self.info(*args, **kwargs)
175        pairs = [[w.strip() for w in line.split(":", 1)] for line in lines]
176        info = dict(pairs)
177        return info
178         
179    def ls(self, path, **kwargs):
180        cmd = ["ls", path]
181        status, output = self._execsvn(*cmd, **kwargs)
182        if status == 0:
183            return output.split()
184        return None
185
186    def status(self, path, **kwargs):
187        cmd = ["status", path]
188        if kwargs.get("verbose"):
189            cmd.append("-v")
190        if kwargs.get("noignore"):
191            cmd.append("--no-ignore")
192        status, output = self._execsvn(*cmd, **kwargs)
193        if status == 0:
194            return [x.split() for x in output.splitlines()]
195        return None
196
197    def cleanup(self, path, **kwargs):
198        cmd = ["cleanup", path]
199        return self._execsvn_success(*cmd, **kwargs)
200
201    def revert(self, path, **kwargs):
202        cmd = ["revert", path]
203        status, output = self._execsvn(*cmd, **kwargs)
204        if status == 0:
205            return [x.split() for x in output.split()]
206        return None
207
208    def switch(self, url, oldurl=None, path=None, relocate=False, **kwargs):
209        cmd = ["switch"]
210        if relocate:
211            if oldurl is None:
212                raise Error, "You must supply the old URL when "\
213                        "relocating working copies"
214            cmd.append("--relocate")
215            cmd.append(oldurl)
216        cmd.append(url)
217        if path is not None:
218            cmd.append(path)
219        return self._execsvn_success(*cmd, **kwargs)
220
221    def update(self, path, **kwargs):
222        cmd = ["update", path]
223        self._add_revision(cmd, kwargs, optional=1)
224        status, output = self._execsvn(*cmd, **kwargs)
225        if status == 0:
226            return [x.split() for x in output.split()]
227        return None
228
229    def merge(self, url1, url2=None, rev1=None, rev2=None, path=None, 
230            **kwargs):
231        cmd = ["merge"]
232        if rev1 and rev2 and not url2:
233            cmd.append("-r")
234            cmd.append("%s:%s" % (rev1, rev2))
235            cmd.append(url1)
236        else:
237            if not url2:
238                raise ValueError, \
239                      "url2 needed if two revisions are not provided"
240            if rev1:
241                cmd.append("%s@%s" % (url1, rev1))
242            else:
243                cmd.append(url1)
244            if rev2:
245                cmd.append("%s@%s" % (url2, rev2))
246            else:
247                cmd.append(url2)
248        if path:
249            cmd.append(path)
250        status, output = self._execsvn(*cmd, **kwargs)
251        if status == 0:
252            return [x.split() for x in output.split()]
253        return None
254
255    def diff(self, pathurl1, pathurl2=None, **kwargs):
256        cmd = ["diff", pathurl1]
257        self._add_revision(cmd, kwargs, optional=1)
258        if pathurl2:
259            cmd.append(pathurl2)
260        status, output = self._execsvn(*cmd, **kwargs)
261        if status == 0:
262            return output
263        return None
264
265    def cat(self, url, **kwargs):
266        cmd = ["cat", url]
267        self._add_revision(cmd, kwargs, optional=1)
268        status, output = self._execsvn(*cmd, **kwargs)
269        if status == 0:
270            return output
271        return None
272
273    def log(self, url, start=None, end=0, limit=None, **kwargs):
274        cmd = ["log", "-v", url]
275        if start is not None or end != 0:
276            if start is not None and type(start) is not type(0):
277                try:
278                    start = int(start)
279                except (ValueError, TypeError):
280                    raise Error, "invalid log start revision provided"
281            if type(end) is not type(0):
282                try:
283                    end = int(end)
284                except (ValueError, TypeError):
285                    raise Error, "invalid log end revision provided"
286            start = start or "HEAD"
287            cmd.append("-r %s:%s" % (start, end))
288        if limit is not None:
289            try:
290                limit = int(limit)
291            except (ValueError, TypeError):
292                raise Error, "invalid limit number provided"
293            cmd.append("--limit %d" % limit)
294        status, output = self._execsvn(*cmd, **kwargs)
295        if status != 0:
296            return None
297
298        revheader = re.compile("^r(?P<revision>[0-9]+) \| (?P<author>[^\|]+) \| (?P<date>[^\|]+) \| (?P<lines>[0-9]+) (?:line|lines)$")
299        changedpat = re.compile(r"^\s+(?P<action>[^\s]+) (?P<path>[^\s]+)(?: \([^\s]+ (?P<from_path>[^:]+)(?:\:(?P<from_rev>[0-9]+))?\))?$")
300        logseparator = "-"*72
301        linesleft = 0
302        entry = None
303        log = []
304        appendchanged = 0
305        changedheader = 0
306        for line in output.splitlines():
307            line = line.rstrip()
308            if changedheader:
309                appendchanged = 1
310                changedheader = 0
311            elif appendchanged:
312                if not line:
313                    appendchanged = 0
314                    continue
315                m = changedpat.match(line)
316                if m:
317                    changed = m.groupdict().copy()
318                    from_rev = changed.get("from_rev")
319                    if from_rev is not None:
320                        try:
321                            changed["from_rev"] = int(from_rev)
322                        except (ValueError, TypeError):
323                            raise Error, "invalid revision number in svn log"
324                    entry.changed.append(changed)
325            elif linesleft == 0:
326                if line != logseparator:
327                    m = revheader.match(line)
328                    if m:
329                        linesleft = int(m.group("lines"))
330                        timestr = " ".join(m.group("date").split()[:2])
331                        timetuple = time.strptime(timestr,
332                                                  "%Y-%m-%d %H:%M:%S")
333                        entry = SVNLogEntry(int(m.group("revision")),
334                                            m.group("author"), timetuple)
335                        log.append(entry)
336                        changedheader = 1
337            else:
338                entry.lines.append(line)
339                linesleft -= 1
340        log.sort()
341        log.reverse()
342        return log
343
344class SVNLook:
345    def __init__(self, repospath, txn=None, rev=None):
346        self.repospath = repospath
347        self.txn = txn
348        self.rev = rev
349
350    def _execsvnlook(self, cmd, *args, **kwargs):
351        execcmd_args = ["svnlook", cmd, self.repospath]
352        self._add_txnrev(execcmd_args, kwargs)
353        execcmd_args += args
354        execcmd_kwargs = {}
355        keywords = ["show", "noerror"]
356        for key in keywords:
357            if kwargs.has_key(key):
358                execcmd_kwargs[key] = kwargs[key]
359        return execcmd(*execcmd_args, **execcmd_kwargs)
360
361    def _add_txnrev(self, cmd_args, received_kwargs):
362        if received_kwargs.has_key("txn"):
363            txn = received_kwargs.get("txn")
364            if txn is not None:
365                cmd_args += ["-t", txn]
366        elif self.txn is not None:
367            cmd_args += ["-t", self.txn]
368        if received_kwargs.has_key("rev"):
369            rev = received_kwargs.get("rev")
370            if rev is not None:
371                cmd_args += ["-r", rev]
372        elif self.rev is not None:
373            cmd_args += ["-r", self.rev]
374
375    def changed(self, **kwargs):
376        status, output = self._execsvnlook("changed", **kwargs)
377        if status != 0:
378            return None
379        changes = []
380        for line in output.splitlines():
381            line = line.rstrip()
382            if not line:
383                continue
384            entry = [None, None, None]
385            changedata, changeprop, path = None, None, None
386            if line[0] != "_":
387                changedata = line[0]
388            if line[1] != " ":
389                changeprop = line[1]
390            path = line[4:]
391            changes.append((changedata, changeprop, path))
392        return changes
393
394    def author(self, **kwargs):
395        status, output = self._execsvnlook("author", **kwargs)
396        if status != 0:
397            return None
398        return output.strip()
399
400# vim:et:ts=4:sw=4
Note: See TracBrowser for help on using the repository browser.