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

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

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

File size: 13.1 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 ls(self, path, **kwargs):
174        cmd = ["ls", path]
175        status, output = self._execsvn(*cmd, **kwargs)
176        if status == 0:
177            return output.split()
178        return None
179
180    def status(self, path, **kwargs):
181        cmd = ["status", path]
182        if kwargs.get("verbose"):
183            cmd.append("-v")
184        status, output = self._execsvn(*cmd, **kwargs)
185        if status == 0:
186            return [x.split() for x in output.splitlines()]
187        return None
188
189    def cleanup(self, path, **kwargs):
190        cmd = ["cleanup", path]
191        return self._execsvn_success(*cmd, **kwargs)
192
193    def revert(self, path, **kwargs):
194        cmd = ["revert", path]
195        status, output = self._execsvn(*cmd, **kwargs)
196        if status == 0:
197            return [x.split() for x in output.split()]
198        return None
199
200    def update(self, path, **kwargs):
201        cmd = ["update", path]
202        self._add_revision(cmd, kwargs, optional=1)
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 merge(self, url1, url2=None, rev1=None, rev2=None, path=None, **kwargs):
209        cmd = ["merge"]
210        if rev1 and rev2 and not url2:
211            cmd.append("-r")
212            cmd.append("%s:%s" % (rev1, rev2))
213            cmd.append(url1)
214        else:
215            if not url2:
216                raise ValueError, \
217                      "url2 needed if two revisions are not provided"
218            if rev1:
219                cmd.append("%s@%s" % (url1, rev1))
220            else:
221                cmd.append(url1)
222            if rev2:
223                cmd.append("%s@%s" % (url2, rev2))
224            else:
225                cmd.append(url2)
226        if path:
227            cmd.append(path)
228        status, output = self._execsvn(*cmd, **kwargs)
229        if status == 0:
230            return [x.split() for x in output.split()]
231        return None
232
233    def diff(self, pathurl1, pathurl2=None, **kwargs):
234        cmd = ["diff", pathurl1]
235        self._add_revision(cmd, kwargs, optional=1)
236        if pathurl2:
237            cmd.append(pathurl2)
238        status, output = self._execsvn(*cmd, **kwargs)
239        if status == 0:
240            return output
241        return None
242
243    def cat(self, url, **kwargs):
244        cmd = ["cat", url]
245        self._add_revision(cmd, kwargs, optional=1)
246        status, output = self._execsvn(*cmd, **kwargs)
247        if status == 0:
248            return output
249        return None
250
251    def log(self, url, start=None, end=0, limit=None, **kwargs):
252        cmd = ["log", "-v", url]
253        if start is not None or end != 0:
254            if start is not None and type(start) is not type(0):
255                try:
256                    start = int(start)
257                except (ValueError, TypeError):
258                    raise Error, "invalid log start revision provided"
259            if type(end) is not type(0):
260                try:
261                    end = int(end)
262                except (ValueError, TypeError):
263                    raise Error, "invalid log end revision provided"
264            start = start or "HEAD"
265            cmd.append("-r %s:%s" % (start, end))
266        if limit is not None:
267            try:
268                limit = int(limit)
269            except (ValueError, TypeError):
270                raise Error, "invalid limit number provided"
271            cmd.append("--limit %d" % limit)
272        status, output = self._execsvn(*cmd, **kwargs)
273        if status != 0:
274            return None
275
276        revheader = re.compile("^r(?P<revision>[0-9]+) \| (?P<author>[^\|]+) \| (?P<date>[^\|]+) \| (?P<lines>[0-9]+) (?:line|lines)$")
277        changedpat = re.compile(r"^\s+(?P<action>[^\s]+) (?P<path>[^\s]+)(?: \([^\s]+ (?P<from_path>[^:]+)(?:\:(?P<from_rev>[0-9]+))?\))?$")
278        logseparator = "-"*72
279        linesleft = 0
280        entry = None
281        log = []
282        appendchanged = 0
283        changedheader = 0
284        for line in output.splitlines():
285            line = line.rstrip()
286            if changedheader:
287                appendchanged = 1
288                changedheader = 0
289            elif appendchanged:
290                if not line:
291                    appendchanged = 0
292                    continue
293                m = changedpat.match(line)
294                if m:
295                    changed = m.groupdict().copy()
296                    from_rev = changed.get("from_rev")
297                    if from_rev is not None:
298                        try:
299                            changed["from_rev"] = int(from_rev)
300                        except (ValueError, TypeError):
301                            raise Error, "invalid revision number in svn log"
302                    entry.changed.append(changed)
303            elif linesleft == 0:
304                if line != logseparator:
305                    m = revheader.match(line)
306                    if m:
307                        linesleft = int(m.group("lines"))
308                        timestr = " ".join(m.group("date").split()[:2])
309                        timetuple = time.strptime(timestr,
310                                                  "%Y-%m-%d %H:%M:%S")
311                        entry = SVNLogEntry(int(m.group("revision")),
312                                            m.group("author"), timetuple)
313                        log.append(entry)
314                        changedheader = 1
315            else:
316                entry.lines.append(line)
317                linesleft -= 1
318        log.sort()
319        log.reverse()
320        return log
321
322class SVNLook:
323    def __init__(self, repospath, txn=None, rev=None):
324        self.repospath = repospath
325        self.txn = txn
326        self.rev = rev
327
328    def _execsvnlook(self, cmd, *args, **kwargs):
329        execcmd_args = ["svnlook", cmd, self.repospath]
330        self._add_txnrev(execcmd_args, kwargs)
331        execcmd_args += args
332        execcmd_kwargs = {}
333        keywords = ["show", "noerror"]
334        for key in keywords:
335            if kwargs.has_key(key):
336                execcmd_kwargs[key] = kwargs[key]
337        return execcmd(*execcmd_args, **execcmd_kwargs)
338
339    def _add_txnrev(self, cmd_args, received_kwargs):
340        if received_kwargs.has_key("txn"):
341            txn = received_kwargs.get("txn")
342            if txn is not None:
343                cmd_args += ["-t", txn]
344        elif self.txn is not None:
345            cmd_args += ["-t", self.txn]
346        if received_kwargs.has_key("rev"):
347            rev = received_kwargs.get("rev")
348            if rev is not None:
349                cmd_args += ["-r", rev]
350        elif self.rev is not None:
351            cmd_args += ["-r", self.rev]
352
353    def changed(self, **kwargs):
354        status, output = self._execsvnlook("changed", **kwargs)
355        if status != 0:
356            return None
357        changes = []
358        for line in output.splitlines():
359            line = line.rstrip()
360            if not line:
361                continue
362            entry = [None, None, None]
363            changedata, changeprop, path = None, None, None
364            if line[0] != "_":
365                changedata = line[0]
366            if line[1] != " ":
367                changeprop = line[1]
368            path = line[4:]
369            changes.append((changedata, changeprop, path))
370        return changes
371
372    def author(self, **kwargs):
373        status, output = self._execsvnlook("author", **kwargs)
374        if status != 0:
375            return None
376        return output.strip()
377
378# vim:et:ts=4:sw=4
Note: See TracBrowser for help on using the repository browser.