patch: move copyfile() into backends, abstract basedir
authorPatrick Mezard <pmezard@gmail.com>
Tue, 17 May 2011 23:46:38 +0200
changeset 14350 00da6624e167
parent 14349 776ae95b8835
child 14351 d54f9bbcc640
patch: move copyfile() into backends, abstract basedir
mercurial/patch.py
--- a/mercurial/patch.py	Tue May 17 23:46:37 2011 +0200
+++ b/mercurial/patch.py	Tue May 17 23:46:38 2011 +0200
@@ -18,25 +18,6 @@
 class PatchError(Exception):
     pass
 
-# helper functions
-
-def copyfile(src, dst, basedir):
-    abssrc, absdst = [scmutil.canonpath(basedir, basedir, x)
-                        for x in [src, dst]]
-    if os.path.lexists(absdst):
-        raise util.Abort(_("cannot create %s: destination already exists") %
-                         dst)
-
-    dstdir = os.path.dirname(absdst)
-    if dstdir and not os.path.isdir(dstdir):
-        try:
-            os.makedirs(dstdir)
-        except IOError:
-            raise util.Abort(
-                _("cannot create %s: unable to create destination directory")
-                % dst)
-
-    util.copyfile(abssrc, absdst)
 
 # public functions
 
@@ -406,10 +387,17 @@
         """
         pass
 
+    def copy(self, src, dst):
+        """Copy src file into dst file. Create intermediate directories if
+        necessary. Files are specified relatively to the patching base
+        directory.
+        """
+        raise NotImplementedError
+
 class fsbackend(abstractbackend):
-    def __init__(self, ui, opener):
+    def __init__(self, ui, basedir):
         super(fsbackend, self).__init__(ui)
-        self.opener = opener
+        self.opener = scmutil.opener(basedir)
 
     def readlines(self, fname):
         if os.path.islink(fname):
@@ -456,6 +444,23 @@
         fp.writelines(lines)
         fp.close()
 
+    def copy(self, src, dst):
+        basedir = self.opener.base
+        abssrc, absdst = [scmutil.canonpath(basedir, basedir, x)
+                          for x in [src, dst]]
+        if os.path.lexists(absdst):
+            raise util.Abort(_("cannot create %s: destination already exists")
+                             % dst)
+        dstdir = os.path.dirname(absdst)
+        if dstdir and not os.path.isdir(dstdir):
+            try:
+                os.makedirs(dstdir)
+            except IOError:
+                raise util.Abort(
+                    _("cannot create %s: unable to create destination directory")
+                    % dst)
+        util.copyfile(abssrc, absdst)
+
 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
@@ -1147,15 +1152,15 @@
     Callers probably want to call '_updatedir' after this to
     apply certain categories of changes not done by this function.
     """
-    return _applydiff(ui, fp, patchfile, copyfile, changed, strip=strip,
+    return _applydiff(ui, fp, patchfile, changed, strip=strip,
                       eolmode=eolmode)
 
-def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'):
+def _applydiff(ui, fp, patcher, changed, strip=1, eolmode='strict'):
     rejects = 0
     err = 0
     current_file = None
     cwd = os.getcwd()
-    backend = fsbackend(ui, scmutil.opener(cwd))
+    backend = fsbackend(ui, os.getcwd())
 
     for state, values in iterhunks(fp):
         if state == 'hunk':
@@ -1188,7 +1193,7 @@
                 # Binary patches really overwrite target files, copying them
                 # will just make it fails with "target file exists"
                 if gp.op in ('COPY', 'RENAME') and not gp.binary:
-                    copyfn(gp.oldpath, gp.path, cwd)
+                    backend.copy(gp.oldpath, gp.path)
                 changed[gp.path] = gp
         else:
             raise util.Abort(_('unsupported parser state: %s') % state)