Commit Graph

236 Commits

Author SHA1 Message Date
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
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
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
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
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
Mads Kiilerich
38cb771268 spelling: fixes of non-dictionary words 2016-10-17 23:16:55 +02:00
Yuya Nishihara
7e790cf836 revset: for x^2, do not take null as a valid p2 revision
Since we don't count null p2 revision as a parent, x^2 should never return
null even if null is explicitly populated.
2016-10-14 23:33:00 +09:00
Yuya Nishihara
7078b29941 revset: do not rewrite ':y' to '0:y' (issue5385)
That's no longer valid since the revision 0 may be hidden. Bypass validating
the existence of '0' and filter it by spanset.
2016-10-01 20:20:11 +09:00
Yuya Nishihara
6fa461cbb8 revset: make sort() noop depending on ordering requirement (BC)
See the previous patch for why.
2016-05-03 13:36:12 +09:00
Yuya Nishihara
6a7529851f revset: make reverse() noop depending on ordering requirement (BC)
Because smartset.reverse() may modify the underlying subset, it should be
called only if the set can define the ordering.

In the following example, 'a' and 'c' is the same object, so 'b.reverse()'
would reverse 'a' unexpectedly.

  # '0:2 & reverse(all())'
  <filteredset
    <spanset- 0:2>,    # a
    <filteredset       # b
      <spanset- 0:2>,  # c
      <spanset+ 0:9>>>
2016-05-03 13:36:12 +09:00
Yuya Nishihara
2ef98dedc5 revset: fix order of nested 'range' expression (BC)
Enforce range order only if necessary as the comment says "carrying the
sorting over would be more efficient."
2016-05-03 12:52:50 +09:00
Yuya Nishihara
d7145726a7 revset: forward ordering requirement to argument of present()
present() is special in that it returns the argument set with no
modification, so the ordering requirement should be forwarded.

We could make present() fix the order like orset(), but that would be silly
because we know the extra filtering cost is unnecessary.
2016-06-01 20:54:04 +09:00
Yuya Nishihara
eb51a746be revset: fix order of nested '_(|int|hex)list' expression (BC)
This fixes the order of 'x & (y + z)' where 'y' and 'z' are trivial, and the
other uses of _list()-family functions. The original functions are renamed to
'_ordered(|int|hex)list' to say clearly that they do not follow the subset
ordering.
2016-06-26 18:41:28 +09:00
Yuya Nishihara
46051dc16a revset: fix order of nested 'or' expression (BC)
This fixes the order of 'x & (y + z)' where 'y' and 'z' are not trivial.

The follow-order 'or' operation is slower than the ordered operation if
an input set is large:

       #0           #1           #2           #3
    0) 0.002968     0.002980     0.002982     0.073042
    1) 0.004513     0.004485     0.012029     0.075261

    #0: 0:4000 & (0:1099 + 1000:2099 + 2000:3099)
    #1: 4000:0 & (0:1099 + 1000:2099 + 2000:3099)
    #2: 10000:0 & (0:1099 + 1000:2099 + 2000:3099)
    #3: file("path:hg") & (0:1099 + 1000:2099 + 2000:3099)

I've tried another implementation, but which appeared to be slower than
this version.

    ss = [getset(repo, fullreposet(repo), x) for x in xs]
    return subset.filter(lambda r: any(r in s for s in ss), cache=False)
2016-06-26 18:17:12 +09:00
Yuya Nishihara
a8ff6aeb43 revset: pass around ordering flags to operations
Some operations and functions will need them to fix ordering bugs.
2016-08-07 17:46:12 +09:00
Yuya Nishihara
ec5675abe6 revset: wrap arguments of 'or' by 'list' node
This makes the number of 'or' arguments deterministic so we can attach
additional ordering flag to all operator nodes. See the next patch.

We rewrite the tree immediately after chained 'or' operations are flattened
by simplifyinfixops(), so we don't need to care if arguments are stored in
x[1] or x[1:].
2016-08-07 17:04:05 +09:00
Yuya Nishihara
daaa5c994b debugrevspec: add option to verify optimized result
This provides a convenient way to diff "hg debugrevspec" outputs generated
with/without --no-optimized option.
2016-08-21 13:16:21 +09:00
Yuya Nishihara
845ca229f7 debugrevspec: add option to skip optimize() and evaluate unoptimized tree
This will help debugging optimizer bugs.

Maybe '--no-optimized' can be changed to '--optimized' (default: True) when
flags series landed.
2016-08-21 12:40:02 +09:00
Yuya Nishihara
edc60dd7e4 debugrevspec: add option to print parsed tree at given stages
"-p <stage>" is useful for investigating parsing stages. With -p option, a
transformed tree is printed no matter if it is changed or not, which allows
us to know valid stage names by "-p all".
2016-08-21 12:33:57 +09:00
Yuya Nishihara
c0d8e08ed6 revset: make analyze() a separate step from optimize()
This will allow us to evaluate unoptimized tree and compare the result with
optimized one.

