Mercurial > hg-stable
comparison hgext/convert/subversion.py @ 16511:ecd2fbe68b25 stable
convert/svn: make svn sink work with svn 1.7
"svn add file" now fails if "file" is already tracked. To filter them we have
to mirror the svn manifest in the sink.
Tested with svn 1.6.12 and 1.7.4.
author | Patrick Mezard <patrick@mezard.eu> |
---|---|
date | Tue, 24 Apr 2012 12:50:41 +0200 |
parents | c53a49c345e1 |
children | 363e808de349 |
comparison
equal
deleted
inserted
replaced
16510:c7c9473fcc46 | 16511:ecd2fbe68b25 |
---|---|
1 # Subversion 1.4/1.5 Python API backend | 1 # Subversion 1.4/1.5 Python API backend |
2 # | 2 # |
3 # Copyright(C) 2007 Daniel Holth et al | 3 # Copyright(C) 2007 Daniel Holth et al |
4 | 4 |
5 import os | 5 import os, re, sys, tempfile, urllib, urllib2, xml.dom.minidom |
6 import re | |
7 import sys | |
8 import cPickle as pickle | 6 import cPickle as pickle |
9 import tempfile | |
10 import urllib | |
11 import urllib2 | |
12 | 7 |
13 from mercurial import strutil, scmutil, util, encoding | 8 from mercurial import strutil, scmutil, util, encoding |
14 from mercurial.i18n import _ | 9 from mercurial.i18n import _ |
10 | |
11 propertycache = util.propertycache | |
15 | 12 |
16 # Subversion stuff. Works best with very recent Python SVN bindings | 13 # Subversion stuff. Works best with very recent Python SVN bindings |
17 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing | 14 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing |
18 # these bindings. | 15 # these bindings. |
19 | 16 |
1055 self.uuid = self.uuid_re.search(output).group(1).strip() | 1052 self.uuid = self.uuid_re.search(output).group(1).strip() |
1056 | 1053 |
1057 def wjoin(self, *names): | 1054 def wjoin(self, *names): |
1058 return os.path.join(self.wc, *names) | 1055 return os.path.join(self.wc, *names) |
1059 | 1056 |
1057 @propertycache | |
1058 def manifest(self): | |
1059 # As of svn 1.7, the "add" command fails when receiving | |
1060 # already tracked entries, so we have to track and filter them | |
1061 # ourselves. | |
1062 m = set() | |
1063 output = self.run0('ls', recursive=True, xml=True) | |
1064 doc = xml.dom.minidom.parseString(output) | |
1065 for e in doc.getElementsByTagName('entry'): | |
1066 for n in e.childNodes: | |
1067 if n.nodeType != n.ELEMENT_NODE or n.tagName != 'name': | |
1068 continue | |
1069 name = ''.join(c.data for c in n.childNodes | |
1070 if c.nodeType == c.TEXT_NODE) | |
1071 # Entries are compared with names coming from | |
1072 # mercurial, so bytes with undefined encoding. Our | |
1073 # best bet is to assume they are in local | |
1074 # encoding. They will be passed to command line calls | |
1075 # later anyway, so they better be. | |
1076 m.add(encoding.tolocal(name.encode('utf-8'))) | |
1077 break | |
1078 return m | |
1079 | |
1060 def putfile(self, filename, flags, data): | 1080 def putfile(self, filename, flags, data): |
1061 if 'l' in flags: | 1081 if 'l' in flags: |
1062 self.wopener.symlink(data, filename) | 1082 self.wopener.symlink(data, filename) |
1063 else: | 1083 else: |
1064 try: | 1084 try: |
1097 os.unlink(tempname) | 1117 os.unlink(tempname) |
1098 os.rename(wdest, tempname) | 1118 os.rename(wdest, tempname) |
1099 try: | 1119 try: |
1100 self.run0('copy', source, dest) | 1120 self.run0('copy', source, dest) |
1101 finally: | 1121 finally: |
1122 self.manifest.add(dest) | |
1102 if exists: | 1123 if exists: |
1103 try: | 1124 try: |
1104 os.unlink(wdest) | 1125 os.unlink(wdest) |
1105 except OSError: | 1126 except OSError: |
1106 pass | 1127 pass |
1115 dirs.add(f[:i]) | 1136 dirs.add(f[:i]) |
1116 return dirs | 1137 return dirs |
1117 | 1138 |
1118 def add_dirs(self, files): | 1139 def add_dirs(self, files): |
1119 add_dirs = [d for d in sorted(self.dirs_of(files)) | 1140 add_dirs = [d for d in sorted(self.dirs_of(files)) |
1120 if not os.path.exists(self.wjoin(d, '.svn', 'entries'))] | 1141 if d not in self.manifest] |
1121 if add_dirs: | 1142 if add_dirs: |
1143 self.manifest.update(add_dirs) | |
1122 self.xargs(add_dirs, 'add', non_recursive=True, quiet=True) | 1144 self.xargs(add_dirs, 'add', non_recursive=True, quiet=True) |
1123 return add_dirs | 1145 return add_dirs |
1124 | 1146 |
1125 def add_files(self, files): | 1147 def add_files(self, files): |
1148 files = [f for f in files if f not in self.manifest] | |
1126 if files: | 1149 if files: |
1150 self.manifest.update(files) | |
1127 self.xargs(files, 'add', quiet=True) | 1151 self.xargs(files, 'add', quiet=True) |
1128 return files | 1152 return files |
1129 | 1153 |
1130 def tidy_dirs(self, names): | 1154 def tidy_dirs(self, names): |
1131 deleted = [] | 1155 deleted = [] |
1132 for d in sorted(self.dirs_of(names), reverse=True): | 1156 for d in sorted(self.dirs_of(names), reverse=True): |
1133 wd = self.wjoin(d) | 1157 wd = self.wjoin(d) |
1134 if os.listdir(wd) == '.svn': | 1158 if os.listdir(wd) == '.svn': |
1135 self.run0('delete', d) | 1159 self.run0('delete', d) |
1160 self.manifest.remove(d) | |
1136 deleted.append(d) | 1161 deleted.append(d) |
1137 return deleted | 1162 return deleted |
1138 | 1163 |
1139 def addchild(self, parent, child): | 1164 def addchild(self, parent, child): |
1140 self.childmap[parent] = child | 1165 self.childmap[parent] = child |
1168 for s, d in self.copies: | 1193 for s, d in self.copies: |
1169 self._copyfile(s, d) | 1194 self._copyfile(s, d) |
1170 self.copies = [] | 1195 self.copies = [] |
1171 if self.delete: | 1196 if self.delete: |
1172 self.xargs(self.delete, 'delete') | 1197 self.xargs(self.delete, 'delete') |
1198 for f in self.delete: | |
1199 self.manifest.remove(f) | |
1173 self.delete = [] | 1200 self.delete = [] |
1174 entries.update(self.add_files(files.difference(entries))) | 1201 entries.update(self.add_files(files.difference(entries))) |
1175 entries.update(self.tidy_dirs(entries)) | 1202 entries.update(self.tidy_dirs(entries)) |
1176 if self.delexec: | 1203 if self.delexec: |
1177 self.xargs(self.delexec, 'propdel', 'svn:executable') | 1204 self.xargs(self.delexec, 'propdel', 'svn:executable') |