Commit Graph

219 Commits

Author SHA1 Message Date
Yuya Nishihara
9b58e92dbe smartset: fix generatorset.last() to not return the first element (issue5609) 2017-06-27 23:50:22 +09:00
Pulkit Goyal
b4347ea80f py3: make sure commands name are bytes in tests 2017-06-25 08:20:05 +05:30
Yuya Nishihara
44aa43c0dc revset: add depth limit to descendants() (issue5374)
This is naive implementation using two-pass scanning. Tracking descendants
isn't an easy problem if both start and stop depths are specified. It's
impractical to remember all possible depths of each node while scanning from
roots to descendants because the number of depths explodes. Instead, we could
cache (min, max) depths as a good approximation and track ancestors back when
needed, but that's likely to have off-by-one bug.

Since this implementation appears not significantly slower, and is quite
straightforward, I think it's good enough for practical use cases. The time
and space complexity is O(n) ish.

  revisions:
  0) 1-pass scanning with (min, max)-depth cache (worst-case quadratic)
  1) 2-pass scanning (this version)

  repository:
  mozilla-central

  # descendants(0) (for reference)
  *) 0.430353

  # descendants(0, depth=1000)
  0) 0.264889
  1) 0.398289

  # descendants(limit(tip:0, 1, offset=10000), depth=1000)
  0) 0.025478
  1) 0.029099

  # descendants(0, depth=2000, startdepth=1000)
  0) painfully slow (due to quadratic backtracking of ancestors)
  1) 1.531138
2017-06-24 23:05:57 +09:00
Yuya Nishihara
c6472824e6 dagop: change revdescendants() to include all root revisions
Prepares for adding depth support. I want to process depth=0 in
revdescendants() to make things simpler.

only() also calls dagop.revdescendants(), but it filters out root revisions
explicitly. So this should cause no problem.

  # descendants(0) using hg repo
  0) 0.052380
  1) 0.051226

  # only(tip) using hg repo
  0) 0.001433
  1) 0.001425
2017-06-20 22:26:52 +09:00
Yuya Nishihara
42de67c95b test-revset: add a few more tests of descendants()
I'll add depth support to descendants().
2017-06-20 22:11:23 +09:00
Yuya Nishihara
c47ec16b6a revset: add startdepth limit to ancestors() as internal option
This is necessary to implement the set{gen} (set subscript) operator. For
example, set{-n} will be translated to ancestors(set, depth=n, startdepth=n).

https://www.mercurial-scm.org/wiki/RevsetOperatorPlan#ideas_from_mpm

The UI is undecided and I doubt if the startdepth option would be actually
useful, so the option is hidden for now. 'depth' could be extended to take
min:max range, in which case, integer depth should select a single generation.

  ancestors(set, depth=:y)  # scan up to y-th generation
  ancestors(set, depth=x:)  # skip until (x-1)-th generation
  ancestors(set, depth=x)   # select only x-th generation

Any ideas are welcomed.

  # reverse(ancestors(tip)) using hg repo
  3) 0.075951
  4) 0.076175
2017-06-18 00:40:58 +09:00
Yuya Nishihara
3a18a16767 revset: add depth limit to ancestors()
This is proposed by the issue5374, and will be a building block of set{gen}
(set subscript) operator.

https://www.mercurial-scm.org/wiki/RevsetOperatorPlan#ideas_from_mpm

  # reverse(ancestors(tip)) using hg repo
  2) 0.075408
  3) 0.075951
2017-06-18 00:22:41 +09:00
Yuya Nishihara
c1736d34f9 revset: add support of keyword arguments to ancestors() and descendants()
Prepares for adding depth parameter.
2017-06-18 12:06:22 +09:00
Yuya Nishihara
d1abf1770e revsetlang: check arguments passed to ancestors() before optimizing to only()
Future patches will add depth parameter to ancestors(), which isn't compatible
with only().
2017-06-18 11:57:28 +09:00
Yuya Nishihara
9be9c72a7a revset: fix negative ancestor spec to not return changectx objects
The order was unstable because of this.
2017-06-18 12:25:23 +09:00
Yuya Nishihara
5db97a9276 smartset: micro optimize spanset.slice() to narrow range accordingly
-1ms isn't significant, but seems not bad.

  revset #0: limit(0:9999, 100, 9000)
  6) 0.001145
  7) 0.000214
  revset #3: last(0:9999, 100)
  6) 0.000197
  7) 0.000171
2015-04-10 00:14:16 +09:00
Yuya Nishihara
bd5f2e1677 smartset: micro optimize baseset.slice() to use slice of list
-1ms isn't significant, but seems not bad.

  revset #1: limit(0::9999, 100, 9000)
  5) 0.001681
  6) 0.000790
