Commit Graph

712 Commits

Author SHA1 Message Date
Yuya Nishihara
d1927459b6 revset: add function to build dict of positional and keyword arguments
Keyword arguments will be convenient for functions that will take more than
one optional or boolean flags. For example,

  file(pattern[, subrepos=false])
  subrepo([[pattern], status])

Because I don't think all functions should accept key=value syntax, getkwargs()
does not support variadic functions such as 'ancestor(*changeset)'.

The core logic is placed in the parser module because keyword arguments will
be more useful in the templater, where functions take more options. Test cases
will be added by the next patch.
2015-06-27 17:25:01 +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
b41110155b revset: fix a crash in parents() when 'wdir()' is in the set
The crash was "TypeError: expected string or Unicode object, NoneType found"
down in revlog.parentrevs().  This fixes heads() too (which is where I found
it.)
2015-06-29 10:34:56 -04:00
Gregory Szorc
5380dea2a7 global: mass rewrite to use modern exception syntax
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".

This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.

This patch was produced by running `2to3 -f except -w -n .`.
2015-06-23 22:20:08 -07:00
Yuya Nishihara
fe462ed8ac parser: accept iterator of tokens instead of tokenizer function and program
This can simplify the interface of parse() function. Our tokenizer tends to
have optional arguments other than the message to be parsed.

Before this patch, the "lookup" argument existed only for the revset, and the
templater had to pack [program, start, end] to be passed to its tokenizer.
2015-06-21 00:49:26 +09:00
Pierre-Yves David
4686ca0994 revset: rework 'filteredset.last'
'isascending' and 'isdescending' are methods, not attributes. This led 'last()'
to misbehave on some non-ascending filtered sets.
2015-06-22 13:48:01 -07:00
Pierre-Yves David
9c4de6ba91 revset: improves time complexity of 'roots(xxx)'
The canonical way of doing 'roots(X)' is 'X - children(X)'. This is what the
implementation used to be. However, computing children is expensive because it
is unbounded. Any changesets in the repository may be a children of '0' so you
have to look at all changesets in the repository to compute children(0).
Moreover the current revsets implementation for children is not lazy, leading to
bad performance when fetching the first result.


There is a more restricted algorithm to compute roots:

    roots(X) = [r for r in X if not parents(r) & X]

This achieve the same result while only looking for parent/children relation in
the X set itself, making the algorithm 'O(len(X))' membership operation.
Another advantages is that it turns the check into a simple filter, preserving
all laziness property of the underlying revsets.

The speed is very significant and some laziness is restored.

-) revset without 'roots(...)' to compare to base line
0) before this change
1) after this change

revset #0: roots((tip~100::) - (tip~100::tip))
   plain         min           last
-) 0.001082      0.000993      0.000790
0) 0.001366      0.001385      0.001339
1) 0.001257  92% 0.001028  74% 0.000821  61%

revset #1: roots((0::) - (0::tip))
   plain         min           last
-) 0.134551      0.144682      0.068453
0) 0.161822      0.171786      0.157683
1) 0.137583  85% 0.146204  85% 0.070012  44%

revset #2: roots(tip~100:)
   plain         min           first         last
-) 0.000219      0.000225      0.000231      0.000229
0) 0.000513      0.000529      0.000507      0.000539
1) 0.000463  90% 0.000269  50% 0.000267  52% 0.000463  85%

revset #3: roots(:42)
   plain         min           first         last
-) 0.000119      0.000146      0.000146      0.000146
0) 0.000231      0.000254      0.000253      0.000260
1) 0.000216  93% 0.000186  73% 0.000184  72% 0.000244  93%

revset #4: roots(not public())
   plain         min           first
-) 0.000478      0.000502      0.000504
0) 0.000611      0.000639      0.000634
1) 0.000604      0.000560  87% 0.000558

revset #5: roots((0:tip)::)
   plain         min           max           first         last
-) 0.057795      0.004905      0.058260      0.004908      0.038812
0) 0.132845      0.118931      0.130306      0.114280      0.127742
1) 0.111659  84% 0.005023   4% 0.111658  85% 0.005022   4% 0.092490  72%

revset #6: roots(0::tip)
   plain         min           max           first         last
-) 0.032971      0.033947      0.033460      0.032350      0.033125
0) 0.083671      0.081953      0.084074      0.080364      0.086069
1) 0.074720  89% 0.035547  43% 0.077025  91% 0.033729  41% 0.083197

revset #7: 42:68 and roots(42:tip)
   plain         min           max           first         last
-) 0.006827      0.000251      0.006830      0.000254      0.006771
0) 0.000337      0.000353      0.000366      0.000350      0.000366
1) 0.000318  94% 0.000297  84% 0.000353      0.000293  83% 0.000351

revset #8: roots(0:tip)
   plain         min           max           first         last
-) 0.002119      0.000145      0.000147      0.000147      0.000147
0) 0.047441      0.040660      0.045662      0.040284      0.043435
1) 0.038057  80% 0.000187   0% 0.034919  76% 0.000186   0% 0.035097  80%

revset #0: roots(:42 + tip~42:)
   plain         min           max           first         last          sort