The private _analyze() function isn't renamed since I'll add more parameters
to it.
2016-08-21 11:29:57 +09:00
Augie Fackler
cb268cbd2f merge with stable 2016-08-15 12:26:02 -04:00
Yuya Nishihara
320973b5ef revset: fix keyword arguments to go through optimization process
Before, a keyvalue node was processed by the last catch-all condition of
_optimize(). Therefore, topo.firstbranch=expr would bypass tree rewriting
and would crash if an expr wasn't trivial.
2016-08-07 14:58:49 +09:00
Yuya Nishihara
1cc6421086 revset: also parse x^: as (x^):
Given x^:y is (x^):y, this seems sensible.
2016-08-06 20:37:48 +09:00
Yuya Nishihara
992f4bdde9 revset: resolve ambiguity of x^:y before alias expansion
This is purely a parsing problem, which should be resolved before alias
expansion.
2016-08-06 20:21:00 +09:00
Yuya Nishihara
e66927d824 revset: add test for resolution of infix/suffix ambiguity of x^:y
This is the test for cea0a71d7ada, and I'm going to fix the failure of
'x^A' where 'revsetalias.A=:y'.
2016-08-06 19:59:28 +09:00
Yuya Nishihara
ba3291048d revset: check invalid function syntax "func-name"() explicitly
Before the error was caught at func() as an unknown identifier, and the
optimizer failed to detect the syntax error. This patch introduces getsymbol()
helper to ensure that a string is not allowed as a function name.
2016-06-27 20:44:14 +09:00
Martin von Zweigbergk
59e258644a revset: make head() honor order of subset
The ordering of 'x & head()' was broken in 329d82866742 (revset:
improve head revset performance, 2014-03-13). Presumably due to other
optimizations since then, undoing that change to fix the order does
not slow down the simple case of "hg log -r 'head()'" mentioned in
that commit. I see a small slowdown from ~0.16s to about ~0.19s with
'not 0 & head()', but I'd say it's worth it for the correct output.
2016-06-23 12:37:09 -07:00
Yuya Nishihara
296ad7e9c1 test-revset: show how inconsistent the ordering of compound expressions is
This adds mostly broken tests that will be fixed by subsequent patches. We
generally don't do that, but this patch series would be hard to review
without a set of broken tests.

Note that some tests pass thanks to the reordering problem in optimize().
For instance, '2:0 & _intlist(0 1 2)' doesn't fail because it is rewritten
as '_intlist(0 1 2) & 2:0'.
2016-06-22 22:02:25 +09:00
Yuya Nishihara
4659949bd1 revset: fix crash on empty sort key
Make it noop as before ddf6bfe09ab2. We could change it to an error, but
allowing empty key makes some sense for scripting that builds a key string
programmatically.
2016-06-15 20:37:24 +09:00
Martijn Pieters
6cc53d84c9 revset: add new topographical sort
Sort revisions in reverse revision order but grouped by topographical branches.
Visualised as a graph, instead of:

  o  4
  |
  | o  3
  | |
  | o  2
  | |
  o |  1
  |/
  o  0

revisions on a 'main' branch are emitted before 'side' branches:

  o  4
  |
  o  1
  |
  | o  3
  | |
  | o  2
  |/
  o  0

where what constitutes a 'main' branch is configurable, so the sort could also
result in:

  o  3
  |
  o  2
  |
  | o  4
  | |
  | o  1
  |/
  o  0

This sort was already available as an experimental option in the graphmod
module, from which it is now removed.

This sort is best used with hg log -G:

  $ hg log -G "sort(all(), topo)"
2016-06-13 18:20:00 +01:00
Yuya Nishihara
96dc2d0773 test-revset: fix test vector for ordering issue of matching()
9981d464ac53 fixed matching() to preserve the order of the input set, but
the test was incorrect. Given "A and B", "A" should be the input set to "B".
But thanks to our optimizer, the test expression was rewritten as
"(2 or 3 or 1) and matching(1 or 2 or 3)", therefore it was working well.

Since I'm going to fix the overall ordering issue, the test needs to be
adjusted to do the right thing.
2016-06-03 21:49:26 +09:00
Yuya Nishihara
9079f0d3ff revset: factor out reverse flag of sort() key
Prepares for making a table of sort keys. This assumes 'k' has at least one
character, which should be guaranteed by keys.split().
2016-05-14 19:46:18 +09:00
Yuya Nishihara
2644883398 revset: make dagrange preserve order of input set
Unlike range, dagrange has no inverted range (such as '10:0'). So there should
be no practical reason to keep dagrange as a function that forces its own
ordering.

No performance regression is spotted in contrib/base-revsets.txt.
2016-05-03 12:36:44 +09:00
Yuya Nishihara
10fda3d262 parser: shorten prefix of alias parsing errors
These messages seemed to be a bit long. We should try making them fit to
80-col console.
2016-04-17 12:31:06 +09:00
Yuya Nishihara
77a605117c parser: rephrase "'$' not for alias arguments" message
Say which symbol caused the error. The word "alias" is removed since these
messages are prefixed by "failed to parse ... revset alias "...":".
2016-04-17 12:20:57 +09:00
Yuya Nishihara
37d980f070 revset: make sort() do dumb multi-pass sorting for multiple keys (issue5218)
Our invert() function was too clever to not take length into account. I could
fix the problem by appending '\xff' as a terminator (opposite to '\0'), but
it turned out to be slower than simple multi-pass sorting.

