Commit Graph

880 Commits

Author SHA1 Message Date
Yuya Nishihara
e75a42ecc9 dagop: move blockancestors() and blockdescendants() from context
context.py seems not a good place to host these functions.

  % wc -l mercurial/context.py mercurial/dagop.py
    2306 mercurial/context.py
     424 mercurial/dagop.py
    2730 total
2017-02-19 19:37:14 +09:00
Yuya Nishihara
54b39af2a1 dagop: split module hosting DAG-related algorithms from revset
This module hosts the following functions. They are somewhat similar (e.g.
scanning revisions using heap queue or stack) and seem non-trivial in
algorithmic point of view.

 - _revancestors()
 - _revdescendants()
 - reachableroots()
 - _toposort()

I was thinking of adding revset._fileancestors() generator for better follow()
implementation, but it would be called from context.py as well. So I decided
to create new module.

Naming is hard. I couldn't come up with any better module name, so it's called
"dag operation" now. I rejected the following candidates:

 - ancestor.py - existing, revlog-level DAG algorithm
 - ancestorset.py - doesn't always return a set
 - dagalgorithm.py - hard to type
 - dagutil.py - existing
 - revancestor.py - I want to add fileancestors()

  % wc -l mercurial/dagop.py mercurial/revset.py
    339 mercurial/dagop.py
   2020 mercurial/revset.py
   2359 total
2016-10-16 18:03:24 +09:00
Yuya Nishihara
9be9c72a7a revset: fix negative ancestor spec to not return changectx objects
The order was unstable because of this.
2017-06-18 12:25:23 +09:00
Yuya Nishihara
8dc3831c0a smartset: extract method to slice abstractsmartset
Sub classes can provide optimized implementations.
2015-03-24 00:14:53 +09:00
Yuya Nishihara
2fb700c277 revset: fix order of first/last members in compound expression (BC)
Suppose len(subset) >> len(ls) in common cases, 'subset & ls' should be
avoided whenever possible.
2017-06-10 19:48:48 +09:00
Yuya Nishihara
afe324b8ba revset: filter first/last members by __and__ operation
This replaces 'if y in subset' with '& subset'. first(null) and last(wdir())
are fixed thanks to fullreposet.__and__.

This also revealed that first() and last() don't follow the order of the
input set. 'ls & subset' is valid only if the ordering requirement is 'define'
or 'any'.

No performance regression observed:

  revset #0: limit(0:9999, 100, 9000)
  0) 0.001164
  1) 0.001135
  revset #2: 9000 & limit(0:9999, 100, 9000)
  0) 0.001224
  1) 0.001181
  revset #3: last(0:9999, 100)
  0) 0.000237
  1) 0.000199
2017-06-10 19:41:42 +09:00
Yuya Nishihara
1912966e67 revset: reject negative number to select first/last n members
Negative 'lim' doesn't make sense here, and it makes things complicated
when using list[:lim].
2017-06-10 18:35:11 +09:00
Yuya Nishihara
352ebafde5 revset: fix order of last() n members where n > 1 (BC)
last() is implemented using a reversed iterator, so the result should be
reversed again.

I've marked this as BC since it's quite old bug seen in 3.0. The first bad
revision is 1ef0875a62f8 "revset: changed last implementation to use lazy
classes."
2017-06-10 18:04:56 +09:00
David Soria Parra
0e29dd10bc revset: lookup descendents for negative arguments to ancestor operator
Negative offsets to the `~` operator now search for descendents. The search is
aborted when a node has more than one child as we do not have a definition for
'nth child'. Optionally we can introduce such a notion and take the nth child
ordered by rev number.

The current revset language does provides a short operator for ancestor lookup
but not for descendents. This gives user a simple revset to move to the previous
changeset, e.g. `hg up '.~1'` but not to the 'next' changeset. With this change
userse can now use `.~-1` as a shortcut to move to the next changeset.
This fits better into allowing users to specify revisions via revsets and
avoiding the need for special `hg next` and `hg prev` operations.

The alternative to negative offsets is adding a new operator. We do not have
many operators in ascii left that do not require bash escaping (',', '_', and
'/' come to mind). If we decide that we should add a more convenient short
operator such as ('/', e.g. './1') we can later add it and allow ascendents
lookup via negative numbers.
2017-05-27 10:25:09 -07:00
Yuya Nishihara
685172007c revlog: add support for partial matching of wdir node id
The idea is simple. If the given node id prefix is 'ff...f', add +1 to the
number of matches (e.g. ambiguous if partial + maybewdir > 1).