-) 0.000321      0.000317      0.000319      0.000308      0.000369      0.000343
0) 0.000772      0.000751      0.000811      0.000750      0.000802      0.000783
1) 0.000632  81% 0.000369  49% 0.000617  76% 0.000358  47% 0.000601  74% 0.000642  81%
2015-06-22 10:19:12 -07:00
Pierre-Yves David
e0e715574b revsets: use '&' instead of '.filter' in head
More high level operations are more likely to be optimised.
2014-10-10 17:30:09 -07: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
Pierre-Yves David
b62d73dc41 devel-warn: issue a warning for old style revsets
We have move to smartset class more than a year ago, we now have the tool to
aggressively nudge developer into upgrading their extensions.
2015-06-19 11:17:11 -07:00
Pierre-Yves David
da0f39bd8a revset: make use of natively-computed set for 'draft()' and 'secret()'
If the computation of a set for each phase (done in C) is available,
we use it directly instead of applying a simple filter. This give a
massive speed-up in the vast majority of cases.

On my mercurial repo with about 15000 out of 40000 draft changesets:

revset: draft()
   plain         min           first         last
0) 0.011201      0.019950      0.009844      0.000074
1) 0.000284   2% 0.000312   1% 0.000314   3% 0.000315 x4.3

Bad performance for "last" come from the handling of the 15000 elements set
(memory allocation, filtering hidden changesets (99% of it) etc. compared to
applying the filter only on a handfuld of revisions (the first draft changesets
being close of tip).

This is not seen as an issue since:

* Timing is still pretty good and in line with all the other one,
* Current user of Vanilla Mercurial will not have 1/3 of their repo draft,

This bad effect disappears when phase's set is smaller. (about 200 secrets):

revset: secret()
   plain         min           first         last
0) 0.011181      0.022228      0.010851      0.000452
1) 0.000058   0% 0.000084   0% 0.000087   0% 0.000087  19%
2015-06-10 19:18:51 -07:00
Pierre-Yves David
71823c86d9 revset: refactor the non-public phase code
Code for draft and secret are the same. We'll make it more complex to
take advantages of the set recomputed in C, so we first refactor the
code to only have one place to update (and make sure all behave
properly).

We do not refactor the 'public()' code because it does not have a natively
computed set.
2015-06-17 19:19:57 -07:00
Pierre-Yves David
7dc4b61365 revset: translate node directly with changelog in 'head'
Using 'repo[X]' is much slower because it creates a 'changectx' object and goes
though multiple layers of code to do so. It is also error prone if there is
tags, bookmarks, branch or other names that could map to a node hash and take
precedence (user are wicked).

This provides a significant performance boost on repository with a lot of
heads.  Benchmark result for a repo with 1181 heads.

revset: head()
   plain         min           last          reverse
0) 0.014853      0.014371      0.014350      0.015161
1) 0.001402   9% 0.000975   6% 0.000874   6% 0.001415   9%

revset: head() - public()
   plain         min           last          reverse
0) 0.015121      0.014420      0.014560      0.015028
1) 0.001674  11% 0.001109   7% 0.000980   6% 0.001693  11%

revset: draft() and head()
   plain         min           last          reverse
0) 0.015976      0.014490      0.014214      0.015892
1) 0.002335  14% 0.001018   7% 0.000887   6% 0.002340  14%

The speed up is visible even when other more costly revset are in use

revset: head() and author("mpm")
   plain         min           last          reverse
0) 0.105419      0.090046      0.017169      0.108180
1) 0.090721  86% 0.077602  86% 0.003556  20% 0.093324  86%
2015-06-16 19:47:46 -07:00
Pierre-Yves David
2c584c4990 revset: use a baseset in _notpublic()
The '_notpublic()' internal revset was "returning" a set. That was wrong. We now
return a 'baseset' as appropriate. This has no effect on performance in most case,
because we do the exact same operation than what the combination with a
'fullreposet' was doing. This as a small effect on some operation when combined
with other set, because we now apply the filtering in all cases. I think the
correctness is worth the impact on some corner cases. The optimizer should take
care of these corner cases anyway.

revset #0: not public()
   plain         min           max           first         last          reverse
0) 0.000465      0.000491      0.000495      0.000500      0.000494      0.000479
1) 0.000484      0.000503      0.000498      0.000505      0.000504      0.000491

revset #1: (tip~1000::) - public()
   plain         min           max           first         last          reverse
0) 0.002765      0.001742      0.002767      0.001730      0.002761      0.002782
1) 0.002847      0.001777      0.002776      0.001741      0.002764      0.002858

revset #2: not public() and branch("default")
   plain         min           max           first         last          reverse
0) 0.012104      0.011138      0.011189      0.011138      0.011166      0.011578
1) 0.011387  94% 0.011738 105% 0.014220 127% 0.011223      0.011184      0.012077

revset #3: (not public() - obsolete())
   plain         min           max           first         last          reverse
0) 0.000583      0.000556      0.000552      0.000555      0.000552      0.000610
1) 0.000613 105% 0.000559      0.000557      0.000573      0.000558      0.000613

revset #4: head() - public()
   plain         min           max           first         last          reverse