New implementation is pretty straightforward, which just calls sort() from the
last key. We can do that since Python sort() is guaranteed to be stable. It
doesn't sound nice to call sort() multiple times, but actually it is faster.
That's probably because we have fewer Python codes in hot loop, and can avoid
heavy string and list manipulation.

  revset #0: sort(0:10000, 'branch')
  0) 0.412753
  1) 0.393254

  revset #1: sort(0:10000, '-branch')
  0) 0.455377
  1) 0.389191  85%

  revset #2: sort(0:10000, 'date')
  0) 0.408082
  1) 0.376332  92%

  revset #3: sort(0:10000, '-date')
  0) 0.406910
  1) 0.380498  93%

  revset #4: sort(0:10000, 'desc branch user date rev')
  0) 0.542996
  1) 0.486397  89%

  revset #5: sort(0:10000, '-desc -branch -user -date -rev')
  0) 0.965032
  1) 0.518426  53%
2016-04-23 16:09:30 +09:00
Pierre-Yves David
d25fcd8b52 revset: stabilize repr of baseset initialized with a set
Cpython and pypy have different way to build and order set, so the result of
list(myset) is different. We work around this by using the sorted version of the
data when displaying a list.

This get pypy closer to pass test-revset.t.
2016-04-04 17:45:15 -07:00
Yuya Nishihara
6c870f3b69 revset: drop redundant check for unknown alias arguments
Since _parsealiasdefn() rejects unknown alias arguments, _checkaliasarg() is
unnecessary. New test is added to make sure unknown '$n' symbols are rejected.
2016-02-14 20:27:08 +09:00
Yuya Nishihara
208bb924ba revset: move tagging of alias arguments from tokenization to parsing phase
In short, this patch moves the hack from tokenizedefn() to _relabelaliasargs(),
which is called after parsing. This change aims to eliminate tight dependency
on the revset tokenizer.

Before this patch, we had to rewrite an alias argument to a pseudo function:

  "$1" -> "_aliasarg('$1')"
  ('symbol', '$1') -> ('function', ('symbol', '_aliasarg'), ('string', '$1'))

This was because the tokenizer must generate tokens that are syntactically
valid. By moving the process to the parsing phase, we can assign a unique tag
to an alias argument.

  ('symbol', '$1') -> ('_aliasarg', '$1')

Since new _aliasarg node never be generated from a user input, we no longer
have to verify a user input at findaliases(). The test for _aliasarg("$1") is
removed as it is syntactically valid and should pass the parsing phase.
2016-02-14 19:48:33 +09:00
Yuya Nishihara
b7731c18f7 revset: add test that should fail if '_aliasarg' tag is removed
I'm going to refactor the alias processing functions. We need '_aliasarg' tag
to limit the scope of the alias expansion, but it wasn't covered by the test.
This patch adds the test that should fail if '_aliasarg' were 'symbol'.

This is the first half of the second part of the "template alias" series. The
whole series will consist of the following parts:

 1. make parsed template tree to be compatible with parser functions
    (98f4895a3a97 and d7aaf6f4715f)
 2. refactor alias processing to be less dependent on revset module
    (1/2 in this series)
 3. extract reusable component to parser module
 4. clean up it
 5. extend it to support template syntax
 6. add debugging/testing functions of template aliases
 7. add alias expansion routine to templater
2016-02-14 21:46:50 +09:00
Yuya Nishihara
e2dfdaa910 debugrevspec: show expanded/concatenated states before printing trees
The debugrevspec command prints at most 4 parsed trees. It wasn't easy to
tell which tree belongs to which state.
2016-03-26 19:01:12 +09:00
Yuya Nishihara
0703170780 revset: add inspection data to max() and min() functions
We are likely to be interested in how these functions build a result set.
2016-02-16 21:44:13 +09:00
Yuya Nishihara
80f2bcf6b5 revset: add inspection data to limit() and last() functions
We are likely to be interested in how these functions calculate a result set.
2016-02-16 21:43:51 +09:00
Yuya Nishihara
5ec1f7ff3f revset: add inspection data to all filter() calls
This is useful for debugging revset construction.
2016-02-13 20:05:57 +09:00
Yuya Nishihara
587a07dd40 revset: add extra data to filteredset for better inspection
A filteredset is heavily used, but it cannot provide a printable information
how given set is filtered because a condition is an arbitrary callable object.

This patch adds an optional "condrepr" object that is used only by repr(). To
minimize the maintaining/runtime overhead of "condrepr", its type is overloaded
as follows:

  type      example
  --------  ---------------------------------
  tuple     ('<not %r>', other)
  str       '<branch closed>'
  callable  lambda: '<branch %r>' % sorted(b)
  object    other
2016-02-13 19:25:11 +09:00
FUJIWARA Katsunori
60e9ee2742 revset: replace extpredicate by revsetpredicate of registrar
This patch consists of changes below (these can't be applied
separately).

  - replace revset.extpredicate by registrar.revsetpredicate in
    extensions

  - remove setup() on an instance named as revsetpredicate in
    uisetup()/extsetup() of each extensions

    registrar.revsetpredicate doesn't have setup() API.

  - put new entry for revsetpredicate into extraloaders in dispatch

    This causes implicit loading predicate functions at loading
    extension.

    This loading mechanism requires that an extension has an instance
    named as revsetpredicate, and this is reason why
    largefiles/__init__.py is also changed in this patch.

