[PATCH 8 of 9 V2] revlog: make _addrevision only accept rawtext

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490924283 25200
#  Thu Mar 30 18:38:03 2017 -0700
# Node ID 3a4dd24ccf078c47722582f00872a88d33042ac3
# Parent  4bc37a3afb8b56b3d124188cc16ea8d83a0ba92d
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 3a4dd24ccf07
revlog: make _addrevision only accept rawtext

All 3 users of _addrevision use raw:

  - addrevision: passing rawtext to _addrevision
  - addgroup: passing rawtext and raw=True to _addrevision
  - clone: passing rawtext to _addrevision

There is no real user using _addrevision(raw=False). On the other hand,
_addrevision is low-level code dealing with raw revlog deltas and rawtexts.
It should not transform rawtext to non-raw text.

This patch removes the "raw" parameter from "_addrevision", and does some
rename and doc change to make it clear that "_addrevision" expects rawtext.

Archeology shows 2df983125d37 added "raw" flag to "_addrevision", follow-ups
e12c0fa1f65b and c1b7b2285522 seem to make the flag unnecessary.

test-revlog-raw.py no longer complains.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1578,17 +1578,17 @@ class revlog(object):
 return True
 
-def _addrevision(self, node, text, transaction, link, p1, p2, flags,
- cachedelta, ifh, dfh, alwayscache=False, raw=False):
+def _addrevision(self, node, rawtext, transaction, link, p1, p2, flags,
+ cachedelta, ifh, dfh, alwayscache=False):
 """internal function to add revisions to the log
 
 see addrevision for argument descriptions.
+
+note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
+
 invariants:
-- text is optional (can be None); if not set, cachedelta must be set.
+- rawtext is optional (can be None); if not set, cachedelta must be 
set.
   if both are set, they must correspond to each other.
-- raw is optional; if set to True, it indicates the revision data is to
-  be treated by _processflags() as raw. It is usually set by 
changegroup
-  generation and debug commands.
 """
-btext = [text]
+btext = [rawtext]
 def buildtext():
 if btext[0] is not None:
@@ -1608,9 +1608,9 @@ class revlog(object):
 else:
 fh = dfh
-basetext = self.revision(self.node(baserev), _df=fh, raw=raw)
+basetext = self.revision(self.node(baserev), _df=fh, raw=True)
 btext[0] = mdiff.patch(basetext, delta)
 
 try:
-res = self._processflags(btext[0], flags, 'read', raw=raw)
+res = self._processflags(btext[0], flags, 'read', raw=True)
 btext[0], validatehash = res
 if validatehash:
@@ -1664,9 +1664,9 @@ class revlog(object):
 # full versions are inserted when the needed deltas
 # become comparable to the uncompressed text
-if text is None:
+if rawtext is None:
 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
 cachedelta[1])
 else:
-textlen = len(text)
+textlen = len(rawtext)
 
 # should we try to build a delta?
@@ -1709,6 +1709,6 @@ class revlog(object):
 dist, l, data, base, chainbase, chainlen, compresseddeltalen = 
delta
 else:
-text = buildtext()
-data = self.compress(text)
+rawtext = buildtext()
+data = self.compress(rawtext)
 l = len(data[1]) + len(data[0])
 base = chainbase = curr
@@ -1722,9 +1722,9 @@ class revlog(object):
 self._writeentry(transaction, ifh, dfh, entry, data, link, offset)
 
-if alwayscache and text is None:
-text = buildtext()
+if alwayscache and rawtext is None:
+rawtext = buildtext()
 
-if type(text) == str: # only accept immutable objects
-self._cache = (node, curr, text)
+if type(rawtext) == str: # only accept immutable objects
+self._cache = (node, curr, rawtext)
 self._chainbasecache[curr] = chainbase
 return node
@@ -1848,6 +1848,5 @@ class revlog(object):
   p1, p2, flags, (baserev, delta),
   ifh, dfh,
-  alwayscache=bool(addrevisioncb),
-  raw=True)
+  alwayscache=bool(addrevisioncb))
 
 if addrevisioncb:
diff --git a/tests/test-revlog-raw.py.out b/tests/test-revlog-raw.py.out
--- a/tests/test-revlog-raw.py.out
+++ b/tests/test-revlog-raw.py.out
@@ -2,3 +2,3 @@ local test passed
 addgroupcopy test passed
 clone test passed
-abort: crashed: integrity check 

[PATCH 6 of 9 V2] revlog: use raw revisions in revdiff

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490923407 25200
#  Thu Mar 30 18:23:27 2017 -0700
# Node ID 272495735d544f8ab6053752db4e0a648f07415d
# Parent  290c65aad38108cc59c7e8fb7f3b37a7c7a7573b
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 272495735d54
revlog: use raw revisions in revdiff

See the added comment. revdiff is meant to output the raw delta that will be
written to revlog. It should use raw.

test-revlog-raw.py now shows "addgroupcopy test passed", but there is more
to fix.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1240,10 +1240,14 @@ class revlog(object):
 
 def revdiff(self, rev1, rev2):
-"""return or calculate a delta between two revisions"""
+"""return or calculate a delta between two revisions
+
+The delta calculated is in binary form and is intended to be written to
+revlog data directly. So this function needs raw revision data.
+"""
 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
 return bytes(self._chunk(rev2))
 
-return mdiff.textdiff(self.revision(rev1),
-  self.revision(rev2))
+return mdiff.textdiff(self.revision(rev1, raw=True),
+  self.revision(rev2, raw=True))
 
 def revision(self, nodeorrev, _df=None, raw=False):
diff --git a/tests/test-revlog-raw.py.out b/tests/test-revlog-raw.py.out
--- a/tests/test-revlog-raw.py.out
+++ b/tests/test-revlog-raw.py.out
@@ -1,2 +1,3 @@
 local test passed
+addgroupcopy test passed
 abort: crashed: invalid patch
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 7 of 9 V2] revlog: use raw revisions in clone

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490923463 25200
#  Thu Mar 30 18:24:23 2017 -0700
# Node ID 4bc37a3afb8b56b3d124188cc16ea8d83a0ba92d
# Parent  272495735d544f8ab6053752db4e0a648f07415d
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 4bc37a3afb8b
revlog: use raw revisions in clone

test-revlog-raw.py now shows "clone test passed", but there is more to fix.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2085,5 +2085,5 @@ class revlog(object):
 # the revlog chunk is a delta.
 cachedelta = None
-text = None
+rawtext = None
 if populatecachedelta:
 dp = self.deltaparent(rev)
@@ -2092,5 +2092,5 @@ class revlog(object):
 
 if not cachedelta:
-text = self.revision(rev)
+rawtext = self.revision(rev, raw=True)
 
 ifh = destrevlog.opener(destrevlog.indexfile, 'a+',
@@ -2100,5 +2100,5 @@ class revlog(object):
 dfh = destrevlog.opener(destrevlog.datafile, 'a+')
 try:
-destrevlog._addrevision(node, text, tr, linkrev, p1, p2,
+destrevlog._addrevision(node, rawtext, tr, linkrev, p1, p2,
 flags, cachedelta, ifh, dfh)
 finally:
diff --git a/tests/test-revlog-raw.py.out b/tests/test-revlog-raw.py.out
--- a/tests/test-revlog-raw.py.out
+++ b/tests/test-revlog-raw.py.out
@@ -1,3 +1,4 @@
 local test passed
 addgroupcopy test passed
-abort: crashed: invalid patch
+clone test passed
+abort: crashed: integrity check failed on _destrevlog.i:5
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 5 of 9 V2] revlog: use raw content when building delta

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490921883 25200
#  Thu Mar 30 17:58:03 2017 -0700
# Node ID 290c65aad38108cc59c7e8fb7f3b37a7c7a7573b
# Parent  173d73e93cc25abdcac23fcd858a4e94d29e7461
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 290c65aad381
revlog: use raw content when building delta

Using external content provided by flagprocessor when building revlog delta
is wrong, because deltas are applied to raw contents in revlog.

This patch fixes the above issue by adding "raw=True".

test-revlog-raw.py now shows "local test passed", but there is more to fix.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1636,5 +1636,5 @@ class revlog(object):
 else:
 fh = dfh
-ptext = self.revision(self.node(rev), _df=fh)
+ptext = self.revision(self.node(rev), _df=fh, raw=True)
 delta = mdiff.textdiff(ptext, t)
 header, data = self.compress(delta)
diff --git a/tests/test-revlog-raw.py.out b/tests/test-revlog-raw.py.out
--- a/tests/test-revlog-raw.py.out
+++ b/tests/test-revlog-raw.py.out
@@ -1,1 +1,2 @@
-abort: crashed: integrity check failed on _testrevlog.i:11
+local test passed
+abort: crashed: invalid patch
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 9 of 9 V2] revlog: add a fast path for revision(raw=False)

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490934075 25200
#  Thu Mar 30 21:21:15 2017 -0700
# Node ID 70c6b2eecf4d580d38404f157ef99da237593a68
# Parent  3a4dd24ccf078c47722582f00872a88d33042ac3
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 70c6b2eecf4d
revlog: add a fast path for revision(raw=False)

If cache hit and flags are empty, no flag processor runs and "text" equals
to "rawtext". So we check flags, and return rawtext.

This resolves performance issue introduced by a previous patch.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1275,4 +1275,11 @@ class revlog(object):
 if raw:
 return self._cache[2]
+# duplicated, but good for perf
+if rev is None:
+rev = self.rev(node)
+# no extra flags set, no flag processor runs, text = rawtext
+if self.flags(rev) == REVIDX_DEFAULT_FLAGS:
+return self._cache[2]
+
 cachedrev = self._cache[1]
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 9 V2] revlog: add a stronger test for raw processing

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490932137 25200
#  Thu Mar 30 20:48:57 2017 -0700
# Node ID 4a3f09c00a850667225b56d4aa0069e8e8233281
# Parent  dea2a17cbfd00bf08ee87b3e44b1c71499189f89
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 4a3f09c00a85
revlog: add a stronger test for raw processing

There are some issues about revlog raw processing (flag processor). The test
is relatively strong covering many cases. It will verify fixes.

diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py
new file mode 100644
--- /dev/null
+++ b/tests/test-revlog-raw.py
@@ -0,0 +1,290 @@
+# test revlog interaction about raw data (flagprocessor)
+
+from __future__ import absolute_import, print_function
+
+import sys
+
+from mercurial import (
+encoding,
+node,
+revlog,
+transaction,
+vfs,
+)
+
+# TESTTMP is optional. This makes it convenient to run without run-tests.py
+tvfs = vfs.vfs(encoding.environ.get('TESTTMP', b'/tmp'))
+
+# Enable generaldelta otherwise revlog won't use delta as expected by the test
+tvfs.options = {'generaldelta': True, 'revlogv1': True, 'revlogv1': True}
+
+# The test wants to control whether to use delta explicitly, based on
+# "storedeltachains".
+revlog.revlog._isgooddelta = lambda self, d, textlen: self.storedeltachains
+
+def abort(msg):
+print('abort: %s' % msg)
+# Return 0 so run-tests.py could compare the output.
+sys.exit()
+
+# Register a revlog processor for flag EXTSTORED.
+#
+# It simply prepends a fixed header, and replaces '1' to 'i'. So it has
+# insertion and replacement, and may be interesting to test revlog's line-based
+# deltas.
+_extheader = b'E\n'
+
+def readprocessor(self, rawtext):
+# True: the returned text could be used to verify hash
+text = rawtext[len(_extheader):].replace(b'i', b'1')
+return text, True
+
+def writeprocessor(self, text):
+# False: the returned rawtext shouldn't be used to verify hash
+rawtext = _extheader + text.replace(b'1', b'i')
+return rawtext, False
+
+def rawprocessor(self, rawtext):
+# False: do not verify hash. Only the content returned by "readprocessor"
+# can be used to verify hash.
+return False
+
+revlog.addflagprocessor(revlog.REVIDX_EXTSTORED,
+(readprocessor, writeprocessor, rawprocessor))
+
+# Utilities about reading and appending revlog
+
+def newtransaction():
+# A transaction is required to write revlogs
+report = lambda msg: None
+return transaction.transaction(report, tvfs, {'plain': tvfs}, b'journal')
+
+def newrevlog(name=b'_testrevlog.i', recreate=False):
+if recreate:
+tvfs.tryunlink(name)
+rlog = revlog.revlog(tvfs, name)
+return rlog
+
+def appendrev(rlog, text, tr, isext=False, isdelta=True):
+'''Append a revision. If isext is True, set the EXTSTORED flag so flag
+processor will be used (and rawtext is different from text). If isdelta is
+True, force the revision to be a delta, otherwise it's full text.
+'''
+nextrev = len(rlog)
+p1 = rlog.node(nextrev - 1)
+p2 = node.nullid
+if isext:
+flags = revlog.REVIDX_EXTSTORED
+else:
+flags = revlog.REVIDX_DEFAULT_FLAGS
+# Change storedeltachains temporarily, to override revlog's delta decision
+rlog.storedeltachains = isdelta
+try:
+rlog.addrevision(text, tr, nextrev, p1, p2, flags=flags)
+return nextrev
+except Exception as ex:
+abort('rev %d: failed to append: %s' % (nextrev, ex))
+finally:
+# Restore storedeltachains. It is always True, see revlog.__init__
+rlog.storedeltachains = True
+
+def addgroupcopy(rlog, tr, destname=b'_destrevlog.i', optimaldelta=True):
+'''Copy revlog to destname using revlog.addgroup. Return the copied revlog.
+
+This emulates push or pull. They use changegroup. Changegroup requires
+repo to work. We don't have a repo, so a dummy changegroup is used.
+
+If optimaldelta is True, use optimized delta parent, so the destination
+revlog could probably reuse it. Otherwise it builds sub-optimal delta, and
+the destination revlog needs more work to use it.
+
+This exercises some revlog.addgroup (and revlog._addrevision(text=None))
+code path, which is not covered by "appendrev" alone.
+'''
+class dummychangegroup(object):
+@staticmethod
+def deltachunk(pnode):
+pnode = pnode or node.nullid
+parentrev = rlog.rev(pnode)
+r = parentrev + 1
+if r >= len(rlog):
+return {}
+if optimaldelta:
+deltaparent = parentrev
+else:
+# suboptimal deltaparent
+deltaparent = min(0, parentrev)
+return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
+'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
+   

[PATCH 3 of 9 V2] revlog: rename some "text"s to "rawtext"

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490910969 25200
#  Thu Mar 30 14:56:09 2017 -0700
# Node ID 3fb26d049c52534835fd397ceb70b0f83068695a
# Parent  31aa38709dbd983b87302a0f24f4cf78a138ae83
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 3fb26d049c52
revlog: rename some "text"s to "rawtext"

This makes code easier to understand. "_addrevision" is left untouched - it
will be changed in a later patch.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1272,5 +1272,5 @@ class revlog(object):
 
 # look up what we need to read
-text = None
+rawtext = None
 if rev is None:
 rev = self.rev(node)
@@ -1278,5 +1278,5 @@ class revlog(object):
 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
 if stopped:
-text = self._cache[2]
+rawtext = self._cache[2]
 
 # drop cache to save memory
@@ -1284,12 +1284,12 @@ class revlog(object):
 
 bins = self._chunks(chain, df=_df)
-if text is None:
-text = bytes(bins[0])
+if rawtext is None:
+rawtext = bytes(bins[0])
 bins = bins[1:]
 
-text = mdiff.patches(text, bins)
+rawtext = mdiff.patches(rawtext, bins)
 
-text, validatehash = self._processflags(text, self.flags(rev), 'read',
-raw=raw)
+text, validatehash = self._processflags(rawtext, self.flags(rev),
+'read', raw=raw)
 if validatehash:
 self.checkhash(text, node, rev=rev)
@@ -1452,23 +1452,22 @@ class revlog(object):
 node = node or self.hash(text, p1, p2)
 
-newtext, validatehash = self._processflags(text, flags, 'write')
+rawtext, validatehash = self._processflags(text, flags, 'write')
 
 # If the flag processor modifies the revision data, ignore any provided
 # cachedelta.
-if newtext != text:
+if rawtext != text:
 cachedelta = None
-text = newtext
 
-if len(text) > _maxentrysize:
+if len(rawtext) > _maxentrysize:
 raise RevlogError(
 _("%s: size of %d bytes exceeds maximum revlog storage of 
2GiB")
-% (self.indexfile, len(text)))
+% (self.indexfile, len(rawtext)))
 
-node = node or self.hash(text, p1, p2)
+node = node or self.hash(rawtext, p1, p2)
 if node in self.nodemap:
 return node
 
 if validatehash:
-self.checkhash(text, node, p1=p1, p2=p2)
+self.checkhash(rawtext, node, p1=p1, p2=p2)
 
 dfh = None
@@ -1477,5 +1476,5 @@ class revlog(object):
 ifh = self.opener(self.indexfile, "a+", checkambig=self._checkambig)
 try:
-return self._addrevision(node, text, transaction, link, p1, p2,
+return self._addrevision(node, rawtext, transaction, link, p1, p2,
  flags, cachedelta, ifh, dfh)
 finally:
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 9 V2] revlog: fix _cache usage in revision()

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490913248 25200
#  Thu Mar 30 15:34:08 2017 -0700
# Node ID 173d73e93cc25abdcac23fcd858a4e94d29e7461
# Parent  3fb26d049c52534835fd397ceb70b0f83068695a
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 173d73e93cc2
revlog: fix _cache usage in revision()

As documented at revlog.__init__, revlog._cache stores raw text.

The current read and write usage of "_cache" in revlog.revision lacks of
raw=True check.

This patch fixes that by adding check about raw, and storing rawtext
explicitly in _cache.

Note: it may slow down cache hit code path when raw=False and flags=0. That
performance issue will be fixed in a later patch.

test-revlog-raw now points us to a new problem.

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -1268,5 +1268,7 @@ class revlog(object):
 if self._cache:
 if self._cache[0] == node:
-return self._cache[2]
+# _cache only stores rawtext
+if raw:
+return self._cache[2]
 cachedrev = self._cache[1]
 
@@ -1295,5 +1297,5 @@ class revlog(object):
 self.checkhash(text, node, rev=rev)
 
-self._cache = (node, rev, text)
+self._cache = (node, rev, rawtext)
 return text
 
diff --git a/tests/test-revlog-raw.py.out b/tests/test-revlog-raw.py.out
--- a/tests/test-revlog-raw.py.out
+++ b/tests/test-revlog-raw.py.out
@@ -1,1 +1,1 @@
-abort: rev 5: wrong text
+abort: crashed: integrity check failed on _testrevlog.i:11
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 9 V2] revlog: clarify flagprocessor documentation

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490885988 25200
#  Thu Mar 30 07:59:48 2017 -0700
# Node ID 31aa38709dbd983b87302a0f24f4cf78a138ae83
# Parent  4a3f09c00a850667225b56d4aa0069e8e8233281
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 31aa38709dbd
revlog: clarify flagprocessor documentation

The words "text", "newtext", "bool" could be confusing. Use explicit "text"
or "rawtext" and document more about the "bool".

diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -89,9 +89,15 @@ def addflagprocessor(flag, processor):
 - flagprocessors must be 3-tuples of functions (read, write, raw) with the
   following signatures:
-  - (read)  f(self, text) -> newtext, bool
-  - (write) f(self, text) -> newtext, bool
-  - (raw)   f(self, text) -> bool
+  - (read)  f(self, rawtext) -> text, bool
+  - (write) f(self, text) -> rawtext, bool
+  - (raw)   f(self, rawtext) -> bool
+  "text" is presented to the user. "rawtext" is stored in revlog data, not
+  directly visible to the user.
   The boolean returned by these transforms is used to determine whether
-  'newtext' can be used for hash integrity checking.
+  the returned text can be used for hash integrity checking. For example,
+  if "write" returns False, then "text" is used to generate hash. If
+  "write" returns True, that basically means "rawtext" returned by "write"
+  should be used to generate hash. Usually, "write" and "read" return
+  different booleans. And "raw" returns a same boolean as "write".
 
   Note: The 'raw' transform is used for changegroup generation and in some
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH V6] hgweb: expose a followlines UI in filerevision view

2017-03-30 Thread Gregory Szorc
On Thu, Mar 30, 2017 at 1:29 AM, Denis Laxalde  wrote:

> # HG changeset patch
> # User Denis Laxalde 
> # Date 1490819176 -7200
> #  Wed Mar 29 22:26:16 2017 +0200
> # Node ID 1c360ab5640bc326dd6ff70bdee78e4da006dcef
> # Parent  e540846c67e0f838bcdb1db567a57df28d92491c
> # Available At http://hg.logilab.org/users/dlaxalde/hg
> #  hg pull http://hg.logilab.org/users/dlaxalde/hg -r
> 1c360ab5640b
> # EXP-Topic linerange-log/hgweb-filelog
> hgweb: expose a followlines UI in filerevision view
>
> In filerevision view (/file//) we add some event listeners on
> mouse clicks of  elements in the  block.
> Those listeners will capture a range of lines selected between two mouse
> clicks and a box inviting to follow the history of selected lines will then
> show up. Selected lines (i.e. the block of lines) get a CSS class which
> make
> them highlighted. Selection can be cancelled (and restarted) by either
> clicking on the cancel ("x") button in the invite box or clicking on any
> other
> source line. Also clicking twice on the same line will abort the selection
> and
> reset event listeners to restart the process.
>
> As a first step, this action is only advertised by the "cursor: cell" CSS
> rule
> on source lines elements as any other mechanisms would make the code
> significantly more complicated. This might be improved later.
>
> All JavaScript code lives in a new "linerangelog.js" file, sourced in
> filerevision template (only in "paper" style for now).
>

This patch is great! As far as functionality goes, I think it is almost
good enough to queue. There are still some usability improvements (such as
an aid to let users know that clicking a line will allow them to follow
that line). But those features can be implemented as follow-ups IMO.


>
> diff --git a/contrib/wix/templates.wxs b/contrib/wix/templates.wxs
> --- a/contrib/wix/templates.wxs
> +++ b/contrib/wix/templates.wxs
> @@ -225,6 +225,7 @@
>  
>  
>  
> +
>  
>  
>  
> diff --git a/mercurial/templates/paper/filerevision.tmpl
> b/mercurial/templates/paper/filerevision.tmpl
> --- a/mercurial/templates/paper/filerevision.tmpl
> +++ b/mercurial/templates/paper/filerevision.tmpl
> @@ -71,8 +71,11 @@
>  
>  line wrap:  class="linewraplink" href="javascript:toggleLinewrap()">on
>   line source
> -{text%fileline}
> + data-logurl="{url|urlescape}log/{symrev}/{file|urlescape}"
> >{text%fileline}
>  
> +
> +
> +
>  
>  
>
> diff --git a/mercurial/templates/static/linerangelog.js
> b/mercurial/templates/static/linerangelog.js
> new file mode 100644
> --- /dev/null
> +++ b/mercurial/templates/static/linerangelog.js
> @@ -0,0 +1,137 @@
> +// Copyright 2017 Logilab SA 
> +//
> +// This software may be used and distributed according to the terms
> +// of the GNU General Public License, incorporated herein by reference.
>

This license header is slightly different from what is used elsewhere. In
other files, we use "version 2 or any later version." I see this file's
version is used by .c files and a few other random places. But since it is
in the minority, let's stick to the "version 2 or any later version"
language, as seen in e.g. mercurial/__init__.py.

+
> +//** Install event listeners for line block selection and followlines
> action */
> +function installLineSelect() {
> +var sourcelines = document.getElementsByClassName('sourcelines')[0];
> +if (typeof sourcelines === 'undefined') {
> +return;
> +}
> +// URL to complement with "linerange" query parameter
> +var targetUri = sourcelines.dataset.logurl;
> +if (typeof targetUri === 'undefined') {
> +return;
> +}
> +
> +var lineSelectedCSSClass = 'followlines-selected';
> +
> +//** add CSS class on  element in `from`-`to` line range */
> +function addSelectedCSSClass(from, to) {
> +var spans = sourcelines.getElementsByTagName('span');
> +for (var i = from; i <= to; i++) {
> +spans.item(i).classList.add(lineSelectedCSSClass);
> +}
> +}
> +
> +//** remove CSS class from previously selected lines */
> +function removeSelectedCSSClass() {
> +var nodes = sourcelines.getElementsByClassName(
> +lineSelectedCSSClass);
> +while (nodes.length) {
> +nodes[0].classList.remove(lineSelectedCSSClass);
> +}
> +}
> +
> +// add event listener to the whole  block to
> have
> +// it available in all children 
> +sourcelines.addEventListener('click', lineSelectStart);
>

I know this works, but could you please move this until after the
definition of lineSelectStart() because it feels weird to see the reference
to a symbol before it is declared.


> +
> +//** event handler for "click" on the first line of a block */
> +function lineSelectStart(e) {
> +var startElement = e.target;
> +if (startElement.tagName !== 'SPAN') {
> +// not a  (ma

[PATCH] sslutil: clarify internal documentation

2017-03-30 Thread Matt Harbison
# HG changeset patch
# User Matt Harbison 
# Date 1490795674 14400
#  Wed Mar 29 09:54:34 2017 -0400
# Node ID 9505a8771bb00e56230e4c4b265e8369e659a54f
# Parent  2632df096fc0ac7582382b1f94ea4b9ad0bce8f2
sslutil: clarify internal documentation

I ran into this python issue with an incomplete certificate chain on Windows
recently, and this is the clarification that came from that experimenting.  The
comment I left on the bug tracker [1] with a reference to the CPython code [2]
indicates that the original problem I had is a different bug, but happened to
be mentioned under issue20916 on the Python bug tracker.

[1] https://bz.mercurial-scm.org/show_bug.cgi?id=5313#c7
[2] https://hg.python.org/cpython/file/v2.7.12/Modules/_ssl.c#l628

diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -414,8 +414,10 @@
 # a hint to the user.
 # Only modern ssl module exposes SSLContext.get_ca_certs() so we can
 # only show this warning if modern ssl is available.
-# The exception handler is here because of
-# https://bugs.python.org/issue20916.
+# The exception handler is here to handle bugs around cert attributes:
+# https://bugs.python.org/issue20916#msg213479.  (See issues5313.)
+# When the main 20916 bug occurs, 'sslcontext.get_ca_certs()' is a
+# non-empty list, but the following conditional is otherwise True.
 try:
 if (caloaded and settings['verifymode'] == ssl.CERT_REQUIRED and
 modernssl and not sslcontext.get_ca_certs()):
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2 V3] serve: make the URL the same for `hg serve` and `hg serve -S`

2017-03-30 Thread Matt Harbison

On Tue, 28 Mar 2017 10:02:34 -0400, Yuya Nishihara  wrote:


On Sun, 26 Mar 2017 23:04:31 -0400, Matt Harbison wrote:

# HG changeset patch
# User Matt Harbison 
# Date 1488146777 18000
#  Sun Feb 26 17:06:17 2017 -0500
# Node ID d584ca4bc33bd2ebeaf9a7bd86440b3cdcecc138
# Parent  0ff9bef3e0f67422cf29c200fa4a671d861d060b
serve: make the URL the same for `hg serve` and `hg serve -S`

It's perfectly workable to serve up the parent repo without the -S for  
push and
pull, as long as there are no subrepo changes in play.  Therefore,  
having a
different URL for the main repo based on the presence of this option  
seems like

it would get annoying.


This looks good, but more detailed commit message will help since some
changes in hgweb/hgwebdir are really subtle.


Other than noting that this change allows repos to be hosted at "", is  
there something else to mention on this one?

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2 V3] serve: add support for Mercurial subrepositories

2017-03-30 Thread Matt Harbison

On Tue, 28 Mar 2017 10:11:15 -0400, Yuya Nishihara  wrote:


On Sun, 26 Mar 2017 23:04:30 -0400, Matt Harbison wrote:

# HG changeset patch
# User Matt Harbison 
# Date 1488146743 18000
#  Sun Feb 26 17:05:43 2017 -0500
# Node ID 0ff9bef3e0f67422cf29c200fa4a671d861d060b
# Parent  c60091fa1426892552dd6c0dd4b9c49e3c3da045
serve: add support for Mercurial subrepositories



+def addwebdirpath(repo, serverpath, webconf):
+webconf[serverpath] = repo.root
+repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
+
+for r in repo.revs('filelog("path:.hgsub")'):
+ctx = repo[r]
+for subpath in ctx.substate:
+ctx.sub(subpath).addwebdirpath(serverpath, webconf)


[...]


--- a/mercurial/server.py
+++ b/mercurial/server.py
@@ -15,6 +15,7 @@

 from . import (
 chgserver,
+cmdutil,
 commandserver,
 error,
 hgweb,
@@ -130,11 +131,24 @@
 baseui = ui
 webconf = opts.get('web_conf') or opts.get('webdir_conf')
 if webconf:
+if opts.get('subrepos'):
+raise error.Abort(_('--web-conf cannot be used with  
--subrepos'))

+
 # load server settings (e.g. web.port) to "copied" ui, which  
allows

 # hgwebdir to reload webconf cleanly
 servui = ui.copy()
 servui.readconfig(webconf, sections=['web'])
 alluis.add(servui)
+elif opts.get('subrepos'):
+servui = ui.copy()
+alluis.add(servui)


No need to make a copy of ui since nothing loaded into servui.


+@annotatesubrepoerror
+def addwebdirpath(self, serverpath, webconf):
+# The URL request contains the subrepo source path, not the  
local
+# subrepo path.  The distinction matters for 'foo = ../foo'  
type
+# entries.  It isn't possible to serve up 'foo = http://..'  
type
+# entries, because the server path is relative to this local  
server.

+src = self._state[0]
+if util.url(src).islocal():
+path = util.normpath(serverpath + src)
+cmdutil.addwebdirpath(self._repo, path + '/', webconf)


What happens if src is '../../escape_from_web_root' ?

I don't think it's correct to lay out subrepositories by peer URL since  
we're
exporting a _local_ clone. If you do "hg clone sub1 sub2", you'll see  
sub1

in local-path layout. "hg serve -S" just allows us to see sub1 over http.


That was actually how I first coded it, but switched it because it wasn't  
handling the test in test-subrepo-deep-nested-change.t properly.  I forget  
what exactly the problem was.  I'll take another look this weekend.



Maybe it's okay to add all repositories found under repo.root to webconf.
For strictness, we could check if a subrepo path exists in .hgsub of any
revision.


I'd like to avoid searching through the directory tree, if possible.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 07 of 10 shelve-ext v4] shelve: add shelve type saving and loading

2017-03-30 Thread Kostia Balytskyi
On 21/03/2017 21:55, Augie Fackler wrote:

> On Sat, Mar 11, 2017 at 01:00:26PM -0800, Kostia Balytskyi wrote:
>> # HG changeset patch
>> # User Kostia Balytskyi 
>> # Date 1489250294 28800
>> #  Sat Mar 11 08:38:14 2017 -0800
>> # Node ID 5179d6be9d6a33071c8a18cc48166a3f1d5ceec5
>> # Parent  2dbff12d9b22281c8d84328704095d72b3151388
>> shelve: add shelve type saving and loading
> It's not called out anywhere, so I'll ask: do things work okay if you
> have a mix of bundled shelves and obsolete-marker shelves? It kind of
> looks like the answer is yes, but I wanted to make sure.

They are for the most part. But I've started looking into whether I have
test for every case and found a bug. Will add a patch in the initial
series and a separate test patch in test series.

>
>> We need shelve type to be stored in .hg/shelvedstate in order
>> to be able to run abort or continue action properly. If the shelve
>> is obsbased, those actions should create markes, if it is traditional,
>> the actions should strip commits.
>>
>> diff --git a/hgext/shelve.py b/hgext/shelve.py
>> --- a/hgext/shelve.py
>> +++ b/hgext/shelve.py
>> @@ -183,6 +183,8 @@ class shelvedstate(object):
>>   _filename = 'shelvedstate'
>>   _keep = 'keep'
>>   _nokeep = 'nokeep'
>> +_obsbased = 'obsbased'
>> +_traditional = 'traditional'
>>
>>   def __init__(self, ui, repo):
>>   self.ui = ui
>> @@ -204,6 +206,7 @@ class shelvedstate(object):
>>   nodestoprune = [nodemod.bin(h) for h in fp.readline().split()]
>>   branchtorestore = fp.readline().strip()
>>   keep = fp.readline().strip() == cls._keep
>> +obsshelve = fp.readline().strip() == cls._obsbased
>>   except (ValueError, TypeError) as err:
>>   raise error.CorruptedState(str(err))
>>   finally:
>> @@ -218,6 +221,7 @@ class shelvedstate(object):
>>   obj.nodestoprune = nodestoprune
>>   obj.branchtorestore = branchtorestore
>>   obj.keep = keep
>> +obj.obsshelve = obsshelve
>>   except error.RepoLookupError as err:
>>   raise error.CorruptedState(str(err))
>>
>> @@ -225,7 +229,7 @@ class shelvedstate(object):
>>
>>   @classmethod
>>   def save(cls, repo, name, originalwctx, pendingctx, nodestoprune,
>> - branchtorestore, keep=False):
>> + branchtorestore, keep=False, obsshelve=False):
>>   fp = repo.vfs(cls._filename, 'wb')
>>   fp.write('%i\n' % cls._version)
>>   fp.write('%s\n' % name)
>> @@ -237,6 +241,7 @@ class shelvedstate(object):
>>' '.join([nodemod.hex(n) for n in nodestoprune]))
>>   fp.write('%s\n' % branchtorestore)
>>   fp.write('%s\n' % (cls._keep if keep else cls._nokeep))
>> +fp.write('%s\n' % (cls._obsbased if obsshelve else 
>> cls._traditional))
>>   fp.close()
>>
>>   @classmethod
>> ___
>> Mercurial-devel mailing list
>> Mercurial-devel@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
> ___
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 2 V2] verify: document corner cases

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490823901 25200
#  Wed Mar 29 14:45:01 2017 -0700
# Node ID 17b41390f4912a4c18538d778837bc2cf4a1be92
# Parent  dea2a17cbfd00bf08ee87b3e44b1c71499189f89
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 17b41390f491
verify: document corner cases

It seems a good idea to list all kinds of "surprises" and expected behavior
to make the upcoming changes easier to understand.

Note: the comment added does not reflect the actual behavior of the current
code.

diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -380,5 +380,51 @@ class verifier(object):
 del filenodes[f][n]
 
-# verify contents
+# Verify contents. 4 cases to care about:
+#
+#   common: the most common case
+#   rename: with a rename
+#   meta: file content starts with b'\1\n', the metadata
+# header defined in filelog.py, but without a rename
+#   ext: largefiles. content stored elsewhere
+#
+# More formally, their differences are shown below:
+#
+#   | common | rename | meta  | ext
+#  ---
+#   flags() | 0  | 0  | 0 | not 0
+#   renamed()   | False  | True   | False | ?
+#   rawtext[0:2]=='\1\n'| False  | True   | True  | ?
+#
+# "rawtext" means the raw text stored in revlog data, which
+# could be retrieved by "revision(rev, raw=True)". "text"
+# mentioned below is "revision(rev, raw=False)".
+#
+# There are 3 different lengths stored physically:
+#  1. L1: rawsize, stored in revlog index
+#  2. L2: len(rawtext), stored in revlog data
+#  3. L3: len(text), stored in revlog data if flags==0, or
+# possibly somewhere else if flags!=0
+#
+# L1 should be equal to L2. L3 could be different from them.
+# "text" may or may not affect commit hash depending on flag
+# processors (see revlog.addflagprocessor).
+#
+#  | common  | rename | meta  | ext
+# -
+#rawsize() | L1  | L1 | L1| L1
+#   size() | L1  | L2-LM  | L1(*) | L1 (?)
+# len(rawtext) | L2  | L2 | L2| L2
+#len(text) | L2  | L2 | L2| L3
+#  len(read()) | L2  | L2-LM  | L2-LM | L3 (?)
+#
+# LM:  length of metadata, depending on rawtext
+# (*): not ideal, see comment in filelog.size
+# (?): could be "- len(meta)" if the resolved content has
+#  rename metadata
+#
+# Checks needed to be done:
+#  1. length check: L1 == L2, in all cases.
+#  2. hash check: depending on flag processor, we may need to
+# use either "text" (external), or "rawtext" (in revlog).
 try:
 l = len(fl.read(n))
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2 V2] verify: fix length check

2017-03-30 Thread Jun Wu
# HG changeset patch
# User Jun Wu 
# Date 1490824154 25200
#  Wed Mar 29 14:49:14 2017 -0700
# Node ID 35902a0e3f38c76a66d0dfbf76ec72091832
# Parent  17b41390f4912a4c18538d778837bc2cf4a1be92
# Available At https://bitbucket.org/quark-zju/hg-draft
#  hg pull https://bitbucket.org/quark-zju/hg-draft -r 35902a0e3f38
verify: fix length check

According to the document added above, we should check L1 == L2, and the
only way to get L1 in all cases is to call "rawsize()", and the only way to
get L2 is to call "revision(raw=True)". Therefore the fix.

Meanwhile there are still a lot of things about flagprocessor broken in
revlog.py. Tests will be added after revlog.py gets fixed.

diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -431,5 +431,6 @@ class verifier(object):
 rp = fl.renamed(n)
 if l != fl.size(i):
-if len(fl.revision(n)) != fl.size(i):
+# the "L1 == L2" check
+if len(fl.revision(n, raw=True)) != fl.rawsize(i):
 self.err(lr, _("unpacked size is %s, %s expected") 
%
  (l, fl.size(i)), f)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Unifying sparse and narrow "profiles"

2017-03-30 Thread Durham Goode



On 3/30/17 2:10 PM, Martin von Zweigbergk wrote:

On Thu, Mar 30, 2017 at 1:15 PM, Durham Goode  wrote:


If we make some basic assumptions about the UI (i.e. 'hg sparse' is a good
command name, and it will have 'include', 'exclude', 'enable-profile', and
'disable-profile' flags; and .hg/sparse is a good spot to store the client
config), I'd almost say let's ship the current sparse extension in hgext/
and satisfy mode 0. Then once the narrow-sparse unification has occurred
(assuming it implements the same hg sparse UI for mode 0 operations), we can
delete the old sparse code.


I'm not ready to make those assumption (and I'm not sure you were
saying we should). I think we need to discuss UI for the three modes
Augie mentioned and make sure that they feel consistent.


Yea, I wasn't suggesting we use that exact UI.  I'm just pointing out 
that the UI surface area of sparse is small enough that if we can decide 
on a reasonable UI, we could deliver a mode 0 implementation with 
relatively little effort.




That way we can have sparse in 4.3, and there's no pressure to prioritize
the narrow refactor until we feel it's necessary. That opens room for
potential future refactors in narrowhg as Facebook moves towards a lazy
changelog strategy which could influence the public facing narrowness
strategy.


For sparse and/or narrow in core, I think we'll need to pass matchers
around a bit more. We probably will also need to work on matcher
composition, so we can create a matcher with the user's patterns ANDed
together with the sparse/narrow matcher. Do you have that problem
already in the sparse extension? Once we have both sparse and narrow,
it seems likely we will need to compose those two matchers too.


Yea, sparse hacks around matcher composition at the moment by creating 
bare bones union and negation matcher classes.


https://bitbucket.org/facebook/hg-experimental/src/b5df1d5f3e303a75c550f8e8770afad9945edd86/hgext3rd/sparse.py?at=default&fileviewer=file-view-default#sparse.py-938

It's a bit scary, but actual works remarkably well (though it needs an 
update to handle visitdir for treemanifest).






(Also, are there any docs I should read about your sparse stuff and
profiles?)



`hg sparse --help` is about all we have right now but it's pretty good. Just
pay attention to the last sentence in each argument description, since that
tells you when the sparse change is applied (i.e. applied when the command
is run, or applied when the commit is made)


One other thing, the sparse extension is smart about temporarily pulling 
in files necessary for merge conflicts (like during a rebase, we pull in 
files that are being rebased until the rebase is over). This is very 
useful logic and would need to be ported to narrow as well.

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Unifying sparse and narrow "profiles"

2017-03-30 Thread Martin von Zweigbergk via Mercurial-devel
On Thu, Mar 30, 2017 at 1:15 PM, Durham Goode  wrote:
> On 3/29/17 7:47 PM, Augie Fackler wrote:
>>
>> (+martinvonz, durham)
>>
>>> On Mar 29, 2017, at 1:05 PM, Gregory Szorc 
>>> wrote:
>>>
>>> Mozilla has added tens of thousands of files to the Firefox repo in
>>> the past few months and we have plans to add tens of thousands more
>>> shortly. Working directory update times (especially in automation,
>>> which has to do fresh checkouts with a somewhat high frequency
>>> since we rely on ephemeral compute instances) were borderline
>>> tolerable before. With the addition of tens of thousands of new
>>> files, working directory updates are starting to put noticeable
>>> strain on systems.
>>>
>>> Mozilla can make due with sparse checkouts - we don't yet have so
>>> much repo data that we need narrow clone, although narrow would be
>>> useful.
>>>
>>> Facebook's sparse checkout extension has existed for years and my
>>> understanding is it gets the job done. When I asked at the sprint
>>> why sparse isn't part of the core distribution, someone mentioned
>>> it is because sparse and narrow have different, competing concepts
>>> for defining a sparse/narrow profile and these will need to be
>>> reconciled before either can be accepted into core.
>>
>>
>> I think we’ve mostly stopped caring about profiles for our users -
>> Martin, can you confirm that?
>
>
> While Google might not need sparse profiles, I think the feature is critical
> for making sparse usable in a multi-user environment. I think the lack of it
> is one of the reasons Git's sparse implementation is not more widely used
> (along with its unpolished UI).
>
>>
>>> Is there a timeline for unifying the profiles and adding sparse to
>>> the core distribution?
>>
>>
>> This is mostly on me, I think, to clean up narrow and make it so that
>> it can satisfy the varying modes of operation:
>> 0) narrow working directory only
>> 1) narrow working directory and history, but no eliding of irrelevant
>> changes
>> 2) “full narrow”, including elision of irrelevant changes
>>
>> What we’re using at Google is mode 2, but that’s also the most
>> server-expensive and the most likely to have bugs. It shouldn’t be
>> /too/ much work to reconcile our implementation with sparse, add
>> profiles support, and default to mode 0 or 1.

I agree about this.

I'd also like to point out that mode 1 and 2 with treemanifests places
unusual requirements on matching, namely that the client and server
will agree on which directories are needed (the match.visitdir()
method), given a set of patterns. For example, if I include
"glob:foo/*/bar", the client will not know what which subdirectories
in foo/ have a bar (sub)subdirectory, so the server will need to send
all of them (i.e. the server can not skip subdirectories of foo/ that
don't have any 'bar's). It also means that the match.visitdir() has to
match between client and server, which places BC constraints on adding
optimizations to match.visitdir(). So for mode 1 and 2, we should
probably make the server restrictive about what kinds of patterns it
allows, at least when using treemanifests.


>>
>> Durham, do you have opinions on this? Is it a fair assumption on my
>> part that you’d rather we maintain this horror than you?
>
>
> If we make some basic assumptions about the UI (i.e. 'hg sparse' is a good
> command name, and it will have 'include', 'exclude', 'enable-profile', and
> 'disable-profile' flags; and .hg/sparse is a good spot to store the client
> config), I'd almost say let's ship the current sparse extension in hgext/
> and satisfy mode 0. Then once the narrow-sparse unification has occurred
> (assuming it implements the same hg sparse UI for mode 0 operations), we can
> delete the old sparse code.

I'm not ready to make those assumption (and I'm not sure you were
saying we should). I think we need to discuss UI for the three modes
Augie mentioned and make sure that they feel consistent.

>
> Heck, it may even be beneficial to have the 'hg sparse' command control the
> working copy oriented sparseness, and a separate command to control the
> storage sparseness. So introducing them separately may make even more sense.

Possibly.

>
> That way we can have sparse in 4.3, and there's no pressure to prioritize
> the narrow refactor until we feel it's necessary. That opens room for
> potential future refactors in narrowhg as Facebook moves towards a lazy
> changelog strategy which could influence the public facing narrowness
> strategy.

For sparse and/or narrow in core, I think we'll need to pass matchers
around a bit more. We probably will also need to work on matcher
composition, so we can create a matcher with the user's patterns ANDed
together with the sparse/narrow matcher. Do you have that problem
already in the sparse extension? Once we have both sparse and narrow,
it seems likely we will need to compose those two matchers too.

