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