Before this patch, test-revset.t tests that all decorated revset
predicates are loaded by explicit setup() at once ("all or nothing").

Now, test-revset.t tests that any revset predicate isn't loaded at
failure of loading extension, because loading itself is executed by
dispatch and it can't be controlled on extension side.
2016-03-08 23:04:53 +09:00
Durham Goode
5a5c8eeb9e revset: use smartset minus operator
Previously, revsets like 'X - Y' were translated to be 'X and not Y'. This can
be expensive, since if Y is a single commit then 'not Y' becomes a huge set and
sometimes the query optimizer doesn't account for it well.

This patch changes revsets to use the built in smartset minus operator, which is
often smarter than 'X and not Y'.

On a large repo this saves 2.2 seconds on rebase and histedit because "X:: - X"
becomes almost instant.

Relevant performance numbers from revsetbenchmark.py

revset #13: roots((tip~100::) - (tip~100::tip))
   plain         min           max           first         last          reverse       rev..rst      rev..ast      sort          sor..rst      sor..ast
0) 0.001080      0.001107      0.001102      0.001118      0.001121      0.001114      0.001141      0.001123      0.001099      0.001123      0.001137
1) 0.000708  65% 0.000738  66% 0.000735  66% 0.000739  66% 0.000784  69% 0.000780  70% 0.000807  70% 0.000756  67% 0.000727  66% 0.000759  67% 0.000808  71%

revset #14: roots((0::) - (0::tip))
   plain         min           max           first         last          reverse       rev..rst      rev..ast      sort          sor..rst      sor..ast
0) 0.131304      0.079168      0.133129      0.076560      0.048179      0.133349      0.049153      0.077097      0.129689      0.076212      0.048543
1) 0.065066  49% 0.036941  46% 0.066063  49% 0.034755  45% 0.048558      0.071091  53% 0.047679      0.034984  45% 0.064572  49% 0.035680  46% 0.048508

revset #22: (not public() - obsolete())
   plain         min           max           first         last          reverse       rev..rst      rev..ast      sort          sor..rst      sor..ast
0) 0.000139      0.000133      0.000133      0.000138      0.000134      0.000155      0.000157      0.000152      0.000157      0.000156      0.000153
1) 0.000108  77% 0.000129      0.000129      0.000134      0.000132      0.000127  81% 0.000151      0.000147      0.000127  80% 0.000152      0.000149

revset #25: (20000::) - (20000)
   plain         min           max           first         last          reverse       rev..rst      rev..ast      sort          sor..rst      sor..ast
0) 0.050560      0.045513      0.022593      0.043588      0.021909      0.045517      0.021822      0.044660      0.049740      0.044227      0.021819
1) 0.018614  36% 0.000171   0% 0.019659  87% 0.000168   0% 0.015543  70% 0.021069  46% 0.015623  71% 0.000180   0% 0.018658  37% 0.000186   0% 0.015750  72%
2016-02-24 10:41:15 -08:00
Matt Mackall
fd4d3ffdae merge with stable 2016-02-07 00:49:31 -06:00
Yuya Nishihara
6b8c99a6d3 revset: flatten chained 'list' operations (aka function args) (issue5072)
Internal _matchfiles() function can take bunch of arguments, which would
lead to a maximum recursion depth error. This patch avoids the excessive
stack use by flattening 'list' nodes beforehand.

Since getlist() no longer takes a nested 'list' nodes, _parsealiasdecl()
also needs to flatten argument list, "aliasname($1, $2, ...)".
2016-02-02 23:49:49 +09:00
FUJIWARA Katsunori
daba50963a tests: avoid nested quoting on command line for portability
Before this patch, test-revset.t fails on Solaris using ksh as default
"sh", because nested quoting below isn't acceptable for it.

                +-----------------------------+ inner quoting
    "`python -c "print '|'.join(['0:1'] * 500)"`"
    +-------------------------------------------+ outer quoting

This patch does below for portability.

  - omit outer quoting

    This should be safe, because generated string contains no white
    space character.

  - use '+' instead of '|' (for safety)

    '|' has special meaning for many shell, but '+' isn't (at least,
    for ordinary ones).
2016-02-05 22:32:05 +09:00
Bryan O'Sullivan
ca96e23cd1 dispatch: report similar names consistently 2016-01-04 21:52:44 -08:00
FUJIWARA Katsunori
4d06739a86 revset: use delayregistrar to register predicate in extension easily
Previous patch introduced 'revset.predicate' decorator to register
revset predicate function easily.

But it shouldn't be used in extension directly, because it registers
specified function immediately. Registration itself can't be restored,
even if extension loading fails after that.

Therefore, registration should be delayed until 'uisetup()' or so.

This patch uses 'extpredicate' decorator derived from 'delayregistrar'
to register predicate in extension easily.