>
>>
>> (Also, are there any docs I should read about your sparse stuff and
>> profil

Re: [PATCH 7 of 7 shelve-ext v5] shelve: add some forwards compatibility to shelve operations

2017-03-30 Thread Kostia Balytskyi
On 30/03/2017 10:31, Ryan McElroy wrote:

> On 3/29/17 2:18 PM, Kostia Balytskyi wrote:
>> # HG changeset patch
>> # User Kostia Balytskyi 
>> # Date 1490790691 25200
>> #  Wed Mar 29 05:31:31 2017 -0700
>> # Node ID 0953ca0a71a0e1f05078b0f3c255459e1ba56a4e
>> # Parent  9ce0a366a6316d1cffc2a875e7dc6b4a3227c851
>> shelve: add some forwards compatibility to shelve operations
>>
>> This patch handles cases where someone enabled an obs-based
>> shelve in their repo, then disabled it while having made some
>> shelves. Approach of this patch is described below:
>> - assume this is what .hg/shelved looks like:
>>- sh1.patch (created 1s ago)
>>- sh1.oshelve (created 1s ago)
> Would it make sense to have a "compatibility mode" where we also 
> create the bundle, so that unshelving is actually backwards-compatible 
> (if this option is enabled)?
We chatted in person and agreed on the following.
Despite my initial idea of making 'experimental.obsshelve' a clear line 
between Mercurial knowing about obs-shelves and not knowing about them, 
there seem to be no harm in letting list and unshelve know how to deal 
with obsshelves. This means that current patch can be dropped entirely 
and I will need to change a bit of unshelve's behavior. Effectively, it 
will work like this:
- I run 'hg shelve --config experimental.obsshelve=on --name myshelve', 
my changes are obs-shelved
- I run 'hg shelve --list --config experimental.obsshelve=off', 
'myshelve' is shown among other shelves
- I run 'hg unshelve --config experimental.obsshelve=off myshelve', and 
the operation is successful

I will modify shelve to behave like this in the next series unless 
someone objects bofore.
>
>>- sh2.patch (created 2s ago)
>>- sh2.hg (created 2s ago)
>> - when obs-based shelve is enabled, 'hg shelve --list' shows both
>>sh1 and s2 and is able to unshelve both. 'hg unshelbe' (without 
>> --name)
>
> s/unshelbe/unshelve
>
>>will unshelve sh1.
>> - when obs-based shelve is disabled, 'hg shelve --list' only shows
>>sh2, prints a warning that it found an obs-based shelve and is
>>only able to unshelve a traditional shelve. 'hg unshelve'
>>(without --name) will unshelve sh2.
>>
>> diff --git a/hgext/shelve.py b/hgext/shelve.py
>> --- a/hgext/shelve.py
>> +++ b/hgext/shelve.py
>> @@ -66,9 +66,15 @@ testedwith = 'ships-with-hg-core'
>> backupdir = 'shelve-backup'
>>   shelvedir = 'shelved'
>> -shelvefileextensions = ['hg', 'patch', 'oshelve']
>>   # universal extension is present in all types of shelves
>>   patchextension = 'patch'
>> +# extension used for bundle-based traditional shelves
>> +traditionalextension = 'hg'
>> +# extension used for obs-based shelves
>> +obsshelveextension = 'oshelve'
>> +shelvefileextensions = [traditionalextension,
>> +patchextension,
>> +obsshelveextension]
>> # we never need the user, so we use a
>>   # generic user for all shelve operations
>> @@ -530,7 +536,12 @@ def deletecmd(ui, repo, pats):
>>   raise error.Abort(_("shelved change '%s' not found") % 
>> name)
>> def listshelves(repo):
>> -"""return all shelves in repo as list of (time, filename)"""
>> +"""return a tuple of (allshelves, obsshelvespresent)
>> +where
>> +'allshelves' is a list of (time, filename) for shelves available
>> +in current repo configuration
>> +'obsshelvespresent' is a bool indicating whether repo has
>> +any obs-based shelves"""
>>   try:
>>   names = repo.vfs.readdir(shelvedir)
>>   except OSError as err:
>> @@ -538,13 +549,22 @@ def listshelves(repo):
>>   raise
>>   return []
>>   info = []
>> +obsshelvedisabled = not isobsshelve(repo, repo.ui)
>> +obsshelvespresent = False
>>   for (name, _type) in names:
>>   pfx, sfx = name.rsplit('.', 1)
>> +if sfx == obsshelveextension:
>> +obsshelvespresent = True
>>   if not pfx or sfx != patchextension:
>>   continue
>> +traditionalfpath = repo.vfs.join(shelvedir,
>> + pfx + '.' + 
>> traditionalextension)
>> +if obsshelvedisabled and not repo.vfs.exists(traditionalfpath):
>> +# this is not a traditional shelve
>> +continue
>>   st = shelvedfile(repo, name).stat()
>>   info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
>> -return sorted(info, reverse=True)
>> +return sorted(info, reverse=True), obsshelvespresent
>> def listcmd(ui, repo, pats, opts):
>>   """subcommand that displays the list of shelves"""
>> @@ -554,7 +574,13 @@ def listcmd(ui, repo, pats, opts):
>>   width = ui.termwidth()
>>   namelabel = 'shelve.newest'
>>   ui.pager('shelve')
>> -for mtime, name in listshelves(repo):
>> +availableshelves, obsshelvespresent = listshelves(repo)
>> +if (obsshelvespresent and not 

Re: [PATCH 1 of 4 V2] obsolete: track node versions

2017-03-30 Thread Jun Wu
I think this is a very nice approach to move forward. There are some
behavior changes. But I've discussed with Durham and I'm happy about the new
behaviors.

The "node version" approach achieves "unhide" in a fast and more
conservative way. The root-based hidden seems to require some non-trivial
changes so I'll send a new version of "node version" patches solely to solve
the "visibility" issue. Without a more general purposed API targeting future
possibilities like exchange etc.

Excerpts from Durham Goode's message of 2017-03-30 11:28:32 -0700:
> Let's step back a moment and think about what obsmarkers are used for. 
> They are used to hide commits, and to automatically perform rebases. The 
> concerns around obscycles is that allowing cycles (without a perfect 
> version scheme) could affect those two uses.  For hiding, it could 
> result in hiding commits from the user that they didn't mean to be 
> hidden. For rebasing, it means we could rebase onto the wrong successor.
> 
> I think the underlying issue is that we're trying to do too much magic 
> for the user, and we're unable to find a perfect design to make that 
> magic safe and understandable. I think finding the right answer here may 
> be impossible.
> 
> Proposal
> ===
> 
> I propose a series of changes to reduce the magic and remove the need 
> for obs versioning, while maintaining the power and increasing the 
> understandability of these workflows. It has two parts:
> 
> 
> 1. Never hide a commit during hg pull. Only hide commits when the user 
> does an action (strip/rebase/amend/histedit/evolve)
> ---
> 
> One of the recurring issues with obsmarkers is that commits may 
> magically disappear when you pull from another repo. This has two 
> issues: A) we have no good way of explaining it to the user, and B) we 
> can't even be sure the user wants those commits to disappear.
> 
> I propose we *never* hide a commit when doing hg pull. When the user 
> pulls, we download the obsmarkers like normal, but the commits don't 
> disappear. Instead, we show the "[amended|rebased] to HASH" text in a 
> log/smartlog output so the user can know the old commits are dead, then 
> they can strip them at their leisure. This has the added benefit of 
> making it user visible what obsmarker changes the pull brought in.
> 
> This proposal has two optional side features:
> 
> 1a. *Do* hide commits during pull if the pulled version is public.
> 1b. Add an option to strip/prune to auto hide any visible commits that 
> have visible successors and don't have visible descendants. So "hg pull 
> && hg strip/prune --obsolete-commits" would be roughly equivalent to hg 
> pull today.
> 
> This proposal requires a notable change to core:
> 
> - Hidden must be separated from obsmarkers storage and mutable outside 
> obsmarkers. This is possible with Jun's proposed phaseroot-esque hidden 
> storage.
> 
> 
> 2. Auto rebase uses "visible successors" instead of "latest successor"
> ---
> 
> Today auto rebase (i.e. evolve) uses the latest successor as the 
> destination of the rebases. I propose we change that to "visible 
> successor" instead, where visible successor is defined as "any successor 
> commit that is not hidden". This means, regardless of the current 
> obsmarkers setup, the destination of the auto rebase is whatever 
> successor is currently visible. Which is probably what the user wanted 
> anyway.
> 
> If there are multiple visible successors, auto rebase fails and shows a 
> list of the potential visible successors. Each item in the list can have 
> the "[amended|rebased] to HASH" string next to it so users can 
> understand at a glance the ordering and make a decision. They can either 
> use -d on rebase to specify a solution to the conflict, or they  can use 
> the normal visibility commands (hg strip/prune) to remove any 
> undesirable commits.
> 
> The presence of cycles does not affect this at all, and there is no need 
> for marker versioning. Auto rebase still uses whatever successors are 
> visible, even if the successor is "older" than it, because of a cycle. 
> The user can use the same rebase -d or strip/prune resolutions to 
> resolve the conflict.
> 
> Summary of what these two changes achieve
> ===
> 
>  From a single, non-exchanging user's perspective the above proposal 
> does not affect current UX around when things are hidden (like during 
> rebase/amend/etc), but does allows all the benefits of the obscycle 
> discussion (allowing unhiding) without the need for obsmarker versioning.
> 
>  From an exchange user's perspective, this makes exchange much more 
> deterministic for the user (nothing is magically removed from the repo, 
> and what new obs information from the pull is explained via smartlog), 
> while still enabling auto rebase workflows. It also makes obsmarker 
> conflict (divergence/etc) easier to understand and resolve by allowing 
> users to resolve obsmarker conflicts using tools they're already 
> familiar with (rebase -d, st

Re: Unifying sparse and narrow "profiles"

2017-03-30 Thread Durham Goode

On 3/29/17 7:47 PM, Augie Fackler wrote:

(+martinvonz, durham)


On Mar 29, 2017, at 1:05 PM, Gregory Szorc  wrote:

Mozilla has added tens of thousands of files to the Firefox repo in
the past few months and we have plans to add tens of thousands more
shortly. Working directory update times (especially in automation,
which has to do fresh checkouts with a somewhat high frequency
since we rely on ephemeral compute instances) were borderline
tolerable before. With the addition of tens of thousands of new
files, working directory updates are starting to put noticeable
strain on systems.

Mozilla can make due with sparse checkouts - we don't yet have so
much repo data that we need narrow clone, although narrow would be
useful.

Facebook's sparse checkout extension has existed for years and my
understanding is it gets the job done. When I asked at the sprint
why sparse isn't part of the core distribution, someone mentioned
it is because sparse and narrow have different, competing concepts
for defining a sparse/narrow profile and these will need to be
reconciled before either can be accepted into core.


I think we’ve mostly stopped caring about profiles for our users -
Martin, can you confirm that?


While Google might not need sparse profiles, I think the feature is 
critical for making sparse usable in a multi-user environment. I think 
the lack of it is one of the reasons Git's sparse implementation is not 
more widely used (along with its unpolished UI).





Is there a timeline for unifying the profiles and adding sparse to
the core distribution?


This is mostly on me, I think, to clean up narrow and make it so that
it can satisfy the varying modes of operation:
0) narrow working directory only
1) narrow working directory and history, but no eliding of irrelevant
changes
2) “full narrow”, including elision of irrelevant changes

What we’re using at Google is mode 2, but that’s also the most
server-expensive and the most likely to have bugs. It shouldn’t be
/too/ much work to reconcile our implementation with sparse, add
profiles support, and default to mode 0 or 1.

Durham, do you have opinions on this? Is it a fair assumption on my
part that you’d rather we maintain this horror than you?


If we make some basic assumptions about the UI (i.e. 'hg sparse' is a 
good command name, and it will have 'include', 'exclude', 
'enable-profile', and 'disable-profile' flags; and .hg/sparse is a good 
spot to store the client config), I'd almost say let's ship the current 
sparse extension in hgext/ and satisfy mode 0. Then once the 
narrow-sparse unification has occurred (assuming it implements the same 
hg sparse UI for mode 0 operations), we can delete the old sparse code.


Heck, it may even be beneficial to have the 'hg sparse' command control 
the working copy oriented sparseness, and a separate command to control 
the storage sparseness. So introducing them separately may make even 
more sense.


That way we can have sparse in 4.3, and there's no pressure to 
prioritize the narrow refactor until we feel it's necessary. That opens 
room for potential future refactors in narrowhg as Facebook moves 
towards a lazy changelog strategy which could influence the public 
facing narrowness strategy.




(Also, are there any docs I should read about your sparse stuff and
profiles?)


`hg sparse --help` is about all we have right now but it's pretty good. 
Just pay attention to the last sentence in each argument description, 
since that tells you when the sparse change is applied (i.e. applied 
when the command is run, or applied when the commit is made)

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 4 V2] obsolete: track node versions

2017-03-30 Thread Durham Goode

On 3/30/17 11:28 AM, Durham Goode wrote:


1. Never hide a commit during hg pull. Only hide commits when the user
does an action (strip/rebase/amend/histedit/evolve)

2. Auto rebase uses "visible successors" instead of "latest successor"


To elaborate on how I see this obs cycle series affecting this proposal, 
I think the end result of this proposal is that obs versioning won't 
matter anymore.  Or at the very least versioning only becomes a rough 
heuristic to suggest to the user which visible successor is likely to be 
their desired auto rebase destination.


But, this series would be a fast way to introduce the concept of 
unhiding into core, which would let us start developing user experiences 
that benefit from unhiding, until we have truly separate hidden storage. 
So if we think my proposal is a good idea and where we want to be in the 
long run, I think we take this obscycle series, and don't worry about 
date being an imperfect heuristic since it won't matter in the long run. 
And we don't worry about the edge cases where it's unclear if X should 
be visible or Y, because in the future visibility will only ever be 
changed by explicit user action, and never by deducing it from obsmarker.

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 4 V2] obsolete: track node versions

2017-03-30 Thread Durham Goode
Let's step back a moment and think about what obsmarkers are used for. 
They are used to hide commits, and to automatically perform rebases. The 
concerns around obscycles is that allowing cycles (without a perfect 
version scheme) could affect those two uses.  For hiding, it could 
result in hiding commits from the user that they didn't mean to be 
hidden. For rebasing, it means we could rebase onto the wrong successor.


I think the underlying issue is that we're trying to do too much magic 
for the user, and we're unable to find a perfect design to make that 
magic safe and understandable. I think finding the right answer here may 
be impossible.


Proposal
===

I propose a series of changes to reduce the magic and remove the need 
for obs versioning, while maintaining the power and increasing the 
understandability of these workflows. It has two parts:



1. Never hide a commit during hg pull. Only hide commits when the user 
does an action (strip/rebase/amend/histedit/evolve)

---

One of the recurring issues with obsmarkers is that commits may 
magically disappear when you pull from another repo. This has two 
issues: A) we have no good way of explaining it to the user, and B) we 
can't even be sure the user wants those commits to disappear.


I propose we *never* hide a commit when doing hg pull. When the user 
pulls, we download the obsmarkers like normal, but the commits don't 
disappear. Instead, we show the "[amended|rebased] to HASH" text in a 
log/smartlog output so the user can know the old commits are dead, then 
they can strip them at their leisure. This has the added benefit of 
making it user visible what obsmarker changes the pull brought in.


This proposal has two optional side features:

1a. *Do* hide commits during pull if the pulled version is public.
1b. Add an option to strip/prune to auto hide any visible commits that 
have visible successors and don't have visible descendants. So "hg pull 
&& hg strip/prune --obsolete-commits" would be roughly equivalent to hg 
pull today.


This proposal requires a notable change to core:

- Hidden must be separated from obsmarkers storage and mutable outside 
obsmarkers. This is possible with Jun's proposed phaseroot-esque hidden 
storage.



2. Auto rebase uses "visible successors" instead of "latest successor"
---

Today auto rebase (i.e. evolve) uses the latest successor as the 
destination of the rebases. I propose we change that to "visible 
successor" instead, where visible successor is defined as "any successor 
commit that is not hidden". This means, regardless of the current 
obsmarkers setup, the destination of the auto rebase is whatever 
successor is currently visible. Which is probably what the user wanted 
anyway.


If there are multiple visible successors, auto rebase fails and shows a 
list of the potential visible successors. Each item in the list can have 
the "[amended|rebased] to HASH" string next to it so users can 
understand at a glance the ordering and make a decision. They can either 
use -d on rebase to specify a solution to the conflict, or they  can use 
the normal visibility commands (hg strip/prune) to remove any 
undesirable commits.


The presence of cycles does not affect this at all, and there is no need 
for marker versioning. Auto rebase still uses whatever successors are 
visible, even if the successor is "older" than it, because of a cycle. 
The user can use the same rebase -d or strip/prune resolutions to 
resolve the conflict.


Summary of what these two changes achieve
===

From a single, non-exchanging user's perspective the above proposal 
does not affect current UX around when things are hidden (like during 
rebase/amend/etc), but does allows all the benefits of the obscycle 
discussion (allowing unhiding) without the need for obsmarker versioning.


From an exchange user's perspective, this makes exchange much more 
deterministic for the user (nothing is magically removed from the repo, 
and what new obs information from the pull is explained via smartlog), 
while still enabling auto rebase workflows. It also makes obsmarker 
conflict (divergence/etc) easier to understand and resolve by allowing 
users to resolve obsmarker conflicts using tools they're already 
familiar with (rebase -d, strip/prune).

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 7 shelve-ext v5] shelve: add obs-based shelve functionality

2017-03-30 Thread Jun Wu
As long as evolve does not have a way to unhide a commit. I think we do need
to use strip on repos that with obsstore enabled. So I'd say the patch
probably needs to be deferred until we can unhide a commit.

Excerpts from Kostia Balytskyi's message of 2017-03-30 10:11:55 +:
> 
> On 30/03/2017 10:15, Ryan McElroy wrote:
> >
> >
> > On 3/29/17 2:18 PM, Kostia Balytskyi wrote:
> >> # HG changeset patch
> >> # User Kostia Balytskyi 
> >> # Date 1490790691 25200
> >> #  Wed Mar 29 05:31:31 2017 -0700
> >> # Node ID fc1144e5993a5c85060b913e2d92cd4b1b61772e
> >> # Parent  0aa864184c9d78c11d18980cf0faa10828445ff5
> >> shelve: add obs-based shelve functionality
> >>
> >> Obsolescense-based shelve works in a following way:
> >
> > s/ a/ the
> sigh :/ Will fix.
> >
> >> 1. In order to shelve some changes, it creates a commit, records its
> >> node into a .oshelve file and prunes created commit.
> >> 2. In order to finish a shelve operation, transaction is just
> >> closed and not aborted.
> >
> > s/transaction/the transaction
> >
> >>
> >> diff --git a/hgext/shelve.py b/hgext/shelve.py
> >> --- a/hgext/shelve.py
> >> +++ b/hgext/shelve.py
> >> @@ -380,10 +380,15 @@ def _nothingtoshelvemessaging(ui, repo,
> >>   else:
> >>   ui.status(_("nothing changed\n"))
> >>   -def _shelvecreatedcommit(repo, node, name):
> >> -bases = list(mutableancestors(repo[node]))
> >> -shelvedfile(repo, name, 'hg').writebundle(bases, node)
> >> -cmdutil.export(repo, [node],
> >> +def _shelvecreatedcommit(ui, repo, node, name, tr):
> >> +if isobsshelve(repo, ui):
> >> +shelvedfile(repo, name, 'oshelve').writeobsshelveinfo({
> >> +'node': nodemod.hex(node)
> >> +})
> >> +else:
> >> +bases = list(mutableancestors(repo[node]))
> >> +shelvedfile(repo, name, 'hg').writebundle(bases, node)
> >> +cmdutil.export(repo.unfiltered(), [node],
> >>  fp=shelvedfile(repo, name, 
> >> patchextension).opener('wb'),
> >>  opts=mdiff.diffopts(git=True))
> >
> > I'm a latecomer to paying attention to this series, so please push 
> > back on me if this has already been discussed, but I think it would be 
> > "cleaner" to not mix old shelve and logic, and instead have just have 
> > the main function _shelvecreatedcommit() call out to 
> > _obsshelvecreatedcommit() or _abortshelvecreatedcommit() (or whatever 
> > we call the traditional version).
> >
> > Again, feel free to push back if this has already been discussed or 
> > discarded as a direction, or if there are other reasons to not do it.
> I agree that this can be made better. Sean Farley (if I'm not mistaken) 
> suggested that this should be a class. I do not mind refactrong it 
> later, but I want to get it in first as a functionality. Also, 
> currently, if I understand you correctly, you want to split an 11 line 
> function into two. I don't think it's worth it at the moment.
> >
> >>   @@ -394,8 +399,13 @@ def _includeunknownfiles(repo, pats, opt
> >>   extra['shelve_unknown'] = '\0'.join(s.unknown)
> >>   repo[None].add(s.unknown)
> >>   -def _finishshelve(repo):
> >> -_aborttransaction(repo)
> >> +def _finishshelve(ui, repo, tr, node):
> >> +if isobsshelve(repo, ui):
> >> +obsolete.createmarkers(repo, [(repo.unfiltered()[node], ())])
> >> +tr.close()
> >> +tr.release()
> >> +else:
> >> +_aborttransaction(repo)
> >> def _docreatecmd(ui, repo, pats, opts):
> >>   wctx = repo[None]
> >> @@ -417,9 +427,12 @@ def _docreatecmd(ui, repo, pats, opts):
> >>   try:
> >>   lock = repo.lock()
> >>   -# use an uncommitted transaction to generate the bundle to 
> >> avoid
> >> -# pull races. ensure we don't print the abort message to 
> >> stderr.
> >> -tr = repo.transaction('commit', report=lambda x: None)
> >> +# depending on whether shelve is traditional or
> >> +# obsolescense-based, we either abort or commit this
> >> +# transaction in the end. If we abort it, we don't
> >> +# want to print anything to stderr
> >> +report = None if isobsshelve(repo, ui) else (lambda x: None)
> >> +tr = repo.transaction('commit', report=report)
> >> interactive = opts.get('interactive', False)
> >>   includeunknown = (opts.get('unknown', False) and
> >> @@ -447,16 +460,19 @@ def _docreatecmd(ui, repo, pats, opts):
> >>   _nothingtoshelvemessaging(ui, repo, pats, opts)
> >>   return 1
> >>   -_shelvecreatedcommit(repo, node, name)
> >> +_shelvecreatedcommit(ui, repo, node, name, tr)
> >> if ui.formatted():
> >>   desc = util.ellipsis(desc, ui.termwidth())
> >>   ui.status(_('shelved as %s\n') % name)
> >> -hg.update(repo, parent.node())
> >> +# current wc parent may be already obsolete becuase
> >> +# it might have been created previousl

Re: [PATCH RFC] repo: add an ability to hide nodes in an appropriate way

2017-03-30 Thread Martin von Zweigbergk via Mercurial-devel
On Thu, Mar 30, 2017 at 10:08 AM, Ryan McElroy  wrote:
> On 3/30/17 3:15 PM, Pierre-Yves David wrote:
>>
>> On 03/27/2017 07:24 PM, Augie Fackler wrote:
>>>
>>> On Mon, Mar 27, 2017 at 10:27:33AM +0200, Pierre-Yves David wrote:



 On 03/27/2017 12:32 AM, Kostia Balytskyi wrote:
>
> # HG changeset patch
> # User Kostia Balytskyi 
> # Date 1490567500 25200
> #  Sun Mar 26 15:31:40 2017 -0700
> # Node ID 43cd56f38c1ca2ad1920ed6804e1a90a5e263c0d
> # Parent  c60091fa1426892552dd6c0dd4b9c49e3c3da045
> repo: add an ability to hide nodes in an appropriate way
>
> Potentially frequent usecase is to hide nodes in the most appropriate
> for current repo configuration way. Examples of things which use this
> are rebase (strip or obsolete old nodes), shelve (strip of obsolete
> temporary nodes) and probably others.
> Jun Wu had an idea of having one place in core where this functionality
> is implemented so that others can utilize it. This patch
> implements this idea.


 I do not think this is a step in the right direction, creating
 obsolescence
 marker is not just about hiding changeset.
>>>
>>>
>>> But we're using them for that today, all over the place.
>>
>>
>> Actually, we do not use it all over the place. Current markers usages in
>> core are:
>>
>> amend:
>>  - record evolution history
>>  - prune the temporary amend commit
>>   (that I would rather see disappear all together)
>>
>> rebase:
>>  - record evolution history on successful completion
>>
>> histedit:
>>  - record evolution history on successful completion
>>  - prune temporary nodes on successsful completion
>>(This ones used to be stripped even with evolution)
>>
>> (let us talk about shelve later)
>>
>>
>> So they are mainly used to record evolution history on successful
>> operation (their intended usage) between "real-changesets". This is the
>> intended usage of obsolescence markers.
>>
>> In addition, they are also used in a couple of place to hide temporary
>> changesets (in the "utility-space") after an operation succeeed.
>> This a bit an unorthodox uses of the obsolescence markers, but is "okay"
>> to use them in these case because we know:
>>  1) this is utility-space so user never interact with them.
>>  2) we only create them for completed successful operation so we'll never
>> need them ever again.
>> Strictly speaking we could just strip these temporary commits (and we have
>> done so in the past) and this will not change anything for the user. Any
>> other hiding mechanism aimed at "internal temporary" commit would do the job
>> just fine. The internal commit never needs (and actually should ever) to
>> leave the user repository.
>> In practice, we could use in memory commit for most of these temporary
>> commit  (if not all) and never have to deal with hiding them.
>>
>>> We're also having pretty productive (I think!) discussions about
>>> non-obsmarker
>>> based mechanisms for hiding things that are implementation details of
>>> a sort (amend changesets that get folded immediately, shelve changes,
>>> etc).
>>
>>
>> (Let me be at be long to try to be clear and comprehensive)
>>
>> I can see three categories of things we want to hide:
>>
>> :obsolete changeset (evolution semantic):
>>
>>   A rewrite operation has created/recorded a new version of this
>> changesets. that old version no longer needs to be shown to users (if
>> possible). There is a strong semantic associated with such changesets and
>> the property will be propagated to other repositories
>>
>> :temporary/internal changesets:
>>
>>   Such changesets are created as a side effect of other operation (amend,
>> histedit, etc). They have the following properties (once we are done using
>> them)
>>
>>   * They are irrelevant to the users,
>>   * We should never-ever base anything on them,
>>   * We should never-ever access them ever again,
>>   * They should never-ever leave the repository.
>>   * They never stop being internal-changesets
>>
>> :locally-hidden changeset:
>>
>>   An hypothetically (not used) yet local-only hidden mechanism (similar to
>> strip but without actual repo stripping). This could be used for local
>> hiding/masking of changeset in the "real-changeset" space. Such data would
>> not be exchanged. Commit reappears when "recreated" or re-pulled.
>>
>> ---
>>
>> To take practical examples:
>>
>> :amend:
>>   - amend source: "obsolete-changeset"
>>   - temporary changeset: "internal-changeset"
>>
>> :rebase:
>>   - rebase source, on success: "obsolete-changeset"
>>   - rebase result, on abort:  "local-hiding"
>>
>>
>> :histedit:
>>   - histedit source, on success: "obsolete-changeset"
>>   - histedit temporary node, on success: "internal-changeset"
>>   - histedit result, on abort:   "local-hiding"
>>   - histedit temporary node, on abort:   "local-hiding (internal-node)"
>>
>> extra notes:
>>  * If local hiding (strip) would take

Re: [PATCH] test-check-code: prevent files being added to the root directory

2017-03-30 Thread Jun Wu

Excerpts from Ryan McElroy's message of 2017-03-30 09:24:38 +0100:
> On 3/29/17 8:14 PM, Jun Wu wrote:
> > # HG changeset patch
> > # User Jun Wu 
> > # Date 1490814860 25200
> > #  Wed Mar 29 12:14:20 2017 -0700
> > # Node ID 4b4345a62fbd9fb0f4610d013c4ee5c9c06287e0
> > # Parent  cda83a1bfb3ac3a23cfa158c407be93755c1018e
> > test-check-code: prevent files being added to the root directory
> 
> This looks good to me. Marked as pre-reviewed in patchwork.
> 
> > Adding new files in the root directory is probably a mistake, and is usually
> > discouraged [1]. The test catches it to avoid mistakes like [2].
> >
> > Modify the test if files need to be added in the root.
> >
> > [1]: 
> > https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-July/086442.html
> > [2]: 
> > https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-March/095836.html
> 
> OMG I hate proofpoint. I want it to die in a fire. This is why I always 
> remove the footers and the "available at" URLs haha.

I didn't see proofpoint?

This is an advertisement of sup [1].

[1]: https://github.com/quark-zju/sup/
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2] verify: document corner cases

2017-03-30 Thread Ryan McElroy

On 3/30/17 5:01 PM, Jun Wu wrote:

Excerpts from Ryan McElroy's message of 2017-03-30 09:55:50 +0100:

On 3/29/17 10:51 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490823901 25200
#  Wed Mar 29 14:45:01 2017 -0700
# Node ID 1f7890370b5437466534cbd0a313d21671dade03
# Parent  e9fda3b8614a8b701bd48041afa8b709e1227f27
verify: document corner cases

It seems a good idea to list all kinds of "surprises" and expected behavior
to make the upcoming changes easier to understand.

Note: the comment added do not reflect the actual behavior of the current

grammar-nit: s/do/does


code.

diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -381,4 +381,44 @@ class verifier(object):
   
   # verify contents

+#
+# Define 4 cases to help understand corner cases:
+#
+#   | common | rename | meta  | ext

Can you define these four words?

The first table is supposed to define them precisely.


I guess it didn't for me, which is why I asked and thought "english 
descriptions" would be useful.





common = common case?
rename = file was just copied from somewhere else?
meta = ???

"rename" is called "metadata" in filelog.py, so it means metadata without
rename.


When would this happen? It's still not clear to me.




ext = extension that adds a flags processor?

+#  ---
+#   flags() | 0  | 0  | 0 | not 0
+#   renamed()   | False  | True   | False | ?
+#   rawtext[0:2]=='\1\n'| False  | True   | True  | ?
+#
+# "rawtext" means the raw text stored in revlog data, which
+# could be retrieved by "revision(rev, raw=True)". "text"
+# mentioned below is "revision(rev, raw=False)".
+#
+# There are 3 different lengths stored physically:
+#  1. L1: rawsize, stored in revlog index
+#  2. L2: len(rawtext), stored in revlog data
+#  3. L3: len(text), stored in revlog data if flags=0, or
+# possibly somewhere else if flags!=0
+#
+# L1 should be equal to L2. L3 is unrelated to L1 or L2. But

How about "L3 can be different than L1 and L2" -- it would be the same
if there are no flags, right?

Yes. I notice the minor difference between the language. Thanks for the
suggestion!


+# text may or may not affect commit hash depending on flag
+# processors (see revlog.addflagprocessor).
+#
+#  | common  | rename | meta  | ext
+# -
+#rawsize() | L1  | L1 | L1| L1
+#   size() | L1  | L2-LM  | L1(*) | L1 (?)
+# len(rawtext) | L2  | L2 | L2| L2
+#len(text) | L2  | L2 | L2| L3
+#  len(read()) | L2  | L2-LM  | L2-LM | L3
+#
+# LM:  length of metadata, depending on rawtext
+# (*): not ideal, see comment in filelog.size
+# (?): could be "- len(meta)" if the resolved content has
+#  rename metadata
+#
+# Checks needed to be done:
+#  1. length check: L1 == L2, in all cases.
+#  2. hash check: depending on flag processor, we may need to
+# use either "text" (external), or "rawtext" (in revlog).
   try:
   l = len(fl.read(n))

Overall this is pretty easy to follow and adds a lot of clarity. Just a
couple of questions inline.


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 4 V2] obsolete: allow cycles

2017-03-30 Thread Jun Wu
Excerpts from Augie Fackler's message of 2017-03-30 12:43:31 -0400:
> On Thu, Mar 30, 2017 at 12:40 PM, Jun Wu  wrote:
> > I'll drop it from patchwork and send a new version with better documentation
> > and some planned fixes. The next version has a same core idea, but the
> > interface is more formalized and is made future proof in mind. The interface
> > changes are by myself and haven't been discussed here.
> 
> 
> Actually, based on a quick discussion I had with Durham, can you check
> with him before sending another volley? It'll help the reviewers if we
> can keep the patch traffic on this topic at a lower rate until we
> actually get some better understanding of where we want/need to go
> architecturally.
> 
> Thanks!

I'll chat with him today. Thanks!

By the way, for series about histedit - I agree that marmoute was right, and
rolling back is the right choice for now. So everything about histedit
should be considered as "settled for now". A better solution about histedit
*depends on* the "node versions" approach. So I may restart the histedit
change if we have "node versions".

The most interesting discussion to me is so-called "obscycles" (aka this
series), but it's more precisely "node versions" as the first patch title
suggests. "cycles" are just a subset of problems it solves <- this paragraph
is for marmoute who might think I don't even understand my own patches.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH RFC] repo: add an ability to hide nodes in an appropriate way

2017-03-30 Thread Ryan McElroy

On 3/30/17 3:15 PM, Pierre-Yves David wrote:

On 03/27/2017 07:24 PM, Augie Fackler wrote:

On Mon, Mar 27, 2017 at 10:27:33AM +0200, Pierre-Yves David wrote:



On 03/27/2017 12:32 AM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490567500 25200
#  Sun Mar 26 15:31:40 2017 -0700
# Node ID 43cd56f38c1ca2ad1920ed6804e1a90a5e263c0d
# Parent  c60091fa1426892552dd6c0dd4b9c49e3c3da045
repo: add an ability to hide nodes in an appropriate way

Potentially frequent usecase is to hide nodes in the most appropriate
for current repo configuration way. Examples of things which use this
are rebase (strip or obsolete old nodes), shelve (strip of obsolete
temporary nodes) and probably others.
Jun Wu had an idea of having one place in core where this 
functionality

is implemented so that others can utilize it. This patch
implements this idea.


I do not think this is a step in the right direction, creating 
obsolescence

marker is not just about hiding changeset.


But we're using them for that today, all over the place.


Actually, we do not use it all over the place. Current markers usages 
in core are:


amend:
 - record evolution history
 - prune the temporary amend commit
  (that I would rather see disappear all together)

rebase:
 - record evolution history on successful completion

histedit:
 - record evolution history on successful completion
 - prune temporary nodes on successsful completion
   (This ones used to be stripped even with evolution)

(let us talk about shelve later)


So they are mainly used to record evolution history on successful 
operation (their intended usage) between "real-changesets". This is 
the intended usage of obsolescence markers.


In addition, they are also used in a couple of place to hide temporary 
changesets (in the "utility-space") after an operation succeeed.
This a bit an unorthodox uses of the obsolescence markers, but is 
"okay" to use them in these case because we know:

 1) this is utility-space so user never interact with them.
 2) we only create them for completed successful operation so we'll 