This patch also fixes id() revset and shortest() template since _partialmatch()
can raise WdirUnsupported exception.
2016-08-19 18:26:04 +09:00
Yuya Nishihara
09869bc4c0 revset: add support for branch(wdir()) and wdir() & branch() 2016-08-20 18:15:19 +09:00
Yuya Nishihara
00d9212898 revset: add support for integer and hex wdir identifiers
As I said before, partial 'ff...' hash isn't supported yet.
2017-06-03 20:39:33 +09:00
Pulkit Goyal
b9822a4f60 revset: add support for ancestors(wdir())
This is a part of extending support for wdir() predicate.
2017-05-23 01:22:33 +05:30
Pulkit Goyal
a1d8e291f1 revset: add support for using ~ operator on wdir() predicate
We catch the WdirUnsupported exception and handles the wdir() case here.
2017-05-23 01:08:19 +05:30
Pulkit Goyal
585fe1fa03 revset: add support for p2(wdir()) to get second parent of working directory
This adds support for finding the second parent of working directory using the
p2 predicate.
2017-05-22 02:14:22 +05:30
Pulkit Goyal
3b6d2ad7cc revset: use try-except instead of if-else because of perf
For wdir(), we now raises an exception which will be raised when wdir() will be
passed, so catching that exception is better checking for wdir() using if-else.
2017-05-22 02:03:43 +05:30
Pulkit Goyal
86c7c2d2ce revset: remove redundant condition and change to else from elif
Before going to this piece of code, we already check whether n is in [0, 1, 2],
so dropping the redundant condition.
2017-05-22 01:38:00 +05:30
Pulkit Goyal
8ed8bc3674 revset: add support for "wdir()^n"
This patch catches the WdirUnsupported exception raised, and adds support for
wdir^n which will give us the nth parent of the working directory.
2017-05-22 01:01:45 +05:30
Pulkit Goyal
ca6ae50fc1 revset: add parentheses after wdir since its a function
wdir was shown in help rather than wdir().
2017-05-22 00:54:02 +05:30
Pulkit Goyal
6b98477968 revset: make hg log -r 'wdir()^' work (issue4905)
This patch catches the WdirUnsupported exception to support wdir()^.
2017-05-19 20:06:45 +05:30
Martin von Zweigbergk
c3406ac3db cleanup: use set literals
We no longer support Python 2.6, so we can now use set literals.
2017-02-10 16:56:29 -08:00
FUJIWARA Katsunori
1ff2143781 revset: add i18n comments to error messages for followlines predicate
This patch also includes un-quoting "descend" keyword for similarity
to other error messages (this seems too trivial as a separated patch).
2017-05-01 05:52:36 +09:00
Denis Laxalde
9e99218a46 revset: properly parse "descend" argument of followlines()
We parse "descend" symbol as a Boolean using getboolean (prior extraction by
getargsdict already checked that it is a symbol).

In tests, check for error cases and vary Boolean values here and there.
2017-04-15 11:29:42 +02:00
Denis Laxalde
779e08447b revset: add a 'descend' argument to followlines to return descendants
This is useful to follow changes in a block of lines forward in the history
(for instance, when one wants to find out how a function evolved from a point
in history).

We added a 'descend' parameter to followlines(), which defaults to False. If
True, followlines() returns descendants of startrev.

Because context.blockdescendants() does not follow renames, these are not
followed by the revset either, so history will end when a rename occurs (as
can be seen in tests).
2017-01-16 09:24:47 +01:00
Yuya Nishihara
9a27cee441 revset: stop supporting plain list as input set (API)
There was no deprecwarn(), but this is the same kind of API compatibility
as the one removed by the previous patch.
2017-04-02 22:16:03 +09:00
Yuya Nishihara
c0606731ef revset: stop supporting predicate that returns plain list (API)
It's said to be removed after 3.9.
2017-04-02 22:01:32 +09:00
Denis Laxalde
a70f2fcec7 revset: factor out linerange processing into a utility function
Similar processing will be done in hgweb.webutil in forthcoming changeset.
2017-02-24 18:39:08 +01:00
Denis Laxalde
ca5e4eec65 context: also return ancestor's line range in blockancestors 2017-01-16 17:14:36 +01:00
Yuya Nishihara
b2229f5117 revset: split language services to revsetlang module (API)
New revsetlang module hosts parser, tokenizer, and miscellaneous functions
working on parsed tree. It does not include functions for evaluation such as
getset() and match().

  2288 mercurial/revset.py
   684 mercurial/revsetlang.py
  2972 total