0) 0.010869      0.010800      0.011547      0.010843      0.010891      0.010891
1) 0.011031      0.011497 106% 0.011087      0.011100      0.011100      0.011085
2015-06-10 19:58:27 -07:00
Pierre-Yves David
d05c4e4635 revset: ensure we have loaded phases data in '_notpublic()'
If we are the very first rev access (or if the phase cache just got
invalidated) the phasesets will be None even if we support the native
computation. So we explicitly trigger a computation if needed.

This was not an issue before because requesting any phase information
would have triggered such computation.
2015-06-15 16:16:02 -07:00
Pierre-Yves David
48aa2b29f7 revset: use parentsets.min in _children
As stated in the comment, using the smartset 'min' will give more opportunity to
be smart. It give a small but significant boost to the performance. Most of the
time is still spend doing the actual computation but at least we can scrap some
performance when it makes sense.

revset #0: roots(0:tip)
   plain
0) 0.046600
1) 0.044109  94%
2015-06-11 19:02:24 -07:00
Pierre-Yves David
ae45bb4c69 revset: prefetch all attributes before loop in _revsbetween
Python is slow at attributes lookup. No, really, I mean -slow-. prefetching
these three methods give use a measurable performance boost.

revset #0: 0::tip
   plain
0) 0.037655
1) 0.034290  91%
2015-06-11 11:42:46 -07:00
Pierre-Yves David
062add8bae revset: mark spots that use 'set' instead of 'smartset'
Using smartset is better because we can do more optimisation on it. So we are
marking the faulty spot for later processing.
2015-06-11 15:45:02 -07:00
Pierre-Yves David
fb5a589cc8 revset: mark spot that feeds a set to a baseset
Sets have non-defined order and this should break stuff, but as we are lucky
fullreposet is also broken so the result is "not too bad".

We should fix it anyway, but it is too much for my current plate.
2015-06-11 15:43:11 -07:00
Pierre-Yves David
f5b6e24d29 revset: mark the fact we should use '&' instead of 'filter' in 'head'
I do not have time to fix all this now, let's mark it for later.
2015-06-11 15:37:17 -07:00
Pierre-Yves David
b62dbb27c2 revset: gratuitous formating fix in keyword
You will be aligned.
2015-06-11 15:36:03 -07:00
Pierre-Yves David
eb81242d78 revset: gratuitous code move in '_children'
As 'cs' is empty as the time of the conditional, we can just return an empty
'baseset' and create the variable later.
2015-06-11 14:27:52 -07:00
Pierre-Yves David
64a4e299bb revset: mark spots that should use 'smartset.min()'
Using smartset's min will be significantly faster when the input set can provided
an optimised answer. I do not have time to fix all of them but I'm marking the
spot.
2015-06-11 14:26:44 -07:00
Pierre-Yves David
53bc8a61ba revset: mark the place where we are combining sets in the wrong direction
We should always combine with subset as the left operand (to preserve the
order). I do not have time to fix all of them so I'm just marking the spot.
2015-06-11 14:21:21 -07:00
Pierre-Yves David
9bcc184424 revset: point out wrong behavior in fullreposet
I cannot fix all issues in revset because I've got other things to do,
but let's write down all the brokenness to help other people reading
and fixing.
2015-06-11 14:00:13 -07: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
15ea334802 revset: make "null" able to appear in internal _list() expression
This is the same workaround introduced at 3aa0e4733e6f. Without this patch,
"null or x" can't be optimized to _list(null x).

Test case will be added by the next patch.
2015-05-29 21:31:00 +09:00
Yuya Nishihara
003219cbf5 revset: make internal _list() expression remove duplicated revisions
This allows us to optimize chained 'or' operations to _list() expression.

Unlike _intlist() or _hexlist(), it's difficult to remove duplicates by the
caller of _list() because different symbols can point to the same revision.
If the caller knows all symbols are unique, that probably means revisions or
nodes are known, therefore, _intlist() or _hexlist() should be used instead.
So, it makes sense to check duplicates by _list() function.

'%ls' is no longer used in core, this won't cause performance regression.
2015-05-24 14:49:41 +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
Yuya Nishihara
c29c74ec96 revset: add helper to build balanced addsets from chained 'or' operations
This function will be used by revset.orset() and scmutil.revrange() to reduce
the stack depth from O(n) to O(log(n)).

We've bikeshed the interface of this function, but we couldn't come to an
agreement. So we decided to attempt to make it move forward.

 marmoute:
 - new factory function isn't necessary for balanced addsets
 - addset.__init__ can just recurse, should handle "len(subsets) == 2+"

 yuja:
 - want to write all "len(subsets) == 0, 1, 2, 3+" cases in the same function
 - no recursion in __init__ for cosmetic reason: can't return, can't call
   __init__ directly

I've changed it to a private function so that nobody would be tempted to
utilize it.
2015-05-24 14:10:52 +09:00
Yuya Nishihara
cc8b59754d revset: comment that we can't swap 'or' operands by weight
Though the original code did nothing, it tried to optimize the calculation
order by weight. But we can't simply swap 'ta' and 'tb' because it would
change the order of revisions.