This patch also tests whether 'registrar.delayregistrar' avoids
function registration if 'setup()' isn't invoked on it, because
'extpredicate' is the first user of it.
2015-12-29 23:58:30 +09:00
timeless
60432cef00 revset: add hint for list error to use or 2015-12-23 17:54:03 +00:00
Yuya Nishihara
c7bc2fcfb9 revset: add optional offset argument to limit() predicate
It's common for GUI or web frontend to fetch chunk of revisions per batch
size. Previously it was possible only if revisions were sorted by revision
number.

  $ hg log -r 'limit({revspec} & :{last_known}, 101)'

So this patch introduces a general way to retrieve chunk of revisions after
skipping offset revisions.

  $ hg log -r 'limit({revspec}, 100, {last_count})'

This is a dumb implementation. We can optimize it for baseset and spanset
later.
2015-03-24 00:28:28 +09:00
Yuya Nishihara
af229fbc94 revset: do not fall through to revspec for literal: branch (issue4838)
If "literal:" is specified, it must not be a revset expression. It should
error out with a better message.
2015-10-07 23:00:29 +09:00
Yuya Nishihara
b5477ed9b3 revset: handle error of string unescaping 2015-09-10 23:29:55 +09:00
Pierre-Yves David
25876521c9 reachableroots: use baseset lazy sorting
smartset sorting is lazy (so faster in some case) and better (informs that the
set is sorted allowing some optimisation). So we rely on it directly.

Some test output are updated because we now have more information (ordering).
2015-08-20 17:23:21 -07:00
Yuya Nishihara
8e8af6e090 revpair: restrict odd-range handling to top-level x:y expression (issue4774)
The odd-range hack was introduced by 9afcfbca1710 for backward compatibility,
but it was too widely applied. I've checked cmdutil.revpair() at 1.6, and
found that ".:", ":0" and ":" are also handled as pairs. So let's enable the
hack only for "x:y", "x:", "y:" and ":".

test-revset.t is updated because "tip^::tip^ or tip^" shouldn't be taken as
an odd range. This patch adds "tip^:tip^" instead.

This patch is written for the default branch because parse() of the stable
branch lacks compatibility hack for "foo+bar" tag. If we want to mitigate the
issue in stable, we can add something like "and '::' in revs[0]".
2015-08-13 16:15:43 +09:00
Matt Mackall
6c04738a65 merge with stable 2015-08-10 15:30:28 -05:00
Yuya Nishihara
6bf30cb038 revset: prevent crash caused by empty group expression while optimizing "or"
An empty group expression "()" generates None in AST, so it should be tested
before destructuring a tuple.

"A | ()" is still evaluated to an error because I'm not sure whether "()"
represents an empty set or an empty expression (= a unit value). They are
identical in "or" operation, but they should be evaluated differently in
"and" operation.

  expression  empty set  unit value
  ----------  ---------  ----------
  ()          {}         A
  A & ()      {}         A
  A | ()      A          A
2015-08-09 16:09:41 +09:00
Yuya Nishihara
1ebcb08eb6 revset: prevent crash caused by empty group expression while optimizing "and"
An empty group expression "()" generates None in AST, so the optimizer have
to test it before destructuring a tuple. The error message, "missing argument",
is somewhat obscure, but it should be better than crash.
2015-08-09 16:06:36 +09:00
Yuya Nishihara
f7a6661b37 revset: parse nullary ":" operator as "0:tip"
This is necessary for compatibility with the old-style parser that will be
removed by future patches.
2015-07-05 12:15:54 +09:00
Yuya Nishihara
a85993b95a revset: port parsing rule of old-style ranges from scmutil.revrange()
The old-style parser will be removed soon.
2015-07-18 23:30:17 +09:00
Yuya Nishihara
137f249748 debugrevspec: pass lookup function to visualize fallback mechanism
The next patch will move the exceptional parsing of old-style ranges
to revset.tokenize(). This patch will allow us to see the result tree.

Note that the parsing result of '-a-b-c-' is incorrect at this changeset.
It will be fixed soon.
2015-07-18 23:02:18 +09:00
Yuya Nishihara
33dcb19532 revset: work around x:y range where x or y is wdir()
All revisions must be contiguous in spanset, so we need the special case
for the wdir revision.
2015-06-28 16:08:07 +09:00
Yuya Nishihara
3732960ab3 revset: use integer representation of wdir() in revset
This is the simplest way to handle wdir() revision in revset. None didn't
work well because revset heavily depends on integer operations such as min(),
max(), sorted(), x:y, etc.

One downside is that we cannot do "wctx.rev() in set" because wctx.rev() is
still None. We could wrap the result set by wdirproxyset that translates None
to wdirrev, but it seems overengineered at this point.

    result = getset(repo, subset, tree)
    if 'wdir' in funcsused(tree):
        result = wdirproxyset(result)

Test cases need the '(all() + wdir()) &' hack because we have yet to fix the
bootstrapping issue of null and wdir.
2015-03-16 16:17:06 +09:00
Yuya Nishihara
329cd61d62 revset: port extra() to support keyword arguments
This is an example to show how keyword arguments are processed.
2015-06-28 22:57:33 +09:00
Yuya Nishihara
411c9c1693 revset: add parsing rule for key=value pair
It will be used as an keyword argument.