never need them ever again.
Strictly speaking we could just strip these temporary commits (and we 
have done so in the past) and this will not change anything for the 
user. Any other hiding mechanism aimed at "internal temporary" commit 
would do the job just fine. The internal commit never needs (and 
actually should ever) to leave the user repository.
In practice, we could use in memory commit for most of these temporary 
commit  (if not all) and never have to deal with hiding them.


We're also having pretty productive (I think!) discussions about 
non-obsmarker

based mechanisms for hiding things that are implementation details of
a sort (amend changesets that get folded immediately, shelve changes,
etc).


(Let me be at be long to try to be clear and comprehensive)

I can see three categories of things we want to hide:

:obsolete changeset (evolution semantic):

  A rewrite operation has created/recorded a new version of this 
changesets. that old version no longer needs to be shown to users (if 
possible). There is a strong semantic associated with such changesets 
and the property will be propagated to other repositories


:temporary/internal changesets:

  Such changesets are created as a side effect of other operation 
(amend, histedit, etc). They have the following properties (once we 
are done using them)


  * They are irrelevant to the users,
  * We should never-ever base anything on them,
  * We should never-ever access them ever again,
  * They should never-ever leave the repository.
  * They never stop being internal-changesets

:locally-hidden changeset:

  An hypothetically (not used) yet local-only hidden mechanism 
(similar to strip but without actual repo stripping). This could be 
used for local hiding/masking of changeset in the "real-changeset" 
space. Such data would not be exchanged. Commit reappears when 
"recreated" or re-pulled.


---

To take practical examples:

:amend:
  - amend source: "obsolete-changeset"
  - temporary changeset: "internal-changeset"

:rebase:
  - rebase source, on success: "obsolete-changeset"
  - rebase result, on abort:  "local-hiding"


:histedit:
  - histedit source, on success: "obsolete-changeset"
  - histedit temporary node, on success: "internal-changeset"
  - histedit result, on abort:   "local-hiding"
  - histedit temporary node, on abort:   "local-hiding (internal-node)"

extra notes:
 * If local hiding (strip) would take care of obsolescence marker, 
rebase and histedit could create them "as they go" instead of to the 
end: "on success".
 * In rebase --abort and histedit --abort, strip is used on freshly 
created changesets, so its performance impact is limited
 * we use "local hiding" (strip) on temporary nodes on histedit abort 
because we needs to be able to reuse them if histedit is rerun. So we 
cannot throw them in oblivion just yet.


---

regarding implem

Re: [PATCH 4 of 4 V2] obsolete: allow cycles

2017-03-30 Thread Augie Fackler
On Thu, Mar 30, 2017 at 12:40 PM, Jun Wu  wrote:
> I'll drop it from patchwork and send a new version with better documentation
> and some planned fixes. The next version has a same core idea, but the
> interface is more formalized and is made future proof in mind. The interface
> changes are by myself and haven't been discussed here.


Actually, based on a quick discussion I had with Durham, can you check
with him before sending another volley? It'll help the reviewers if we
can keep the patch traffic on this topic at a lower rate until we
actually get some better understanding of where we want/need to go
architecturally.

Thanks!
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 4 V2] obsolete: allow cycles

2017-03-30 Thread Jun Wu
Per discussion on IRC with marmoute, this series lacks of documentation.

I'll drop it from patchwork and send a new version with better documentation
and some planned fixes. The next version has a same core idea, but the
interface is more formalized and is made future proof in mind. The interface
changes are by myself and haven't been discussed here.

Excerpts from Augie Fackler's message of 2017-03-23 18:05:45 -0400:
> On Mon, Mar 13, 2017 at 11:57:08AM -0700, Pierre-Yves David wrote:
> >
> >
> > On 03/13/2017 09:23 AM, Durham Goode wrote:
> > >On 3/13/17 2:48 AM, Jun Wu wrote:
> > >># HG changeset patch
> > >># User Jun Wu 
> > >># Date 1489395002 25200
> > >>#  Mon Mar 13 01:50:02 2017 -0700
> > >># Node ID 6ae6d1069ba1d4089afaeb0bb8ef2411983a1292
> > >># Parent  0280ee091bd0ae33aa0a67b0c8a55ccffd2e0718
> > >># Available At
> > >>https://bitbucket.org/quark-zju/hg-draft
> > >>
> > >>#  hg pull
> > >>https://bitbucket.org/quark-zju/hg-draft
> > >>-r 6ae6d1069ba1
> > >>obsolete: allow cycles
> > >>
> > >>Now we can handle cycles nicely, allow them to be created. Some practical
> > >>examples:
> > >>
> > >>  - To revive X, just create a marker X -> X, with a newer date.
> > >>  - To prune X again, just create a marker X -> (), with a newer date.
> > >>  - The above two could be repeated.
> > >>
> > >>  - To unamend A -> B, just create a marker B -> A, with a newer date.
> > >>
> > >>It's now possible for "touch" and "unamend" to reuse hashes (therefore
> > >>more
> > >>user-friendly). And it's no longer necessary to write "*_source" in
> > >>commit
> > >>metadata to workarounds obs cycles. The hacky inhibit extension also
> > >>becomes
> > >>unnecessary.
> > >>
> > >>Finally. I have been wanting all these for a long time.
> > >
> > >Seems pretty elegant, though I haven't fully understood it yet. Maybe
> > >you guys talked about this in person, but what effect (if any) does this
> > >have on exchange?
> >
> > We did not really discuss this at the sprint :-/
> >
> > This probably has effect on two aspects of pull and push:
> >
> > * Computation of the relevant markers for a None
> >
> > * Computation of "head replacement" when pushing branches obsoleting another
> > one.
> >
> > The proposal have some very interesting aspect, I'll try to do a deep review
> > of its impact on the general concept soon™ (probably not this week)
> 
> I've had a look over the code, and it's surprisingly simple (though it
> could probably use more comments for future code archaeologists.) I'm
> wary (as is indygreg) of using the date field for this sorting, just
> because clocks are known sources of evil and consternation.
> 
> (I acknowledge we might not have a significantly better choice though,
> although I'd like to give it some more thought.)
> 
> >
> > Cheers,
> >
> > --
> > Pierre-Yves David
> > ___
> > Mercurial-devel mailing list
> > Mercurial-devel@mercurial-scm.org
> > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 4 V2] obsolete: track node versions

2017-03-30 Thread Jun Wu
Per discussion on IRC. I'll drop this series from patchwork and send a new
version with better documentation and some planned fixes.

Excerpts from Jun Wu's message of 2017-03-27 01:49:03 -0700:
> Thanks for the detailed reply. I have replies on multiple subtopics. But I
> deleted topics that I think are less important, to make the most important
> topic clear, and make the discussion more efficient. If you think I need to
> respond to more topics, feel free to point me at them.
> 
> Excerpts from Pierre-Yves David's message of 2017-03-27 09:14:53 +0200:
> 
> [snip]
> 
> > Simple practical example with date:
> > ---
> > 
> > [time-1] repo-B: changeset C-A is pulled from repo-A
> > [time-2] repo-A: changeset C-A is rewritten as C-B (time-2)
> > [time-3] repo-B: changeset C-C is marked as superceeded by C-A (time-3)
> > [time-4] repo-B: Changeset C-B (with marker) is pulled from repo-A
> > 
> > The markers pointing from C-B to C-A have a version "time-2" but "C-A" 
> > now have a version of "time-3". "C-A" become wrongly un-obsoleted (and 
> 
> I think we basically disagree here. You said that "C-A" being visible does
> not match "the meaning of the user action", could you define "the meaning of
> the user action" formally ?
> 
> In the "node version" approach, the "meaning of a user action", where action
> is "creating a marker", is defined as below:
> 
>   When the user replace changeset X with Y, the marker X -> Y gets created,
>   they want Y to be visible, regardless of what previous (local or remote)
>   attempts hiding it.
> 
> So the un-obsolete behavior is expected.
> 
> > C-B is in strange state). The fact C-A is un-obsoleted here is a bug and 
> 
> Strictly speaking, C-B still has an obsoleted precursor of C-A. If we draw a
> 2-D graph, where Y-axis is revision, X-axis is time, and markers are edges,
> the above case could be represented like:
> 
>^ rev
>|  C-C
>|\
>|  C-A   C-A
>| \
>| C-B
>|
>+---> time
> 
> Note that there are 2 "C-A"s, the right one is visible, the left one is not.
> We show users the right one. Internally, the code could distinguish the
> different of 2 "C-A"s, if it wants.
> 
> > do not match the meaning of the user action. This is a regression from 
> > what evolution is currently able to achieve.
> 
> [snip] 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2] verify: document corner cases

2017-03-30 Thread Jun Wu
Excerpts from Ryan McElroy's message of 2017-03-30 09:55:50 +0100:
> On 3/29/17 10:51 PM, Jun Wu wrote:
> > # HG changeset patch
> > # User Jun Wu 
> > # Date 1490823901 25200
> > #  Wed Mar 29 14:45:01 2017 -0700
> > # Node ID 1f7890370b5437466534cbd0a313d21671dade03
> > # Parent  e9fda3b8614a8b701bd48041afa8b709e1227f27
> > verify: document corner cases
> >
> > It seems a good idea to list all kinds of "surprises" and expected behavior
> > to make the upcoming changes easier to understand.
> >
> > Note: the comment added do not reflect the actual behavior of the current
> grammar-nit: s/do/does
> 
> > code.
> >
> > diff --git a/mercurial/verify.py b/mercurial/verify.py
> > --- a/mercurial/verify.py
> > +++ b/mercurial/verify.py
> > @@ -381,4 +381,44 @@ class verifier(object):
> >   
> >   # verify contents
> > +#
> > +# Define 4 cases to help understand corner cases:
> > +#
> > +#   | common | rename | meta  | ext
> 
> Can you define these four words?

The first table is supposed to define them precisely.

> common = common case?
> rename = file was just copied from somewhere else?
> meta = ???

"rename" is called "metadata" in filelog.py, so it means metadata without
rename.

> ext = extension that adds a flags processor?
> > +#  ---
> > +#   flags() | 0  | 0  | 0 | not 0
> > +#   renamed()   | False  | True   | False | ?
> > +#   rawtext[0:2]=='\1\n'| False  | True   | True  | ?
> > +#
> > +# "rawtext" means the raw text stored in revlog data, which
> > +# could be retrieved by "revision(rev, raw=True)". "text"
> > +# mentioned below is "revision(rev, raw=False)".
> > +#
> > +# There are 3 different lengths stored physically:
> > +#  1. L1: rawsize, stored in revlog index
> > +#  2. L2: len(rawtext), stored in revlog data
> > +#  3. L3: len(text), stored in revlog data if flags=0, or
> > +# possibly somewhere else if flags!=0
> > +#
> > +# L1 should be equal to L2. L3 is unrelated to L1 or L2. 
> > But
> 
> How about "L3 can be different than L1 and L2" -- it would be the same 
> if there are no flags, right?

Yes. I notice the minor difference between the language. Thanks for the
suggestion!

> > +# text may or may not affect commit hash depending on flag
> > +# processors (see revlog.addflagprocessor).
> > +#
> > +#  | common  | rename | meta  | ext
> > +# -
> > +#rawsize() | L1  | L1 | L1| L1
> > +#   size() | L1  | L2-LM  | L1(*) | L1 (?)
> > +# len(rawtext) | L2  | L2 | L2| L2
> > +#len(text) | L2  | L2 | L2| L3
> > +#  len(read()) | L2  | L2-LM  | L2-LM | L3
> > +#
> > +# LM:  length of metadata, depending on rawtext
> > +# (*): not ideal, see comment in filelog.size
> > +# (?): could be "- len(meta)" if the resolved content has
> > +#  rename metadata
> > +#
> > +# Checks needed to be done:
> > +#  1. length check: L1 == L2, in all cases.
> > +#  2. hash check: depending on flag processor, we may need 
> > to
> > +# use either "text" (external), or "rawtext" (in 
> > revlog).
> >   try:
> >   l = len(fl.read(n))
> 
> Overall this is pretty easy to follow and adds a lot of clarity. Just a 
> couple of questions inline.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 7 V5] hgweb: add a "patch" query parameter to filelog command

2017-03-30 Thread Yuya Nishihara
On Fri, 31 Mar 2017 00:37:22 +0900, Yuya Nishihara wrote:
> On Thu, 30 Mar 2017 17:10:28 +0200, Denis Laxalde wrote:
> > Yuya Nishihara a écrit :
> > > On Sat, 25 Mar 2017 10:20:57 +0100, Denis Laxalde wrote:
> > >> # HG changeset patch
> > >> # User Denis Laxalde 
> > >> # Date 1489398073 -3600
> > >> #  Mon Mar 13 10:41:13 2017 +0100
> > >> # Node ID a7b9bc1af8b81c332cf34960f581359e6942ca17
> > >> # Parent  ffd1a15d456342caba744f5049b97862fcb697c7
> > >> # Available At https://hg.logilab.org/users/dlaxalde/hg
> > >> #  hg pull https://hg.logilab.org/users/dlaxalde/hg -r 
> > >> a7b9bc1af8b8
> > >> # EXP-Topic linerange-log/hgweb-filelog
> > >> hgweb: add a "patch" query parameter to filelog command
> > >
> > >> @@ -981,12 +985,27 @@ def filelog(web, req, tmpl):
> > >>  repo = web.repo
> > >>  revs = fctx.filelog().revs(start, end - 1)
> > >>  entries = []
> > >> +
> > >> +diffstyle = web.config('web', 'style', 'paper')
> > >> +if 'style' in req.form:
> > >> +diffstyle = req.form['style'][0]
> > >> +
> > >> +def diff(fctx):
> > >> +ctx = fctx.changectx()
> > >> +basectx = ctx.p1()
> > >> +path = fctx.path()
> > >> +return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle)
> > >> +
> > >>  for i in revs:
> > >>  iterfctx = fctx.filectx(i)
> > >> +diffs = None
> > >> +if patch:
> > >> +diffs = diff(iterfctx)
> > >
> > > Got an exception at hidden revision '5cb3b7d1f50f' which had been rebased 
> > > (in
> > > my local repo.) Perhaps linkrev wouldn't be adjusted because we walk 
> > > revision
> > > numbers, not a history of filelog.
> > >
> > 
> > Maybe hidden revisions shouldn't be listed at all? I mean, without the
> > "patch" query parameter, you don't get a crash on the /log// 
> > view,
> > but a 404 when following a link pointing to a hidden revision in the
> > table, so these log entries are arguably not very useful.
> 
> Hidden revisions aren't listed.

I was wrong. Hidden revisions are listed. Maybe we'll need the logic which
"hg log FILE" uses.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 7 V5] hgweb: add a "patch" query parameter to filelog command