For future reference, this patch keeps the modified version of the original
code as comment.
2015-04-26 18:27:32 +09:00
Matt Mackall
07ca4361bb merge with stable 2015-05-26 07:44:37 -05: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
Yuya Nishihara
09759e9679 parser: move prettyformat() function from revset module
I want to use it in doctests that I'll add by future patches. Also, it can
be used in "hg debugfileset" command.
2015-04-26 22:20:03 +09:00
Yuya Nishihara
0aa2a7df4d revset: move validation of incomplete parsing to parse() function
revset.parse() should be responsible for all parsing errors. Perhaps it wasn't
because 'revset.parse' was not a real function when the validation code was
added at ac01134d0a40.
2015-04-26 19:42:47 +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
Yuya Nishihara
eae9526460 revset: undocument wdir() until its command outputs get stable
wdir() implementation is still incomplete and shouldn't be advertised to
users. This patch will be backed out when

 - template values such as {rev} and {node} are settled
 - major commands and revsets work without crashing
2015-04-12 19:00:31 +09:00
Gregory Szorc
7498d10d47 revset: don't import discovery at module level
discovery.py imports a lot of the world. Pierre-Yves told me to move it
to a function-level import to avoid an import cycle in a future patch.
2015-04-14 12:54:16 -04: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
Laurent Charignon
dfc226357c revset: add hook after tree parsing
This will be useful to execute actions after the tree is parsed and
before the revset returns a match. Finding symbols in the parse tree
will later allow hashes of hidden revisions to work on the command
line without the --hidden flag.
2015-03-24 14:24:55 -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
2c5f3cb86d revset: add __repr__ to all smartset classes
This is sometimes useful for debugging.
2015-03-16 18:15:06 +09:00
Matt Harbison
1abecad109 revset: add the 'subrepo' symbol
This returns the csets where matching subrepos have changed with respect to the
containing repo's first parent.  The second parent shouldn't matter, because it
is either syncing up to the first parent (i.e. it hasn't changed from the
current branch's POV), or the merge changed it with respect to the first parent
(which already adds it to the set).

There's already a 'subrepo' fileset, but it is prefixed with 'set:', so there
should be no ambiguity (in code anyway).  The only test I see for it is to
revert subrepos named by a glob pattern (in test-subrepo.t, line 58).  Since it
doesn't return a tracked file, neither 'log "set:subrepo()"' nor
'files "set:subrepo()"' print anything.  Therefore, it seems useful to have a
revset that will return something for log (and can be added to a revsetalias to
be chained with 'file' revsets.)

It might be nice to be able to filter for added, modified and removed
separately, but add/remove should be rare.  It might also be nice to be able to
do a 'contains' check, in addition to this mutated check.  Maybe it is possible
to get those with the existing 'adds', 'contains', 'modifies' and 'removes' by
teaching them to chase explicit paths into subrepos.

I'm not sure if this should be added to the 'modifies adds removes' line in
revset.optimize() (since it is doing an AMR check on .hgsubstate), or if it is
OK to put into 'safesymbols' (things like 'file' are on the list, and that takes
a regex, among other patterns).
2015-03-25 14:56:54 -04:00
Yuya Nishihara
e50dcd48fb revset: drop translation marker from error message of _notpublic()
It is a kind of an internal error. End user won't see it.
2015-05-19 23:29:20 +09:00
Yuya Nishihara
9dda746eb9 revset: drop docstring from internal _notpublic() function
It shouldn't be listed in "hg help revset".
2015-05-19 23:26:25 +09:00
Laurent Charignon
be38dd4abe revset: optimize not public revset
This patvh speeds up the computation of the not public() changeset
and incidentally speed up the computation of divergents() changeset on our big
repo by 100x from 50% to 0.5% of the time spent in smartlog with evolve.

In this patch we optimize not public() to _notpublic() (new revset) and use
the work on phaseset (from the previous commit) to be able to compute
_notpublic() quickly.

We use a non-lazy approach making the assumption the number of notpublic
change will not be in the order of magnitude of the repo size. Adopting a
lazy approach gives a speedup of 5x (vs 100x) only due to the overhead of the
code for lazy generation.
2015-04-24 14:30:30 -07:00
Augie Fackler
a5b17bd9d1 cleanup: use __builtins__.any instead of util.any
any() is available in all Python versions we support now.
2015-05-16 14:30:07 -04:00
Pierre-Yves David
49fcb055f4 generatorset: use 'next()' to simplify the code
The 'next()' built-in accept a default value. This remove the needs to check if
self non-empty before returning a value.
2015-05-17 18:06:09 -07:00
Pierre-Yves David
db5d2b0a12 revset: use 'next()' to detect end of iteration in 'last'
The 'next()' built-in can return a default value, allow to get rid of the
confusing try/except code flow.
2015-05-17 18:00:38 -07:00
Pierre-Yves David
95c104ceb7 revset: use 'next()' to detect end of iteration in 'limit'
The 'next()' built-in can return a default value, allow to get rid of the
confusing try/except code flow.
2015-05-17 17:58:39 -07:00
Pierre-Yves David
3e86398675 _revancestors: use 'next' to remove the verbose try except clauses
The 'next()' built-in can return a default value, making the final iteration
case simpler and clearer.
2015-05-17 17:54:58 -07:00
Yuya Nishihara
498cbbe4ca revset: extract addset._iterordered to free function
It never uses self, so let's make it less dependent on variables.
2015-05-16 21:42:09 +09:00
Yuya Nishihara
4f23717a35 revset: use fastasc/fastdesc switch consistently in addset.__iter__ 2015-05-16 14:05:02 +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
Pierre-Yves David
fc3daddf63 revset: fix iteration over ordered addset composed of non-ordered operands
Before this change, doing ordered iteration over an 'addset' object composed of
operands without fastasc or fastdesc method could result in duplicated entries.
This was the result of applying '_iterordered' on an unordered set.

We fix it by ensuring we iterate over the set in a sorted order. Using the fast
iterator when it exists on any operand. We kill the '_iterator' method in the
process because it did not make a lot of sense independently.

Thanks goes to Yuya Nishihara for reporting the issue and analysing the cause.
2015-05-15 00:25:43 -07: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
5780b536c6 revset: remove duplicated definition of choice() from addset._iterordered()
choice() is already defined before val1 = None. Perhaps there was merge or
rebase error.
2015-04-27 23:03:20 +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
Durham Goode
23a18a419d revbranchcache: store repo on the object
Previously we would instantiate the revbranchcache with a repo object, use it
briefly, then require it be passed in every time we wanted to fetch any
information. This seems unnecessary since it's obviously specific to that repo
(since it was constructed with it).

This patch stores the repo on the revbranchcache object, and removes the repo
parameter from the various functions on that class. This has the other nice
benefit of removing the double-revbranchcache-read that existed before (it was
read once for the branch revset, and once for the repo.revbranchcache).
2015-02-10 19:57:51 -08:00
Yuya Nishihara
34da300653 revset: replace "working copy" with "working directory" in function help 2015-03-17 20:50:19 +09:00
Jordi Gutiérrez Hermoso
8eb132f5ea style: kill ersatz if-else ternary operators
Although Python supports `X = Y if COND else Z`, this was only
introduced in Python 2.5. Since we have to support Python 2.4, it was
a very common thing to write instead `X = COND and Y or Z`, which is a
bit obscure at a glance. It requires some intricate knowledge of
Python to understand how to parse these one-liners.

We change instead all of these one-liners to 4-liners. This was
executed with the following perlism:

    find -name "*.py" -exec perl -pi -e 's,(\s*)([\.\w]+) = \(?(\S+)\s+and\s+(\S*)\)?\s+or\s+(\S*)$,$1if $3:\n$1    $2 = $4\n$1else:\n$1    $2 = $5,' {} \;

I tweaked the following cases from the automatic Perl output:

    prev = (parents and parents[0]) or nullid
    port = (use_ssl and 443 or 80)
    cwd = (pats and repo.getcwd()) or ''
    rename = fctx and webutil.renamelink(fctx) or []
    ctx = fctx and fctx or ctx
    self.base = (mapfile and os.path.dirname(mapfile)) or ''

I also added some newlines wherever they seemd appropriate for readability

There are probably a few ersatz ternary operators still in the code
somewhere, lurking away from the power of a simple regex.
2015-03-13 17:00:06 -04:00
Augie Fackler
0b9e6790bf revset: use UnknownIdentifier where appropriate 2015-01-26 14:32:30 -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
f6f2cc07d6 revset: duplicate spanset.__contains__ to fullreposet for modification
fcccbf073394 says we should avoid function calls in __contains__, so
super(fullreposet, self).__contains__(rev) is not an option.

Actually the super call doubled the benchmark result of trivial query:

revisions:
0) 6aa81b0c4658 (tip when I wrote this patch)
1) rev == node.nullrev or super(fullreposet, self).__contains__(rev)

