--- a/hgext/largefiles/lfcommands.py Sun Nov 17 18:13:55 2013 -0500
+++ b/hgext/largefiles/lfcommands.py Sun Nov 17 20:22:59 2013 -0500
@@ -438,91 +438,93 @@
if filelist is not None:
lfiles = [f for f in lfiles if f in filelist]
- printed = False
- if printmessage and lfiles:
- ui.status(_('getting changed largefiles\n'))
- printed = True
+ update = {}
+ updated, removed = 0, 0
+ for lfile in lfiles:
+ abslfile = repo.wjoin(lfile)
+ absstandin = repo.wjoin(lfutil.standin(lfile))
+ if os.path.exists(absstandin):
+ if (os.path.exists(absstandin + '.orig') and
+ os.path.exists(abslfile)):
+ shutil.copyfile(abslfile, abslfile + '.orig')
+ expecthash = lfutil.readstandin(repo, lfile)
+ if (expecthash != '' and
+ (not os.path.exists(abslfile) or
+ expecthash != lfutil.hashfile(abslfile))):
+ if lfile not in repo[None]: # not switched to normal file
+ util.unlinkpath(abslfile, ignoremissing=True)
+ # use normallookup() to allocate entry in largefiles
+ # dirstate, because lack of it misleads
+ # lfilesrepo.status() into recognition that such cache
+ # missing files are REMOVED.
+ lfdirstate.normallookup(lfile)
+ update[lfile] = expecthash
+ else:
+ # Remove lfiles for which the standin is deleted, unless the
+ # lfile is added to the repository again. This happens when a
+ # largefile is converted back to a normal file: the standin
+ # disappears, but a new (normal) file appears as the lfile.
+ if (os.path.exists(abslfile) and
+ repo.dirstate.normalize(lfile) not in repo[None]):
+ util.unlinkpath(abslfile)
+ removed += 1
+
+ # largefile processing might be slow and be interrupted - be prepared
+ lfdirstate.write()
+
+ if lfiles:
+ if printmessage:
+ ui.status(_('getting changed largefiles\n'))
cachelfiles(ui, repo, None, lfiles)
- updated, removed = 0, 0
- for f in lfiles:
- i = _updatelfile(repo, lfdirstate, f)
- if i:
- if i > 0:
- updated += i
+ for lfile in lfiles:
+ update1 = 0
+
+ expecthash = update.get(lfile)
+ if expecthash:
+ if not lfutil.copyfromcache(repo, expecthash, lfile):
+ # failed ... but already removed and set to normallookup
+ continue
+ # Synchronize largefile dirstate to the last modified
+ # time of the file
+ lfdirstate.normal(lfile)
+ update1 = 1
+
+ # copy the state of largefile standin from the repository's
+ # dirstate to its state in the lfdirstate.
+ abslfile = repo.wjoin(lfile)
+ absstandin = repo.wjoin(lfutil.standin(lfile))
+ if os.path.exists(absstandin):
+ mode = os.stat(absstandin).st_mode
+ if mode != os.stat(abslfile).st_mode:
+ os.chmod(abslfile, mode)
+ update1 = 1
+
+ updated += update1
+
+ state = repo.dirstate[lfutil.standin(lfile)]
+ if state == 'n':
+ # When rebasing, we need to synchronize the standin and the
+ # largefile, because otherwise the largefile will get reverted.
+ # But for commit's sake, we have to mark the file as unclean.
+ if getattr(repo, "_isrebasing", False):
+ lfdirstate.normallookup(lfile)
else:
- removed -= i
- if printmessage and (removed or updated) and not printed:
- ui.status(_('getting changed largefiles\n'))
- printed = True
+ lfdirstate.normal(lfile)
+ elif state == 'r':
+ lfdirstate.remove(lfile)
+ elif state == 'a':
+ lfdirstate.add(lfile)
+ elif state == '?':
+ lfdirstate.drop(lfile)
lfdirstate.write()
- if printed and printmessage:
+ if printmessage and lfiles:
ui.status(_('%d largefiles updated, %d removed\n') % (updated,
removed))
finally:
wlock.release()
-def _updatelfile(repo, lfdirstate, lfile):
- '''updates a single largefile and copies the state of its standin from
- the repository's dirstate to its state in the lfdirstate.
-
- returns 1 if the file was modified, -1 if the file was removed, 0 if the
- file was unchanged, and None if the needed largefile was missing from the
- cache.'''
- ret = 0
- abslfile = repo.wjoin(lfile)
- absstandin = repo.wjoin(lfutil.standin(lfile))
- if os.path.exists(absstandin):
- if os.path.exists(absstandin + '.orig') and os.path.exists(abslfile):
- shutil.copyfile(abslfile, abslfile + '.orig')
- expecthash = lfutil.readstandin(repo, lfile)
- if (expecthash != '' and
- (not os.path.exists(abslfile) or
- expecthash != lfutil.hashfile(abslfile))):
- if not lfutil.copyfromcache(repo, expecthash, lfile):
- # use normallookup() to allocate entry in largefiles dirstate,
- # because lack of it misleads lfilesrepo.status() into
- # recognition that such cache missing files are REMOVED.
- if lfile not in repo[None]: # not switched to normal file
- util.unlinkpath(abslfile, ignoremissing=True)
- lfdirstate.normallookup(lfile)
- return None # don't try to set the mode
- else:
- # Synchronize largefile dirstate to the last modified time of
- # the file
- lfdirstate.normal(lfile)
- ret = 1
- mode = os.stat(absstandin).st_mode
- if mode != os.stat(abslfile).st_mode:
- os.chmod(abslfile, mode)
- ret = 1
- else:
- # Remove lfiles for which the standin is deleted, unless the
- # lfile is added to the repository again. This happens when a
- # largefile is converted back to a normal file: the standin
- # disappears, but a new (normal) file appears as the lfile.
- if (os.path.exists(abslfile) and
- repo.dirstate.normalize(lfile) not in repo[None]):
- util.unlinkpath(abslfile)
- ret = -1
- state = repo.dirstate[lfutil.standin(lfile)]
- if state == 'n':
- # When rebasing, we need to synchronize the standin and the largefile,
- # because otherwise the largefile will get reverted. But for commit's
- # sake, we have to mark the file as unclean.
- if getattr(repo, "_isrebasing", False):
- lfdirstate.normallookup(lfile)
- else:
- lfdirstate.normal(lfile)
- elif state == 'r':
- lfdirstate.remove(lfile)
- elif state == 'a':
- lfdirstate.add(lfile)
- elif state == '?':
- lfdirstate.drop(lfile)
- return ret
-
def lfpull(ui, repo, source="default", **opts):
"""pull largefiles for the specified revisions from the specified source
--- a/hgext/shelve.py Sun Nov 17 18:13:55 2013 -0500
+++ b/hgext/shelve.py Sun Nov 17 20:22:59 2013 -0500
@@ -610,7 +610,7 @@
# but it doesn't update the inmemory structures, so addchangegroup
# hooks still fire and try to operate on the missing commits.
# Clean up manually to prevent this.
- repo.changelog.strip(oldtiprev, tr)
+ repo.unfiltered().changelog.strip(oldtiprev, tr)
unshelvecleanup(ui, repo, basename, opts)
finally:
--- a/tests/test-largefiles-small-disk.t Sun Nov 17 18:13:55 2013 -0500
+++ b/tests/test-largefiles-small-disk.t Sun Nov 17 20:22:59 2013 -0500
@@ -64,3 +64,4 @@
The largefile is not created in .hg/largefiles:
$ ls bob/.hg/largefiles
+ dirstate
--- a/tests/test-shelve.t Sun Nov 17 18:13:55 2013 -0500
+++ b/tests/test-shelve.t Sun Nov 17 20:22:59 2013 -0500
@@ -520,4 +520,23 @@
$ hg status
A d
+test bug 4073 we need to enable obsolete markers for it
+
+ $ cat > ../obs.py << EOF
+ > import mercurial.obsolete
+ > mercurial.obsolete._enabled = True
+ > EOF
+ $ echo '[extensions]' >> $HGRCPATH
+ $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
+ $ hg shelve
+ shelved as default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg debugobsolete `hg --debug id -i -r 1`
+ $ hg unshelve
+ unshelving change 'default'
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 2 files (+1 heads)
+
$ cd ..