get*() functions are aliased since they are common in revset.py.
2017-02-19 18:19:33 +09:00
Jun Wu
bc5a0cb908 revset: use phasecache.getrevset
This is part of a refactoring that moves some phase query optimization from
revset.py to phases.py. See the previous patch for motivation.

This patch changes revset code to use phasecache.getrevset so it no longer
accesses the private field: _phasecache._phasesets directly.

For performance impact, this patch was tested using the following query, on
my hg-committed repo:

    for i in 'public()' 'not public()' 'draft()' 'not draft()'; do
        echo $i;
        hg perfrevset "$i";
        hg perfrevset "$i" --hidden;
    done

For the CPython implementation, most operations are unchanged (within
+/- 1%), while "not public()" and "draft()" is noticeably faster on an
unfiltered repo. It may be because the new code avoids a set copy if
filteredrevs is empty.

  revset  | public()      | not public() | draft()    | not draft()
  hidden  |  yes  |  no   |   yes |  no  | yes |  no  | yes  |  no
  ------------------------------------------------------------------
  before  | 19006 | 17352 |   239 |  286 | 180 |  228 | 7690 | 5745
  after   | 19137 | 17231 |   240 |  207 | 182 |  150 | 7687 | 5658
  delta   |                       | -38% |     | -52% |

  (timed in microseconds)

For the pure Python implementation, some operations are faster while "not
draft()" is noticeably slower:

  revset  | public()      | not public()  | draft()       | not draft()
  hidden  |  yes  |  no   |   yes |  no   | yes   |  no   | yes   |  no
  ------------------------------------------------------------------------
  before  | 18852 | 17183 | 17758 | 15921 | 17505 | 15973 | 41521 | 39822
  after   | 18924 | 17380 | 17558 | 14545 | 16727 | 13593 | 48356 | 43992
  delta   |                       |   -9% |   -5% |  -15% |  +16% |  +10%

That may be the different performance characters of generatorset vs.
filteredset. The "not draft()" query could be optimized in this case where
both "public" and "secret" are passed to "getrevsets" so it won't iterate
the whole repo twice.
2017-02-18 00:39:31 -08:00
Martin von Zweigbergk
7ddb655b81 destutil: drop now-unused "check" parameter from destupdate() 2017-02-13 11:32:09 -08:00
Yuya Nishihara
2e50d5587f smartset: move set classes and related functions from revset module (API)
These classes are pretty large and independent from revset computation.

  2961 mercurial/revset.py
   973 mercurial/smartset.py
  3934 total

revset.prettyformatset() is renamed to smartset.prettyformat(). Smartset
classes are aliased since they are quite common in revset.py.
2016-10-16 17:28:51 +09:00
Yuya Nishihara
74023f2b13 revset: prevent using outgoing() and remote() in hgweb session (BC)
outgoing() and remote() may stall for long due to network I/O, which seems
unsafe per definition, "whether a predicate is safe for DoS attack." But I'm
not 100% sure about this. If our concern isn't elapsed time but CPU resource,
these predicates are considered safe. Perhaps that would be up to the
web/application server configuration?

Anyway, outgoing() and remote() wouldn't be useful in hgweb, so I think
it's okay to ban them.
2017-01-20 21:33:18 +09:00
Yuya Nishihara
5ade140d5c revset: abuse x:y syntax to specify line range of followlines()
This slightly complicates the parsing (see the previous patch), but the
overall result seems not bad.

