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