Mercurial > hgsubversion
comparison fetch_command.py @ 77:ed3dd5bf45da
fetch_command: bypass export3() and checkout manually
This method has several advantages:
- export3() does not work very well under Windows, while client.list() and
ra.get_file() do
- File modes are retrieved from get_file() for free, instead of being read from
the filesystem, which does not work under Windows, more generally the
filesystem is bypassed completely.
- It can be made much smarter by checkouting changed files only, like convert
extension does.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Sun, 09 Nov 2008 18:08:35 -0600 |
parents | 6c62bd201785 |
children | 2e47623fa174 |
comparison
equal
deleted
inserted
replaced
76:6c62bd201785 | 77:ed3dd5bf45da |
---|---|
286 if not hg_editor.aresamefiles(sourcectx, parentctx, sources): | 286 if not hg_editor.aresamefiles(sourcectx, parentctx, sources): |
287 continue | 287 continue |
288 hgcopies.update(copies) | 288 hgcopies.update(copies) |
289 return hgcopies | 289 return hgcopies |
290 | 290 |
291 def stupid_fetch_branchrev(svn, hg_editor, branch, branchpath, r, parentid): | |
292 """Extract all 'branch' content at a given revision. | |
293 | |
294 Return a tuple (files, filectxfn) where 'files' is the list of all files | |
295 in the branch at the given revision, and 'filectxfn' is a memctx compatible | |
296 callable to retrieve individual file information. | |
297 """ | |
298 files = [] | |
299 try: | |
300 for path, kind in svn.list_files(branchpath, r.revnum): | |
301 if kind == 'f': | |
302 files.append(path) | |
303 except IOError: | |
304 # Branch does not exist at this revision. Get parent revision and | |
305 # remove everything. | |
306 parentctx = hg_editor.repo[parentid] | |
307 files = parentctx.manifest().keys() | |
308 def filectxfn(repo, memctx, path): | |
309 raise IOError() | |
310 return files, filectxfn | |
311 | |
312 copies = getcopies(svn, hg_editor, branch, branchpath, r, files, parentid) | |
313 | |
314 linkprefix = 'link ' | |
315 def filectxfn(repo, memctx, path): | |
316 data, mode = svn.get_file(branchpath + '/' + path, r.revnum) | |
317 isexec = 'x' in mode | |
318 islink = 'l' in mode | |
319 if islink and data.startswith(linkprefix): | |
320 data = data[len(linkprefix):] | |
321 copied = copies.get(path) | |
322 return context.memfilectx(path=path, data=data, islink=islink, | |
323 isexec=isexec, copied=copied) | |
324 | |
325 return files, filectxfn | |
326 | |
291 def stupid_svn_server_pull_rev(ui, svn, hg_editor, r): | 327 def stupid_svn_server_pull_rev(ui, svn, hg_editor, r): |
292 used_diff = True | |
293 delete_all_files = False | 328 delete_all_files = False |
294 # this server fails at replay | 329 # this server fails at replay |
295 branches = hg_editor.branches_in_paths(r.paths) | 330 branches = hg_editor.branches_in_paths(r.paths) |
296 temp_location = os.path.join(hg_editor.path, '.hg', 'svn', 'temp') | 331 temp_location = os.path.join(hg_editor.path, '.hg', 'svn', 'temp') |
297 if not os.path.exists(temp_location): | 332 if not os.path.exists(temp_location): |
443 link_path = open(path).read() | 478 link_path = open(path).read() |
444 link_path = link_path[len('link '):] | 479 link_path = link_path[len('link '):] |
445 os.remove(path) | 480 os.remove(path) |
446 link_files[m] = link_path | 481 link_files[m] = link_path |
447 files_touched.add(m) | 482 files_touched.add(m) |
448 except core.SubversionException, e: | 483 except (core.SubversionException, BadPatchApply), e: |
449 if (e.apr_err == 160013 or (hasattr(e, 'message') and | 484 if (hasattr(e, 'apr_err') and e.apr_err != 160013): |
450 'was not found in the repository at revision ' in e.message)): | 485 raise |
451 # Either this revision or the previous one does not exist. | 486 # Either this revision or the previous one does not exist. |
452 try: | 487 ui.status("fetching entire rev previous rev does not exist.\n") |
453 ui.status("fetching entire rev previous rev does not exist.\n") | 488 files_touched, filectxfn = stupid_fetch_branchrev( |
454 used_diff = False | 489 svn, hg_editor, b, branches[b], r, parent_ha) |
455 svn.fetch_all_files_to_dir(diff_path, r.revnum, our_tempdir) | 490 else: |
456 except core.SubversionException, e: | 491 for p in r.paths: |
457 if e.apr_err == 170000 or (e.message.startswith("URL '") | 492 if p.startswith(diff_path) and r.paths[p].action == 'D': |
458 and e.message.endswith("' doesn't exist")): | 493 p2 = p[len(diff_path)+1:] |
459 delete_all_files = True | 494 files_touched.add(p2) |
460 else: #pragma: no cover | 495 p3 = os.path.join(our_tempdir, p2) |
461 raise | 496 if os.path.exists(p3) and not os.path.isdir(p3): |
462 | 497 os.unlink(p3) |
463 except BadPatchApply, e: | 498 if p2 and p2[0] == '/': |
464 # previous rev didn't exist, so this is most likely the first | 499 p2 = p2[1:] |
465 # revision. We'll have to pull all files by hand. | 500 # If this isn't in the parent ctx, it must've been a dir |
466 try: | 501 if not p2 in hg_editor.repo[parent_ha]: |
467 ui.status("fetching entire rev because raised.\n") | 502 d_files = [f for f in hg_editor.repo[parent_ha].manifest().iterkeys() |
468 used_diff = False | 503 if f.startswith(p2 + '/')] |
469 shutil.rmtree(our_tempdir) | 504 for d in d_files: |
470 os.makedirs(our_tempdir) | 505 files_touched.add(d) |
471 try: | 506 if delete_all_files: |
472 svn.fetch_all_files_to_dir(diff_path, r.revnum, our_tempdir) | 507 for p in hg_editor.repo[parent_ha].manifest().iterkeys(): |
473 except core.SubversionException, e: | 508 if p: |
474 # apr_err 21 means that we couldn't rename a file to be a dir. | 509 files_touched.add(p) |
475 # This happens only in the case (at least right now) of a file | 510 |
476 # located in brances or tags, which we don't support anyway. | 511 copies = getcopies(svn, hg_editor, b, branches[b], r, files_touched, |
477 if e.apr_err == 21: | 512 parent_ha) |
478 continue | 513 |
479 else: | 514 def filectxfn(repo, memctx, path): |
480 raise | 515 disk_path = os.path.join(our_tempdir, path) |
481 except core.SubversionException, e: | 516 if path in link_files: |
482 if e.apr_err == 170000 or (e.message.startswith("URL '") | 517 return context.memfilectx(path=path, data=link_files[path], |
483 and e.message.endswith("' doesn't exist")): | 518 islink=True, isexec=False, |
484 delete_all_files = True | 519 copied=False) |
485 else: | 520 fp = open(disk_path) |
486 raise | 521 exe = exec_files.get(path, None) |
487 for p in r.paths: | 522 if exe is None and path in hg_editor.repo[parent_ha]: |
488 if p.startswith(diff_path) and r.paths[p].action == 'D': | 523 exe = 'x' in hg_editor.repo[parent_ha].filectx(path).flags() |
489 p2 = p[len(diff_path)+1:] | 524 copied = copies.get(path) |
490 files_touched.add(p2) | 525 return context.memfilectx(path=path, data=fp.read(), islink=False, |
491 p3 = os.path.join(our_tempdir, p2) | 526 isexec=exe, copied=copied) |
492 if os.path.exists(p3) and not os.path.isdir(p3): | |
493 os.unlink(p3) | |
494 if p2 and p2[0] == '/': | |
495 p2 = p2[1:] | |
496 # If this isn't in the parent ctx, it must've been a dir | |
497 if not p2 in hg_editor.repo[parent_ha]: | |
498 d_files = [f for f in hg_editor.repo[parent_ha].manifest().iterkeys() | |
499 if f.startswith(p2 + '/')] | |
500 for d in d_files: | |
501 files_touched.add(d) | |
502 if delete_all_files: | |
503 for p in hg_editor.repo[parent_ha].manifest().iterkeys(): | |
504 if p: | |
505 files_touched.add(p) | |
506 if not used_diff: | |
507 for p in reduce(operator.add, [[os.path.join(x[0], y) for y in x[2]] | |
508 for x in | |
509 list(os.walk(our_tempdir))]): | |
510 p_real = p[len(our_tempdir)+1:] | |
511 if os.path.islink(p): | |
512 link_files[p_real] = os.readlink(p) | |
513 exec_files[p_real] = (os.lstat(p).st_mode & 0100 != 0) | |
514 files_touched.add(p_real) | |
515 for p in hg_editor.repo[parent_ha].manifest().iterkeys(): | |
516 # TODO this might not be a required step. | |
517 if p: | |
518 files_touched.add(p) | |
519 | |
520 copies = getcopies(svn, hg_editor, b, branches[b], r, files_touched, | |
521 parent_ha) | |
522 | 527 |
523 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] | 528 date = r.date.replace('T', ' ').replace('Z', '').split('.')[0] |
524 date += ' -0000' | 529 date += ' -0000' |
525 def filectxfn(repo, memctx, path): | |
526 disk_path = os.path.join(our_tempdir, path) | |
527 if path in link_files: | |
528 return context.memfilectx(path=path, data=link_files[path], | |
529 islink=True, isexec=False, | |
530 copied=False) | |
531 fp = open(disk_path) | |
532 exe = exec_files.get(path, None) | |
533 if exe is None and path in hg_editor.repo[parent_ha]: | |
534 exe = 'x' in hg_editor.repo[parent_ha].filectx(path).flags() | |
535 copied = copies.get(path) | |
536 return context.memfilectx(path=path, data=fp.read(), islink=False, | |
537 isexec=exe, copied=copied) | |
538 extra = {} | 530 extra = {} |
539 if b: | 531 if b: |
540 extra['branch'] = b | 532 extra['branch'] = b |
541 if '' in files_touched: | 533 if '' in files_touched: |
542 files_touched.remove('') | 534 files_touched.remove('') |