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('') |
