442 if printmessage: |
442 if printmessage: |
443 ui.status(_('getting changed largefiles\n')) |
443 ui.status(_('getting changed largefiles\n')) |
444 cachelfiles(ui, repo, None, lfiles) |
444 cachelfiles(ui, repo, None, lfiles) |
445 |
445 |
446 updated, removed = 0, 0 |
446 updated, removed = 0, 0 |
447 for f in lfiles: |
447 for lfile in lfiles: |
448 i = _updatelfile(repo, lfdirstate, f) |
448 # updates a single largefile and copies the state of its standin from |
449 if i: |
449 # the repository's dirstate to its state in the lfdirstate. |
450 if i > 0: |
450 abslfile = repo.wjoin(lfile) |
451 updated += i |
451 absstandin = repo.wjoin(lfutil.standin(lfile)) |
|
452 if os.path.exists(absstandin): |
|
453 if (os.path.exists(absstandin + '.orig') and |
|
454 os.path.exists(abslfile)): |
|
455 shutil.copyfile(abslfile, abslfile + '.orig') |
|
456 update1 = 0 |
|
457 expecthash = lfutil.readstandin(repo, lfile) |
|
458 if (expecthash != '' and |
|
459 (not os.path.exists(abslfile) or |
|
460 expecthash != lfutil.hashfile(abslfile))): |
|
461 if not lfutil.copyfromcache(repo, expecthash, lfile): |
|
462 # use normallookup() to allocate entry in largefiles |
|
463 # dirstate, because lack of it misleads |
|
464 # lfilesrepo.status() into recognition that such cache |
|
465 # missing files are REMOVED. |
|
466 if lfile not in repo[None]: # not switched to normal |
|
467 util.unlinkpath(abslfile, ignoremissing=True) |
|
468 lfdirstate.normallookup(lfile) |
|
469 continue # don't try to set the mode |
|
470 else: |
|
471 # Synchronize largefile dirstate to the last modified |
|
472 # time of the file |
|
473 lfdirstate.normal(lfile) |
|
474 update1 = 1 |
|
475 mode = os.stat(absstandin).st_mode |
|
476 if mode != os.stat(abslfile).st_mode: |
|
477 os.chmod(abslfile, mode) |
|
478 update1 = 1 |
|
479 updated += update1 |
|
480 else: |
|
481 # Remove lfiles for which the standin is deleted, unless the |
|
482 # lfile is added to the repository again. This happens when a |
|
483 # largefile is converted back to a normal file: the standin |
|
484 # disappears, but a new (normal) file appears as the lfile. |
|
485 if (os.path.exists(abslfile) and |
|
486 repo.dirstate.normalize(lfile) not in repo[None]): |
|
487 util.unlinkpath(abslfile) |
|
488 removed += 1 |
|
489 state = repo.dirstate[lfutil.standin(lfile)] |
|
490 if state == 'n': |
|
491 # When rebasing, we need to synchronize the standin and the |
|
492 # largefile, because otherwise the largefile will get reverted. |
|
493 # But for commit's sake, we have to mark the file as unclean. |
|
494 if getattr(repo, "_isrebasing", False): |
|
495 lfdirstate.normallookup(lfile) |
452 else: |
496 else: |
453 removed -= i |
497 lfdirstate.normal(lfile) |
|
498 elif state == 'r': |
|
499 lfdirstate.remove(lfile) |
|
500 elif state == 'a': |
|
501 lfdirstate.add(lfile) |
|
502 elif state == '?': |
|
503 lfdirstate.drop(lfile) |
454 |
504 |
455 lfdirstate.write() |
505 lfdirstate.write() |
456 if printmessage and lfiles: |
506 if printmessage and lfiles: |
457 ui.status(_('%d largefiles updated, %d removed\n') % (updated, |
507 ui.status(_('%d largefiles updated, %d removed\n') % (updated, |
458 removed)) |
508 removed)) |
459 finally: |
509 finally: |
460 wlock.release() |
510 wlock.release() |
461 |
|
462 def _updatelfile(repo, lfdirstate, lfile): |
|
463 '''updates a single largefile and copies the state of its standin from |
|
464 the repository's dirstate to its state in the lfdirstate. |
|
465 |
|
466 returns 1 if the file was modified, -1 if the file was removed, 0 if the |
|
467 file was unchanged, and None if the needed largefile was missing from the |
|
468 cache.''' |
|
469 ret = 0 |
|
470 abslfile = repo.wjoin(lfile) |
|
471 absstandin = repo.wjoin(lfutil.standin(lfile)) |
|
472 if os.path.exists(absstandin): |
|
473 if os.path.exists(absstandin + '.orig') and os.path.exists(abslfile): |
|
474 shutil.copyfile(abslfile, abslfile + '.orig') |
|
475 expecthash = lfutil.readstandin(repo, lfile) |
|
476 if (expecthash != '' and |
|
477 (not os.path.exists(abslfile) or |
|
478 expecthash != lfutil.hashfile(abslfile))): |
|
479 if not lfutil.copyfromcache(repo, expecthash, lfile): |
|
480 # use normallookup() to allocate entry in largefiles dirstate, |
|
481 # because lack of it misleads lfilesrepo.status() into |
|
482 # recognition that such cache missing files are REMOVED. |
|
483 if lfile not in repo[None]: # not switched to normal file |
|
484 util.unlinkpath(abslfile, ignoremissing=True) |
|
485 lfdirstate.normallookup(lfile) |
|
486 return None # don't try to set the mode |
|
487 else: |
|
488 # Synchronize largefile dirstate to the last modified time of |
|
489 # the file |
|
490 lfdirstate.normal(lfile) |
|
491 ret = 1 |
|
492 mode = os.stat(absstandin).st_mode |
|
493 if mode != os.stat(abslfile).st_mode: |
|
494 os.chmod(abslfile, mode) |
|
495 ret = 1 |
|
496 else: |
|
497 # Remove lfiles for which the standin is deleted, unless the |
|
498 # lfile is added to the repository again. This happens when a |
|
499 # largefile is converted back to a normal file: the standin |
|
500 # disappears, but a new (normal) file appears as the lfile. |
|
501 if (os.path.exists(abslfile) and |
|
502 repo.dirstate.normalize(lfile) not in repo[None]): |
|
503 util.unlinkpath(abslfile) |
|
504 ret = -1 |
|
505 state = repo.dirstate[lfutil.standin(lfile)] |
|
506 if state == 'n': |
|
507 # When rebasing, we need to synchronize the standin and the largefile, |
|
508 # because otherwise the largefile will get reverted. But for commit's |
|
509 # sake, we have to mark the file as unclean. |
|
510 if getattr(repo, "_isrebasing", False): |
|
511 lfdirstate.normallookup(lfile) |
|
512 else: |
|
513 lfdirstate.normal(lfile) |
|
514 elif state == 'r': |
|
515 lfdirstate.remove(lfile) |
|
516 elif state == 'a': |
|
517 lfdirstate.add(lfile) |
|
518 elif state == '?': |
|
519 lfdirstate.drop(lfile) |
|
520 return ret |
|
521 |
511 |
522 def lfpull(ui, repo, source="default", **opts): |
512 def lfpull(ui, repo, source="default", **opts): |
523 """pull largefiles for the specified revisions from the specified source |
513 """pull largefiles for the specified revisions from the specified source |
524 |
514 |
525 Pull largefiles that are referenced from local changesets but missing |
515 Pull largefiles that are referenced from local changesets but missing |