2015-04-09 23:56:06 +09:00
Yuya Nishihara
8dc3831c0a smartset: extract method to slice abstractsmartset
Sub classes can provide optimized implementations.
2015-03-24 00:14:53 +09:00
Yuya Nishihara
00575a85de smartset: change repr of spanset to show revisions as half-open range
Before, an empty spanset was displayed as '<spanset+ 0:-1>', which seemed
confusing.
2017-06-11 00:21:38 +09:00
Yuya Nishihara
2fb700c277 revset: fix order of first/last members in compound expression (BC)
Suppose len(subset) >> len(ls) in common cases, 'subset & ls' should be
avoided whenever possible.
2017-06-10 19:48:48 +09:00
Yuya Nishihara
afe324b8ba revset: filter first/last members by __and__ operation
This replaces 'if y in subset' with '& subset'. first(null) and last(wdir())
are fixed thanks to fullreposet.__and__.

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

No performance regression observed:

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

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

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

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

This patch also fixes id() revset and shortest() template since _partialmatch()
can raise WdirUnsupported exception.
2016-08-19 18:26:04 +09:00
Yuya Nishihara
09869bc4c0 revset: add support for branch(wdir()) and wdir() & branch() 2016-08-20 18:15:19 +09:00
Yuya Nishihara
00d9212898 revset: add support for integer and hex wdir identifiers
As I said before, partial 'ff...' hash isn't supported yet.
2017-06-03 20:39:33 +09:00
Boris Feld
f7e21a1d7c util: raise ParseError when parsing dates (BC)
d46a7814be5f refactored util.parsedate in order to raise ValueError instead
of Abort for using with ui.configwith. It causes several problems, putting
arbitrary bytes in ValueError can cause issues with Python 3. Moreover, we
added a function to convert ValueError exceptions back to Abort.

A better approach would be to make parsedate raises ParseError, removing
the convert function and update configwith to also catch ParseError.

The side-effect is that error message when giving an invalid date in CLI
change from:

  abort: invalid date: 'foo bar'

to:

  hg: parse error: invalid date: 'foo bar'

I'm not sure if it's an acceptable change, I found personally the error
message more clear but more verbose too.
2017-05-24 17:50:17 +02:00
Pulkit Goyal
b9822a4f60 revset: add support for ancestors(wdir())
This is a part of extending support for wdir() predicate.
2017-05-23 01:22:33 +05:30
Pulkit Goyal
a1d8e291f1 revset: add support for using ~ operator on wdir() predicate
We catch the WdirUnsupported exception and handles the wdir() case here.
2017-05-23 01:08:19 +05:30
Pulkit Goyal
585fe1fa03 revset: add support for p2(wdir()) to get second parent of working directory
This adds support for finding the second parent of working directory using the
p2 predicate.
2017-05-22 02:14:22 +05:30
Pulkit Goyal
5a41587537 tests: add tests for predicates and operators which works with wdir()
This one is cluttering up the test file though.
2017-05-22 01:35:53 +05:30
Pulkit Goyal
8ed8bc3674 revset: add support for "wdir()^n"
This patch catches the WdirUnsupported exception raised, and adds support for
wdir^n which will give us the nth parent of the working directory.
2017-05-22 01:01:45 +05:30
Pulkit Goyal
6b98477968 revset: make hg log -r 'wdir()^' work (issue4905)
This patch catches the WdirUnsupported exception to support wdir()^.
2017-05-19 20:06:45 +05:30
Yuya Nishihara
3e663dde68 registrar: move cmdutil.command to registrar module (API)
cmdutil.command wasn't a member of the registrar framework only for a
historical reason. Let's make that happen. This patch keeps cmdutil.command
as an alias for extension compatibility.
2016-01-09 23:07:20 +09:00
Yuya Nishihara
2b723f40bc parser: verify excessive number of args excluding kwargs in buildargsdict()
This makes the next patch slightly simpler. We don't need to check the
excessive number of keyword arguments since unknown and duplicated kwargs
are rejected.
2017-04-08 20:07:37 +09:00
Yuya Nishihara
d4c8257977 revsetlang: enable optimization of 'x + y' expression
It's been disabled since fa623f8a8cdd, but it can be enabled now as the
ordering requirement is resolved at analyze().
2016-05-14 20:51:57 +09:00
Yuya Nishihara
b2229f5117 revset: split language services to revsetlang module (API)
New revsetlang module hosts parser, tokenizer, and miscellaneous functions
working on parsed tree. It does not include functions for evaluation such as
getset() and match().

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

get*() functions are aliased since they are common in revset.py.
2017-02-19 18:19:33 +09:00
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