Show More
@@ -15,7 +15,8 | |||
|
15 | 15 | |
|
16 | 16 | import pprint |
|
17 | 17 | import locale |
|
18 | ||
|
18 | import os | |
|
19 | import cPickle as pickle | |
|
19 | 20 | from mercurial import util |
|
20 | 21 | |
|
21 | 22 | # Subversion stuff. Works best with very recent Python SVN bindings |
@@ -38,6 +39,12 except ImportError: | |||
|
38 | 39 | |
|
39 | 40 | class CompatibilityException(Exception): pass |
|
40 | 41 | |
|
42 | class changedpath(object): | |
|
43 | def __init__(self, p): | |
|
44 | self.copyfrom_path = p.copyfrom_path | |
|
45 | self.copyfrom_rev = p.copyfrom_rev | |
|
46 | self.action = p.action | |
|
47 | ||
|
41 | 48 | # SVN conversion code stolen from bzr-svn and tailor |
|
42 | 49 | class convert_svn(converter_source): |
|
43 | 50 | def __init__(self, ui, url, rev=None): |
@@ -73,7 +80,7 class convert_svn(converter_source): | |||
|
73 | 80 | try: |
|
74 | 81 |
self.transport = transport.SvnRaTransport(url |
|
75 | 82 | self.ra = self.transport.ra |
|
76 |
self.ctx = s |
|
|
83 | self.ctx = self.transport.client | |
|
77 | 84 | self.base = svn.ra.get_repos_root(self.ra) |
|
78 | 85 | self.module = self.url[len(self.base):] |
|
79 | 86 | self.modulemap = {} # revision, module |
@@ -174,10 +181,65 class convert_svn(converter_source): | |||
|
174 | 181 | del self.commits[rev] |
|
175 | 182 | return commit |
|
176 | 183 | |
|
184 | def get_log(self, paths, start, end, limit=0, discover_changed_paths=True, | |
|
185 | strict_node_history=False): | |
|
186 | '''wrapper for svn.ra.get_log. | |
|
187 | on a large repository, svn.ra.get_log pins huge amounts of | |
|
188 | memory that cannot be recovered. work around it by forking | |
|
189 | and writing results over a pipe.''' | |
|
190 | ||
|
191 | def child(fp): | |
|
192 | protocol = -1 | |
|
193 | def receiver(orig_paths, revnum, author, date, message, pool): | |
|
194 | if orig_paths is not None: | |
|
195 | for k, v in orig_paths.iteritems(): | |
|
196 | orig_paths[k] = changedpath(v) | |
|
197 | pickle.dump((orig_paths, revnum, author, date, message), | |
|
198 | fp, protocol) | |
|
199 | ||
|
200 | try: | |
|
201 | # Use an ra of our own so that our parent can consume | |
|
202 | # our results without confusing the server. | |
|
203 | t = transport.SvnRaTransport(url=self.url) | |
|
204 | svn.ra.get_log(t.ra, paths, start, end, limit, | |
|
205 | discover_changed_paths, | |
|
206 | strict_node_history, | |
|
207 | receiver) | |
|
208 | except SubversionException, (_, num): | |
|
209 | pickle.dump(num, fp, protocol) | |
|
210 | else: | |
|
211 | pickle.dump(None, fp, protocol) | |
|
212 | fp.close() | |
|
213 | ||
|
214 | def parent(fp): | |
|
215 | while True: | |
|
216 | entry = pickle.load(fp) | |
|
217 | try: | |
|
218 | orig_paths, revnum, author, date, message = entry | |
|
219 | except: | |
|
220 | if entry is None: | |
|
221 | break | |
|
222 | raise SubversionException("child raised exception", entry) | |
|
223 | yield entry | |
|
224 | ||
|
225 | rfd, wfd = os.pipe() | |
|
226 | pid = os.fork() | |
|
227 | if pid: | |
|
228 | os.close(wfd) | |
|
229 | for p in parent(os.fdopen(rfd, 'rb')): | |
|
230 | yield p | |
|
231 | ret = os.waitpid(pid, 0)[1] | |
|
232 | if ret: | |
|
233 | raise util.Abort(_('get_log %s') % util.explain_exit(ret)) | |
|
234 | else: | |
|
235 | os.close(rfd) | |
|
236 | child(os.fdopen(wfd, 'wb')) | |
|
237 | os._exit(0) | |
|
238 | ||
|
177 | 239 | def gettags(self): |
|
178 | 240 | tags = {} |
|
179 | def parselogentry(*arg, **args): | |
|
180 |
orig_paths, revnum, author, date, message |
|
|
241 | for entry in self.get_log(['/tags'], 0, self.revnum(self.head)): | |
|
242 | orig_paths, revnum, author, date, message = entry | |
|
181 | 243 | for path in orig_paths: |
|
182 | 244 | if not path.startswith('/tags/'): |
|
183 | 245 | continue |
@@ -186,15 +248,7 class convert_svn(converter_source): | |||
|
186 | 248 | rev = ent.copyfrom_rev |
|
187 | 249 | tag = path.split('/', 2)[2] |
|
188 | 250 | tags[tag] = self.revid(rev, module=source) |
|
189 | ||
|
190 | start = self.revnum(self.head) | |
|
191 | try: | |
|
192 | svn.ra.get_log(self.ra, ['/tags'], 0, start, 0, True, False, | |
|
193 | parselogentry) | |
|
194 | 251 |
|
|
195 | except SubversionException: | |
|
196 | self.ui.note('no tags found at revision %d\n' % start) | |
|
197 | return {} | |
|
198 | 252 | |
|
199 | 253 | # -- helper functions -- |
|
200 | 254 | |
@@ -276,23 +330,10 class convert_svn(converter_source): | |||
|
276 | 330 | self.ui.debug('Ignoring %r since it is not under %r\n' % (path, module)) |
|
277 | 331 | return None |
|
278 | 332 | |
|
279 | received = [] | |
|
280 | # svn.ra.get_log requires no other calls to the ra until it completes, | |
|
281 | # so we just collect the log entries and parse them afterwards | |
|
282 | def receivelog(orig_paths, revnum, author, date, message, pool): | |
|
283 | if self.is_blacklisted(revnum): | |
|
284 | self.ui.note('skipping blacklisted revision %d\n' % revnum) | |
|
285 | return | |
|
286 | ||
|
287 | if orig_paths is None: | |
|
288 | self.ui.debug('revision %d has no entries\n' % revnum) | |
|
289 | return | |
|
290 | ||
|
291 | received.append((revnum, orig_paths.items(), author, date, message)) | |
|
292 | ||
|
293 | 333 | self.child_cset = None |
|
294 |
def parselogentry( |
|
|
295 |
self.ui.debug("parsing revision %d\n" % |
|
|
334 | def parselogentry(orig_paths, revnum, author, date, message): | |
|
335 | self.ui.debug("parsing revision %d (%d changes)\n" % | |
|
336 | (revnum, len(orig_paths))) | |
|
296 | 337 | |
|
297 | 338 | if revnum in self.modulemap: |
|
298 | 339 | new_module = self.modulemap[revnum] |
@@ -318,6 +359,7 class convert_svn(converter_source): | |||
|
318 | 359 | except IndexError: |
|
319 | 360 | branch = None |
|
320 | 361 | |
|
362 | orig_paths = orig_paths.items() | |
|
321 | 363 | orig_paths.sort() |
|
322 | 364 | for path, ent in orig_paths: |
|
323 | 365 | # self.ui.write("path %s\n" % path) |
@@ -527,13 +569,15 class convert_svn(converter_source): | |||
|
527 | 569 | try: |
|
528 | 570 | discover_changed_paths = True |
|
529 | 571 | strict_node_history = False |
|
530 |
|
|
|
531 | discover_changed_paths, strict_node_history, | |
|
532 | receivelog) | |
|
533 | self.ui.note('parsing %d log entries for "%s"\n' % | |
|
534 | (len(received), self.module)) | |
|
535 | for entry in received: | |
|
536 | parselogentry(entry) | |
|
572 | for entry in self.get_log([self.module], from_revnum, to_revnum): | |
|
573 | orig_paths, revnum, author, date, message = entry | |
|
574 | if self.is_blacklisted(revnum): | |
|
575 | self.ui.note('skipping blacklisted revision %d\n' % revnum) | |
|
576 | continue | |
|
577 | if orig_paths is None: | |
|
578 | self.ui.debug('revision %d has no entries\n' % revnum) | |
|
579 | continue | |
|
580 | parselogentry(orig_paths, revnum, author, date, message) | |
|
537 | 581 | except SubversionException, (_, num): |
|
538 | 582 | if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: |
|
539 | 583 | raise NoSuchRevision(branch=self, |
General Comments 0
You need to be logged in to leave comments.
Login now