2017-03-30 Thread Yuya Nishihara
On Thu, 30 Mar 2017 17:10:28 +0200, Denis Laxalde wrote:
> Yuya Nishihara a écrit :
> > On Sat, 25 Mar 2017 10:20:57 +0100, Denis Laxalde wrote:
> >> # HG changeset patch
> >> # User Denis Laxalde 
> >> # Date 1489398073 -3600
> >> #  Mon Mar 13 10:41:13 2017 +0100
> >> # Node ID a7b9bc1af8b81c332cf34960f581359e6942ca17
> >> # Parent  ffd1a15d456342caba744f5049b97862fcb697c7
> >> # Available At https://hg.logilab.org/users/dlaxalde/hg
> >> #  hg pull https://hg.logilab.org/users/dlaxalde/hg -r 
> >> a7b9bc1af8b8
> >> # EXP-Topic linerange-log/hgweb-filelog
> >> hgweb: add a "patch" query parameter to filelog command
> >
> >> @@ -981,12 +985,27 @@ def filelog(web, req, tmpl):
> >>  repo = web.repo
> >>  revs = fctx.filelog().revs(start, end - 1)
> >>  entries = []
> >> +
> >> +diffstyle = web.config('web', 'style', 'paper')
> >> +if 'style' in req.form:
> >> +diffstyle = req.form['style'][0]
> >> +
> >> +def diff(fctx):
> >> +ctx = fctx.changectx()
> >> +basectx = ctx.p1()
> >> +path = fctx.path()
> >> +return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle)
> >> +
> >>  for i in revs:
> >>  iterfctx = fctx.filectx(i)
> >> +diffs = None
> >> +if patch:
> >> +diffs = diff(iterfctx)
> >
> > Got an exception at hidden revision '5cb3b7d1f50f' which had been rebased 
> > (in
> > my local repo.) Perhaps linkrev wouldn't be adjusted because we walk 
> > revision
> > numbers, not a history of filelog.
> >
> 
> Maybe hidden revisions shouldn't be listed at all? I mean, without the
> "patch" query parameter, you don't get a crash on the /log// 
> view,
> but a 404 when following a link pointing to a hidden revision in the
> table, so these log entries are arguably not very useful.

Hidden revisions aren't listed. I suspect fctx.changectx() would return
a hidden changectx because fctx wasn't traversed from a visible parent and
bypassed linkrev adjustment.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 7 V5] hgweb: add a "patch" query parameter to filelog command

2017-03-30 Thread Denis Laxalde

Yuya Nishihara a écrit :

On Sat, 25 Mar 2017 10:20:57 +0100, Denis Laxalde wrote:

# HG changeset patch
# User Denis Laxalde 
# Date 1489398073 -3600
#  Mon Mar 13 10:41:13 2017 +0100
# Node ID a7b9bc1af8b81c332cf34960f581359e6942ca17
# Parent  ffd1a15d456342caba744f5049b97862fcb697c7
# Available At https://hg.logilab.org/users/dlaxalde/hg
#  hg pull https://hg.logilab.org/users/dlaxalde/hg -r a7b9bc1af8b8
# EXP-Topic linerange-log/hgweb-filelog
hgweb: add a "patch" query parameter to filelog command



@@ -981,12 +985,27 @@ def filelog(web, req, tmpl):
 repo = web.repo
 revs = fctx.filelog().revs(start, end - 1)
 entries = []
+
+diffstyle = web.config('web', 'style', 'paper')
+if 'style' in req.form:
+diffstyle = req.form['style'][0]
+
+def diff(fctx):
+ctx = fctx.changectx()
+basectx = ctx.p1()
+path = fctx.path()
+return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle)
+
 for i in revs:
 iterfctx = fctx.filectx(i)
+diffs = None
+if patch:
+diffs = diff(iterfctx)


Got an exception at hidden revision '5cb3b7d1f50f' which had been rebased (in
my local repo.) Perhaps linkrev wouldn't be adjusted because we walk revision
numbers, not a history of filelog.



Maybe hidden revisions shouldn't be listed at all? I mean, without the
"patch" query parameter, you don't get a crash on the /log// 
view,

but a 404 when following a link pointing to a hidden revision in the
table, so these log entries are arguably not very useful.





+  --- /dev/nullThu Jan 01 00:00:00 1970 +


We'll need a prefix to make 'id' unique.



That's true. Will work on a follow-up.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 07 of 11] revlog: fix many file handle opens to explicitly use bytes mode

2017-03-30 Thread Yuya Nishihara
On Wed, 29 Mar 2017 19:24:11 -0700, Gregory Szorc wrote:
> On Mon, Mar 27, 2017 at 6:54 AM, Yuya Nishihara  wrote:
> > On Sun, 26 Mar 2017 18:36:41 -0400, Augie Fackler wrote:
> > > # HG changeset patch
> > > # User Augie Fackler 
> > > # Date 1490567324 14400
> > > #  Sun Mar 26 18:28:44 2017 -0400
> > > # Node ID e7fe3ab60132647a9c3b86b2960b385e61b9dcf0
> > > # Parent  48144fe2d912b7d9fc300955d0c881aceead6930
> > > revlog: fix many file handle opens to explicitly use bytes mode
> > >
> > > This broke on Python 3, but we've probably been getting lucky that
> > > this hasn't caused EOL corruption on Windows or something for
> > > years. :(
> > >
> > > diff --git a/mercurial/revlog.py b/mercurial/revlog.py
> > > --- a/mercurial/revlog.py
> > > +++ b/mercurial/revlog.py
> > > @@ -1467,8 +1467,8 @@ class revlog(object):
> > >
> > >  dfh = None
> > >  if not self._inline:
> > > -dfh = self.opener(self.datafile, "a+")
> > > -ifh = self.opener(self.indexfile, "a+",
> > checkambig=self._checkambig)
> > > +dfh = self.opener(self.datafile, "a+b")
> > > +ifh = self.opener(self.indexfile, "a+b",
> > checkambig=self._checkambig)
> >
> > 'b' shouldn't be needed since vfs adds 'b' unless text=True is explicitly
> > specified.
> >
> 
> That "text" argument always seemed weird to me because all it does is
> reinvent the wheel for the "mode" argument to open(). I'd prefer we
> deprecate the argument and use explicit mode values so the I/O code more
> closely aligns with what Python does. Principal of least surprise.

Perhaps it exists because 'b' is too subtle and unix programmers would easily
miss it. I'd rather get rid of the text mode at all for Py3 compatibility.
Optionally we can make vfs raise exception if 'b' isn't explicitly specified.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 4 NEW-CONCEPT] track-tags: write all tag changes to a file

2017-03-30 Thread Pierre-Yves David
# HG changeset patch
# User Pierre-Yves David 
# Date 1490688902 -7200
#  Tue Mar 28 10:15:02 2017 +0200
# Node ID 46005886092380991a30c2a02486c2876ecac341
# Parent  2dcaa99d6160561166269f192a89b25f84fd4667
# EXP-Topic tags
# Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/
#  hg pull 
https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 460058860923
track-tags: write all tag changes to a file

The tag changes information we compute are not written to disk. This gives
hooks full acces to that data.

The format picked for that file use a 2 characters prefix for the action:

-R: tag removed
+A: tag added
-M: tag moved (old value)
+M: tag moved (new value)

This format allows hooks to easily select the line that matters to them without
having to post process the file too much. Here is
a couple of example:

 * to select all newly tagged changeset, match "^+",
 * to detect tag move, match "^.M",
 * to detect tag deletion, match "-R".

Once again we rely on the fact the tag tests run through all possible
situations to test this change.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1015,6 +1015,25 @@ class localrepository(object):
 # and do not use caches as much as it could.  The current focus is on
 # the behavior of the feature so we disable it by default. The flag
 # will be removed when we are happy with the performance impact.
+#
+# Once this feature is no longer experimental move the following
+# documentation to the appropriate help section:
+#
+# The ``HG_TAG_MOVED`` variable will be set if the transaction touched
+# tags (new or changed or deleted tags). In addition the details of
+# these changes are made available in a file at:
+# ``REPOROOT/.hg/changes/tags.changes``.
+# Make sure you check for HG_TAG_MOVED before reading that file as it
+# might exist from a previous transaction even if no tag were touched
+# in this one. Change are recorded in a line base format::
+#
+#   \n
+#
+# Actions are defined as follow:
+#   "-R": tag is removed,
+#   "+A": tag is added,
+#   "-M": tag is moved (old value),
+#   "+M": tag is moved (new value),
 tracktags = lambda x: None
 # experimental config: experimental.hook-track-tags
 shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags',
@@ -1031,6 +1050,12 @@ class localrepository(object):
 changes = tagsmod.difftags(repo.ui, repo, oldfnodes, newfnodes)
 if changes:
 tr2.hookargs['tag_moved'] = '1'
+with repo.vfs('changes/tags.changes', 'w',
+  atomictemp=True) as changesfile:
+# note: we do not register the file to the transaction
+# because we needs it to still exist on the transaction
+# is close (for txnclose hooks)
+tagsmod.writediff(changesfile, changes)
 def validate(tr2):
 """will run pre-closing hooks"""
 # XXX the transaction API is a bit lacking here so we take a hacky
diff --git a/mercurial/tags.py b/mercurial/tags.py
--- a/mercurial/tags.py
+++ b/mercurial/tags.py
@@ -129,6 +129,44 @@ def difftags(ui, repo, oldfnodes, newfno
 entries.sort()
 return entries
 
+def writediff(fp, difflist):
+"""write tags diff information to a file.
+
+Data are stored with a line based format:
+
+  \n
+
+Action are defined as follow:
+   -R tag is removed,
+   +A tag is added,
+   -M tag is moved (old value),
+   +M tag is moved (new value),
+
+Example:
+
+ +A 875517b4806a848f942811a315a5bce30804ae85 t5
+
+See documentation of difftags output for details about the input.
+"""
+add = '+A %s %s\n'
+remove = '-R %s %s\n'
+updateold = '-M %s %s\n'
+updatenew = '+M %s %s\n'
+for tag, old, new in difflist:
+# translate to hex
+if old is not None:
+old = hex(old)
+if new is not None:
+new = hex(new)
+# write to file
+if old is None:
+fp.write(add % (new, tag))
+elif new is None:
+fp.write(remove % (old, tag))
+else:
+fp.write(updateold % (old, tag))
+fp.write(updatenew % (new, tag))
+
 def findglobaltags(ui, repo):
 '''Find global tags in a repo: return a tagsmap
 
diff --git a/tests/test-tag.t b/tests/test-tag.t
--- a/tests/test-tag.t
+++ b/tests/test-tag.t
@@ -11,6 +11,7 @@
   > # file...
   > if [ -n "\$HG_TAG_MOVED" ]; then
   > echo 'hook: tag changes detected'
+  > sed 's/^/hook: /' .hg/changes/tags.changes
   > fi
   > EOF
   $ chmod +x taghook.sh
@@ -37,6 +38,7

[PATCH 1 of 4 NEW-CONCEPT] tags: introduce a function to return a valid fnodes list from revs

2017-03-30 Thread Pierre-Yves David
# HG changeset patch
# User Pierre-Yves David 
# Date 1490670416 -7200
#  Tue Mar 28 05:06:56 2017 +0200
# Node ID f6e7b8a14f4a94db6742410331db752112c76b82
# Parent  dea2a17cbfd00bf08ee87b3e44b1c71499189f89
# EXP-Topic tags
# Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/
#  hg pull 
https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r f6e7b8a14f4a
tags: introduce a function to return a valid fnodes list from revs

This will get used to compare tags between two set of revisions during a
transaction (pre and post heads). The end goal is to be able to track tags
movement in transaction hooks.

diff --git a/mercurial/tags.py b/mercurial/tags.py
--- a/mercurial/tags.py
+++ b/mercurial/tags.py
@@ -78,6 +78,18 @@ from . import (
 # The most recent changeset (in terms of revlog ordering for the head
 # setting it) for each tag is last.
 
+def fnoderevs(ui, repo, revs):
+"""return the list of '.hgtags' fnodes used in a set revisions
+
+This is returned as list of unique fnodes. We use a list instead of a set
+because order matters when it comes to tags."""
+unfi = repo.unfiltered()
+tonode = unfi.changelog.node
+nodes = [tonode(r) for r in revs]
+fnodes = _getfnodes(ui, repo, nodes[::-1]) # reversed help the cache
+fnodes = _filterfnodes(fnodes, nodes)
+return fnodes
+
 def findglobaltags(ui, repo):
 '''Find global tags in a repo: return a tagsmap
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 4 NEW-CONCEPT] track-tags: introduce first bits of tags tracking during transaction

2017-03-30 Thread Pierre-Yves David
# HG changeset patch
# User Pierre-Yves David 
# Date 1490675889 -7200
#  Tue Mar 28 06:38:09 2017 +0200
# Node ID 25952f350daaae03506991d566c8de170b5db094
# Parent  f6e7b8a14f4a94db6742410331db752112c76b82
# EXP-Topic tags
# Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/
#  hg pull 
https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 25952f350daa
track-tags: introduce first bits of tags tracking during transaction

This changeset introduces detection of tags changes during transaction. When
this happens a 'tag_moved=1' argument is set for hooks, similar to what we do
for bookmarks and phases.

This code is disabled by default as there is still various performance
concerns.  Some require a smarter use of our existing tag caches and some other
require rework around the transaction logic to skip execution when unneeded.
These performance improvement have been delayed, I would like to be able to
experiment and stabilize the feature behavior first.

Later changesets will push the concept further and provide a way for hooks to
knows what are the actual changes introduced by the transaction. Similar work
is needed for the other families of changes (bookmark, phase, obsolescence,
etc). Upgrade of the transaction logic will likely be performed at the same
time.

The current code can report some false positive when .hgtags file changes but
resulting tags are unchanged. This will be fixed in the next changeset.

For testing, we simply globally enable a hook in the tag test as all the
possible tag update cases should exist there. A couple of them show the false
positive mentionned above.

See in code documentation for more details.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1001,8 +1001,54 @@ class localrepository(object):
 vfsmap = {'plain': self.vfs} # root of .hg/
 # we must avoid cyclic reference between repo and transaction.
 reporef = weakref.ref(self)
-def validate(tr):
+# Code to track tag movement
+#
+# Since tags are all handled as file content, it is actually quite hard
+# to track these movement from a code perspective. So we fallback to a
+# tracking at the repository level. One could envision to track changes
+# to the '.hgtags' file through changegroup apply but that fails to
+# cope with case where transaction expose new heads without changegroup
+# being involved (eg: phase movement).
+#
+# For now, We gate the feature behind a flag since this likely comes
+# with performance impacts. The current code run more often than needed
+# and do not use caches as much as it could.  The current focus is on
+# the behavior of the feature so we disable it by default. The flag
+# will be removed when we are happy with the performance impact.
+tracktags = lambda x: None
+# experimental config: experimental.hook-track-tags
+shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags',
+ False)
+if desc != 'strip' and shouldtracktags:
+oldheads = self.changelog.headrevs()
+def tracktags(tr2):
+repo = reporef()
+oldfnodes = tagsmod.fnoderevs(repo.ui, repo, oldheads)
+newheads = repo.changelog.headrevs()
+newfnodes = tagsmod.fnoderevs(repo.ui, repo, newheads)
+# notes: we compare lists here.
+# As we do it only once buiding set would not be cheaper
+if oldfnodes != newfnodes:
+tr2.hookargs['tag_moved'] = '1'
+def validate(tr2):
 """will run pre-closing hooks"""
+# XXX the transaction API is a bit lacking here so we take a hacky
+# path for now
+#
+# We cannot add this as a "pending" hooks since the 'tr.hookargs'
+# dict is copied before these run. In addition we needs the data
+# available to in memory hooks too.
+#
+# Moreover, we also needs to make sure this runs before txnclose
+# hooks and there is no "pending" mechanism that would execute
+# logic only if hooks are about to run.
+#
+# Fixing this limitation of the transaction is also needed to track
+# other families of changes (bookmarks, phases, obsolescence).
+#
+# This will have to be fixed before we remove the experimental
+# gating.
+tracktags(tr2)
 reporef().hook('pretxnclose', throw=True,
txnname=desc, **pycompat.strkwargs(tr.hookargs))
 def releasefn(tr, success):
diff --git a/tests/test-tag.t b/tests/test-tag.t
--- a/tests/test-tag.t
+++ b/tests/test-tag.t
@@ -1,3 +1,19 @@

[PATCH 3 of 4 NEW-CONCEPT] track-tags: compute the actual differences between tags pre/post transaction

2017-03-30 Thread Pierre-Yves David
# HG changeset patch
# User Pierre-Yves David 
# Date 1490688895 -7200
#  Tue Mar 28 10:14:55 2017 +0200
# Node ID 2dcaa99d6160561166269f192a89b25f84fd4667
# Parent  25952f350daaae03506991d566c8de170b5db094
# EXP-Topic tags
# Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/
#  hg pull 
https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 2dcaa99d6160
track-tags: compute the actual differences between tags pre/post transaction

We now compute the proper actuall differences between tags before and after the
transaction. This catch a couple of false positives in the tests.

The compute the full difference since we are about to make this data available
to hooks in the next changeset.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1028,7 +1028,8 @@ class localrepository(object):
 newfnodes = tagsmod.fnoderevs(repo.ui, repo, newheads)
 # notes: we compare lists here.
 # As we do it only once buiding set would not be cheaper
-if oldfnodes != newfnodes:
+changes = tagsmod.difftags(repo.ui, repo, oldfnodes, newfnodes)
+if changes:
 tr2.hookargs['tag_moved'] = '1'
 def validate(tr2):
 """will run pre-closing hooks"""
diff --git a/mercurial/tags.py b/mercurial/tags.py
--- a/mercurial/tags.py
+++ b/mercurial/tags.py
@@ -90,6 +90,45 @@ def fnoderevs(ui, repo, revs):
 fnodes = _filterfnodes(fnodes, nodes)
 return fnodes
 