Note that our "=" operator is left-associative. In general, the assignment
operator is right-associative, but we don't care because it isn't allowed to
chain "=" operations.
2015-06-27 17:05:28 +09:00
Matt Harbison
198604740e revset: don't suggest private or undocumented queries
I noticed when I mistyped 'matching', that it suggested '_matchfiles' as well.
Rather than simply exclude names that start with '_', this excludes anything
without a docstring.  That way, if it isn't in the help text, it isn't
suggested, such as 'wdir()'.
2015-06-20 10:59:56 -04:00
Yuya Nishihara
6bf5f80705 revrange: build balanced tree of addsets from revisions (issue4565)
This reduces the stack depth from O(n) to O(log(n)). Therefore, repeated
-rREV options will never exceed the Python stack limit.

Currently it depends on private revset._combinesets() function. But at some
point, we'll be able to drop the old-style parser, and revrange() can be
completely rewritten without using _combinesets():

  trees = [parse(s) for s in revs]
  optimize(('or',) + trees)  # combine trees and optimize at once
  ...

Blockers that prevent eliminating old-style parser:

 - nullary ":" operator
 - revrange(repo, [intrev, ...]), can be mapped to 'rev(%d)' ?
 - revrange(repo, [binnode, ...]), should be banned ?
2015-05-24 18:11:33 +09:00
Yuya Nishihara
8807625c4d revrange: drop unnecessary deduplication of revisions
Because "l" is a smartset, duplicated entries are omitted by addsets.
2015-05-24 17:53:22 +09:00
Yuya Nishihara
0fcfb8834b revset: add fast path for _list() of integer revisions
This can greatly speed up chained 'or' of integer revisions.

1) reduce nesting of chained 'or' operations
2) optimize to a list
3) fast path for integer revisions (this patch)

revset #0: 0 + 1 + 2 + ... + 1000
1) wall 0.483341 comb 0.480000 user 0.480000 sys 0.000000 (best of 20)
2) wall 0.025393 comb 0.020000 user 0.020000 sys 0.000000 (best of 107)
3) wall 0.008371 comb 0.000000 user 0.000000 sys 0.000000 (best of 317)

revset #1: sort(0 + 1 + 2 + ... + 1000)
1) wall 0.035240 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
2) wall 0.026432 comb 0.030000 user 0.030000 sys 0.000000 (best of 102)
3) wall 0.008418 comb 0.000000 user 0.000000 sys 0.000000 (best of 322)

revset #2: first(0 + 1 + 2 + ... + 1000)
1) wall 0.028949 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)
2) wall 0.025503 comb 0.030000 user 0.030000 sys 0.000000 (best of 106)
3) wall 0.008423 comb 0.010000 user 0.010000 sys 0.000000 (best of 319)

But I admit that it is still slower than the spanset.

revset #3: 0:1000
3) wall 0.000132 comb 0.000000 user 0.000000 sys 0.000000 (best of 19010)
2015-05-17 15:16:13 +09:00
Yuya Nishihara
f19a0ca9bc revset: optimize 'or' operation of trivial revisions to a list
As seen in issue4565 and issue4624, GUI wrappers and automated scripts are
likely to generate a long query that just has numeric revisions joined by 'or'.
One reason why is that they allows users to choose arbitrary revisions from
a list. Because this use case isn't handled well by smartset, let's optimize
it to a plain old list.

Benchmarks:

1) reduce nesting of chained 'or' operations
2) optimize to a list (this patch)

revset #0: 0 + 1 + 2 + ... + 1000
1) wall 0.483341 comb 0.480000 user 0.480000 sys 0.000000 (best of 20)
2) wall 0.025393 comb 0.020000 user 0.020000 sys 0.000000 (best of 107)

revset #1: sort(0 + 1 + 2 + ... + 1000)
1) wall 0.035240 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
2) wall 0.026432 comb 0.030000 user 0.030000 sys 0.000000 (best of 102)

revset #2: first(0 + 1 + 2 + ... + 1000)
1) wall 0.028949 comb 0.030000 user 0.030000 sys 0.000000 (best of 100)
2) wall 0.025503 comb 0.030000 user 0.030000 sys 0.000000 (best of 106)
2015-05-17 15:11:38 +09:00
Yuya Nishihara
d23a5c2002 revset: reduce nesting of chained 'or' operations (issue4624)
This reduces the stack depth of chained 'or' operations:
 - from O(n) to O(1) at the parsing, alias expansion and optimization phases
 - from O(n) to O(log(n)) at the evaluation phase

simplifyinfixops() must be applied immediately after the parsing phase.
Otherwise, alias expansion would crash by "maximum recursion depth exceeded"
error.

Test cases use 'x:y|y:z' instead of 'x|y' because I'm planning to optimize
'x|y' in a different way.

Benchmarks:

0) a2acce8dcd95
1) this patch

revset #0: 0 + 1 + 2 + ... + 200
0) wall 0.026347 comb 0.030000 user 0.030000 sys 0.000000 (best of 101)
1) wall 0.023858 comb 0.030000 user 0.030000 sys 0.000000 (best of 112)

