source: tailor/vcpx/cvs.py @ 13

Revision 13, 6.5 KB checked in by lele@…, 9 years ago (diff)

Changelog and entries are optional

Line 
1#! /usr/bin/python
2# -*- mode: python; coding: utf-8 -*-
3# :Progetto: vcpx -- CVS details
4# :Creato:   mer 16 giu 2004 00:46:12 CEST
5# :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
6#
7
8__docformat__ = 'reStructuredText'
9
10from cvsync.shwrap import SystemCommand
11from source import UpdatableSourceWorkingDir
12from target import SyncronizableTargetWorkingDir
13
14
15class CvsPsLog(SystemCommand):
16    COMMAND = "cvsps %(update)s-b%(branch)s"
17
18    def __call__(self, output=None, dry_run=False, **kwargs):
19        update = kwargs.get('update', '')
20        if update:
21            update = '-u '
22        kwargs['update'] = update
23       
24        return SystemCommand.__call__(self, output=output,
25                                      dry_run=dry_run, **kwargs)
26
27   
28class CvsUpdate(SystemCommand):
29    COMMAND = 'cvs %(dry)supdate -d -r%(revision)s %(entry)s2>&1'
30   
31    def __call__(self, output=None, dry_run=False, **kwargs):
32        if dry_run:
33            kwargs['dry'] = '-n '
34        else:
35            kwargs['dry'] = ''
36
37        return SystemCommand.__call__(self, output=output,
38                                      dry_run=False, **kwargs)
39
40
41class CvsAdd(SystemCommand):
42    COMMAND = "cvs add %(entry)s"
43
44
45class CvsCommit(SystemCommand):
46    COMMAND = "cvs ci -F %(logfile)s %(entries)s"
47   
48
49class CvsRemove(SystemCommand):
50    COMMAND = "cvs remove %(entry)s"
51
52
53from textwrap import TextWrapper
54from re import compile, MULTILINE
55   
56itemize_re = compile('^[ ]*[-*] ', MULTILINE)
57
58def refill(msg):
59    wrapper = TextWrapper()
60    s = []
61    items = itemize_re.split(msg)
62    if len(items)>1:
63        wrapper.initial_indent = ' - '
64        wrapper.subsequent_indent = ' '*3
65               
66    for m in items:
67        if m:
68            s.append(wrapper.fill(m))
69            s.append('')
70
71    return '\n'.join(s)
72
73
74class CvsWorkingDir(UpdatableSourceWorkingDir,
75                    SyncronizableTargetWorkingDir):
76
77    ## UpdatableSourceWorkingDir
78   
79    def __getLastUpstreamRevision(self, root):
80        from os.path import join, exists
81       
82        fname = join(root, 'CVS', 'last-synced-revision')
83        if exists(fname):
84            return open(fname).read()
85
86    def __setLastUpstreamRevision(self, root, revision):
87        from os.path import join, exists
88       
89        fname = join(root, 'CVS', 'last-synced-revision')
90        open(fname, 'w').write(revision)
91       
92    def _getUpstreamChangesets(self, root):
93        cvsps = CvsPsLog(update=True, working_dir=root)
94
95        startfrom_rev = self.__getLastUpstreamRevision(root)
96        if startfrom_rev:
97            startfrom_rev = int(startfrom_rev)
98           
99        from os.path import join, exists
100       
101        fname = join(self.root, 'CVS', 'Tag')
102        if exists(fname):
103            branch=open(fname).read()[1:-1]
104        else:
105            branch="HEAD"
106
107        log = cvsps(output=True, branch=branch)
108        for cs in self.__enumerateChangesets(log):
109            if not startfrom_rev or (startfrom_rev<=cs.revision):
110                self.changesets.append(cs)
111               
112    def __enumerateChangesets(self, log):
113        """
114        Parse CVSps log.
115        """
116
117        from changes import Changeset, ChangesetEntry
118
119        # cvsps output sample:
120        ## ---------------------
121        ## PatchSet 1500
122        ## Date: 2004/05/09 17:54:22
123        ## Author: grubert
124        ## Branch: HEAD
125        ## Tag: (none)
126        ## Log:
127        ## Tell the reason for using mbox (not wrapping long lines).
128        ##
129        ## Members:
130        ##         docutils/writers/latex2e.py:1.78->1.79
131       
132        log.seek(0)
133
134        l = None
135        while 1:
136            l = log.readline()
137            if l <> '---------------------\n':
138                break
139
140            l = log.readline()
141            assert l.startswith('PatchSet '), "Parse error: %s"%l
142
143            pset = {}
144            pset['revision'] = l[9:-1]
145            l = log.readline()
146            while not l.startswith('Log:'):
147                field,value = l.split(':',1)
148                pset[field.lower()] = value.strip()
149                l = log.readline()
150
151            msg = []
152            l = log.readline()
153            msg.append(l)
154            l = log.readline()
155            while l <> 'Members: \n':
156                msg.append(l)
157                l = log.readline()
158
159            pset['log'] = refill(''.join(msg))
160
161            assert l.startswith('Members:'), "Parse error: %s" % l
162
163            pset['entries'] = entries = []
164            l = log.readline()
165
166            while l.startswith('\t'):
167                file,revs = l[1:-1].split(':')
168                fromrev,torev = revs.split('->')
169
170                e = ChangesetEntry(file)
171                e.old_revision = fromrev
172                e.new_revision = torev
173
174                if fromrev=='INITIAL':
175                    e.action_kind = e.ADDED
176                elif "(DEAD)" in torev:
177                    e.action_kind = e.DELETED
178                else:
179                    e.action_kind = e.UPDATED
180
181                entries.append(e)
182                l = log.readline()
183
184            yield Changeset(**pset)
185
186    def _applyChangeset(self, root, changeset):
187        cvsup = CvsUpdate(working_dir=root)
188        for e in cs.entries:
189            cvsup(entry=e.name, revision=e.new_revision)
190        self.__setLastUpstreamRevision(root, revision)
191       
192    ## SyncronizableTargetWorkingDir
193
194    def _addEntry(self, root, entry):
195        """
196        Add a new entry, maybe registering the directory as well.
197        """
198
199        from os.path import split, join, exists
200
201        basedir = split(entry)[0]
202        if basedir and not exists(join(basedir, 'CVS')):
203            self._addEntry(root, basedir)
204       
205        c = CvsAdd(working_dir=root)
206        c(entry=entry)
207
208    def _commit(self, root, author, remark, changelog=None, entries=None):
209        """
210        Commit the changeset.
211        """
212       
213        from tempfile import NamedTemporaryFile
214       
215        log = NamedTemporaryFile(bufsize=0)
216        log.write(remark)
217        log.write('\n')
218        if changelog:
219            log.write(changelog)
220            log.write('\n')
221       
222        c = CvsCommit(working_dir=root)
223        c(entries=entries, logfile=log.name)
224        log.close()
225       
226    def _removeEntry(self, root, entry):
227        """
228        Remove an entry.
229        """
230
231        c = CvsRemove(working_dir=root)
232        c(entry=entry)
233
234    def _renameEntry(self, root, oldentry, newentry):
235        """
236        Rename an entry.
237        """
238
239        self._removeEntry(root, oldentry)
240        self._addEntry(root, newentry)
Note: See TracBrowser for help on using the repository browser.