source: tailor/vcpx/svn.py @ 23

Revision 23, 8.5 KB checked in by lele@…, 9 years ago (diff)

Catch the conflicts under svn

Line 
1#! /usr/bin/python
2# -*- mode: python; coding: utf-8 -*-
3# :Progetto: vcpx -- Subversion details
4# :Creato:   ven 18 giu 2004 15:00:52 CEST
5# :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
6#
7
8"""
9This module contains supporting classes for Subversion.
10"""
11
12__docformat__ = 'reStructuredText'
13
14from cvsync.shwrap import SystemCommand
15from source import UpdatableSourceWorkingDir
16from target import SyncronizableTargetWorkingDir
17
18
19class SvnUpdate(SystemCommand):
20    COMMAND = "svn update --revision %(revision)s %(entry)s"
21
22
23class SvnInfo(SystemCommand):
24    COMMAND = "LANG= svn info %(entry)s"
25
26    def __call__(self, output=None, dry_run=False, **kwargs):
27        output = SystemCommand.__call__(self, output=True,
28                                        dry_run=dry_run,
29                                        **kwargs)
30        res = {}
31        for l in output:
32            l = l[:-1]
33            if l:
34                key, value = l.split(':', 1)
35                res[key] = value[1:]
36        return res
37
38                 
39class SvnPropGet(SystemCommand):
40    COMMAND = "svn propget %(property)s %(entry)s"
41
42   
43class SvnPropSet(SystemCommand):
44    COMMAND = "svn propset --quiet %(property)s %(value)s %(entry)s"
45
46
47class SvnLog(SystemCommand):
48    COMMAND = "svn log %(quiet)s %(xml)s --revision %(startrev)s:%(endrev)s %(entry)s"
49   
50    def __call__(self, output=None, dry_run=False, **kwargs):
51        quiet = kwargs.get('quiet', True)
52        if quiet == True:
53            kwargs['quiet'] = '--quiet'
54        elif quiet == False:
55            kwargs['quiet'] = ''
56           
57        xml = kwargs.get('xml', False)
58        if xml:
59            kwargs['xml'] = '--xml'
60            output = True
61        else:
62            kwargs['xml'] = ''
63
64        startrev = kwargs.get('startrev')
65        if not startrev:
66            kwargs['startrev'] = 'BASE'
67
68        endrev = kwargs.get('endrev')
69        if not endrev:
70            kwargs['endrev'] = 'HEAD'
71
72        output = SystemCommand.__call__(self, output=output,
73                                        dry_run=dry_run, **kwargs)
74
75        if xml:
76            # parse the output and return the result
77            pass
78
79        return output
80
81
82class SvnCheckout(SystemCommand):
83    COMMAND = "svn co --quiet --revision %(revision)s %(repository)s %(wc)s"
84
85   
86class SvnCommit(SystemCommand):
87    COMMAND = "svn commit --quiet %(logfile)s %(entries)s"
88
89    def __call__(self, output=None, dry_run=False, **kwargs):
90        logfile = kwargs.get('logfile')
91        if not logfile:
92            from tempfile import NamedTemporaryFile
93
94            log = NamedTemporaryFile(bufsize=0)
95            logmessage = kwargs.get('logmessage')
96            if logmessage:
97                print >>log, logmessage
98           
99            kwargs['logfile'] = log.name
100       
101        return SystemCommand.__call__(self, output=output,
102                                      dry_run=dry_run, **kwargs)
103
104
105class SvnAdd(SystemCommand):
106    COMMAND = "svn add --quiet --no-auto-props --non-recursive %(entry)s"
107
108       
109class SvnRemove(SystemCommand):
110    COMMAND = "svn remove --quiet --force %(entry)s"
111
112
113class SvnMv(SystemCommand):
114    COMMAND = "svn mv --quiet %(old)s %(new)s"
115
116   
117class SvnCheckout(SystemCommand):
118    COMMAND = "svn co --quiet --revision %(revision)s %(repository)s %(wc)s"
119
120   
121class SvnWorkingDir(UpdatableSourceWorkingDir, SyncronizableTargetWorkingDir):
122
123    ## UpdatableSourceWorkingDir
124
125    def _getUpstreamChangesets(self, root, startfrom_rev=None):
126        actualrev = SvnInfo(working_dir=root)(entry='.')['Revision']
127        svnlog = SvnLog(working_dir=root)
128        log = svnlog(quiet='--verbose', output=True, xml=True,
129                     startrev=int(actualrev)+1, entry='.')
130
131        return self.__parseSvnLog(log)
132
133    def __parseSvnLog(self, log):
134        """Return an object representation of the ``svn log`` thru HEAD."""
135
136        from xml.sax import parseString
137        from xml.sax.handler import ContentHandler
138        from changes import ChangesetEntry, Changeset
139       
140        class SvnXMLLogHandler(ContentHandler):
141            def __init__(self):
142                self.changesets = []
143                self.current = None
144                self.current_field = []
145
146            def startElement(self, name, attributes):
147                if name == 'logentry':
148                    self.current = {}
149                    self.current['revision'] = attributes['revision']
150                    self.current['entries'] = []
151                elif name in ['author', 'date', 'msg']:
152                    self.current_field = []
153                elif name == 'path':
154                    self.current_field = []
155                    if attributes.has_key('copyfrom-path'):
156                        self.current_path_action = (
157                            attributes['action'],
158                            attributes['copyfrom-path'][1:], # make it relative
159                            attributes['copyfrom-rev'])
160                    else:
161                        self.current_path_action = attributes['action']
162
163            def endElement(self, name):
164                if name == 'logentry':
165                    # Sort the paths to make tests easier
166                    self.current['entries'].sort()
167                    self.changesets.append(Changeset(self.current['revision'],
168                                                     self.current['date'],
169                                                     self.current['author'],
170                                                     self.current['msg'],
171                                                     self.current['entries']))
172                    self.current = None
173                elif name in ['author', 'date', 'msg']:
174                    self.current[name] = ''.join(self.current_field)
175                elif name == 'path':
176                    entry = ChangesetEntry(''.join(self.current_field)[1:])
177                    if type(self.current_path_action) == type( () ):
178                        entry.action_kind = entry.RENAMED
179                        entry.old_name = self.current_path_action[1]
180                    else:
181                        entry.action_kind = self.current_path_action
182
183                    self.current['entries'].append(entry)
184
185            def characters(self, data):
186                self.current_field.append(data)
187
188       
189        handler = SvnXMLLogHandler()
190        parseString(log.getvalue(), handler)
191        return handler.changesets
192   
193    def _applyChangeset(self, root, changeset):
194        svnup = SvnUpdate(working_dir=root)
195        out = svnup(output=True, entry='.', revision=changeset.revision)       
196        result = {}
197        for line in out:
198            if len(line)>2 and line[0] == 'C' and line[1] == ' ':
199                try: result[line[0]].append(line[2:-1])
200                except KeyError: result[line[0]] = [line[2:-1]]
201           
202        return result
203       
204    ## SyncronizableTargetWorkingDir
205
206    def _addEntry(self, root, entry):
207        """
208        Add a new entry, maybe registering the directory as well.
209        """
210
211        from os.path import split, join, exists
212
213        basedir = split(entry)[0]
214        if basedir and not exists(join(basedir, '.svn')):
215            self._addEntry(root, basedir)
216
217        c = SvnAdd(working_dir=root)
218        c(entry=entry)
219
220    def _checkoutUpstreamRevision(self, basedir, repository, module, revision):
221        """
222        Concretely do the checkout of the upstream revision.
223        """
224       
225        svnco = SvnCheckout(working_dir=basedir)
226        svnco(repository=repository, wc=module, revision=revision)
227       
228    def _commit(self, root, author, remark, changelog=None, entries=None):
229        """
230        Commit the changeset.
231        """
232
233        c = SvnCommit(working_dir=root)
234       
235        logmessage = remark + '\n'
236        if changelog:
237            logmessage = logmessage + changelog + '\n'
238           
239        if entries:
240            entries = ' '.join(entries)
241        else:
242            entries = '.'
243           
244        c(logmessage=logmessage, entries=entries)
245       
246    def _removeEntry(self, root, entry):
247        """
248        Remove an entry.
249        """
250
251        c = SvnRemove(working_dir=root)
252        c(entry=entry)
253
254    def _renameEntry(self, root, oldentry, newentry):
255        """
256        Rename an entry.
257        """
258
259        c = SvnMv(working_dir=root)
260        c(old=oldentry, new=newentry)
261
262    def _initializeWorkingDir(self, root, addentry=None):
263        """
264        Add the given directory to an already existing svn working tree.
265        """
266       
267        SyncronizableTargetWorkingDir._initializeWorkingDir(self, root, SvnAdd)
Note: See TracBrowser for help on using the repository browser.