revset #1: 0 + 1 + 2 + ... + 1000
0) maximum recursion depth exceeded
1) wall 0.483341 comb 0.480000 user 0.480000 sys 0.000000 (best of 20)

revset #2: sort(0 + 1 + 2 + ... + 200)
0) wall 0.013404 comb 0.010000 user 0.010000 sys 0.000000 (best of 196)
1) wall 0.006814 comb 0.010000 user 0.010000 sys 0.000000 (best of 375)

revset #3: sort(0 + 1 + 2 + ... + 1000)
0) maximum recursion depth exceeded
1) wall 0.035240 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
2015-04-26 18:13:48 +09:00
Matt Mackall
1b6a04b2ec branch: don't warn about branches if repository has multiple branches already
This warning exists to prevent git users from prematurely polluting
their namespace when trying out Mercurial. But for repos that already
have multiple branches, understanding what branches are is not
optional so we should just shut up.
2015-05-22 17:08:59 -05:00
Yuya Nishihara
d6cec5ba07 test-revset: update test that isn't broken on default branch
"X or wdir()" just works because the default branch includes 9ee7595f7f11.
2015-05-26 23:14:50 +09:00
Matt Mackall
07ca4361bb merge with stable 2015-05-26 07:44:37 -05:00
Yuya Nishihara
3ca8d79bef revbranchcache: return uncached branchinfo for nullrev (issue4683)
This fixes the crash caused by "branch(null)" revset. No cache should be
necessary for nullrev because changelog.branchinfo(nullrev) does not involve
IO operation.

Note that the problem of "branch(wdir())" isn't addressed by this patch.
"wdir()" will raise TypeError in many places because of None. This is the
reason why "wdir()" is still experimental.
2015-05-23 11:14:00 +09:00
Yuya Nishihara
799e490a3c revset: drop magic of fullreposet membership test (issue4682)
This patch partially backs out a9a86cbbc5b2 and adds an alternative workaround
to functions that evaluate "null" and "wdir()". Because the new workaround is
incomplete, "first(null)" and "min(null)" don't work as expected. But they were
not usable until 3.4 and "null" isn't commonly used, we can postpone a complete
fix for 3.5.

The issue4682 was caused because "branch(default)" is evaluated to
"<filteredset <fullreposet>>", keeping fullreposet magic. The next patch will
fix crash on "branch(null)", but without this patch, it would make
"null in <branch(default)>" be True, which means "children(branch(default))"
would return all revisions but merge (p2 != null).

I believe the right fix is to stop propagating fullreposet magic on filter(),
but it wouldn't fit to stable release. Also, we should discuss how to handle
"null" and "wdir()" in revset before.
2015-05-24 10:29:33 +09:00
Yuya Nishihara
cc6506056b revset: map postfix '%' to only() to optimize operand recursively (issue4670)
Instead of keeping 'onlypost' as a method, this patch rewrites it to 'only'
function. This way, 'x%' always has the same weight as 'only(x)'.
2015-05-15 22:32:31 +09:00
Alexander Drozdov
f95ceba6f9 revset: id() called with 40-byte strings should give the same results as for short strings
The patch solves two issues:
1. id(unknown_full_hash) aborts, but id(unknown_short_hash) doesn't
2. id(40byte_tag_or_bookmark) returns tagged/bookmarked revision,
   but id(non-40byte_tag_or_bookmark) doesn't

After the patch:
1. id(unknown_full_hash) doesn't abort
2. id(40byte_tag_or_bookmark) returns empty set
2015-04-20 10:52:20 +03:00
FUJIWARA Katsunori
2d5a78fede tests: make tests with temporary environment setting portable
With "dash" (as "/bin/sh" on Debian GNU/Linux), command execution in
"ENV=val foo bar" style doesn't work as expect in test script files,
if "foo" is user-defined function: it works fine, if "foo" is existing
commands like "hg".

5acecb004820 introduced tests for HGPLAIN and HGPLAINEXCEPT into
test-revset.t, and all of them are in such style.

This patch doesn't:

  - add explicit unsetting for HGPLAIN and HGPLAINEXCEPT

    they are already introduced by 5acecb004820

  - write assignment and exporting in one line

    "ENV=val; export ENV" for two or more environment variables in one
    line causes failure of test-check-code-hg.t: it is recognized as
    "don't export and assign at once" unfortunately.
2015-05-02 00:15:03 +09:00
Siddharth Agarwal
eba77fa34f ui: disable revsetaliases in plain mode (BC)
ui.plain() is supposed to disable config options that change the UI to the
detriment of scripts. As the test demonstrates, revset aliases can actually
override builtin ones, just like command aliases. Therefore I believe this is a
bugfix and appropriate for stable.
2015-04-30 07:46:54 -07:00
Ryan McElroy
0bcb80448a revsets: more informative syntax error message
I came across a case where an internal command was using a revset that I didn't
immediately pass in and it was difficult to debug what was going wrong with the
revset. This prints out the revset and informs the user that the error is with
a rebset so it should be more obvious what and where the error is.
2015-04-13 20:53:05 -07:00
Ryan McElroy
7500433d6e revsets: show current revset abort behavior 2015-04-13 21:06:21 -07:00
Yuya Nishihara
499c2ed6e7 revset: optimize "x & fullreposet" case
If self is a smartset and other is a fullreposet, nothing should be necessary.

