Patchwork [1,of,5] lfs: add a repo requirement for this extension once an lfs file is committed

mail settings
Submitter Matt Harbison
Date Nov. 26, 2017, 10:45 p.m.
Message ID <ccc7eae771760a638f98.1511736301@Envy>
Download mbox | patch
Permalink /patch/25757/
State Accepted
Headers show


Matt Harbison - Nov. 26, 2017, 10:45 p.m.
# HG changeset patch
# User Matt Harbison <>
# Date 1510807395 18000
#      Wed Nov 15 23:43:15 2017 -0500
# Node ID ccc7eae771760a638f9809caa8c3eb4747f94f01
# Parent  32bb27dd52825236ba1b6c06fe60e140d6b5ea45
lfs: add a repo requirement for this extension once an lfs file is committed

Largefiles does the same thing (also delayed until the first largefile commit),
to prevent access to the repo without the extension.  In the case of this
extension, not having the extension loaded while accessing an lfs file results
in cryptic errors about "missing processor for flag '0x2000'".  If enabled
locally but not remotely, the cryptic error message is about no common
changegroup version.  (It wants '03', which is currently experimental.)

The largefiles extension looks for any tracked file that starts with '.hglf/'.
Unfortunately, that doesn't work here.  I didn't see any way to get the files
that were just committed, without doing a full status.  But since there's no
secondary check on adding an lfs file once the extension is loaded and a
threshold set, the best practice is to only enable this locally on a repo that
needs it.  That should minimize the unnecessary overhead for repos without an
lfs file.


diff --git a/hgext/lfs/ b/hgext/lfs/
--- a/hgext/lfs/
+++ b/hgext/lfs/
@@ -37,6 +37,7 @@ 
+    localrepo,
@@ -84,6 +85,13 @@ 
 templatekeyword = registrar.templatekeyword()
+def featuresetup(ui, supported):
+    # don't die on seeing a repo with the lfs requirement
+    supported |= {'lfs'}
+def uisetup(ui):
+    localrepo.localrepository.featuresetupfuncs.add(featuresetup)
 def reposetup(ui, repo):
     # Nothing to do with a remote repo
     if not repo.local():
@@ -98,6 +106,17 @@ 
     # Push hook
     repo.prepushoutgoinghooks.add('lfs', wrapper.prepush)
+    if 'lfs' not in repo.requirements:
+        def checkrequireslfs(ui, repo, **kwargs):
+            if 'lfs' not in repo.requirements:
+                ctx = repo[kwargs['node']]
+                # TODO: is there a way to just walk the files in the commit?
+                if any(ctx[f].islfs() for f in ctx.files()):
+                    repo.requirements.add('lfs')
+                    repo._writerequirements()
+        ui.setconfig('hooks', 'commit.lfs', checkrequireslfs, 'lfs')
 def wrapfilelog(filelog):
     wrapfunction = extensions.wrapfunction
diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -20,7 +20,11 @@ 
 # Commit large file
   $ echo $LONG > largefile
+  $ grep lfs .hg/requires
+  [1]
   $ hg commit --traceback -Aqm "add large file"
+  $ grep lfs .hg/requires
+  lfs
 # Ensure metadata is stored
   $ hg debugdata largefile 0