+def _nulltonone(value):
+"""convert nullid to None
+
+For tag value, nullid means "deleted". This small utility function helps
+translating that to None."""
+if value == nullid:
+return None
+return value
+
+def difftags(ui, repo, oldfnodes, newfnodes):
+"""list differences between tags expressed in two set of file-nodes
+
+The list contains entries in the form: (tagname, oldvalue, new value).
+None is used to expressed missing value:
+('foo', None, 'abcd') is a new tag,
+('bar', 'ef01', None) is a deletion,
+('baz', 'abcd', 'ef01') is a tag movement.
+"""
+if oldfnodes == newfnodes:
+return []
+oldtags = _tagsfromfnodes(ui, repo, oldfnodes)
+newtags = _tagsfromfnodes(ui, repo, newfnodes)
+
+# list of (tag, old, new): None means missing
+entries = []
+for tag, (new, __) in newtags.items():
+new = _nulltonone(new)
+old, __ = oldtags.pop(tag, (None, None))
+old = _nulltonone(old)
+if old != new:
+entries.append((tag, old, new))
+# handle deleted tags
+for tag, (old, __) in oldtags.items():
+old = _nulltonone(old)
+if old is not None:
+entries.append((tag, old, None))
+entries.sort()
+return entries
+
 def findglobaltags(ui, repo):
 '''Find global tags in a repo: return a tagsmap
 
diff --git a/tests/test-tag.t b/tests/test-tag.t
--- a/tests/test-tag.t
+++ b/tests/test-tag.t
@@ -230,7 +230,6 @@ doesn't end with EOL
   > f = file('.hgtags', 'w'); f.write(last); f.close()
   > EOF
   $ hg ci -m'broken manual edit of .hgtags'
-  hook: tag changes detected
   $ cat .hgtags; echo
   acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
   $ hg tag newline
@@ -635,7 +634,6 @@ handle the loss of tags
   $ printf '' > .hgtags
   $ hg commit -m 'delete all tags'
   created new head
-  hook: tag changes detected
   $ hg log -r 'max(t7::)'
   changeset:   17:ffe462b50880
   user:test
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 3 V2] hardlink: extract topic text logic of copyfiles

2017-03-30 Thread Yuya Nishihara
On Wed, 29 Mar 2017 12:42:16 -0700, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu 
> # Date 1490815275 25200
> #  Wed Mar 29 12:21:15 2017 -0700
> # Node ID b1ef68e4196e01f723b78746d752f60e46e33cc0
> # Parent  cda83a1bfb3ac3a23cfa158c407be93755c1018e
> # Available At https://bitbucket.org/quark-zju/hg-draft
> #  hg pull https://bitbucket.org/quark-zju/hg-draft -r 
> b1ef68e4196e
> hardlink: extract topic text logic of copyfiles

Looks good, queued, thanks.

> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -1130,8 +1130,7 @@ def copyfiles(src, dst, hardlink=None, p
>  hardlink = (os.stat(src).st_dev ==
>  os.stat(os.path.dirname(dst)).st_dev)
> -if hardlink:
> -topic = _('linking')
> -else:
> -topic = _('copying')
> +
> +gettopic = lambda: hardlink and _('linking') or _('copying')
> +topic = gettopic()

IIRC, we prefer not using and/or ternary. I would instead do:

  topicmap = [_('copying'), _('linking')]
  topicmap[hardlink]
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] hgweb: fix diff hunks filtering by line range in webutil.diffs()

2017-03-30 Thread Gregory Szorc


> On Mar 30, 2017, at 01:27, Denis Laxalde  wrote:
> 
> Gregory Szorc a écrit :
>>> On Wed, Mar 29, 2017 at 6:10 AM, Denis Laxalde  wrote:
>>> 
>>> # HG changeset patch
>>> # User Denis Laxalde 
>>> # Date 1490782027 -7200
>>> #  Wed Mar 29 12:07:07 2017 +0200
>>> # Node ID 28297d6c3ae842f4c26f878bf5b107619366fbd5
>>> # Parent  e540846c67e0f838bcdb1db567a57df28d92491c
>>> # Available At http://hg.logilab.org/users/dlaxalde/hg
>>> #  hg pull http://hg.logilab.org/users/dlaxalde/hg -r
>>> 28297d6c3ae8
>>> # EXP-Topic linerange-log/hgweb-filelog
>>> hgweb: fix diff hunks filtering by line range in webutil.diffs()
>>> 
>>> The previous clause for filter out a diff hunk was too restrictive. We
>>> need to
>>> consider the following cases (assuming linerange=(lb, ub) and the @s2,l2
>>> hunkrange):
>>> 
>>><-(s2)(s2+l2)->
>>>  <-(lb)---(ub)->
>>>   <-(lb)---(ub)->
>>>   <-(lb)---(ub)->
>>> 
>>> previously on the first and last situations were considered.
>>> 
>>> In test-hgweb-filelog.t, add a couple of lines at the beginning of file
>>> "b" so
>>> that the line range we will follow does not start at the beginning of file.
>>> This covers the change in aforementioned diff hunk filter clause.
>>> 
>> I think this is better. But there's still some oddity here. Specifically, a
>> number of diffs render extra lines that don't appear to be relevant to the
>> initial line range. For example, on mozilla-central, the request for
>> /log/60d7a0496a36/layout/base/nsCSSFrameConstructor.cpp?patch=&linerange=519:534
>> has an initial diff covering 13,000+ lines (the entire file). It seems we
>> went from showing too little diff (no diff) to too much diff (all diff).
> 
> 
> As far as I can tell, in all diffs on this page, there are only hunks
> (in general one, sometimes two) in which there are changes that concern
> the initial line range (GetLastIBSplitSibling function, renamed as
> GetLastSpecialSibling). Do you agree with that?
> 
> It is true that some hunks spread far from the target line range (for
> instance the second row "Bug 508665 - part 3 [...]" (75c14b62556e) or
> "Fix crash bug 393517. [...]" (8d561edb0012)). This is because the
> algorithm does not split hunks but only filter them. In other words, if
> mdiff.allblocks() (or more likely bdiff.blocks()) produces "too big"
> hunks, there's nothing we can do with the current implementation.

Ahh, I understand now. The new behavior obviously makes sense given the 
underlying implementation of being hunk based instead of line based.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH RFC] repo: add an ability to hide nodes in an appropriate way

2017-03-30 Thread Pierre-Yves David

On 03/27/2017 07:24 PM, Augie Fackler wrote:

On Mon, Mar 27, 2017 at 10:27:33AM +0200, Pierre-Yves David wrote:



On 03/27/2017 12:32 AM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490567500 25200
#  Sun Mar 26 15:31:40 2017 -0700
# Node ID 43cd56f38c1ca2ad1920ed6804e1a90a5e263c0d
# Parent  c60091fa1426892552dd6c0dd4b9c49e3c3da045
repo: add an ability to hide nodes in an appropriate way

Potentially frequent usecase is to hide nodes in the most appropriate
for current repo configuration way. Examples of things which use this
are rebase (strip or obsolete old nodes), shelve (strip of obsolete
temporary nodes) and probably others.
Jun Wu had an idea of having one place in core where this functionality
is implemented so that others can utilize it. This patch
implements this idea.


I do not think this is a step in the right direction, creating obsolescence
marker is not just about hiding changeset.


But we're using them for that today, all over the place.


Actually, we do not use it all over the place. Current markers usages in 
core are:


amend:
 - record evolution history
 - prune the temporary amend commit
  (that I would rather see disappear all together)

rebase:
 - record evolution history on successful completion

histedit:
 - record evolution history on successful completion
 - prune temporary nodes on successsful completion
   (This ones used to be stripped even with evolution)

(let us talk about shelve later)


So they are mainly used to record evolution history on successful 
operation (their intended usage) between "real-changesets". This is the 
intended usage of obsolescence markers.


In addition, they are also used in a couple of place to hide temporary 
changesets (in the "utility-space") after an operation succeeed.
This a bit an unorthodox uses of the obsolescence markers, but is "okay" 
to use them in these case because we know:

 1) this is utility-space so user never interact with them.
 2) we only create them for completed successful operation so we'll 
never need them ever again.
Strictly speaking we could just strip these temporary commits (and we 
have done so in the past) and this will not change anything for the 
user. Any other hiding mechanism aimed at "internal temporary" commit 
would do the job just fine. The internal commit never needs (and 
actually should ever) to leave the user repository.
In practice, we could use in memory commit for most of these temporary 
commit  (if not all) and never have to deal with hiding them.



We're also having pretty productive (I think!) discussions about non-obsmarker
based mechanisms for hiding things that are implementation details of
a sort (amend changesets that get folded immediately, shelve changes,
etc).


(Let me be at be long to try to be clear and comprehensive)

I can see three categories of things we want to hide:

:obsolete changeset (evolution semantic):

  A rewrite operation has created/recorded a new version of this 
changesets. that old version no longer needs to be shown to users (if 
possible). There is a strong semantic associated with such changesets 
and the property will be propagated to other repositories


:temporary/internal changesets:

  Such changesets are created as a side effect of other operation 
(amend, histedit, etc). They have the following properties (once we are 
done using them)


  * They are irrelevant to the users,
  * We should never-ever base anything on them,
  * We should never-ever access them ever again,
  * They should never-ever leave the repository.
  * They never stop being internal-changesets

:locally-hidden changeset:

  An hypothetically (not used) yet local-only hidden mechanism (similar 
to strip but without actual repo stripping). This could be used for 
local hiding/masking of changeset in the "real-changeset" space. Such 
data would not be exchanged. Commit reappears when "recreated" or re-pulled.


---

To take practical examples:

:amend:
  - amend source: "obsolete-changeset"
  - temporary changeset: "internal-changeset"

:rebase:
  - rebase source, on success: "obsolete-changeset"
  - rebase result, on abort:  "local-hiding"


:histedit:
  - histedit source, on success: "obsolete-changeset"
  - histedit temporary node, on success: "internal-changeset"
  - histedit result, on abort:   "local-hiding"
  - histedit temporary node, on abort:   "local-hiding (internal-node)"

extra notes:
 * If local hiding (strip) would take care of obsolescence marker, 
rebase and histedit could create them "as they go" instead of to the 
end: "on success".
 * In rebase --abort and histedit --abort, strip is used on freshly 
created changesets, so its performance impact is limited
 * we use "local hiding" (strip) on temporary nodes on histedit abort 
because we needs to be able to reuse them if histedit is rerun. So we 
cannot throw them in oblivion just yet.


---

regarding implementations

"obsolete-changesets": we already have a 

Re: [PATCH 3 of 3] minirst: remove redundant _admonitions set

2017-03-30 Thread Yuya Nishihara
On Thu, 30 Mar 2017 09:38:31 +0100, Ryan McElroy wrote:
> On 3/30/17 4:19 AM, Gregory Szorc wrote:
> > # HG changeset patch
> > # User Gregory Szorc 
> > # Date 1490843966 25200
> > #  Wed Mar 29 20:19:26 2017 -0700
> > # Node ID 191b0b4697cc979464ec5ad9f04ef1ffa0f2a6cb
> > # Parent  c4329b811738046b70661f5647df50d7d28b2362
> > minirst: remove redundant _admonitions set
> 
> This series looks good to me and is a nice cleanup. Marked as 
> pre-reviewed in patchwork.

Queued, many thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2 py3] color: replace str() with pycompat.bytestr()

2017-03-30 Thread Yuya Nishihara
On Thu, 30 Mar 2017 01:21:38 +0530, Pulkit Goyal wrote:
> # HG changeset patch
> # User Pulkit Goyal <7895pul...@gmail.com>
> # Date 1490779072 -19800
> #  Wed Mar 29 14:47:52 2017 +0530
> # Node ID 7339bf21508131c90a44317ff16214b81ebe62c1
> # Parent  08aeba5bc7c623a700eea9011e0d904e3732134a
> color: replace str() with pycompat.bytestr()

Queued these, thanks.

> --- a/mercurial/color.py  Sun Mar 26 20:52:51 2017 +0530
> +++ b/mercurial/color.py  Wed Mar 29 14:47:52 2017 +0530
> @@ -332,9 +332,10 @@
>  stop = _effect_str(ui, 'none')
>  else:
>  activeeffects = _activeeffects(ui)
> -start = [str(activeeffects[e]) for e in ['none'] + effects.split()]
> +start = [pycompat.bytestr(activeeffects[e]) for e in ['none']
> ++ effects.split()]
>  start = '\033[' + ';'.join(start) + 'm'
> -stop = '\033[' + str(activeeffects['none']) + 'm'
> +stop = '\033[' + pycompat.bytestr(activeeffects['none']) + 'm'

This could be '%d'.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH py3 V2] diff: slice over bytes to make sure conditions work normally

2017-03-30 Thread Yuya Nishihara
On Thu, 30 Mar 2017 01:16:07 +0530, Pulkit Goyal wrote:
> # HG changeset patch
> # User Pulkit Goyal <7895pul...@gmail.com>
> # Date 1490541771 -19800
> #  Sun Mar 26 20:52:51 2017 +0530
> # Node ID 08aeba5bc7c623a700eea9011e0d904e3732134a
> # Parent  331cc4433efe0d897bb16ad4ff08a3fbe850869b
> diff: slice over bytes to make sure conditions work normally

Queued, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 7 V2] tags: extract fnode retrieval in its own function

2017-03-30 Thread Yuya Nishihara
On Tue, 28 Mar 2017 20:20:05 +0100, Ryan McElroy wrote:
> On 3/28/17 1:03 PM, Pierre-Yves David wrote:
> > # HG changeset patch
> > # User Pierre-Yves David 
> > # Date 1490673691 -7200
> > #  Tue Mar 28 06:01:31 2017 +0200
> > # Node ID a710d3c24acd544408fe77243102325514f5f697
> > # Parent  e6fd7930cf0b37710e379de37b7d87d5c1ea5dc9
> > # EXP-Topic tags
> > tags: extract fnode retrieval in its own function
> s/in/into
> 
> Other than this nitpick (which I missed the first time), this whole 
> series looks good to me and is a nice clean-up. Marked at pre-reviewed.

Yeah, looks nice. Queued, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] hgweb: fix diff hunks filtering by line range in webutil.diffs()

2017-03-30 Thread Yuya Nishihara
On Wed, 29 Mar 2017 15:10:23 +0200, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde 
> # Date 1490782027 -7200
> #  Wed Mar 29 12:07:07 2017 +0200
> # Node ID 28297d6c3ae842f4c26f878bf5b107619366fbd5
> # Parent  e540846c67e0f838bcdb1db567a57df28d92491c
> # Available At http://hg.logilab.org/users/dlaxalde/hg
> #  hg pull http://hg.logilab.org/users/dlaxalde/hg -r 28297d6c3ae8
> # EXP-Topic linerange-log/hgweb-filelog
> hgweb: fix diff hunks filtering by line range in webutil.diffs()
> 
> The previous clause for filter out a diff hunk was too restrictive. We need to
> consider the following cases (assuming linerange=(lb, ub) and the @s2,l2
> hunkrange):
> 
> <-(s2)(s2+l2)->
>   <-(lb)---(ub)->
><-(lb)---(ub)->
><-(lb)---(ub)->
> 
> previously on the first and last situations were considered.
> 
> In test-hgweb-filelog.t, add a couple of lines at the beginning of file "b" so
> that the line range we will follow does not start at the beginning of file.
> This covers the change in aforementioned diff hunk filter clause.
> 
> diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
> --- a/mercurial/hgweb/webutil.py
> +++ b/mercurial/hgweb/webutil.py
> @@ -473,7 +473,7 @@ def diffs(web, tmpl, ctx, basectx, files
>  if linerange is not None and hunkrange is not None:
>  s1, l1, s2, l2 = hunkrange
>  lb, ub = linerange
> -if not (lb <= s2 < ub or lb < s2 + l2 <= ub):
> +if not (lb < s2 +l2 and ub > s2):

Looks correct compared to mdiff.blocksinrange(). Queued, thanks.

Maybe it'll be nice to add a helper (with docstring) that tests if a hunk
range is included in line range.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 7 V5] hgweb: add a "patch" query parameter to filelog command

2017-03-30 Thread Yuya Nishihara
On Sat, 25 Mar 2017 10:20:57 +0100, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde 
> # Date 1489398073 -3600
> #  Mon Mar 13 10:41:13 2017 +0100
> # Node ID a7b9bc1af8b81c332cf34960f581359e6942ca17
> # Parent  ffd1a15d456342caba744f5049b97862fcb697c7
> # Available At https://hg.logilab.org/users/dlaxalde/hg
> #  hg pull https://hg.logilab.org/users/dlaxalde/hg -r 
> a7b9bc1af8b8
> # EXP-Topic linerange-log/hgweb-filelog
> hgweb: add a "patch" query parameter to filelog command

> @@ -981,12 +985,27 @@ def filelog(web, req, tmpl):
>  repo = web.repo
>  revs = fctx.filelog().revs(start, end - 1)
>  entries = []
> +
> +diffstyle = web.config('web', 'style', 'paper')
> +if 'style' in req.form:
> +diffstyle = req.form['style'][0]
> +
> +def diff(fctx):
> +ctx = fctx.changectx()
> +basectx = ctx.p1()
> +path = fctx.path()
> +return webutil.diffs(web, tmpl, ctx, basectx, [path], diffstyle)
> +
>  for i in revs:
>  iterfctx = fctx.filectx(i)
> +diffs = None
> +if patch:
> +diffs = diff(iterfctx)

Got an exception at hidden revision '5cb3b7d1f50f' which had been rebased (in
my local repo.) Perhaps linkrev wouldn't be adjusted because we walk revision
numbers, not a history of filelog.

Traceback (most recent call last):
  File "mercurial/hgweb/server.py", line 100, in do_POST
self.do_write()
  File "mercurial/hgweb/server.py", line 93, in do_write
self.do_hgweb()
  File "mercurial/hgweb/server.py", line 161, in do_hgweb
for chunk in self.server.application(env, self._start_response):
  File "mercurial/hgweb/hgweb_mod.py", line 315, in run_wsgi
for r in self._runwsgi(req, repo):
  File "mercurial/util.py", line 867, in increasingchunks
for chunk in source:
  File "mercurial/templater.py", line 1035, in _flatten
for j in _flatten(i):
  File "mercurial/templater.py", line 1035, in _flatten
for j in _flatten(i):
  File "mercurial/templater.py", line 1035, in _flatten
for j in _flatten(i):
  File "mercurial/templater.py", line 1035, in _flatten
for j in _flatten(i):
  File "mercurial/templater.py", line 1035, in _flatten
for j in _flatten(i):
  File "mercurial/templater.py", line 1027, in _flatten
for i in thing:
  File "mercurial/hgweb/webutil.py", line 467, in diffs
diffhunks = patch.diffhunks(repo, node1, node2, m, opts=diffopts)
  File "mercurial/patch.py", line 2283, in diffhunks
ctx1 = repo[node1]
  File "mercurial/localrepo.py", line 579, in __getitem__
return context.changectx(self, changeid)
  File "mercurial/context.py", line 526, in __init__
_("unknown revision '%s'") % changeid)
RepoLookupError: unknown revision '5cb3b7d1f50f9857cc5316d3211789158deab238'

> +  --- /dev/nullThu Jan 01 00:00:00 
> 1970 +

We'll need a prefix to make 'id' unique.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5 v2] rebase: test to show brokenness with requiredest

2017-03-30 Thread Ryan McElroy
# HG changeset patch
# User Ryan McElroy 
# Date 1490871010 25200
#  Thu Mar 30 03:50:10 2017 -0700
# Node ID 8f154b4f7255427303aed7fff2d78ff84e49bfeb
# Parent  9f25299c45b39fbdfc34c0c3ef1c454bcd42ed02
rebase: test to show brokenness with requiredest

As shown in issue5513, --continue is broken when destination is required. This
adds a patch that demonstates this silly behavior, which will be fixed in a
future patch.

diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
--- a/tests/test-rebase-dest.t
+++ b/tests/test-rebase-dest.t
@@ -31,3 +31,30 @@ Require a destination
   rebasing 2:279de9495438 "cc" (tip)
   saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/279de9495438-ab0a5128-backup.hg (glob)
 
+Requiring dest should not break continue or other rebase options
+  $ hg up 1 -q
+  $ echo d >> c
+  $ hg commit -qAm dc
+  $ hg log -G -T '{rev} {desc}'
+  @  3 dc
+  |
+  | o  2 cc
+  |/
+  o  1 bb
+  |
+  o  0 aa
+  
+  $ hg rebase -d 2
+  rebasing 3:0537f6b50def "dc" (tip)
+  merging c
+  warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ echo d > c
+  $ hg resolve --mark --all
+  (no more unresolved files)
+  continue: hg rebase --continue
+  $ hg rebase --continue
+  abort: you must specify a destination
+  (use: hg rebase -d REV)
+  [255]
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 5 v2] rebase: move destination test to new test file

2017-03-30 Thread Ryan McElroy
# HG changeset patch
# User Ryan McElroy 
# Date 1490871010 25200
#  Thu Mar 30 03:50:10 2017 -0700
# Node ID 9f25299c45b39fbdfc34c0c3ef1c454bcd42ed02
# Parent  2632df096fc0ac7582382b1f94ea4b9ad0bce8f2
rebase: move destination test to new test file

We'll be adding a lot more tests here, so it makes sense to have this in its
own file now.

diff --git a/tests/test-rebase-base.t b/tests/test-rebase-base.t
--- a/tests/test-rebase-base.t
+++ b/tests/test-rebase-base.t
@@ -391,33 +391,3 @@ Multiple roots. Two children share two p
/
   o  0: A
   
-Require a destination
-  $ cat >> $HGRCPATH < [commands]
-  > rebase.requiredest = True
-  > EOF
-  $ hg init repo
-  $ cd repo
-  $ echo a >> a
-  $ hg commit -qAm aa
-  $ echo b >> b
-  $ hg commit -qAm bb
-  $ hg up ".^"
-  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  $ echo c >> c
-  $ hg commit -qAm cc
-  $ hg rebase
-  abort: you must specify a destination
-  (use: hg rebase -d REV)
-  [255]
-  $ hg rebase -d 1
-  rebasing 2:5db65b93a12b "cc" (tip)
-  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/5db65b93a12b-4fb789ec-backup.hg (glob)
-  $ hg rebase -d 0 -r . -q
-  $ HGPLAIN=1 hg rebase
-  rebasing 2:889b0bc6a730 "cc" (tip)
-  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/889b0bc6a730-41ec4f81-backup.hg (glob)
-  $ hg rebase -d 0 -r . -q
-  $ hg --config commands.rebase.requiredest=False rebase
-  rebasing 2:279de9495438 "cc" (tip)
-  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/279de9495438-ab0a5128-backup.hg (glob)
diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
new file mode 100644
--- /dev/null
+++ b/tests/test-rebase-dest.t
@@ -0,0 +1,33 @@
+Require a destination
+  $ cat >> $HGRCPATH < [extensions]
+  > rebase =
+  > [commands]
+  > rebase.requiredest = True
+  > EOF
+  $ hg init repo
+  $ cd repo
+  $ echo a >> a
+  $ hg commit -qAm aa
+  $ echo b >> b
+  $ hg commit -qAm bb
+  $ hg up ".^"
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo c >> c
+  $ hg commit -qAm cc
+  $ hg rebase
+  abort: you must specify a destination
+  (use: hg rebase -d REV)
+  [255]
+  $ hg rebase -d 1
+  rebasing 2:5db65b93a12b "cc" (tip)
+  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/5db65b93a12b-4fb789ec-backup.hg (glob)
+  $ hg rebase -d 0 -r . -q
+  $ HGPLAIN=1 hg rebase
+  rebasing 2:889b0bc6a730 "cc" (tip)
+  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/889b0bc6a730-41ec4f81-backup.hg (glob)
+  $ hg rebase -d 0 -r . -q
+  $ hg --config commands.rebase.requiredest=False rebase
+  rebasing 2:279de9495438 "cc" (tip)
+  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/279de9495438-ab0a5128-backup.hg (glob)
+
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 4 of 5 v2] rebase: demonstrate behavior with requiredest and pull --rebase

2017-03-30 Thread Ryan McElroy
# HG changeset patch
# User Ryan McElroy 
# Date 1490871010 25200
#  Thu Mar 30 03:50:10 2017 -0700
# Node ID 2b8f2a54323459455a1038ca3b5a98a03cf4fe0e
# Parent  50219901327938be2f4d6df041b69d7498a7914d
rebase: demonstrate behavior with requiredest and pull --rebase

diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
--- a/tests/test-rebase-dest.t
+++ b/tests/test-rebase-dest.t
@@ -57,3 +57,28 @@ Requiring dest should not break continue
   $ hg rebase --continue
   rebasing 3:0537f6b50def "dc" (tip)
   saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/0537f6b50def-be4c7386-backup.hg (glob)
+
+  $ cd ..
+
+Check rebase.requiredest interaction with pull --rebase
+  $ hg clone repo clone
+  updating to branch default
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd repo
+  $ echo e > e
+  $ hg commit -qAm ee
+  $ cd ..
+  $ cd clone
+  $ echo f > f
+  $ hg commit -qAm ff
+  $ hg pull --rebase
+  pulling from $TESTTMP/repo
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 2 changes to 2 files (+1 heads)
+  abort: you must specify a destination
+  (use: hg rebase -d REV)
+  [255]
+
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 5 of 5 v2] rebase: abort hg pull --rebase if rebase.requiredest is set (issue5514)

2017-03-30 Thread Ryan McElroy
# HG changeset patch
# User Ryan McElroy 
# Date 1490871010 25200
#  Thu Mar 30 03:50:10 2017 -0700
# Node ID 982ea504f855ed143d714e2923332e223b7feef4
# Parent  2b8f2a54323459455a1038ca3b5a98a03cf4fe0e
rebase: abort hg pull --rebase if rebase.requiredest is set (issue5514)

Previously, the pull would succeed, but the subsequent rebase would fail due
to the rebase.requiredest flag. Now abort earlier with a more useful error
message.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -1362,6 +1362,11 @@ def pullrebase(orig, ui, repo, *args, **
 'Call rebase after pull if the latter has been invoked with --rebase'
 ret = None
 if opts.get('rebase'):
+if ui.configbool('commands', 'rebase.requiredest'):
+msg = _('rebase destination required by configuration')
+hint = _('use hg pull followed by hg rebase -d DEST')
+raise error.Abort(msg, hint=hint)
+
 wlock = lock = None
 try:
 wlock = repo.wlock()
diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
--- a/tests/test-rebase-dest.t
+++ b/tests/test-rebase-dest.t
@@ -72,13 +72,7 @@ Check rebase.requiredest interaction wit
   $ echo f > f
   $ hg commit -qAm ff
   $ hg pull --rebase
-  pulling from $TESTTMP/repo
-  searching for changes
-  adding changesets
-  adding manifests
-  adding file changes
-  added 1 changesets with 2 changes to 2 files (+1 heads)
-  abort: you must specify a destination
-  (use: hg rebase -d REV)
+  abort: rebase destination required by configuration
+  (use hg pull followed by hg rebase -d DEST)
   [255]
 
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 3 of 5 v2] rebase: allow destination-free continue and abort (issue5513)

2017-03-30 Thread Ryan McElroy
# HG changeset patch
# User Ryan McElroy 
# Date 1490871010 25200
#  Thu Mar 30 03:50:10 2017 -0700
# Node ID 50219901327938be2f4d6df041b69d7498a7914d
# Parent  8f154b4f7255427303aed7fff2d78ff84e49bfeb
rebase: allow destination-free continue and abort (issue5513)

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -685,12 +685,6 @@ def rebase(ui, repo, **opts):
 
 # Validate input and define rebasing points
 destf = opts.get('dest', None)
-
-if ui.configbool('commands', 'rebase.requiredest'):
-if not destf:
-raise error.Abort(_('you must specify a destination'),
-  hint=_('use: hg rebase -d REV'))
-
 srcf = opts.get('source', None)
 basef = opts.get('base', None)
 revf = opts.get('rev', [])
@@ -776,6 +770,10 @@ def _definesets(ui, repo, destf=None, sr
 cmdutil.checkunfinished(repo)
 cmdutil.bailifchanged(repo)
 
+if ui.configbool('commands', 'rebase.requiredest') and not destf:
+raise error.Abort(_('you must specify a destination'),
+  hint=_('use: hg rebase -d REV'))
+
 if destf:
 dest = scmutil.revsingle(repo, destf)
 
diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
--- a/tests/test-rebase-dest.t
+++ b/tests/test-rebase-dest.t
@@ -55,6 +55,5 @@ Requiring dest should not break continue
   (no more unresolved files)
   continue: hg rebase --continue
   $ hg rebase --continue
-  abort: you must specify a destination
-  (use: hg rebase -d REV)
-  [255]
+  rebasing 3:0537f6b50def "dc" (tip)
+  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/0537f6b50def-be4c7386-backup.hg (glob)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 7 shelve-ext v5] shelve: add obs-based shelve functionality

2017-03-30 Thread Kostia Balytskyi


On 30/03/2017 10:15, Ryan McElroy wrote:
>
>
> On 3/29/17 2:18 PM, Kostia Balytskyi wrote:
>> # HG changeset patch
>> # User Kostia Balytskyi 
>> # Date 1490790691 25200
>> #  Wed Mar 29 05:31:31 2017 -0700
>> # Node ID fc1144e5993a5c85060b913e2d92cd4b1b61772e
>> # Parent  0aa864184c9d78c11d18980cf0faa10828445ff5
>> shelve: add obs-based shelve functionality
>>
>> Obsolescense-based shelve works in a following way:
>
> s/ a/ the
sigh :/ Will fix.
>
>> 1. In order to shelve some changes, it creates a commit, records its
>> node into a .oshelve file and prunes created commit.
>> 2. In order to finish a shelve operation, transaction is just
>> closed and not aborted.
>
> s/transaction/the transaction
>
>>
>> diff --git a/hgext/shelve.py b/hgext/shelve.py
>> --- a/hgext/shelve.py
>> +++ b/hgext/shelve.py
>> @@ -380,10 +380,15 @@ def _nothingtoshelvemessaging(ui, repo,
>>   else:
>>   ui.status(_("nothing changed\n"))
>>   -def _shelvecreatedcommit(repo, node, name):
>> -bases = list(mutableancestors(repo[node]))
>> -shelvedfile(repo, name, 'hg').writebundle(bases, node)
>> -cmdutil.export(repo, [node],
>> +def _shelvecreatedcommit(ui, repo, node, name, tr):
>> +if isobsshelve(repo, ui):
>> +shelvedfile(repo, name, 'oshelve').writeobsshelveinfo({
>> +'node': nodemod.hex(node)
>> +})
>> +else:
>> +bases = list(mutableancestors(repo[node]))
>> +shelvedfile(repo, name, 'hg').writebundle(bases, node)
>> +cmdutil.export(repo.unfiltered(), [node],
>>  fp=shelvedfile(repo, name, 
>> patchextension).opener('wb'),
>>  opts=mdiff.diffopts(git=True))
>
> I'm a latecomer to paying attention to this series, so please push 
> back on me if this has already been discussed, but I think it would be 
> "cleaner" to not mix old shelve and logic, and instead have just have 
> the main function _shelvecreatedcommit() call out to 
> _obsshelvecreatedcommit() or _abortshelvecreatedcommit() (or whatever 
> we call the traditional version).
>
> Again, feel free to push back if this has already been discussed or 
> discarded as a direction, or if there are other reasons to not do it.
I agree that this can be made better. Sean Farley (if I'm not mistaken) 
suggested that this should be a class. I do not mind refactrong it 
later, but I want to get it in first as a functionality. Also, 
currently, if I understand you correctly, you want to split an 11 line 
function into two. I don't think it's worth it at the moment.
>
>>   @@ -394,8 +399,13 @@ def _includeunknownfiles(repo, pats, opt
>>   extra['shelve_unknown'] = '\0'.join(s.unknown)
>>   repo[None].add(s.unknown)
>>   -def _finishshelve(repo):
>> -_aborttransaction(repo)
>> +def _finishshelve(ui, repo, tr, node):
>> +if isobsshelve(repo, ui):
>> +obsolete.createmarkers(repo, [(repo.unfiltered()[node], ())])
>> +tr.close()
>> +tr.release()
>> +else:
>> +_aborttransaction(repo)
>> def _docreatecmd(ui, repo, pats, opts):
>>   wctx = repo[None]
>> @@ -417,9 +427,12 @@ def _docreatecmd(ui, repo, pats, opts):
>>   try:
>>   lock = repo.lock()
>>   -# use an uncommitted transaction to generate the bundle to 
>> avoid
>> -# pull races. ensure we don't print the abort message to 
>> stderr.
>> -tr = repo.transaction('commit', report=lambda x: None)
>> +# depending on whether shelve is traditional or
>> +# obsolescense-based, we either abort or commit this
>> +# transaction in the end. If we abort it, we don't
>> +# want to print anything to stderr
>> +report = None if isobsshelve(repo, ui) else (lambda x: None)
>> +tr = repo.transaction('commit', report=report)
>> interactive = opts.get('interactive', False)
>>   includeunknown = (opts.get('unknown', False) and
>> @@ -447,16 +460,19 @@ def _docreatecmd(ui, repo, pats, opts):
>>   _nothingtoshelvemessaging(ui, repo, pats, opts)
>>   return 1
>>   -_shelvecreatedcommit(repo, node, name)
>> +_shelvecreatedcommit(ui, repo, node, name, tr)
>> if ui.formatted():
>>   desc = util.ellipsis(desc, ui.termwidth())
>>   ui.status(_('shelved as %s\n') % name)
>> -hg.update(repo, parent.node())
>> +# current wc parent may be already obsolete becuase
>> +# it might have been created previously and shelve just
>> +# reuses it
>> +hg.update(repo.unfiltered(), parent.node())
>>   if origbranch != repo['.'].branch() and not 
>> _isbareshelve(pats, opts):
>>   repo.dirstate.setbranch(origbranch)
>>   -_finishshelve(repo)
>> +_finishshelve(ui, repo, tr, node)
>>   finally:
>>   _restoreactivebookmark(repo, activebookmark)
>>   lockmod.release(tr, lock)
>>
>
> ___

Re: [PATCH 7 of 7 shelve-ext v5] shelve: add some forwards compatibility to shelve operations

2017-03-30 Thread Ryan McElroy

On 3/29/17 2:18 PM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490790691 25200
#  Wed Mar 29 05:31:31 2017 -0700
# Node ID 0953ca0a71a0e1f05078b0f3c255459e1ba56a4e
# Parent  9ce0a366a6316d1cffc2a875e7dc6b4a3227c851
shelve: add some forwards compatibility to shelve operations

This patch handles cases where someone enabled an obs-based
shelve in their repo, then disabled it while having made some
shelves. Approach of this patch is described below:
- assume this is what .hg/shelved looks like:
   - sh1.patch (created 1s ago)
   - sh1.oshelve (created 1s ago)
Would it make sense to have a "compatibility mode" where we also create 
the bundle, so that unshelving is actually backwards-compatible (if this 
option is enabled)?



   - sh2.patch (created 2s ago)
   - sh2.hg (created 2s ago)
- when obs-based shelve is enabled, 'hg shelve --list' shows both
   sh1 and s2 and is able to unshelve both. 'hg unshelbe' (without --name)


s/unshelbe/unshelve


   will unshelve sh1.
- when obs-based shelve is disabled, 'hg shelve --list' only shows
   sh2, prints a warning that it found an obs-based shelve and is
   only able to unshelve a traditional shelve. 'hg unshelve'
   (without --name) will unshelve sh2.

diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -66,9 +66,15 @@ testedwith = 'ships-with-hg-core'
  
  backupdir = 'shelve-backup'

  shelvedir = 'shelved'
-shelvefileextensions = ['hg', 'patch', 'oshelve']
  # universal extension is present in all types of shelves
  patchextension = 'patch'
+# extension used for bundle-based traditional shelves
+traditionalextension = 'hg'
+# extension used for obs-based shelves
+obsshelveextension = 'oshelve'
+shelvefileextensions = [traditionalextension,
+patchextension,
+obsshelveextension]
  
  # we never need the user, so we use a

  # generic user for all shelve operations
@@ -530,7 +536,12 @@ def deletecmd(ui, repo, pats):
  raise error.Abort(_("shelved change '%s' not found") % name)
  
  def listshelves(repo):

-"""return all shelves in repo as list of (time, filename)"""
+"""return a tuple of (allshelves, obsshelvespresent)
+where
+'allshelves' is a list of (time, filename) for shelves available
+in current repo configuration
+'obsshelvespresent' is a bool indicating whether repo has
+any obs-based shelves"""
  try:
  names = repo.vfs.readdir(shelvedir)
  except OSError as err:
@@ -538,13 +549,22 @@ def listshelves(repo):
  raise
  return []
  info = []
+obsshelvedisabled = not isobsshelve(repo, repo.ui)
+obsshelvespresent = False
  for (name, _type) in names:
  pfx, sfx = name.rsplit('.', 1)
+if sfx == obsshelveextension:
+obsshelvespresent = True
  if not pfx or sfx != patchextension:
  continue
+traditionalfpath = repo.vfs.join(shelvedir,
+ pfx + '.' + traditionalextension)
+if obsshelvedisabled and not repo.vfs.exists(traditionalfpath):
+# this is not a traditional shelve
+continue
  st = shelvedfile(repo, name).stat()
  info.append((st.st_mtime, shelvedfile(repo, pfx).filename()))
-return sorted(info, reverse=True)
+return sorted(info, reverse=True), obsshelvespresent
  
  def listcmd(ui, repo, pats, opts):

  """subcommand that displays the list of shelves"""
@@ -554,7 +574,13 @@ def listcmd(ui, repo, pats, opts):
  width = ui.termwidth()
  namelabel = 'shelve.newest'
  ui.pager('shelve')
-for mtime, name in listshelves(repo):
+availableshelves, obsshelvespresent = listshelves(repo)
+if (obsshelvespresent and not isobsshelve(repo, repo.ui) and
+ui.configbool('shelve', 'showobswarning', True)):

New configs need to be documented.


+ui.warn(_('warning: obsolescense-based shelve is disabled, but '
+  'obs-based shelve files are in the repo\n'
+  '(hint: set experimental.obsshelve=on in your hgrc)\n'))
+for mtime, name in availableshelves :
  sname = util.split(name)[1]
  if pats and sname not in pats:
  continue
@@ -952,7 +978,7 @@ def _dounshelve(ui, repo, *shelved, **op
  elif len(shelved) > 1:
  raise error.Abort(_('can only unshelve one change at a time'))
  elif not shelved:
-shelved = listshelves(repo)
+shelved, __ = listshelves(repo)
  if not shelved:
  raise error.Abort(_('no shelved changes to apply!'))
  basename = util.split(shelved[0][1])[1]



I like the idea of warning users in this case -- thanks for thinking 
about this case. I think that a backwards-compat mode might be a nice 
option to allow safely testing this feature before diving in with both 
feet. I know that would be a b

Re: [PATCH 6 of 7 shelve-ext v5] shelve: add obs-based unshelve functionality

2017-03-30 Thread Ryan McElroy

On 3/29/17 2:18 PM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490790691 25200
#  Wed Mar 29 05:31:31 2017 -0700
# Node ID 9ce0a366a6316d1cffc2a875e7dc6b4a3227c851
# Parent  743fea249a852994c5bd3e47cdfb617719f19a0a
shelve: add obs-based unshelve functionality

Obsolescense-based unshelve works as follows:
1. Instead of stripping temporary nodes, markers are created to
obsolete them.
2. Restoring commit is just finding it in an unfiltered repo.
3. '--keep' is only passed to rebase on traditional unshelves
(and thus traditional rebases), becuase we want markers to be
created fro obsolete-based rebases.

s/fro/for


4. 'hg unshelve' uses unfiltered repo to perform rebases
because we want rebase to be able to create markers between original
and new commits. 'rebaseskipobsolete' is disabled to make rebase not
skip the commit altogether.
5. As per sprint discussions, hiding commits with obsmarkers is
not ideal. This is okay for now, as long as obsshelve is an
experimental feature. In future, once a better approach to

s/In future/In the future


hiding things is implemented, we can change the way obsshelve
works (and also change its name to not refer to obsolescense).

This is a great comment.



Tests for obs-shelve are coming in a separate series.

Why?



diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -25,6 +25,7 @@ from __future__ import absolute_import
  import collections
  import errno
  import itertools
+import time
  
  from mercurial.i18n import _

  from mercurial import (
@@ -254,8 +255,13 @@ class shelvedstate(object):
  
  def prunenodes(self, ui, repo):

  """Cleanup temporary nodes from the repo"""
-repair.strip(ui, repo, self.nodestoprune, backup=False,
- topic='shelve')
+if self.obsshelve:
+unfi = repo.unfiltered()
+relations = [(unfi[n], ()) for n in self.nodestoprune]
+obsolete.createmarkers(repo, relations)
+else:
+repair.strip(ui, repo, self.nodestoprune, backup=False,
+ topic='shelve')
  
  def cleanupoldbackups(repo):

  vfs = vfsmod.vfs(repo.vfs.join(backupdir))
@@ -675,9 +681,14 @@ def unshelvecontinue(ui, repo, state, op
  
  repo.vfs.rename('unshelverebasestate', 'rebasestate')

  try:
-rebase.rebase(ui, repo, **{
-'continue' : True
-})
+# if shelve is obs-based, we want rebase to be able
+# to create markers to already-obsoleted commits
+_repo = repo.unfiltered() if state.obsshelve else repo
+with ui.configoverride({('experimental', 'rebaseskipobsolete'):
+'off'}, 'unshelve'):
+rebase.rebase(ui, _repo, **{
+'continue' : True,
+})
  except Exception:
  repo.vfs.rename('rebasestate', 'unshelverebasestate')
  raise
@@ -717,31 +728,59 @@ def _commitworkingcopychanges(ui, repo,
  with ui.configoverride({('ui', 'quiet'): True}):
  node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
  tmpwctx = repo[node]
+ui.debug("temporary working copy commit: %s:%s\n" %
+ (tmpwctx.rev(), nodemod.short(node)))
  return tmpwctx, addedbefore
  
-def _unshelverestorecommit(ui, repo, basename):

+def _unshelverestorecommit(ui, repo, basename, obsshelve):
  """Recreate commit in the repository during the unshelve"""
  with ui.configoverride({('ui', 'quiet'): True}):
-shelvedfile(repo, basename, 'hg').applybundle()
-shelvectx = repo['tip']
+if obsshelve:
+md = shelvedfile(repo, basename, 'oshelve').readobsshelveinfo()
+shelvenode = nodemod.bin(md['node'])
+repo = repo.unfiltered()
+try:
+shelvectx = repo[shelvenode]
+except error.RepoLookupError:
+m = _("shelved node %s not found in repo")
+raise error.Abort(m % md['node'])
+else:
+shelvedfile(repo, basename, 'hg').applybundle()
+shelvectx = repo['tip']
  return repo, shelvectx
  
  def _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, basename, pctx,

tmpwctx, shelvectx, branchtorestore,
-  activebookmark):
+  activebookmark, obsshelve):
  """Rebase restored commit from its original location to a destination"""
  # If the shelve is not immediately on top of the commit
  # we'll be merging with, rebase it to be on top.
  if tmpwctx.node() == shelvectx.parents()[0].node():
+# shelvectx is immediately on top of the tmpwctx
  return shelvectx
  
+# we need a new commit extra every time we perform a rebase to ensure

+# that "nothing to rebase" does not happen with obs-based shelve
+# "noth

Re: [PATCH 2 of 7 shelve-ext v5] shelve: add a function to check whether obs-based shelve is enabled

2017-03-30 Thread Ryan McElroy

On 3/29/17 2:18 PM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490790691 25200
#  Wed Mar 29 05:31:31 2017 -0700
# Node ID 0aa864184c9d78c11d18980cf0faa10828445ff5
# Parent  b5d6e501621808f330e46295d09526a5d1e9064a
shelve: add a function to check whether obs-based shelve is enabled

A central place to check whether code should use traditional or
obsolescense-based shelve behavior.

diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -41,6 +41,7 @@ from mercurial import (
  mdiff,
  merge,
  node as nodemod,
+obsolete,
  patch,
  phases,
  repair,
@@ -72,6 +73,18 @@ patchextension = 'patch'
  # generic user for all shelve operations
  shelveuser = 'shelve@localhost'
  
+def isobsshelve(repo, ui):

+"""Check whether obsolescense-based shelve is enabled"""
+obsshelve = ui.configbool('experimental', 'obsshelve')


Even though check-code doesn't require experimental flags to be 
documented yet, we should be good citizens and add documentation for any 
configuration we introduce.



+if not obsshelve:
+return False
+if not obsolete.isenabled(repo, obsolete.createmarkersopt):
+w = _('ignoring experimental.obsshelve because createmarkers option '
+  'is disabled')
+ui.warn(w)
+return False
+return True
+
  class shelvedfile(object):
  """Helper for the file storing a single shelve
  



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 7 shelve-ext v5] shelve: add obs-based shelve functionality

2017-03-30 Thread Ryan McElroy



On 3/29/17 2:18 PM, Kostia Balytskyi wrote:

# HG changeset patch
# User Kostia Balytskyi 
# Date 1490790691 25200
#  Wed Mar 29 05:31:31 2017 -0700
# Node ID fc1144e5993a5c85060b913e2d92cd4b1b61772e
# Parent  0aa864184c9d78c11d18980cf0faa10828445ff5
shelve: add obs-based shelve functionality

Obsolescense-based shelve works in a following way:


s/ a/ the


1. In order to shelve some changes, it creates a commit, records its
node into a .oshelve file and prunes created commit.
2. In order to finish a shelve operation, transaction is just
closed and not aborted.


s/transaction/the transaction



diff --git a/hgext/shelve.py b/hgext/shelve.py
--- a/hgext/shelve.py
+++ b/hgext/shelve.py
@@ -380,10 +380,15 @@ def _nothingtoshelvemessaging(ui, repo,
  else:
  ui.status(_("nothing changed\n"))
  
-def _shelvecreatedcommit(repo, node, name):

-bases = list(mutableancestors(repo[node]))
-shelvedfile(repo, name, 'hg').writebundle(bases, node)
-cmdutil.export(repo, [node],
+def _shelvecreatedcommit(ui, repo, node, name, tr):
+if isobsshelve(repo, ui):
+shelvedfile(repo, name, 'oshelve').writeobsshelveinfo({
+'node': nodemod.hex(node)
+})
+else:
+bases = list(mutableancestors(repo[node]))
+shelvedfile(repo, name, 'hg').writebundle(bases, node)
+cmdutil.export(repo.unfiltered(), [node],
 fp=shelvedfile(repo, name, patchextension).opener('wb'),
 opts=mdiff.diffopts(git=True))


I'm a latecomer to paying attention to this series, so please push back 
on me if this has already been discussed, but I think it would be 
"cleaner" to not mix old shelve and logic, and instead have just have 
the main function _shelvecreatedcommit() call out to 
_obsshelvecreatedcommit() or _abortshelvecreatedcommit() (or whatever we 
call the traditional version).


Again, feel free to push back if this has already been discussed or 
discarded as a direction, or if there are other reasons to not do it.


  
@@ -394,8 +399,13 @@ def _includeunknownfiles(repo, pats, opt

  extra['shelve_unknown'] = '\0'.join(s.unknown)
  repo[None].add(s.unknown)
  
-def _finishshelve(repo):

-_aborttransaction(repo)
+def _finishshelve(ui, repo, tr, node):
+if isobsshelve(repo, ui):
+obsolete.createmarkers(repo, [(repo.unfiltered()[node], ())])
+tr.close()
+tr.release()
+else:
+_aborttransaction(repo)
  
  def _docreatecmd(ui, repo, pats, opts):

  wctx = repo[None]
@@ -417,9 +427,12 @@ def _docreatecmd(ui, repo, pats, opts):
  try:
  lock = repo.lock()
  
-# use an uncommitted transaction to generate the bundle to avoid

-# pull races. ensure we don't print the abort message to stderr.
-tr = repo.transaction('commit', report=lambda x: None)
+# depending on whether shelve is traditional or
+# obsolescense-based, we either abort or commit this
+# transaction in the end. If we abort it, we don't
+# want to print anything to stderr
+report = None if isobsshelve(repo, ui) else (lambda x: None)
+tr = repo.transaction('commit', report=report)
  
  interactive = opts.get('interactive', False)

  includeunknown = (opts.get('unknown', False) and
@@ -447,16 +460,19 @@ def _docreatecmd(ui, repo, pats, opts):
  _nothingtoshelvemessaging(ui, repo, pats, opts)
  return 1
  
-_shelvecreatedcommit(repo, node, name)

+_shelvecreatedcommit(ui, repo, node, name, tr)
  
  if ui.formatted():

  desc = util.ellipsis(desc, ui.termwidth())
  ui.status(_('shelved as %s\n') % name)
-hg.update(repo, parent.node())
+# current wc parent may be already obsolete becuase
+# it might have been created previously and shelve just
+# reuses it
+hg.update(repo.unfiltered(), parent.node())
  if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts):
  repo.dirstate.setbranch(origbranch)
  
-_finishshelve(repo)

+_finishshelve(ui, repo, tr, node)
  finally:
  _restoreactivebookmark(repo, activebookmark)
  lockmod.release(tr, lock)



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 5 of 5] perf: workaround check-code

2017-03-30 Thread Ryan McElroy

On 3/30/17 12:57 AM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490831529 25200
#  Wed Mar 29 16:52:09 2017 -0700
# Node ID 5ca313b3da12d145f1d49a85dd8b753e22d51521
# Parent  265ea657d75905fb59a27194a75aaff49be94598
perf: workaround check-code


The code int his series all looks good to me. I'll mark as pre-reviewed 
in patchwork. The only question I have is whether we prefer to leave 
check-code errors in place inside the test, or workaround it with hacks 
like this?


I'd prefer to leave the "expected failures" inside the test because it 
documents that we intend to keep them (probably with a comment at the 
site of the "error"). Also, if the check-code regex gets smarter in the 
future, we don't have to go and change our hack again.


However, I don't know what the rest of the community thinks about this. 
I don't have a strong enough opinion, so I guess I'm -0 on this patch, 
but +1 on the rest of the series. I'll be happy as long as the first 
four get in regardless of if patch 5 is included or not.



The check-code suggests using rev instead of node for revlog.revision. But
early Mercurial does not support that (see 9117c6561b0b). So let's just
workaround check-code in perf.py

diff --git a/contrib/perf.py b/contrib/perf.py
--- a/contrib/perf.py
+++ b/contrib/perf.py
@@ -847,4 +847,5 @@ def perfrevlog(ui, repo, file_=None, sta
  def d():
  r = cmdutil.openrevlog(repo, 'perfrevlog', file_, opts)
+r2 = r # workaround check-code
  
  startrev = 0

@@ -857,5 +858,5 @@ def perfrevlog(ui, repo, file_=None, sta
  
  for x in xrange(startrev, endrev, dist):

-r.revision(r.node(x))
+r2.revision(r.node(x))
  
  timer(d)

diff --git a/tests/test-check-code.t b/tests/test-check-code.t
--- a/tests/test-check-code.t
+++ b/tests/test-check-code.t
@@ -10,7 +10,4 @@ New errors are not allowed. Warnings are
$ hg locate -X contrib/python-zstandard -X hgext/fsmonitor/pywatchman |
> sed 's-\\-/-g' | xargs "$check_code" --warnings --per-file=0 || false
-  contrib/perf.py:859:
-   > r.revision(r.node(x))
-   don't covert rev to node before passing to revision(nodeorrev)
Skipping i18n/polib.py it has no-che?k-code (glob)
mercurial/demandimport.py:312:



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] test-verify: add a testcase where the file has magic meta header

2017-03-30 Thread Ryan McElroy

On 3/29/17 9:45 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490820077 25200
#  Wed Mar 29 13:41:17 2017 -0700
# Node ID e9fda3b8614a8b701bd48041afa8b709e1227f27
# Parent  cda83a1bfb3ac3a23cfa158c407be93755c1018e
test-verify: add a testcase where the file has magic meta header

We use a magic header "\1\n" to store metadata like renames. See filelog.py.
The patch adds tests about files with the special header.


Sure, but why? Just to prevent regressions of handling files with this 
data that "looks like" metadata in them? What's the motivation for 
adding this test? Just future safety or did you run into something?


I'm not against it -- adding this test seems like a good idea, but I'd 
love more context on what led you to write it.




diff --git a/tests/test-verify.t b/tests/test-verify.t
--- a/tests/test-verify.t
+++ b/tests/test-verify.t
@@ -318,2 +318,18 @@ test revlog format 0
1 files, 1 changesets, 1 total revisions
$ cd ..
+
+Files with the meta header (see comment in filelog.size)
+
+  $ cat > $TESTTMP/writemeta.py < import sys
+  > with open(sys.argv[1], 'wb') as f:
+  > f.write(b'\x01\n\x01\n%s' % sys.argv[2])
+  > EOF
+
+  $ hg init c
+  $ cd c
+  $ $PYTHON $TESTTMP/writemeta.py a ''
+  $ $PYTHON $TESTTMP/writemeta.py b 'b'
+  $ hg ci -Aqm meta a b
+  $ hg verify -q
+  $ cd ..



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2] verify: fix length check

2017-03-30 Thread Ryan McElroy



On 3/29/17 10:52 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490824154 25200
#  Wed Mar 29 14:49:14 2017 -0700
# Node ID ab735d6798fb133efdc2be8a441b51e7ba4d547b
# Parent  1f7890370b5437466534cbd0a313d21671dade03
verify: fix length check

According to the document added above, we should check L1 == L2, and the
only way to get L1 in all cases is to call "rawsize()", and the only way to
get L2 is to call "revision(raw=True)". Therefore the fix.

Meanwhile there are still a lot of things about flagprocessor broken in
revlog.py. Tests will be added after revlog.py gets fixed.

diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -425,5 +425,6 @@ class verifier(object):
  rp = fl.renamed(n)
  if l != fl.size(i):
-if len(fl.revision(n)) != fl.size(i):
+# the "L1 == L2" check
+if len(fl.revision(n, raw=True)) != fl.rawsize(i):
  self.err(lr, _("unpacked size is %s, %s 
expected") %
   (l, fl.size(i)), f)



This fix looks good and important to me.

I'd suggest sending a v2 with the names in the table documented more 
clearly (from patch 1), as well as the typo you mentioned in your reply.


I'll mark as "changes requested" in patchwork.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2] verify: document corner cases

2017-03-30 Thread Ryan McElroy

On 3/29/17 10:51 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490823901 25200
#  Wed Mar 29 14:45:01 2017 -0700
# Node ID 1f7890370b5437466534cbd0a313d21671dade03
# Parent  e9fda3b8614a8b701bd48041afa8b709e1227f27
verify: document corner cases

It seems a good idea to list all kinds of "surprises" and expected behavior
to make the upcoming changes easier to understand.

Note: the comment added do not reflect the actual behavior of the current

grammar-nit: s/do/does


code.

diff --git a/mercurial/verify.py b/mercurial/verify.py
--- a/mercurial/verify.py
+++ b/mercurial/verify.py
@@ -381,4 +381,44 @@ class verifier(object):
  
  # verify contents

+#
+# Define 4 cases to help understand corner cases:
+#
+#   | common | rename | meta  | ext


Can you define these four words?

common = common case?
rename = file was just copied from somewhere else?
meta = ???
ext = extension that adds a flags processor?

+#  ---
+#   flags() | 0  | 0  | 0 | not 0
+#   renamed()   | False  | True   | False | ?
+#   rawtext[0:2]=='\1\n'| False  | True   | True  | ?
+#
+# "rawtext" means the raw text stored in revlog data, which
+# could be retrieved by "revision(rev, raw=True)". "text"
+# mentioned below is "revision(rev, raw=False)".
+#
+# There are 3 different lengths stored physically:
+#  1. L1: rawsize, stored in revlog index
+#  2. L2: len(rawtext), stored in revlog data
+#  3. L3: len(text), stored in revlog data if flags=0, or
+# possibly somewhere else if flags!=0
+#
+# L1 should be equal to L2. L3 is unrelated to L1 or L2. But


How about "L3 can be different than L1 and L2" -- it would be the same 
if there are no flags, right?



+# text may or may not affect commit hash depending on flag
+# processors (see revlog.addflagprocessor).
+#
+#  | common  | rename | meta  | ext
+# -
+#rawsize() | L1  | L1 | L1| L1
+#   size() | L1  | L2-LM  | L1(*) | L1 (?)
+# len(rawtext) | L2  | L2 | L2| L2
+#len(text) | L2  | L2 | L2| L3
+#  len(read()) | L2  | L2-LM  | L2-LM | L3
+#
+# LM:  length of metadata, depending on rawtext
+# (*): not ideal, see comment in filelog.size
+# (?): could be "- len(meta)" if the resolved content has
+#  rename metadata
+#
+# Checks needed to be done:
+#  1. length check: L1 == L2, in all cases.
+#  2. hash check: depending on flag processor, we may need to
+# use either "text" (external), or "rawtext" (in revlog).
  try:
  l = len(fl.read(n))


Overall this is pretty easy to follow and adds a lot of clarity. Just a 
couple of questions inline.

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 7 of 7 V5] hgweb: expose a followlines UI in filerevision view (RFC)

2017-03-30 Thread Denis Laxalde

Gregory Szorc a écrit :

On Sat, Mar 25, 2017 at 2:21 AM, Denis Laxalde  wrote:


# HG changeset patch
# User Denis Laxalde 
# Date 1489594320 -3600
#  Wed Mar 15 17:12:00 2017 +0100
# Node ID ec77aa4ff2993057b604bdffb449d2d179525a9f
# Parent  2f75006a7f31c97d29fd6dd9b72fa7cc9e7ab840
# Available At https://hg.logilab.org/users/dlaxalde/hg
#  hg pull https://hg.logilab.org/users/dlaxalde/hg -r
ec77aa4ff299
# EXP-Topic linerange-log/hgweb-filelog
hgweb: expose a followlines UI in filerevision view (RFC)

In filerevision view (/file//) we add some event listeners on
mouse selection of  elements in the  block.
Those listeners will capture the range of mouse-selected lines and, upon
mouse
release, a box inviting to follow the history of selected lines will show
up.
This action is advertised by a :after pseudo-element on file lines that
shows
up on hover and invite to "select a block of lines to follow its history".

All JavaScript code lives in a new "linerangelog.js" file, sourced in
filerevision template (only in "paper" style for now).

This is proposal implementation, comments welcome on any aspects.


This feature is frigging awesome!!! I can pretty much guarantee that some
engineers at Mozilla will go completely crazy for this feature.

As I'm playing with it locally, I found a few paper cuts.

First, on the initial revision introducing lines (last revision as rendered
in hgweb), the diff is often (always?) empty. I can also see empty diffs in
the intermediate changesets. For example, run this on mercurial/exchange.py
and ask it for the line range of the _pushdiscovery(pushop) function. For
this function, I get 2 empty diffs (revisions 233623d58c9a and
ddb56e7e1b92). Highlighting _pushdiscoverychangeset() yields only an empty
initial diff.

Second, the highlighting UI is a bit confusing. It took me a few seconds to
realize I had to actually hold down the mouse button and highlight the
lines. I don't think users are accustomed to do this on text in web pages
unless they are copying text. It was definitely surprising to me that
highlighting lines of text resulted in a special pop-up appearing. I'm no
web design expert, but how about this design.

As you mouseover lines, you see a graphic cursor somewhere on that line.
There is likely a label next to it saying "click anywhere to follow from
this line" or something like that. This is similar to the floating text
label you have now. When you mouse click, that floating cursor is dropped
and locked into place on that line. On subsequent mouseovers, another
cursor+label appears. The lines between the initial cursor and the current
mouse location are highlighted somehow (possibly adding a different
background color). The label says "click anywhere to follow lines XX to YY"
or something. When the user clicks to drop the 2nd cursor, either they're
taken directly to the filelog view or we get an inline box with links (like
the line number mouseovers on the annotate page). If the user accidentally
clicks to drop a cursor, they can clear the cursor be clicking the cursor
or an "x" next to it.

Another minor nitpick with the highlighting UI is the "follow lines" box
may not appear next to the mouse cursor. I think we want it to appear near
the cursor so it is easier to find/use.


Just sent a V6 of this patch implementing most of you proposal. I only
left aside the floating cursor and box ideas; the patch being already
quite large, I'd like to postpone this for a follow-up.


The UX can obviously be improved as a follow-up. I don't want to detract
from getting the core of the feature landed. This is shaping up to be
pretty amazing!




___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 3 of 3] minirst: remove redundant _admonitions set

2017-03-30 Thread Ryan McElroy

On 3/30/17 4:19 AM, Gregory Szorc wrote:

# HG changeset patch
# User Gregory Szorc 
# Date 1490843966 25200
#  Wed Mar 29 20:19:26 2017 -0700
# Node ID 191b0b4697cc979464ec5ad9f04ef1ffa0f2a6cb
# Parent  c4329b811738046b70661f5647df50d7d28b2362
minirst: remove redundant _admonitions set


This series looks good to me and is a nice cleanup. Marked as 
pre-reviewed in patchwork.




As Yuya pointed out during a review a month ago, _admonitions and
_admonitiontitles are largely redundant. With the last commit, they
are exactly redundant. So, remove _admonitions and use
_admonitiontitles.keys() instead.

diff --git a/mercurial/minirst.py b/mercurial/minirst.py
--- a/mercurial/minirst.py
+++ b/mercurial/minirst.py
@@ -413,24 +413,12 @@ def prunecomments(blocks):
  return blocks
  
  
-_admonitions = set([

-'attention',
-'caution',
-'danger',
-'error',
-'hint',
-'important',
-'note',
-'tip',
-'warning',
-])
-
  def findadmonitions(blocks, admonitions=None):
  """
  Makes the type of the block an admonition block if
  the first line is an admonition directive
  """
-admonitions = admonitions or _admonitions
+admonitions = admonitions or _admonitiontitles.keys()
  
  admonitionre = re.compile(br'\.\. (%s)::' % '|'.join(sorted(admonitions)),

flags=re.IGNORECASE)



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 6] rebase: allow destination-free continue and abort (issue5513)

2017-03-30 Thread Ryan McElroy

On 3/29/17 6:15 PM, Martin von Zweigbergk wrote:

On Tue, Mar 28, 2017 at 2:31 PM, Ryan McElroy  wrote:

# HG changeset patch
# User Ryan McElroy 
# Date 1490735056 25200
#  Tue Mar 28 14:04:16 2017 -0700
# Node ID ac6634fab80b59ba48958ca03289c4434e9483c4
# Parent  409a87200f6b079c9bfe1e85fd0715822346c402
rebase: allow destination-free continue and abort (issue5513)

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -705,7 +705,7 @@ def rebase(ui, repo, **opts):
  raise error.Abort(msg)

  if ui.configbool('commands', 'rebase.requiredest'):
-if not destf:
+if not contf and not abortf and not destf:

Instead of saying here that we don't care about the destination being
missing here, why not move it just above the call to _definesets() so
we're checking it only when we do care about? We could even move it
inside _definesets(). I hesitated to suggest that at first, because I
thought it was a lower-level function that should not deal with
command line parsing, but it already does a fair bit of that, so it
seems fine to handle this case there too. What do you think?


Looking at the code, this suggestion seems great. There are already a 
number of aborts in there for conflicting flags; this is an obvious 
addition there. Thanks for the suggestion! I'll send a v2 out in a bit 
after also playing around with Jun's drawdag suggestion to see if it 
helps me write more understandable tests.





  raise error.Abort(_('you must specify a destination'),
hint=_('use: hg rebase -d REV'))

diff --git a/tests/test-rebase-dest.t b/tests/test-rebase-dest.t
--- a/tests/test-rebase-dest.t
+++ b/tests/test-rebase-dest.t
@@ -55,6 +55,5 @@ Requiring dest should not break continue
(no more unresolved files)
continue: hg rebase --continue
$ hg rebase --continue
-  abort: you must specify a destination
-  (use: hg rebase -d REV)
-  [255]
+  rebasing 3:0537f6b50def "dc" (tip)
+  saved backup bundle to 
$TESTTMP/repo/.hg/strip-backup/0537f6b50def-be4c7386-backup.hg (glob)
  


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH V6] hgweb: expose a followlines UI in filerevision view

2017-03-30 Thread Denis Laxalde
# HG changeset patch
# User Denis Laxalde 
# Date 1490819176 -7200
#  Wed Mar 29 22:26:16 2017 +0200
# Node ID 1c360ab5640bc326dd6ff70bdee78e4da006dcef
# Parent  e540846c67e0f838bcdb1db567a57df28d92491c
# Available At http://hg.logilab.org/users/dlaxalde/hg
#  hg pull http://hg.logilab.org/users/dlaxalde/hg -r 1c360ab5640b
# EXP-Topic linerange-log/hgweb-filelog
hgweb: expose a followlines UI in filerevision view

In filerevision view (/file//) we add some event listeners on
mouse clicks of  elements in the  block.
Those listeners will capture a range of lines selected between two mouse
clicks and a box inviting to follow the history of selected lines will then
show up. Selected lines (i.e. the block of lines) get a CSS class which make
them highlighted. Selection can be cancelled (and restarted) by either
clicking on the cancel ("x") button in the invite box or clicking on any other
source line. Also clicking twice on the same line will abort the selection and
reset event listeners to restart the process.

As a first step, this action is only advertised by the "cursor: cell" CSS rule
on source lines elements as any other mechanisms would make the code
significantly more complicated. This might be improved later.

All JavaScript code lives in a new "linerangelog.js" file, sourced in
filerevision template (only in "paper" style for now).

diff --git a/contrib/wix/templates.wxs b/contrib/wix/templates.wxs
--- a/contrib/wix/templates.wxs
+++ b/contrib/wix/templates.wxs
@@ -225,6 +225,7 @@
 
 
 
+
 
 
 
diff --git a/mercurial/templates/paper/filerevision.tmpl 
b/mercurial/templates/paper/filerevision.tmpl
--- a/mercurial/templates/paper/filerevision.tmpl
+++ b/mercurial/templates/paper/filerevision.tmpl
@@ -71,8 +71,11 @@
 
 line wrap: on
  line source
-{text%fileline}
+{text%fileline}
 
+
+
+
 
 
 
diff --git a/mercurial/templates/static/linerangelog.js 
b/mercurial/templates/static/linerangelog.js
new file mode 100644
--- /dev/null
+++ b/mercurial/templates/static/linerangelog.js
@@ -0,0 +1,137 @@
+// Copyright 2017 Logilab SA 
+//
+// This software may be used and distributed according to the terms
+// of the GNU General Public License, incorporated herein by reference.
+
+//** Install event listeners for line block selection and followlines action */
+function installLineSelect() {
+var sourcelines = document.getElementsByClassName('sourcelines')[0];
+if (typeof sourcelines === 'undefined') {
+return;
+}
+// URL to complement with "linerange" query parameter
+var targetUri = sourcelines.dataset.logurl;
+if (typeof targetUri === 'undefined') {
+return;
+}
+
+var lineSelectedCSSClass = 'followlines-selected';
+
+//** add CSS class on  element in `from`-`to` line range */
+function addSelectedCSSClass(from, to) {
+var spans = sourcelines.getElementsByTagName('span');
+for (var i = from; i <= to; i++) {
+spans.item(i).classList.add(lineSelectedCSSClass);
+}
+}
+
+//** remove CSS class from previously selected lines */
+function removeSelectedCSSClass() {
+var nodes = sourcelines.getElementsByClassName(
+lineSelectedCSSClass);
+while (nodes.length) {
+nodes[0].classList.remove(lineSelectedCSSClass);
+}
+}
+
+// add event listener to the whole  block to have
+// it available in all children 
+sourcelines.addEventListener('click', lineSelectStart);
+
+//** event handler for "click" on the first line of a block */
+function lineSelectStart(e) {
+var startElement = e.target;
+if (startElement.tagName !== 'SPAN') {
+// not a  (maybe ): abort, keeping event listener
+// registered for other click with  target
+return;
+}
+var startId = parseInt(startElement.id.slice(1));
+startElement.classList.add(lineSelectedCSSClass); // CSS
+
+// remove this event listener
+sourcelines.removeEventListener('click', lineSelectStart);
+
+//** event handler for "click" on the last line of the block */
+function lineSelectEnd(e) {
+var endElement = e.target;
+if (endElement.tagName !== 'SPAN') {
+// not a  (maybe ): abort, keeping event listener
+// registered for other click with  target
+return;
+}
+
+// remove this event listener
+sourcelines.removeEventListener('click', lineSelectEnd);
+
+// compute line range (startId, endId)
+var endId = parseInt(endElement.id.slice(1));
+if (endId == startId) {
+// clicked twice the same line, cancel and reset initial state
+// (CSS and event listener for selection start)
+removeSelectedCSSClass();
+sourcelines.ad

Re: [PATCH] hgweb: fix diff hunks filtering by line range in webutil.diffs()

2017-03-30 Thread Denis Laxalde

Gregory Szorc a écrit :

On Wed, Mar 29, 2017 at 6:10 AM, Denis Laxalde  wrote:


# HG changeset patch
# User Denis Laxalde 
# Date 1490782027 -7200
#  Wed Mar 29 12:07:07 2017 +0200
# Node ID 28297d6c3ae842f4c26f878bf5b107619366fbd5
# Parent  e540846c67e0f838bcdb1db567a57df28d92491c
# Available At http://hg.logilab.org/users/dlaxalde/hg
#  hg pull http://hg.logilab.org/users/dlaxalde/hg -r
28297d6c3ae8
# EXP-Topic linerange-log/hgweb-filelog
hgweb: fix diff hunks filtering by line range in webutil.diffs()

The previous clause for filter out a diff hunk was too restrictive. We
need to
consider the following cases (assuming linerange=(lb, ub) and the @s2,l2
hunkrange):

<-(s2)(s2+l2)->
  <-(lb)---(ub)->
   <-(lb)---(ub)->
   <-(lb)---(ub)->

previously on the first and last situations were considered.

In test-hgweb-filelog.t, add a couple of lines at the beginning of file
"b" so
that the line range we will follow does not start at the beginning of file.
This covers the change in aforementioned diff hunk filter clause.


I think this is better. But there's still some oddity here. Specifically, a
number of diffs render extra lines that don't appear to be relevant to the
initial line range. For example, on mozilla-central, the request for
/log/60d7a0496a36/layout/base/nsCSSFrameConstructor.cpp?patch=&linerange=519:534
has an initial diff covering 13,000+ lines (the entire file). It seems we
went from showing too little diff (no diff) to too much diff (all diff).



As far as I can tell, in all diffs on this page, there are only hunks
(in general one, sometimes two) in which there are changes that concern
the initial line range (GetLastIBSplitSibling function, renamed as
GetLastSpecialSibling). Do you agree with that?

It is true that some hunks spread far from the target line range (for
instance the second row "Bug 508665 - part 3 [...]" (75c14b62556e) or
"Fix crash bug 393517. [...]" (8d561edb0012)). This is because the
algorithm does not split hunks but only filter them. In other words, if
mdiff.allblocks() (or more likely bdiff.blocks()) produces "too big"
hunks, there's nothing we can do with the current implementation.




___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH] test-check-code: prevent files being added to the root directory

2017-03-30 Thread Ryan McElroy



On 3/29/17 8:14 PM, Jun Wu wrote:

# HG changeset patch
# User Jun Wu 
# Date 1490814860 25200
#  Wed Mar 29 12:14:20 2017 -0700
# Node ID 4b4345a62fbd9fb0f4610d013c4ee5c9c06287e0
# Parent  cda83a1bfb3ac3a23cfa158c407be93755c1018e
test-check-code: prevent files being added to the root directory


This looks good to me. Marked as pre-reviewed in patchwork.


Adding new files in the root directory is probably a mistake, and is usually
discouraged [1]. The test catches it to avoid mistakes like [2].

Modify the test if files need to be added in the root.

[1]: 
https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_pipermail_mercurial-2Ddevel_2016-2DJuly_086442.html&d=DwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=Jw8rundaE7TbmqBYd1txIQ&m=7_IYmz-lrpqA1zpgDDo4EeVrvcwTfaFdAiVidGqOBWY&s=xA-QLqFwEuB9rS_dq7YumUvHY2zl3rwx0hZWq4lVgxQ&e=
[2]: 
https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_pipermail_mercurial-2Ddevel_2017-2DMarch_095836.html&d=DwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=Jw8rundaE7TbmqBYd1txIQ&m=7_IYmz-lrpqA1zpgDDo4EeVrvcwTfaFdAiVidGqOBWY&s=KUM_-mbWo_TeA41nPw9KKJrrcbuK9jFLugGhN9B7fEY&e=


OMG I hate proofpoint. I want it to die in a fire. This is why I always 
remove the footers and the "available at" URLs haha.




diff --git a/tests/test-check-code.t b/tests/test-check-code.t
--- a/tests/test-check-code.t
+++ b/tests/test-check-code.t
@@ -55,2 +55,19 @@ New errors are not allowed. Warnings are
...   'command is %s; expected %s' % (commands[i], command))
... break
+
+Prevent adding new files in the root directory accidentally.
+
+  $ hg files 'glob:*'
+  .editorconfig
+  .hgignore
+  .hgsigs
+  .hgtags
+  CONTRIBUTING
+  CONTRIBUTORS
+  COPYING
+  Makefile
+  README
+  hg
+  hgeditor
+  hgweb.cgi
+  setup.py



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 5] repair: use ProgrammingError

2017-03-30 Thread Ryan McElroy

On 3/29/17 4:56 PM, Jun Wu wrote:

Excerpts from Pierre-Yves David's message of 2017-03-29 13:24:39 +0200:

On 03/28/2017 08:59 PM, Ryan McElroy wrote:

On 3/27/17 2:11 PM, Augie Fackler wrote:

On Mon, Mar 27, 2017 at 09:18:55AM +0200, Pierre-Yves David wrote:

Sure, that seems like a good idea. Can you see to it ?

It's a good idea, but I feel like the name "ProgrammingError" alone
provides some clue as to what's going on, and the migration is good.

Queued, I wouldn't mind a followup to make the hint generic to all
ProgrammingError instances, but I'm not willing to block on it either.

FWIW, I agree that losing the hint is sad. How confident are we that
core won't have these errors? Can we blame all ProgrammingError
exceptions on extensions?

The general idea about pointing at extensions here is that such bug in
Mercurial should be caught by the Mercurial test suite (or local
development process) so user should not be exposed to it (in theory). On
the other hand, existing extensions code might use API wrong in a way
that did not raised the error in previous version. So if the user get
exposed to that error, it it probably because of an extension.

I think the question was about *all* ProgrammingErrors, not about a
particular one. I'm not sure if you have answered that. But maybe my English
reading is just bad.

FWIW, I think you can answer the question by either:

   Yes, all ProgrammingErrors are extensions' fault.

or,

   No, some ProgrammingErrors are unrelated to extensions.

which is just 60 bytes, more cleaner, 5x shorter, and save time for us all.


Not sure how this is intended, Jun, but this statement come across text 
pretty harshly. Just be careful with your wording and your statements 
please.


I think Pierre-Yves' statement adds important subtlety, which is that we 
expect all ProgrammingErrors in the wild to be caused by extensions. If 
a core developer sees one, we quickly fix it and add a test. I think we 
can use that subtlety in a hint for any programming error. I'll think 
about some possible hints to add here.


Remember we're all on the same team here.

Cheers,

~Ryan
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 7] revlog: add test to check raw processing is sane

2017-03-30 Thread Ryan McElroy

On 3/29/17 4:34 PM, Jun Wu wrote:

Although that's doable, that requires significant time. And the bugs are
cancelling each other somehow: When you fix none, test 1 fails. When you fix
test 1, test 2 previously passed fails. Since the bugs won't be able to be
fixed incrementally (fixing the second introduce regression on the first),
I'll prefer keeping it this way, that is to test all cases after the fixes.


This is a great point. Carry on.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: Post-pull updates and hooks

2017-03-30 Thread Pierre-Yves David



On 03/29/2017 11:57 PM, Augie Fackler wrote:

Howdy folks,

Alex (cc'ed) asked me a question on IRC today, and I can't figure out a fix for 
what is a basically-reasonable and sort-of-obvious feature. In Git, due to 
implementation details of how 'git pull' works[0], you can get a post-pull 
summary of the update from/to and a diffstat of what's changing out from under 
you. I swear this should be doable in hg (probably as a hook of some sort), but 
I can't figure out it. Anyone have any clever ideas?

Relatedly, I noticed we don't appear to have a set of 'pull' hooks at all. 
Since 'changegroup' is now used for a lot of things internally (for example, 
histedit and rebase), should we add an explicit set of pre/post pull hooks for 
use in cases like this?


The generic transaction set of hooks should do, the transaction "name" 
is available as HG_TXNNAME, it it set to "pull" in the pull case. You 
can get more details in `hg help config hooks` (pretxnopen, pretxnclose, 
txnclose).


If you also want to get data about what --update did, the "update" hook 
should fit your needs (also see hg help config.hooks).


If you want to push things a bit further, the '_destmerge' and 
'_destupdate' are experimental revset that can tell you about default 
update and merge destination.


Cheers,

--
Pierre-Yves David
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel