largefile: consider `updatelfiles` as a `parentchange`
authorPierre-Yves David <pierre-yves.david@octobus.net>
Thu, 08 Jul 2021 01:44:49 +0200
changeset 47651 40811cc7fa56
parent 47650 1e5a9783bba8
child 47652 12300ee6840b
largefile: consider `updatelfiles` as a `parentchange` This is not strictly a `parentchange`, however this is still some internal dirstate adjustment as "similar" enough that it seems find to do so. Differential Revision: https://phab.mercurial-scm.org/D11107
hgext/largefiles/lfcommands.py
--- a/hgext/largefiles/lfcommands.py	Thu Jul 08 01:24:29 2021 +0200
+++ b/hgext/largefiles/lfcommands.py	Thu Jul 08 01:44:49 2021 +0200
@@ -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: