[PATCH STABLE] largefiles: access to specific fields only if largefiles enabled (issue4547)

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Wed Feb 25 15:06:46 CST 2015


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1424898219 -32400
#      Thu Feb 26 06:03:39 2015 +0900
# Branch stable
# Node ID 8049e948fa335fb6cfcce88197dc9963cf4698b7
# Parent  942a5a34b2d0611ab284380fbe45b9bb1897af98
largefiles: access to specific fields only if largefiles enabled (issue4547)

Even if largefiles extension is enabled in a repository, "repo"
object, which isn't "largefiles.reposetup()"-ed, is passed to
overridden functions in the cases below unexpectedly, because
extensions are enabled for each repositories strictly.

  (1) clone without -U:
  (2) pull with -U:
  (3) pull with --rebase:

    combination of "enabled at src", "disabled at dst" and
    "not-required at src" cause this situation.

       largefiles     requirement
    @src     @dst     @src            result
    -------- -------- --------------- --------------------
    enabled  disabled not-required    aborted unexpectedly
                      required        requirement error (intentional)
    -------- -------- --------------- --------------------
    enabled  enabled  *               success
    -------- -------- --------------- --------------------
    disabled enabled  *               success (only for "pull")
    -------- -------- --------------- --------------------
    disabled disabled not-required    success
                      required        requirement error (intentional)
    -------- -------- --------------- --------------------

  (4) update/revert with a subrepo disabling largefiles

In these cases, overridden functions cause accessing to largefiles
specific fields of not "largefiles.reposetup()"-ed "repo" object, and
execution is aborted.

  - (1), (2), (4) cause accessing to "_lfstatuswriters" in
    "getstatuswriter()" invoked via "updatelfiles()"

  - (3) causes accessing to "_lfcommithooks" in "overriderebase()"

For safe accessing to these fields, this patch examines whether passed
"repo" object is "largefiles.reposetup()"-ed or not before accessing
to them.

This patch chooses examining existence of newly introduced
"_largefilesenabled" instead of "_lfcommithooks" and
"_lfstatuswriters" directly, because the former is better name for the
generic "largefiles is enabled in this repo" mark than the latter.

In the future, all other overridden functions should avoid largefiles
specific processing for efficiency, and "_largefilesenabled" is better
also for such purpose.

BTW, "lfstatus" can't be used for such purpose, because some code
paths set it forcibly regardless of existence of it in specified
"repo" object.

diff --git a/hgext/largefiles/lfutil.py b/hgext/largefiles/lfutil.py
--- a/hgext/largefiles/lfutil.py
+++ b/hgext/largefiles/lfutil.py
@@ -577,7 +577,7 @@
     Otherwise, this returns the function to always write out (or
     ignore if ``not forcibly``) status.
     '''
-    if forcibly is None:
+    if forcibly is None and util.safehasattr(repo, '_largefilesenabled'):
         return repo._lfstatuswriters[-1]
     else:
         if forcibly:
diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -832,6 +832,9 @@
     return result
 
 def overriderebase(orig, ui, repo, **opts):
+    if not util.safehasattr(repo, '_largefilesenabled'):
+        return orig(ui, repo, **opts)
+
     resuming = opts.get('continue')
     repo._lfcommithooks.append(lfutil.automatedcommithook(resuming))
     repo._lfstatuswriters.append(lambda *msg, **opts: None)
diff --git a/hgext/largefiles/reposetup.py b/hgext/largefiles/reposetup.py
--- a/hgext/largefiles/reposetup.py
+++ b/hgext/largefiles/reposetup.py
@@ -24,6 +24,9 @@
         return
 
     class lfilesrepo(repo.__class__):
+        # the mark to examine whether "repo" object enables largefiles or not
+        _largefilesenabled = True
+
         lfstatus = False
         def status_nolfiles(self, *args, **kwargs):
             return super(lfilesrepo, self).status(*args, **kwargs)
diff --git a/tests/test-largefiles-misc.t b/tests/test-largefiles-misc.t
--- a/tests/test-largefiles-misc.t
+++ b/tests/test-largefiles-misc.t
@@ -907,6 +907,77 @@
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
 #endif
 
+Test overridden functions work correctly even for repos disabling
+largefiles (issue4547)
+
+  $ hg showconfig extensions | grep largefiles
+  extensions.largefiles=!
+
+(test updating implied by clone)
+
+  $ hg init enabled-but-no-largefiles
+  $ echo normal1 > enabled-but-no-largefiles/normal1
+  $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal1
+  $ hg -R enabled-but-no-largefiles commit -m '#0 at enabled-but-no-largefiles'
+  Invoking status precommit hook
+  A normal1
+  $ cat >> enabled-but-no-largefiles/.hg/hgrc <<EOF
+  > [extensions]
+  > # enable locally
+  > largefiles=
+  > EOF
+  $ hg clone -q enabled-but-no-largefiles no-largefiles
+
+(test rebasing implied by pull: precommit while rebasing unexpectedly
+shows "normal3" as "?", because lfdirstate isn't yet written out at
+that time)
+
+  $ echo normal2 > enabled-but-no-largefiles/normal2
+  $ hg -R enabled-but-no-largefiles add enabled-but-no-largefiles/normal2
+  $ hg -R enabled-but-no-largefiles commit -m '#1 at enabled-but-no-largefiles'
+  Invoking status precommit hook
+  A normal2
+
+  $ echo normal3 > no-largefiles/normal3
+  $ hg -R no-largefiles add no-largefiles/normal3
+  $ hg -R no-largefiles commit -m '#1 at no-largefiles'
+  Invoking status precommit hook
+  A normal3
+
+  $ hg -R no-largefiles -q pull --rebase
+  Invoking status precommit hook
+  ? normal3
+
+(test reverting)
+
+  $ hg init subrepo-root
+  $ cat >> subrepo-root/.hg/hgrc <<EOF
+  > [extensions]
+  > # enable locally
+  > largefiles=
+  > EOF
+  $ echo large > subrepo-root/large
+  $ hg -R subrepo-root add --large subrepo-root/large
+  $ hg clone -q no-largefiles subrepo-root/no-largefiles
+  $ cat > subrepo-root/.hgsub <<EOF
+  > no-largefiles = no-largefiles
+  > EOF
+  $ hg -R subrepo-root add subrepo-root/.hgsub
+  $ hg -R subrepo-root commit -m '#0'
+  Invoking status precommit hook
+  A .hgsub
+  A large
+  ? .hgsubstate
+  $ echo dirty >> subrepo-root/large
+  $ echo dirty >> subrepo-root/no-largefiles/normal1
+  $ hg -R subrepo-root status -S
+  M large
+  M no-largefiles/normal1
+  $ hg -R subrepo-root revert --all
+  reverting subrepo-root/.hglf/large (glob)
+  reverting subrepo no-largefiles
+  reverting subrepo-root/no-largefiles/normal1 (glob)
+
   $ cd ..
 
 


More information about the Mercurial-devel mailing list