Index: vcpx/cvs.py
===================================================================
--- vcpx/cvs.py	(revision 41)
+++ vcpx/cvs.py	(revision 44)
@@ -81,42 +81,14 @@
     repository.
 
-    They use `cvsps` to actual fetch the changesets metadata from the
-    server, so that we can reasonably group related changes that would
-    otherwise be sparsed, as CVS is file-centric.
-
-    To accomodate this, the last revision (from cvsps point of view)
-    imported in the repository is stored in a file in the `CVS`
-    directory at the root of the working copy. This shouldn't
-    interfere with the normal operations, but since the file isn't
-    versioned you may easily loose it....
+    It uses `cvsps` to do the actual fetch of the changesets metadata
+    from the server, so that we can reasonably group together related
+    changes that would otherwise be sparsed, as CVS is file-centric.
     """
     
     ## UpdatableSourceWorkingDir
     
-    def __getLastUpstreamRevision(self, root):
-        from os.path import join, exists
-        
-        fname = join(root, 'CVS', 'last-synced-revision')
-        if exists(fname):
-            f = open(fname)
-            lastrev = f.read()
-            f.close()
-            return lastrev
-
-    def __setLastUpstreamRevision(self, root, revision):
-        from os.path import join, exists
-        
-        fname = join(root, 'CVS', 'last-synced-revision')
-        f = open(fname, 'w')
-        f.write(revision)
-        f.close()
-
-    def _getUpstreamChangesets(self, root):
+    def _getUpstreamChangesets(self, root, sincerev=None):
         cvsps = CvsPsLog(working_dir=root)
-
-        startfrom_rev = self.__getLastUpstreamRevision(root)
-        if startfrom_rev:
-            startfrom_rev = int(startfrom_rev)+1
-            
+        
         from os.path import join, exists
         
@@ -127,12 +99,15 @@
             branch="HEAD"
 
+        if sincerev:
+            sincerev = int(sincerev)
+            
         changesets = []
         log = cvsps(output=True, update=True, branch=branch)
-        for cs in self.__enumerateChangesets(log, startfrom_rev):
+        for cs in self.__enumerateChangesets(log, sincerev):
             changesets.append(cs)
 
         return changesets
     
-    def __enumerateChangesets(self, log, startfrom_rev):
+    def __enumerateChangesets(self, log, sincerev=None):
         """
         Parse CVSps log.
@@ -190,5 +165,5 @@
 
             while l.startswith('\t'):
-                if not startfrom_rev or (startfrom_rev<=int(pset['revision'])):
+                if not sincerev or (sincerev<int(pset['revision'])):
                     file,revs = l[1:-1].split(':')
                     fromrev,torev = revs.split('->')
@@ -210,5 +185,5 @@
                 l = log.readline()
 
-            if not startfrom_rev or (startfrom_rev<=int(pset['revision'])):
+            if not sincerev or (sincerev<int(pset['revision'])):
                 cvsdate = pset['date']
                 y,m,d = map(int, cvsdate[:10].split('/'))
@@ -235,6 +210,4 @@
                 pass
                 
-        self.__setLastUpstreamRevision(root, changeset.revision)
-
 
     ## SyncronizableTargetWorkingDir
@@ -265,5 +238,4 @@
         
         wdir = join(basedir, module)
-
         if not exists(wdir):
             c = CvsCheckout(working_dir=basedir)
@@ -293,6 +265,7 @@
                 last = cset
                 break
-        
-        self.__setLastUpstreamRevision(wdir, last.revision)
+
+        assert found, "Something went wrong, did not find the right cvsps revision in '%s'" % wdir
+        
         return last.revision
     
Index: vcpx/source.py
===================================================================
--- vcpx/source.py	(revision 41)
+++ vcpx/source.py	(revision 44)
@@ -43,5 +43,5 @@
     """
 
-    def applyUpstreamChangesets(self, root, replay=None):
+    def applyUpstreamChangesets(self, root, sincerev, replay=None):
         """
         Apply the collected upstream changes.
@@ -52,8 +52,12 @@
         changes on the target.
 
-        Return a sequence (potentially empty!) of conflicts.
+        Return a tuple of two elements:
+
+        - the last applied changeset, if any
+        - the sequence (potentially empty!) of conflicts.
         """
 
-        changesets = self._getUpstreamChangesets(root)
+        changesets = self._getUpstreamChangesets(root, sincerev)
+        c = None
         conflicts = []
         for c in changesets:
@@ -67,5 +71,5 @@
                 except KeyboardInterrupt:
                     print "INTERRUPTED BY THE USER!"
-                    return conflicts
+                    return c, conflicts
                 
             if replay:
@@ -74,7 +78,7 @@
             print
             
-        return conflicts
+        return c, conflicts
         
-    def _getUpstreamChangesets(self, root):
+    def _getUpstreamChangesets(self, root, sincerev):
         """
         Query the upstream repository about what happened on the
@@ -98,14 +102,17 @@
         raise "%s should override this method" % self.__class__
 
-    def checkoutUpstreamRevision(self, root, repository, revision):
+    def checkoutUpstreamRevision(self, root, repository, module, revision):
         """
         Extract a working copy from a repository.
 
-        :root: the name of the directory (that should **not** exists)
-               that will contain the working copy of the sources
+        :root: the name of the directory (that **must** exists)
+               that will contain the working copy of the sources under the
+               *module* subdirectory
 
         :repository: the address of the repository (the format depends on
                      the actual method used by the subclass)
 
+        :module: the name of the module to extract
+        
         :revision: extract that revision/branch
 
@@ -113,9 +120,5 @@
         """
 
-        from os.path import split
-
-        basedir,module = split(root)
-        
-        return self._checkoutUpstreamRevision(basedir, repository,
+        return self._checkoutUpstreamRevision(root, repository,
                                               module, revision)
         
Index: vcpx/target.py
===================================================================
--- vcpx/target.py	(revision 42)
+++ vcpx/target.py	(revision 44)
@@ -110,5 +110,5 @@
     def _initializeWorkingDir(self, root, addentry=None):
         """
-        Assuming the `root` directory is a new working copy extracted
+        Assuming the `root` directory is a working copy extracted
         from some VC repository, add it and all its content to the
         target repository.
Index: vcpx/darcs.py
===================================================================
--- vcpx/darcs.py	(revision 41)
+++ vcpx/darcs.py	(revision 44)
@@ -66,5 +66,5 @@
     ## UpdatableSourceWorkingDir
     
-    def _getUpstreamChangesets(self, root):
+    def _getUpstreamChangesets(self, root, sincerev=None):
         """
         Do the actual work of fetching the upstream changeset.
@@ -238,5 +238,5 @@
                                                               repository,
                                                               revision)
-        self._createTag(root, 'Upstream revision %s' % revision)
+        #self._createTag(root, 'Upstream revision %s' % revision)
 
     def _createTag(self, root, tagname):
Index: vcpx/svn.py
===================================================================
--- vcpx/svn.py	(revision 41)
+++ vcpx/svn.py	(revision 44)
@@ -46,5 +46,5 @@
 
 class SvnLog(SystemCommand):
-    COMMAND = "svn log %(quiet)s %(xml)s --revision %(startrev)s:%(endrev)s %(entry)s"
+    COMMAND = "svn log %(quiet)s %(xml)s --revision %(startrev)s:%(endrev)s %(entry)s 2>&1"
     
     def __call__(self, output=None, dry_run=False, **kwargs):
@@ -119,10 +119,22 @@
     ## UpdatableSourceWorkingDir
 
-    def _getUpstreamChangesets(self, root, startfrom_rev=None):
-        actualrev = SvnInfo(working_dir=root)(entry='.')['Revision']
+    def _getUpstreamChangesets(self, root, sincerev=None):
+        if sincerev:
+            sincerev = int(sincerev)
+        else:
+            sincerev = 0
+            
         svnlog = SvnLog(working_dir=root)
         log = svnlog(quiet='--verbose', output=True, xml=True,
-                     startrev=int(actualrev)+1, entry='.')
-
+                     startrev=sincerev+1, entry='.')
+        
+        if svnlog.exit_status:
+            errmsg = log.getvalue()
+            # XXX
+            if 'No such revision' in errmsg:
+                return []
+            else:
+                raise 'XXX: svn log error: %s' % errmsg
+        
         return self.__parseSvnLog(log)
 
Index: vcpx/dualwd.py
===================================================================
--- vcpx/dualwd.py	(revision 41)
+++ vcpx/dualwd.py	(revision 44)
@@ -41,10 +41,12 @@
     ## UpdatableSourceWorkingDir
         
-    def applyUpstreamChangesets(self, root, replay=None):
-        return self.source.applyUpstreamChangesets(root,
+    def applyUpstreamChangesets(self, root, sincerev, replay=None):
+        return self.source.applyUpstreamChangesets(root, sincerev,
                                                    self.target.replayChangeset)
         
-    def checkoutUpstreamRevision(self, root, repository, revision):
-        return self.source.checkoutUpstreamRevision(root, repository, revision)
+    def checkoutUpstreamRevision(self, root, repository, module, revision):
+        return self.source.checkoutUpstreamRevision(root,
+                                                    repository, module,
+                                                    revision)
 
     ## SyncronizableTargetWorkingDir
@@ -52,37 +54,2 @@
     def initializeNewWorkingDir(self, root, repository, revision):
         self.target.initializeNewWorkingDir(root, repository, revision)
-
-    ## Facilities
-        
-    def bootstrap(self, root, repository, revision):
-        """
-        Bootstrap a new tailorized module.
-
-        Extract a copy of the `repository` at given `revision` in the `root`
-        directory and initialize a target repository with its content.
-        """
-        
-        actual = self.checkoutUpstreamRevision(root, repository, revision)
-        self.initializeNewWorkingDir(root, repository, actual)
-
-if __name__ == '__main__':
-##     dwd = DualWorkingDir('svn', 'darcs')
-##     dwd.bootstrap('/tmp/prove/provapyde',
-##                   'svn+ssh://caia/ND/svn/tests/provapyde',
-##                   '1')
-##     dwd.applyUpstreamChangesets('/tmp/prove/provapyde')
-
-##     dwd = DualWorkingDir('cvs', 'darcs')
-##     dwd.bootstrap('/tmp/prove/PyApache', '/usr/local/CVSROOT/', 'HEAD')
-##     dwd.applyUpstreamChangesets('/tmp/prove/PyApache')
-    
-    dwd = DualWorkingDir('cvs', 'svn')
-    dwd.bootstrap('/tmp/prove/reportman', ':pserver:anonymous@cvs.sourceforge.net:/cvsroot/reportman', 'HEAD')
-    dwd.applyUpstreamChangesets('/tmp/prove/reportman')
-
-##     dwd = DualWorkingDir('svn', 'darcs')
-##     dwd.bootstrap('/tmp/prove/CMFPlone',
-##                   'http://svn.plone.org/plone/CMFPlone/branches/Plone-2_0-branch',
-##                   '4818')
-##     dwd.applyUpstreamChangesets('/tmp/prove/CMFPlone')
-    
Index: vcpx/tailor.py
===================================================================
--- vcpx/tailor.py	(revision 43)
+++ vcpx/tailor.py	(revision 45)
@@ -1,5 +1,5 @@
 #! /usr/bin/python
 # -*- mode: python; coding: utf-8 -*-
-# :Progetto: vcpx -- 
+# :Progetto: vcpx -- Frontend capabilities
 # :Creato:   dom 04 lug 2004 00:40:54 CEST
 # :Autore:   Lele Gaifax <lele@nautilus.homeip.net>
@@ -7,4 +7,9 @@
 
 """
+Implement the basic capabilities of the frontend.
+
+This implementation stores the relevant project information, needed to
+keep the whole thing going on, such as the last synced revision, in a
+unversioned file named `tailor.info` at the root.
 """
 
@@ -17,5 +22,10 @@
     
 class TailorizedProject(object):
-
+    """
+    A TailorizedProject has two main capabilities: it may be bootstrapped
+    from an upstream repository or brought in sync with current upstream
+    revision.
+    """
+    
     def __init__(self, root):
         import logging
@@ -37,4 +47,8 @@
                 
     def __saveStatus(self):
+        """
+        Save relevant project information in a persistent way.
+        """
+        
         from os.path import join, exists
 
@@ -49,4 +63,8 @@
         
     def __loadStatus(self):
+        """
+        Load relevant project information.
+        """
+        
         from os.path import join, exists
 
@@ -69,4 +87,6 @@
         Extract a copy of the `repository` at given `revision` in the `root`
         directory and initialize a target repository with its content.
+
+        The actual information on the project are stored in a text file.
         """
 
@@ -94,4 +114,12 @@
 
     def update(self):
+        """
+        Update an existing tailorized project.
+
+        Fetch the upstream changesets and apply them to the working copy.
+        Use the information stored in the `tailor.info` file to ask just
+        the new changeset since last bootstrap/synchronization.
+        """
+        
         from os.path import join
         
