[PATCH 6 of 6] [RFC] extension: `dummy` and composition with `lfs`

Remi Chaintron remi at fb.com
Thu Oct 27 11:04:04 EDT 2016


# HG changeset patch
# User Remi Chaintron <remi at fb.com>
# Date 1477579974 -3600
#      Thu Oct 27 15:52:54 2016 +0100
# Branch stable
# Node ID c7dc98eb24cd40e46e73dea275b4c5b245155efb
# Parent  202b2a6872d3b3ffb1f373910c4eadffda8f727a
[RFC] extension: `dummy` and composition with `lfs`

This is a proof of concept for the composition of non-reflexive operations on
filelogs using extensions relying on the flagprocessor design.

diff --git a/hgext/dummy.py b/hgext/dummy.py
new file mode 100644
--- /dev/null
+++ b/hgext/dummy.py
@@ -0,0 +1,83 @@
+# coding=UTF-8
+
+from __future__ import absolute_import
+
+from mercurial import (
+    cmdutil,
+    commands,
+    extensions,
+    filelog,
+    revlog,
+)
+
+def wrappedread(self, text):
+    return text[6:], True
+
+def getfilelogcontent(self, text):
+    return text, False
+
+extensionflag = revlog.REVIDX_ISDUMMY
+transformmap = {
+    extensionflag: wrappedread
+}
+
+def revision(orig, self, nodeorrev, _df=None):
+    self.flagprocessor.register(transformmap)
+    try:
+        return orig(self, nodeorrev, _df=_df)
+    finally:
+        self.flagprocessor.unregister(transformmap)
+
+
+def addrevision(orig, self, text, transaction, link, p1, p2, cachedelta=None,
+                node=None, flags=revlog.REVLOG_DEFAULT_FLAGS):
+    self.flagprocessor.register(transformmap)
+    try:
+      if self._peek_isdummy(text):
+          if node is None:
+             node = revlog.hash(text, p1, p2)
+          text = 'DUMMY:%s' % (text)
+          flags |= extensionflag
+      return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta,
+                  node=node, flags=flags)
+    finally:
+        self.flagprocessor.unregister(transformmap)
+
+def addgroup(orig, self, cg, linkmapper, transaction, addrevisioncb=None):
+    self.flagprocessor.register(transformmap)
+    try:
+        return orig(self, cg, linkmapper, transaction,
+                    addrevisioncb=addrevisioncb)
+    finally:
+        self.flagprocessor.unregister(transformmap)
+
+def debugdata(orig, ui, repo, file_, rev=None, **opts):
+    transformmap[extensionflag] = getfilelogcontent
+    orig(ui, repo, file_, rev=rev, **opts)
+    transformmap[extensionflag] = wrappedread
+
+def push(orig, ui, repo, dest=None, **opts):
+    transformmap[extensionflag] = getfilelogcontent
+    orig(ui, repo, dest=dest, **opts)
+    transformmap[extensionflag] = wrappedread
+
+def pull(orig, ui, repo, source="default", **opts):
+    transformmap[extensionflag] = getfilelogcontent
+    orig(ui, repo, source=source, **opts)
+    transformmap[extensionflag] = wrappedread
+
+def _peek_isdummy(orig, self, text):
+    return 'dummy' in text
+
+def extsetup(ui):
+    wrapfunction = extensions.wrapfunction
+    wrapcommand = extensions.wrapcommand
+
+    wrapfunction(filelog.filelog, 'revision', revision)
+    wrapfunction(filelog.filelog, 'addrevision', addrevision)
+    wrapfunction(filelog.filelog, 'addgroup', addgroup)
+    wrapfunction(filelog.filelog, '_peek_isdummy', _peek_isdummy)
+
+    wrapcommand(commands.table, 'debugdata', debugdata)
+    wrapcommand(commands.table, 'push', push)
+    wrapcommand(commands.table, 'pull', pull)
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -55,8 +55,9 @@
 # revlog index flags
 REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be verified
 REVIDX_ISLARGEFILE = (1 << 14)
+REVIDX_ISDUMMY = (1 << 13)
 REVIDX_DEFAULT_FLAGS = 0
-REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED | REVIDX_ISLARGEFILE
+REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED | REVIDX_ISLARGEFILE | REVIDX_ISDUMMY
 
 # max size of revlog with inline data
 _maxinline = 131072
@@ -97,6 +98,7 @@
         self.flagsbypriority = [
             REVIDX_ISCENSORED,
             REVIDX_ISLARGEFILE,
+            REVIDX_ISDUMMY,
         ]
         self.transformmap = {}
         self.revlogobject = revlogobject
@@ -1775,6 +1777,9 @@
     def islargefile(self, rev):
         return False
 
+    def _peek_isdummy(self, text):
+        return False
+
     def _peek_iscensored(self, baserev, delta, flush):
         """Quickly check if a delta produces a censored revision."""
         return False
diff --git a/tests/test-lfs.t b/tests/test-lfs.t
--- a/tests/test-lfs.t
+++ b/tests/test-lfs.t
@@ -19,6 +19,7 @@
   $ cat >> .hg/hgrc <<EOF
   > [extensions]
   > lfs=$TESTDIR/../hgext/lfs/
+  > dummy=
   > [lfs]
   > threshold=1000B
   > blobstore=cache/localblobstore
@@ -49,19 +50,43 @@
   version https://git-lfs.github.com/spec/v1
   oid sha256:1228f8759b018cca5b58d3e5d1740d0b827f06cecf8868fd17f35a87ef8aacf6
   size 1501
-
-# Check the contents of the file are fetched from the blobstore when requested
-  $ hg cat -r . largefile
+  $ hg cat --traceback -r . largefile
   AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 
-# Push the blobs to the server
-  $ hg push
+# Commit a dummy file (will take the dummy flag)
+  $ echo 'dummy' > dummyfile
+  $ hg commit -Aqm 'add dummy file'
+
+# Check the dummy extension adds metadata on write
+  $ hg debugdata dummyfile 0
+  DUMMY:dummy
+
+# Check the extension removes the metadata on read
+  $ hg cat -r . dummyfile
+  dummy
+
+# Commit a lfs + dummy triggering file
+  $ echo dummyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > dummylargefile
+  $ hg commit -Aqm 'add dummy large file'
+
+# Check the filelog contains metadata (as dummy has priority on lfs)
+  $ hg debugdata dummylargefile 0
+  version https://git-lfs.github.com/spec/v1
+  oid sha256:22a3bdbccf152a786e35ca856dfef423c022968fc42f80f1c2eff8e8b116c37d
+  size 1512
+
+# Check the file contents are restored on read
+  $ hg cat -r . dummylargefile
+  dummyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+# Push changes to the server
+  $ hg push --traceback
   pushing to $TESTTMP/server (glob)
   searching for changes
   adding changesets
   adding manifests
   adding file changes
-  added 2 changesets with 2 changes to 2 files
+  added 4 changesets with 4 changes to 4 files
 
 # Initialize new client (not cloning) and setup extension
   $ cd ../
@@ -76,6 +101,7 @@
   > default = $TESTTMP/server
   > [extensions]
   > lfs=$TESTDIR/../hgext/lfs/
+  > dummy=
   > [lfs]
   > threshold=1000B
   > blobstore=cache/localblobstore
@@ -88,7 +114,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 2 changesets with 2 changes to 2 files
+  added 4 changesets with 4 changes to 4 files
   (run 'hg update' to get a working copy)
 
 # Check the blobstore is not yet populated
@@ -97,7 +123,7 @@
 
 # Update to the last revision containing the large file
   $ hg update
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  4 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 # Check the filelog contents actually contain metadata
   $ hg debugdata largefile 0
@@ -110,6 +136,8 @@
   .hg/cache/localblobstore
   .hg/cache/localblobstore/12
   .hg/cache/localblobstore/12/28f8759b018cca5b58d3e5d1740d0b827f06cecf8868fd17f35a87ef8aacf6
+  .hg/cache/localblobstore/22
+  .hg/cache/localblobstore/22/a3bdbccf152a786e35ca856dfef423c022968fc42f80f1c2eff8e8b116c37d
 
 # Check the contents of the file are fetched from blobstore when requested
   $ hg cat -r . largefile


More information about the Mercurial-devel mailing list