hgext/convert/subversion.py
branchstable
changeset 16511 ecd2fbe68b25
parent 16466 c53a49c345e1
child 16514 363e808de349
--- a/hgext/convert/subversion.py	Wed Apr 25 23:28:54 2012 +0200
+++ b/hgext/convert/subversion.py	Tue Apr 24 12:50:41 2012 +0200
@@ -2,17 +2,14 @@
 #
 # Copyright(C) 2007 Daniel Holth et al
 
-import os
-import re
-import sys
+import os, re, sys, tempfile, urllib, urllib2, xml.dom.minidom
 import cPickle as pickle
-import tempfile
-import urllib
-import urllib2
 
 from mercurial import strutil, scmutil, util, encoding
 from mercurial.i18n import _
 
+propertycache = util.propertycache
+
 # Subversion stuff. Works best with very recent Python SVN bindings
 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing
 # these bindings.
@@ -1057,6 +1054,29 @@
     def wjoin(self, *names):
         return os.path.join(self.wc, *names)
 
+    @propertycache
+    def manifest(self):
+        # As of svn 1.7, the "add" command fails when receiving
+        # already tracked entries, so we have to track and filter them
+        # ourselves.
+        m = set()
+        output = self.run0('ls', recursive=True, xml=True)
+        doc = xml.dom.minidom.parseString(output)
+        for e in doc.getElementsByTagName('entry'):
+            for n in e.childNodes:
+                if n.nodeType != n.ELEMENT_NODE or n.tagName != 'name':
+                    continue
+                name = ''.join(c.data for c in n.childNodes
+                               if c.nodeType == c.TEXT_NODE)
+                # Entries are compared with names coming from
+                # mercurial, so bytes with undefined encoding. Our
+                # best bet is to assume they are in local
+                # encoding. They will be passed to command line calls
+                # later anyway, so they better be.
+                m.add(encoding.tolocal(name.encode('utf-8')))
+                break
+        return m
+
     def putfile(self, filename, flags, data):
         if 'l' in flags:
             self.wopener.symlink(data, filename)
@@ -1099,6 +1119,7 @@
         try:
             self.run0('copy', source, dest)
         finally:
+            self.manifest.add(dest)
             if exists:
                 try:
                     os.unlink(wdest)
@@ -1117,13 +1138,16 @@
 
     def add_dirs(self, files):
         add_dirs = [d for d in sorted(self.dirs_of(files))
-                    if not os.path.exists(self.wjoin(d, '.svn', 'entries'))]
+                    if d not in self.manifest]
         if add_dirs:
+            self.manifest.update(add_dirs)
             self.xargs(add_dirs, 'add', non_recursive=True, quiet=True)
         return add_dirs
 
     def add_files(self, files):
+        files = [f for f in files if f not in self.manifest]
         if files:
+            self.manifest.update(files)
             self.xargs(files, 'add', quiet=True)
         return files
 
@@ -1133,6 +1157,7 @@
             wd = self.wjoin(d)
             if os.listdir(wd) == '.svn':
                 self.run0('delete', d)
+                self.manifest.remove(d)
                 deleted.append(d)
         return deleted
 
@@ -1170,6 +1195,8 @@
             self.copies = []
         if self.delete:
             self.xargs(self.delete, 'delete')
+            for f in self.delete:
+                self.manifest.remove(f)
             self.delete = []
         entries.update(self.add_files(files.difference(entries)))
         entries.update(self.tidy_dirs(entries))