revset #0: tip:0
0) wall 0.008441 comb 0.010000 user 0.010000 sys 0.000000 (best of 282)
1) wall 0.016152 comb 0.010000 user 0.010000 sys 0.000000 (best of 146)
2015-01-10 18:09:25 +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
Yuya Nishihara
bc28702606 revset: drop unnecessary calls of getall() with empty argument
If x is None, getall(repo, subset, x) == subset.
2015-01-10 16:41:36 +09:00
Matt Mackall
b907416f7b merge with stable 2015-03-02 01:20:14 -06:00
Mads Kiilerich
56207b4242 revisionbranchcache: fall back to slow path if starting readonly (issue4531)
Transitioning to Mercurial versions with revision branch cache could be slow as
long as all operations were readonly (revset queries) and the cache would be
populated but not written back.

Instead, fall back to using the consistently slow path when readonly and the
cache doesn't exist yet. That avoids the overhead of populating the cache
without writing it back.

If not readonly, it will still populate all missing entries initially. That
avoids repeated writing of the cache file with small updates, and it also makes
sure a fully populated cache available for the readonly operations.
2015-02-06 02:52:10 +01:00
FUJIWARA Katsunori
8a439b3cc6 revset: mask specific names for named() predicate
Before this patch, revset predicate "tag()" and "named('tags')" differ
from each other, because the former doesn't include "tip" but the
latter does.

For equivalence, "named('tags')" shouldn't include the revision
corresponded to "tip". But just removing "tip" from the "tags"
namespace causes breaking backward compatibility, even though "tip"
itself is planned to be eliminated, as mentioned below.

    http://selenic.com/pipermail/mercurial-devel/2015-February/066157.html

To mask specific names ("tip" in this case) for "named()" predicate,
this patch introduces "deprecated" into "namespaces", and makes
"named()" predicate examine whether each names are masked by the
namespace, to which they belong.

"named()" will really work correctly after 3.3.1 (see a3c326a7f57a for
detail), and fixing this on STABLE before 3.3.1 can prevent initial
users of "named()" from expecting "named('tags')" to include "tip".

It is reason why this patch is posted for STABLE, even though problem
itself isn't so serious.

This may have to be flagged as "(BC)", if applied on DEFAULT.
2015-02-05 14:45:49 +09:00
FUJIWARA Katsunori
c3172b4737 revset: get revision number of each node from target namespaces
Before this patch, revset predicate "named()" uses each nodes gotten
from target namespaces directly.

This causes problems below:

  - combination of other predicates doesn't work correctly, because
    they assume that revisions are listed up in number

  - "hg log" doesn't show any revisions for "named()" result, because:

    - "changeset_printer" stores formatted output for each revisions
      into dict with revision number (= ctx.rev()) as a key of them

    - "changeset_printer.flush(rev)" writes stored output for
      the specified revision, but

    - "commands.log" invokes it with the node, gotten from "named()"

  - "hg debugrevspec" shows nodes (= may be binary) directly

Difference between revset predicate "tag()" and "named('tags')" in
tests is fixed in subsequent patch.
2015-02-03 21:56:29 +09:00
FUJIWARA Katsunori
6a05d7fab8 revset: raise RepoLookupError to make present() predicate continue the query
Before this patch, "bookmark()", "named()" and "tag()" predicates
raise "Abort", when the specified pattern doesn't match against
existing ones.

This prevents "present()" predicate from continuing the query, because
it only catches "RepoLookupError".

This patch raises "RepoLookupError" instead of "Abort", to make
"present()" predicate continue the query, even if "bookmark()",
"named()" or "tag()" in the sub-query of it are aborted.

This patch doesn't contain raising "RepoLookupError" for "re:" pattern
in "tag()", because "tag()" treats it differently from others. Actions
of each predicates at failure of pattern matching can be summarized as
below:

  predicate  "literal:"  "re:"
  ---------- ----------- ------------
  bookmark   abort       abort
  named      abort       abort
  tag        abort       continue (*1)

  branch     abort       continue (*2)
  ---------- ----------- ------------

"tag()" may have to abort in the (*1) case for similarity, but this
change may break backward compatibility of existing revset queries. It
seems to have to be changed on "default" branch (with "BC" ?).

On the other hand, (*2) seems to be reasonable, even though it breaks
similarity, because "branch()" in this case doesn't check exact
existence of branches, but does pick up revisions of which branch
matches against the pattern.

This patch also adds tests for "branch()" to clarify behavior around
"present()" of similar predicates, even though this patch doesn't
change "branch()".
2015-01-31 01:00:50 +09:00
Yuya Nishihara
b5f973788a revset: fix ancestors(null) to include null revision (issue4512)
Since fe39bbbf31f0, null parent is explicitly excluded. So, there is no reason
to have nullrev in the initial seen set.
2015-01-25 20:20:27 +09:00
Yuya Nishihara
78d778b5ef revset: allow rev(-1) to indicate null revision (BC)
This can simplify the conversion from numeric revision to string. Without it,
we have to handle -1 specially because repo['-1'] != repo[-1].

The -1 revision is not officially documented, but this change makes sense
assuming that "rev(%d)" exists for scripting or third-party tools.
2015-01-10 12:56:38 +09:00
Martin von Zweigbergk
4b40ac0110 log: evaluate filesets on working copy, not its parent
When running "hg log 'set:added()'", we create two matchers: one used
for producing the revset and one used for finding files to match. In
185b6b930e8c (graphlog: evaluate FILE/-I/-X filesets on the working
dir, 2012-02-26), we started passing a revision argument along from
what's currently in cmdutil._makelogrevset() to
revset._matchfiles(). When the revision was an empty string, it
referred to the working copy. This was subtly done with "repo[rev or
None]". Then, in 5ff5c5c9e69f (revset: avoid recalculating filesets,
2014-10-22), that conversion from empty string to None was lost. Note
that repo[''] is equivalent to repo['.'], not repo[None].

The consequence of this, to the user, is that when running "hg log
'set:added()'", the file matcher matches files added in the working
copy, while the revset matcher matches revisions that touch files
added in the parent of the working copy. As a result, only revisions
that touch any files added in the parent of the working copy will be
considered, but they will only be included if they also touch files
added in the working copy.

Fix the bug by converting '' to None again, but make it a little more
explicit this time (plus, we now have tests for it).
2015-01-21 15:23:13 -08:00
Yuya Nishihara
4c1f7f24d7 revset: drop factory that promotes spanset to fullreposet
All callers use fullreposet where appropriate.