A small win for trivial query in mozilla-central repo:

revset #0: (0:100000)
0) wall 0.017211 comb 0.020000 user 0.020000 sys 0.000000 (best of 163)
1) wall 0.001324 comb 0.000000 user 0.000000 sys 0.000000 (best of 2160)
2015-03-16 17:11:25 +09:00
Yuya Nishihara
bc9e0dc64b debugrevspec: show nesting structure of smartsets if verbose
This shows how smartsets are constructed from the query. It will be somewhat
useful to track problems such as stack overflow.
2015-03-16 18:36:53 +09:00
Yuya Nishihara
be1e504983 revset: drop redundant filteredset from right-hand side set of "or" operation
Since b4681ae82d4a, it should no longer be necessary because the addset can
remove duplicates correctly.
2015-03-30 20:56:37 +09:00
Yuya Nishihara
7c8dcbb212 revset: remove unused 'only' from methods table
The infix 'only' operator is mapped to 'only()' function by optimize(), so
it won't be looked up as a method. The test shows it.
2015-05-15 22:38:24 +09:00
Matt Mackall
e71173010b merge with stable 2015-05-15 11:52:09 -05:00
Yuya Nishihara
17d1eb2f7e revset: test current behavior of addset class
The addset class isn't simple and it has a hidden bug that will be fixed by
future patches. So let's test the current behavior.
2015-03-30 19:51:40 +09:00
Yuya Nishihara
4290eff5ce revset: add wdir() function to specify workingctx revision by command
The main purpose of wdir() is to annotate working-directory files.

Currently many commands and revsets cannot handle workingctx and may raise
exception. For example, -r ":wdir()" results in TypeError. This problem will
be addressed by future patches.

We could add "wdir" symbol instead, but it would conflict with the existing
tag, bookmark or branch. So I decided not to.

List of commands that will potentially support workingctx revision:

  command   default  remarks
  --------  -------  -----------------------------------------------------
  annotate  p1       useful
  archive   p1       might be useful
  cat       p1       might be useful on Windows (no cat)
  diff      p1:wdir  (default)
  export    p1       might be useful if wctx can have draft commit message
  files     wdir     (default)
  grep      tip:0    might be useful
  identify  wdir     (default)
  locate    wdir     (default)
  log       tip:0    might be useful with -p or -G option
  parents   wdir     (default)
  status    wdir     (default)

This patch includes minimal test of "hg status" that should be able to handle
the workingctx revision.
2014-08-16 13:44:16 +09:00
Augie Fackler
dbd43329ce dispatch: offer suggestions of similar-named commands
When suggestions are available, we show those suggestions instead of
showing some help output.
2015-02-10 15:59:12 -05:00
Augie Fackler
6941008520 dispatch: offer near-edit-distance suggestions for {file,rev}set functions
Before this patch, when I have a brain fart and type `hg log -r
'add(foo)'`, hg exits and just says add isn't a function, leading me
to the help page for revset to figure out how to spell the
function. With this patch, it suggests 'adds' as a function I might
have meant.
2015-01-26 15:43:13 -05:00
Augie Fackler
009581a07d test-revset: add tests for missing function output
An upcoming change will slightly alter behavior here. Adding the test
now so the output change stands out in the later changeset.
2015-01-26 15:52:46 -05:00
Yuya Nishihara
3adf9bf0f3 revset: extend fullreposet to make "null" revision magically appears in set
As per fullreposet.__and__, it can omit the range check of rev.  Therefore,
"null" revision is accepted automagically.

It seems this can fix many query results involving null symbol.  Originally,
the simplest "(null)" query did fail if there were hidden revisions.  Tests
are randomly chosen.

fullreposet mimics the behavior of localrepo, where "null" revision is not
listed but contained.
2015-01-08 23:05:45 +09:00
Yuya Nishihara
ee4ca20b38 revset: have all() filter out null revision
I'm not sure if "all()" should filter out "null", but "all()" is stated as
'the same as "0:tip"' (except that it doesn't reorder the subset, I think.)

This patch is intended to avoid exposing a fullreposet to graphmod.dagwalker(),
which would result in strange drawing in future version:

  |
  o  changeset:   0:f8035bb17114
  |  user:        test
  |  date:        Thu Jan 01 00:00:00 1970 +0000
  |  summary:     add a

caused by:

    parents = sorted(set([p.rev() for p in ctx.parents()
                          if p.rev() in revs]))

We cannot add "and p.rev() != nullrev" here because revs may actually include
"null" revision.
2015-01-10 14:49:50 +09:00
Jordi Gutiérrez Hermoso
ed917f2095 revrange: don't parse revset aliases as hash prefixes (issue4553)
If a user has a revsetalias defined, it is their explicit wish for
this alias to be parsed as a revset and nothing else. Although the
case of the alias being short enough and only contain the letters a-f
is probably kind of rare, it may still happen.
2015-02-25 18:12:01 -05:00
Matt Mackall
b907416f7b merge with stable 2015-03-02 01:20:14 -06:00