I keep x:, :y and : for future extension.
2017-01-09 17:58:19 +09:00
Yuya Nishihara
615f3c1669 revset: do not transform range* operators in parsed tree
This allows us to handle x:y range as a general range object. A primary user
of it is followlines().
2017-01-09 16:55:56 +09:00
Yuya Nishihara
0f4a24bbbf revset: add default value to getinteger() helper
This seems handy.
2017-01-09 17:45:11 +09:00
Yuya Nishihara
49d42c696d revset: factor out getinteger() helper
We have 4 revset functions that take integer arguments, and they handle
their arguments in slightly different ways. This patch unifies them:

 - getstring() in place of getsymbol(), which is more consistent with the
   handling of integer revisions (both 1 and '1' are valid)
 - say "expects" instead of "requires" for type errors

We don't need to catch TypeError since getstring() must return a string.
2017-01-09 17:39:44 +09:00
Yuya Nishihara
a73b0aaf6b revset: rename rev argument of followlines() to startrev
The rev argument has the same meaning as startrev of follow(), and I think
startrev is more informative.

followlines() is new function, we can make BC now.
2017-01-09 16:16:26 +09:00
Yuya Nishihara
a0c3bc199a help: use :hg: role and canonical name to point to revset string patterns
Follows up ae418afed3f6. Now revisions.txt and revsets.txt has been merged,
so use revisions.* as a pointer.
2017-01-13 23:48:21 +09:00
Matt Harbison
d3bfb5a06a help: eliminate duplicate text for revset string patterns
There's no reason to duplicate this so many times, and it's likely an instance
will be missed if support for a new pattern is added and documented.  The
stringmatcher is mostly used by revsets, though it is also used for the 'tag'
related templates, and namespace filtering in the journal extension.  So maybe
there's a better place to document it.  `hg help patterns` seems inappropriate,
because that is all file pattern matching.

While here, indicate how to perform case insensitive regex searches.
2017-01-07 23:35:35 -05:00
Matt Harbison
e0b76f5323 revset: add regular expression support to 'desc'
This is a case insensitive predicate like 'author', so it conforms to the
existing behavior of performing a case insensitive regex.
2017-01-07 21:26:32 -05:00
Matt Harbison
840ab22fff revset: stop lowercasing the regex pattern for 'author'
It was probably unintentional for regex, as the meaning of some sequences like
\S and \s is actually inverted by changing the case.  For backward compatibility
however, the matching is forced to case insensitive.
2017-01-11 22:42:10 -05:00
Matt Harbison
762a49215b revset: point to 'grep' in the 'keyword' help for regex searches
The help for 'grep' already points to 'keyword'.
2017-01-11 23:13:51 -05:00
Yuya Nishihara
d04abe7517 revset: parse variable-length arguments of followlines() by getargsdict() 2017-01-09 16:02:56 +09:00
Yuya Nishihara
b1575d5948 parser: extend buildargsdict() to support variable-length positional args
This can simplify the argument parsing of followlines(). Tests are added by
the next patch.
2017-01-09 15:25:52 +09:00
Denis Laxalde
20d1dad252 revset: add a followlines(file, fromline, toline[, rev]) revset
This revset returns the history of a range of lines (fromline, toline) of a
file starting from `rev` or the current working directory.

Added tests in test-annotate.t which already contains a reasonably complex
repository.
2017-01-04 16:47:49 +01:00
Yuya Nishihara
a7a60a2e43 revset: drop TODO comment about sorting issue of fullreposet
The bootstrapping issue was addressed at the parsing phase and we expect
that fullreposet.__and__() fully complies to the smartset API, in which
'self & other' should return a result set in self's order. See also
ab938e7ae803.
2016-05-14 20:52:44 +09:00
Yuya Nishihara
2fa6a1e65e revset: document wdir() as an experimental function
Let's resurrect the docstring since our help module can detect the EXPERIMENTAL
tag and display it only if -v is specified.

This patch updates the test added by bbdfa2d5aaa2 since wdir() is now
documented.
2017-01-05 22:53:42 +09:00
Yuya Nishihara
ec99971228 revset: categorize wdir() as very fast function
The cost of wdir() should be identical to or cheaper than _intlist().
2016-08-20 17:50:23 +09:00
Yuya Nishihara
14fa3ba925 revset: make children() not look at p2 if null (issue5439)
Unlike p1 = null, p2 = null denotes the revision has only one parent, which
shouldn't be considered a child of the null revision. This was spotted while
fixing the issue4682 and rediscovered as issue5439.
2015-05-23 11:04:11 +09:00