Backed out changeset 6c2c046ac382
2015-01-08 23:43:15 +09:00
Yuya Nishihara
878c8b67df revset: specify fullreposet without using spanset factory
The factory function will be removed because the subsequent patches will
make fullreposet(repo) not fully compatible with spanset(repo).
2015-01-08 23:46:54 +09:00
Yuya Nishihara
25fac1a15b revset: make match function initiate query from full set by default
This change is intended to avoid exposing the implementation detail to
callers. I'm going to extend fullreposet to support "null" revision, so
these mfunc calls will have to use fullreposet() instead of spanset().
2015-02-02 22:21:07 +09:00
FUJIWARA Katsunori
ac41d830e2 revset: check for collisions between alias argument names in the declaration
Before this patch, collisions between alias argument names in the
declaration are ignored, and this silently causes unexpected alias
evaluation.

This patch checks for such collisions, and aborts (or shows a warning) when
collisions are detected.

This patch doesn't add a test to "test-revset.t", because a doctest is
enough to test the collisions detection itself.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
e416b72fc5 revset: parse alias declaration strictly by _parsealiasdecl
Before this patch, alias declaration is parsed by string base
operations: matching against "^([^(]+)\(([^)]+)\)$" and splitting by
",".

This overlooks many syntax errors like below (see the previous patch
introducing "_parsealiasdecl" for detail):

  - un-closed parenthesis causes being treated as "alias symbol"
  - symbol/function name aren't examined whether they are valid or not
  - invalid argument list causes unexpected argument names

To parse alias declaration strictly, this patch replaces parsing
implementation by "_parsealiasdecl".

This patch tests only one typical declaration error case, because
error detection itself is already tested in the doctest of
"_parsealiasdecl".

This also removes class property "args" and "error", because these are
certainly initialized in "revsetalias.__init__".
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
87958c780f revset: introduce "_parsealiasdecl" to parse alias declarations strictly
This patch introduces "_parsealiasdecl" to parse alias declarations
strictly. For example, "_parsealiasdecl" can detect problems below,
which current implementation can't.

  - un-closed parenthesis causes being treated as "alias symbol"

    because all of declarations not in "func(....)" style are
    recognized as "alias symbol".

    for example, "foo($1, $2" is treated as the alias symbol.

  - alias symbol/function names aren't examined whether they are valid
    as symbol or not

    for example, "foo bar" can be treated as the alias symbol, but of
    course such invalid symbol can't be referred in revset.

  - just splitting argument list by "," causes overlooking syntax
    problems in the declaration

    for example, all of invalid declarations below are overlooked:

    - foo("bar")     => taking one argument named as '"bar"'
    - foo("unclosed) => taking one argument named as '"unclosed'
    - foo(bar::baz)  => taking one argument named as 'bar::baz'
    - foo(bar($1))   => taking one argument named as 'bar($1)'

To decrease complication of patch, current implementation for alias
declarations is replaced by "_parsealiasdecl" in the subsequent
patch. This patch just introduces it.

This patch defines "_parsealiasdecl" not as a method of "revsetalias"
class but as a one of "revset" module, because of ease of testing by
doctest.

This patch factors some helper functions for "tree" out, because:

  - direct accessing like "if tree[0] == 'func' and len(tree) > 1"
    decreases readability

  - subsequent patch (and also existing code paths, in the future) can
    use them for readability

This patch also factors "_tokenizealias" out, because it can be used
also for parsing alias definitions strictly.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
883b1f7edf revset: store full detail into revsetalias.error for error source distinction
Before this patch, any errors in the declaration of revset alias
aren't detected at all, and there is no information about error source
in the error message.

As a part of preparation for parsing alias declarations and
definitions more strictly, this patch stores full detail into
"revsetalias.error" for error source distinction.

This makes raising "Abort" and warning potential errors just use
"revsetalias.error" without any message composing.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
ae25ee95c4 revset: factor out composing error message for ParseError to reuse
This patch defines the composing function not in "ParseError" class but
in "revset" module, because:

  - "_()" shouldn't be used in "ParseError", to avoid adding "from
    i18n import _" i18n" to "error" module

  - generalizing message composition of"ParseError" for all code paths
    other than revset isn't the purpose of this patch

    we should also take care of showing "unexpected leading
    whitespace" for some code paths, to generalize widely.
2015-01-10 23:18:11 +09:00
FUJIWARA Katsunori
48233206c2 revset: make tokenize extensible to parse alias declarations and definitions
Before this patch, "tokenize" doesn't recognize the symbol starting
with "$" as a valid one.

This prevents revset alias declarations and definitions from being
parsed with "tokenize", because "$" may be used as the initial letter
of alias arguments.

BTW, the alias argument name doesn't require leading "$" itself, in
fact. But we have to assume that users may use "$" as the initial
letter of argument names in their aliases, because examples in "hg
help revsets" uses such names for a long time.

To make "tokenize" extensible to parse alias declarations and
definitions, this patch introduces optional arguments "syminitletters"
and "symletters". Giving these sets can change the policy of "valid
symbol" in tokenization easily.

This patch keeps original examination of letter validity for
reviewability, even though there is redundant interchanging between
"chr"/"ord" at initialization of "_syminitletters" and "_symletters".
At most 256 times examination (per initialization) is cheaper enough
than revset evaluation itself.

This patch is a part of preparation for parsing alias declarations and
definitions more strictly.
2015-01-10 23:18:11 +09:00
Sean Farley
f534500188 namespaces: add revset for 'named(namespace)'
This patch adds functionality for listing all changesets in a given namespace
via the revset language.
2015-01-13 15:07:08 -08:00
Matt Mackall
d829c30933 merge with stable 2015-01-14 12:50:46 -08:00
Yuya Nishihara
47e97cb140 revset: fix spanset.isascending() to honor sort() or reverse() request
Because spanset.isascending() ignored the ascending flag, the result of
"fullreposet() & x" was always sorted in ascending order.

The test case is carefully chosen to call fullreposet.__and__.
2015-01-10 21:31:59 +09:00
Yuya Nishihara
bf8b92850c revset: simplify fullreposet.__and__ to call sort() with boolean flag
Note that sort() takes a boolean flag, so other.sort(reverse) was wrong.
It just worked fine because there is a top-level function, reverse().
2015-01-10 21:36:42 +09:00
Martin von Zweigbergk
c91c749e46 filelog: fix backwards comment for 'backrevref' 2015-01-12 09:46:56 -08:00
Martin von Zweigbergk
63a49977e2 filelog: remove trailing "form feed" character 2015-01-12 09:49:25 -08:00
Martin von Zweigbergk
3e0453e7c4 filelog: remove unused variable 'lkr'
It's used further down, but it's overwritten before, so it's
technically a dead assignment, but unnecessary nevertheless.
2015-01-12 09:48:05 -08:00
Mads Kiilerich
61a36ea4fe revset: use localrepo revbranchcache for branch name filtering
Branch name filtering in revsets was expensive. For every rev it created a
changectx and called .branch() which retrieved the branch name from the
changelog.

Instead, use the revbranchcache.

The revbranchcache is used read-only. The revset implementation with generators
and callbacks makes it hard to figure out when we are done using/updating the
cache and could write it back. It would also be 'tricky' to lock the repo for
writing from within a revset execution. Finally, the branchmap update will
usually make sure that the cache is updated before any revset can be run.
The revbranchcache is used without any locking but is short-lived and used in a
tight loop where we can assume that the changelog doesn't change ... or where
it not is relevant to us if it does.

perfrevset 'branch(mobile)' on mozilla-central.
Before:
! wall 10.989637 comb 10.970000 user 10.940000 sys 0.030000 (best of 3)
After, no cache:
! wall 7.368656 comb 7.370000 user 7.360000 sys 0.010000 (best of 3)
After, with cache:
! wall 0.528098 comb 0.530000 user 0.530000 sys 0.000000 (best of 18)

The performance improvement even without cache come from being based on
branchinfo on the changelog instead of using ctx.branch().

Some tests are added to verify that the revbranchcache works and keep an eye on
when the cache files actually are updated.
2015-01-08 00:01:03 +01:00
Yuya Nishihara
b67b0a75ea revset: drop pre-lazyset optimization for stringset of subset == entire repo
It was introduced at deb42ca4dd93, where spanset.__contains__() did not exist.
Nowadays, we have to pay huge penalty for len(subset).

The following example showed that OR operation could be O(n * m^2)
(n: len(repo), m: number of OR operators, m >= 2) probably because of
filteredset.__len__.

revset #0: 0|1|2|3|4|5|6|7|8|9
0) wall 8.092713 comb 8.090000 user 8.090000 sys 0.000000 (best of 3)
1) wall 0.445354 comb 0.450000 user 0.430000 sys 0.020000 (best of 22)
2) wall 0.000389 comb 0.000000 user 0.000000 sys 0.000000 (best of 7347)
(0: 3.2.4, 1: 3.1.2, 2: this patch)
2015-01-03 10:25:08 +09:00
Pierre-Yves David
56b039c98c revset: fix first and last for generatorset (issue4465)
The code was just plain wrong.
2014-12-01 05:18:12 -08:00
Sean Farley
2a4b30c27c revset: use '%' as an operator for 'only'
With this patch, we can make it much easier to specify 'only(A,B)' ->
A%B. Similarly, 'only(A)' -> A%.

On Windows, '%' is a semi-reserved symbol in the following way: using non-bash
shells (e.g. cmd.exe but NOT PowerShell, ConEmu, and cmder), %var% is only
expanded when 'var' exists and is surrounded by '%'.

That only leaves batch scripts which could prove to be problematic. I posit
that this isn't a big issue because any developer of batch scripts already
knows that to use '%' one needs to escape it by using a double '%%'.

Alternatives to '%' could be '=' but that might be limiting our future if we
ever decide to use temporary assignments in a revset.
2014-11-06 14:55:18 -08:00
Yuya Nishihara
23dc58b88d revset: have rev() validate input by repo.changelog.__contains__()
fullreposet.__contains__() will be rewritten in order to support "null"
revision, and "rev()" won't be possible to rely on it.

This backs out 23ac42e12ce5, but there is no performance regression now.

revisions:
0) bd19f94d30e9 "l not in fullreposet(repo)"
1) this patch   "l not in repo.changelog"

revset #0: rev(210000)
0) wall 0.000056 comb 0.000000 user 0.000000 sys 0.000000 (best of 48036)
1) wall 0.000049 comb 0.000000 user 0.000000 sys 0.000000 (best of 54969)
2015-02-04 21:37:06 +09:00