Patchwork D11107: largefile: consider `updatelfiles` as a `parentchange`

login
register
mail settings
Submitter phabricator
Date July 18, 2021, 9:53 p.m.
Message ID <differential-rev-PHID-DREV-77clc7eu5e3t3um6kp23-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49420/
State Superseded
Headers show

Comments

phabricator - July 18, 2021, 9:53 p.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  This is not strictly a `parentchange`, however this is still some internal
  dirstate adjustment as "similar" enough that it seems find to do so.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11107

AFFECTED FILES
  hgext/largefiles/lfcommands.py

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/hgext/largefiles/lfcommands.py b/hgext/largefiles/lfcommands.py
--- a/hgext/largefiles/lfcommands.py
+++ b/hgext/largefiles/lfcommands.py
@@ -519,96 +519,98 @@ 
             filelist = set(filelist)
             lfiles = [f for f in lfiles if f in filelist]
 
-        update = {}
-        dropped = set()
-        updated, removed = 0, 0
-        wvfs = repo.wvfs
-        wctx = repo[None]
-        for lfile in lfiles:
-            lfileorig = os.path.relpath(
-                scmutil.backuppath(ui, repo, lfile), start=repo.root
-            )
-            standin = lfutil.standin(lfile)
-            standinorig = os.path.relpath(
-                scmutil.backuppath(ui, repo, standin), start=repo.root
-            )
-            if wvfs.exists(standin):
-                if wvfs.exists(standinorig) and wvfs.exists(lfile):
-                    shutil.copyfile(wvfs.join(lfile), wvfs.join(lfileorig))
-                    wvfs.unlinkpath(standinorig)
-                expecthash = lfutil.readasstandin(wctx[standin])
-                if expecthash != b'':
-                    if lfile not in wctx:  # not switched to normal file
-                        if repo.dirstate[standin] != b'?':
-                            wvfs.unlinkpath(lfile, ignoremissing=True)
-                        else:
-                            dropped.add(lfile)
+        with lfdirstate.parentchange():
+            update = {}
+            dropped = set()
+            updated, removed = 0, 0
+            wvfs = repo.wvfs
+            wctx = repo[None]
+            for lfile in lfiles:
+                lfileorig = os.path.relpath(
+                    scmutil.backuppath(ui, repo, lfile), start=repo.root
+                )
+                standin = lfutil.standin(lfile)
+                standinorig = os.path.relpath(
+                    scmutil.backuppath(ui, repo, standin), start=repo.root
+                )
+                if wvfs.exists(standin):
+                    if wvfs.exists(standinorig) and wvfs.exists(lfile):
+                        shutil.copyfile(wvfs.join(lfile), wvfs.join(lfileorig))
+                        wvfs.unlinkpath(standinorig)
+                    expecthash = lfutil.readasstandin(wctx[standin])
+                    if expecthash != b'':
+                        if lfile not in wctx:  # not switched to normal file
+                            if repo.dirstate[standin] != b'?':
+                                wvfs.unlinkpath(lfile, ignoremissing=True)
+                            else:
+                                dropped.add(lfile)
 
-                    # use normallookup() to allocate an entry in largefiles
-                    # dirstate to prevent lfilesrepo.status() from reporting
-                    # missing files as 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 (
-                    wvfs.exists(lfile)
-                    and repo.dirstate.normalize(lfile) not in wctx
-                ):
-                    wvfs.unlinkpath(lfile)
-                    removed += 1
+                        # use normallookup() to allocate an entry in largefiles
+                        # dirstate to prevent lfilesrepo.status() from reporting
+                        # missing files as 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 (
+                        wvfs.exists(lfile)
+                        and repo.dirstate.normalize(lfile) not in wctx
+                    ):
+                        wvfs.unlinkpath(lfile)
+                        removed += 1
 
         # largefile processing might be slow and be interrupted - be prepared
         lfdirstate.write()
 
-        if lfiles:
-            lfiles = [f for f in lfiles if f not in dropped]
-
-            for f in dropped:
-                repo.wvfs.unlinkpath(lfutil.standin(f))
+        with lfdirstate.parentchange():
+            if lfiles:
+                lfiles = [f for f in lfiles if f not in dropped]
 
-                # This needs to happen for dropped files, otherwise they stay in
-                # the M state.
-                lfutil.synclfdirstate(repo, lfdirstate, f, normallookup)
+                for f in dropped:
+                    repo.wvfs.unlinkpath(lfutil.standin(f))
 
-            statuswriter(_(b'getting changed largefiles\n'))
-            cachelfiles(ui, repo, None, lfiles)
-
-        for lfile in lfiles:
-            update1 = 0
+                    # This needs to happen for dropped files, otherwise they stay in
+                    # the M state.
+                    lfutil.synclfdirstate(repo, lfdirstate, f, normallookup)
 
-            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
+                statuswriter(_(b'getting changed largefiles\n'))
+                cachelfiles(ui, repo, None, lfiles)
+
+            for lfile in lfiles:
+                update1 = 0
 
-            # copy the exec mode of largefile standin from the repository's
-            # dirstate to its state in the lfdirstate.
-            standin = lfutil.standin(lfile)
-            if wvfs.exists(standin):
-                # exec is decided by the users permissions using mask 0o100
-                standinexec = wvfs.stat(standin).st_mode & 0o100
-                st = wvfs.stat(lfile)
-                mode = st.st_mode
-                if standinexec != mode & 0o100:
-                    # first remove all X bits, then shift all R bits to X
-                    mode &= ~0o111
-                    if standinexec:
-                        mode |= (mode >> 2) & 0o111 & ~util.umask
-                    wvfs.chmod(lfile, mode)
+                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
 
-            updated += update1
+                # copy the exec mode of largefile standin from the repository's
+                # dirstate to its state in the lfdirstate.
+                standin = lfutil.standin(lfile)
+                if wvfs.exists(standin):
+                    # exec is decided by the users permissions using mask 0o100
+                    standinexec = wvfs.stat(standin).st_mode & 0o100
+                    st = wvfs.stat(lfile)
+                    mode = st.st_mode
+                    if standinexec != mode & 0o100:
+                        # first remove all X bits, then shift all R bits to X
+                        mode &= ~0o111
+                        if standinexec:
+                            mode |= (mode >> 2) & 0o111 & ~util.umask
+                        wvfs.chmod(lfile, mode)
+                        update1 = 1
 
-            lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup)
+                updated += update1
+
+                lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup)
 
         lfdirstate.write()
         if lfiles: