Commit Graph

925 Commits

Author SHA1 Message Date
Mark Thomas
43c0f83739 revset: fix gendoc for ancestorsaged
Summary:
The ancestorsaged revset documentation is invalid as it attempts to use a
literal block, which can't be used in doc comments.  Change it to use a bullet
list for now.

Reviewed By: singhsrb

Differential Revision: D10255821

fbshipit-source-id: 6f75b5ba22899d938cdf585fc87082372468e352
2018-10-09 06:59:27 -07:00
Mark Thomas
f353521eb9 revset: move age extension to core
Summary:
The age extension provides a couple of revsets relating to commit ages.  Move
these to core.

Differential Revision: D10239000

fbshipit-source-id: 6ebf3aa263b72e4bbbe25bd516f77b17145e6e7f
2018-10-08 12:01:44 -07:00
Mark Thomas
171b310857 fbamend: move predecessor/successor revsets to core
Summary:
Move the `predecessors` and `successors` revsets to core, and unify the
variants as a single revset.

Before:
* `predecessors` (provided by fbamend) only returned the immediate
  predecessors.
* `successors` (provided by core) returned the given commit and all eventual
  successors.
* `allpredecessors` and `allsuccessors` (provided by fbamend) returned all
  eventual predecessors and successors, not including the original commit.

Now all these revsets work like the old core `successors`, and additionally
have `depth` and `startdepth` parameters which can be used to customize the
behaviour.  This makes them analogous to `ancestors` and `descendants`.

To maintain compatibility with existing users of `allpredecessors` and
`allsuccessors`, these revsets default to a start depth of 1, so they
do not include the original commits.

Reviewed By: quark-zju

Differential Revision: D10028043

fbshipit-source-id: e006700ccf430b7c5d6bd9588253872bce9a18ed
2018-10-03 13:32:56 -07:00
Mark Thomas
d24d46e393 revset: increase weights of predicates that use filter
Summary:
Revset predicates that work substantially through `subset.filter` should have a
higher weight than the default value of 1, to prevent the optimizer incorrectly
optimizing operations like:
```
  reverse(ancestors(node, limit)) & filterpredicate()
```
in a way that filters all the revisions in the repo according the predicate
before performing the dag search.

Reviewed By: ikostia

Differential Revision: D8588027

fbshipit-source-id: 57be642761af013be8c8aa27ec126b3919c34256
2018-06-22 07:40:08 -07:00
Mark Thomas
363a42a8fa revset: increase weight of public revsetpredicate
Summary:
The `public()` revsetpredicate has the default weight of 1, which means
expressions like `::x & public()` are optimized to `('andsmally', ::x, public())`,
which will actually result in iterating over all commits in the repo.

Increase the weight to 3 to ensure it's optimized in a way that favours
following ancestry links and then checking the phase.

Reviewed By: ikostia

Differential Revision: D8549645

fbshipit-source-id: f58750ecb1918079b7e350ce27b7a61771489233
2018-06-22 04:34:18 -07:00
Jun Wu
584656dff3 codemod: join the auto-formatter party
Summary:
Turned on the auto formatter. Ran `arc lint --apply-patches --take BLACK **/*.py`.
Then run `arc lint` again so some other autofixers like spellchecker etc. looked
at the code base. Manually accept the changes whenever they make sense, or use
a workaround (ex. changing "dict()" to "dict constructor") where autofix is false
positive. Disabled linters on files that are hard (i18n/polib.py) to fix, or less
interesting to fix (hgsubversion tests), or cannot be fixed without breaking
OSS build (FBPYTHON4).

Conflicted linters (test-check-module-imports.t, part of test-check-code.t,
test-check-pyflakes.t) are removed or disabled.

Duplicated linters (test-check-pyflakes.t, test-check-pylint.t) are removed.

An issue of the auto-formatter is lines are no longer guarnateed to be <= 80
chars. But that seems less important comparing with the benefit auto-formatter
provides.

As we're here, also remove test-check-py3-compat.t, as it is currently broken
if `PYTHON3=/bin/python3` is set.

Reviewed By: wez, phillco, simpkins, pkaush, singhsrb

Differential Revision: D8173629

fbshipit-source-id: 90e248ae0c5e6eaadbe25520a6ee42d32005621b
2018-05-25 22:17:29 -07:00
Jun Wu
2946a1c198 codemod: use single blank line
Summary: This makes test-check-code cleaner.

Reviewed By: ryanmce

Differential Revision: D6937934

fbshipit-source-id: 8f92bc32f75b9792ac67db77bb3a8756b37fa941
2018-04-13 21:51:08 -07:00
Hollis Blanchard
7a617027ed outgoing: respect ":pushurl" paths (issue5365)
Make 'hg outgoing' respect "paths.default:pushurl" in addition to
"paths.default-push".

'hg outgoing' has always meant "what will happen if I run 'hg push'?" and it's
still documented that way:

    Show changesets not found in the specified destination repository or the
    default push location. These are the changesets that would be pushed if a
    push was requested.

If the user uses the now-deprecated "paths.default-push" path, it continues to
work that way. However, as described at
https://bz.mercurial-scm.org/show_bug.cgi?id=5365, it doesn't behave the same
with "paths.default:pushurl".

Why does it matter? Similar to the bugzilla reporter, I have a read-only mirror
of a non-Mercurial repository:

  upstream -> imported mirror -> user clone
         ^-----------------------/

Users push directly to upstream, and that content is then imported into the
mirror. However, those repositories are not the same; it's possible that the
mirroring has either broken completely, or an import process is running and not
yet complete. In those cases, 'hg outgoing' will list changesets that have
already been pushed.

Mozilla's desired behavior described in bug 5365 can be accomplished through
other means (e.g. 'hg outgoing default'), preserving the consistency and
meaning of 'hg outgoing'.
2017-12-14 15:03:55 -08:00
Pulkit Goyal
77c5fc90a9 py3: handle keyword arguments correctly in revset.py
Differential Revision: https://phab.mercurial-scm.org/D1640
2017-12-10 04:48:12 +05:30
Jun Wu
4ca48aa8cc revset: use phasecache.getrevset to calculate public()
Other revsets like secret(), draft(), _nonpublic() are using
phasescache.getrevset already. The latter is more efficient after D1606.
So let's migrate the public() revset function too.

Tested using:

  $ hg debugshell --hidden --cwd hg-committed`
  In [1]: %timeit len(repo.revs('public()'))

* Before D1606: 10 loops, best of 3: 22.5 ms per loop
* Before this change, after D1606: 10 loops, best of 3: 28.6 ms per loop
* After this change: 10 loops, best of 3: 20.2 ms per loop

Therefore `public()` revset becomes even slightly faster after the data
structure change by D1606. A similar performance win could also be observed
on a large repo.

A side effect is `phasecache.getrevset` needs to take a `subset` parameter.
That was added with a default value so it won't cause BC issues.

Differential Revision: https://phab.mercurial-scm.org/D1620
2017-12-08 14:20:34 -08:00
Yuya Nishihara
5db2725c37 revset: make follow() accept empty startrev
This is the same behavior as ancestors(emptyset).
2016-09-22 19:41:42 +09:00
Yuya Nishihara
85d4b98f53 revset: alias follow(startrev=rev) to ancestors(rev)
This seems natural given 'log -frREV' (with no file pattern) is equivalent
to 'log -frREV *'.
2016-09-22 19:40:07 +09:00
Yuya Nishihara
08c3b37347 revset: make follow() accept keyword arguments
Also renamed the argument from 'pattern' to 'file' conforming to
followlines().
2016-09-22 19:35:36 +09:00
Yuya Nishihara
3142b0e7d7 revset: make follow() accept multiple startrevs
The diff might look slightly complicated, but the initial "c = repo['.']" was
effective if rev = None.
2016-09-22 19:11:26 +09:00
Yuya Nishihara
e49a4312a9 dagop: add smartset interface to filectxancestors()
The original filectx API is kept public since we'll need it to walk ancestor
(rev, match) pairs efficiently. The current implementation scans ancestors
twice for 'hg log -fp FILE'.
2017-10-22 18:57:42 +09:00
Yuya Nishihara
4c0e4dc497 dagop: extend filectxancestors() to walk multiple files 2016-09-22 18:23:58 +09:00
Yuya Nishihara
70940bffa0 dagop: yield intro filectx by filectxancestors()
This is the convention of dagop.*ancestors() functions.
2016-09-22 17:48:46 +09:00
Yuya Nishihara
f55866843d dagop: copy basefilectx.ancestors() to free function
The primary goal of this series is to make follow() support multiple start
revisions.

dagop.filectxancestors() will be extended to take multiple filectxs.
basefilectx.ancestors() is not forwarded to this function because doing that
would resurrect the performance issue fixed by a5b8b1052ef6.
2016-09-22 17:16:53 +09:00
Denis Laxalde
5c56737c70 revset: extract a parsefollowlinespattern helper function
We'll need the same logic in forthcoming changeset to handle --line-range
option in 'hg log' command.
The function lives in scmutil.py (rather than util.py) as it uses match and
pathutil modules.
2017-10-04 15:27:43 +02:00
Yuya Nishihara
235c46722f revset: add experimental support for extdata
This is minimal and non-controversial implementation of extdata() revset.
Originally extdata sources were exposed to the symbol namespace, but I've
changed it to a plain function for simplicity.
2017-10-01 10:50:00 +01:00
Jun Wu
a29ad18d8b revset: move weight information to predicate
Previously revset weight is hardcoded and cannot be modified. This patch
moves it to predicate so newly registered revsets could define their weight
to properly give static optimization some hint.

Differential Revision: https://phab.mercurial-scm.org/D657
2017-09-01 19:42:09 -07:00
Jun Wu
eaaeecf0d5 revset: optimize "draft() & ::x" pattern
The `draft() & ::x` type query could be common for selecting one or more
draft feature branches being worked on.

Before this patch, `::x` may travel through the changelog DAG for a long
distance until it gets a smaller revision number than `min(draft())`. It
could be very slow on long changelog with distant (in terms of revision
numbers) drafts.

This patch adds a fast path for this situation, and will stop traveling the
changelog DAG once `::x` hits a non-draft revision.

The fast path also works for `secret()` and `not public()`.

To measure the performance difference, I used drawdag to create a repo that
emulates distant drafts:

          DRAFT4
           |
          DRAFT3 # draft
          /
  PUBLIC9999 # public
      |
  PUBLIC9998
      |
      .   DRAFT2
      .    |
      .   DRAFT1 # draft
      |   /
  PUBLIC0001 # public

And measured the performance using the repo:

  (BEFORE)
  $ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
  ! wall 0.017132 comb 0.010000 user 0.010000 sys 0.000000 (best of 156)
  $ hg perfrevset 'draft() & ::(all())'
  ! wall 0.024221 comb 0.030000 user 0.030000 sys 0.000000 (best of 113)
  (AFTER)
  $ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
  ! wall 0.000243 comb 0.000000 user 0.000000 sys 0.000000 (best of 9303)
  $ hg perfrevset 'draft() & ::(all())'
  ! wall 0.004319 comb 0.000000 user 0.000000 sys 0.000000 (best of 655)

Differential Revision: https://phab.mercurial-scm.org/D441
2017-08-28 14:49:00 -07:00
Jun Wu
4cd80fdd9c revset: do not flip "and" arguments when optimizing
Rewrite `flipand(y, x)` to `andsmally(x, y)` so the AST order is unchanged,
which could be more friendly to developers.

Differential Revision: https://phab.mercurial-scm.org/D579
2017-08-30 16:05:12 -07:00
Yuya Nishihara
507a4c9e22 revset: make match function follow given subset if specified (API)
This should be sensible default since mfunc(subset) is roughly equivalent
to 'subset & mfunc'. The order argument is still there so we can specify
'anyorder' if the order doesn't really matter.
2017-08-30 22:51:28 +09:00
Yuya Nishihara
abe6c88072 revset: move order argument to run-time match function
We no longer need the order flag to build a parsed tree.
2017-08-30 22:41:36 +09:00
Yuya Nishihara
389688d31e revset: fix example describing how ordering is determined
It was 'X & !Y' before.
2017-08-30 23:53:30 +09:00
Yuya Nishihara
3de7eef1fb revset: move order constants from revsetlang
Thanks to the recent refactor, the ordering rule is fully processed at
runtime.
2017-08-30 22:32:47 +09:00
Jun Wu
647a38e249 revset: remove order information from tree (API)
Keeping `order` in tree makes AST operation harder. And there could be
invalid cases if trees could be generated and compounded freely, like:

  SetA(order=define) & SetB(order=define)
                                  ^^^^^^ couldn't be satisfied

This patch changes the code to calculate order on the fly, during tree
traversal. Optimization of reordering `and` arguments is preserved by
introducing a new internal operation `flipand`.

.. api::

   revset.stringset() now takes 'order' as the last argument.

Differential Revision: https://phab.mercurial-scm.org/D451
2017-08-20 10:55:11 -07:00
Boris Feld
7524f9d434 revset: mark evolution-related revsets as experimental
Differential Revision: https://phab.mercurial-scm.org/D416
2017-08-16 16:48:41 +02:00
Boris Feld
971a5a6f59 obsolete: rename bumped volatile set into phasedivergent volatile set
The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D255
2017-08-04 19:39:34 +02:00
Boris Feld
ac541e6eb8 obsolete: rename divergent volatile set into contentdivergent volatile set
The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D254
2017-08-04 19:36:27 +02:00
Boris Feld
98e598e611 obsolete: rename unstable volatile set into orphan volatile set
The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D253
2017-08-04 19:27:39 +02:00
Boris Feld
5489bbeda4 revset: rename bumped into phasedivergent
Don't touch bumped volatile set name, only the revset name. The volatile set
name will be updated in a later patch.

The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D252
2017-08-03 14:08:39 +02:00
Boris Feld
cf0c39bfeb revset: remane divergent into contentdivergent
Don't touch divergent volatile set name, only the revset name. The volatile
set name will be updated in a later patch.

The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D251
2017-08-03 14:01:51 +02:00
Boris Feld
aaaa0c98dc revset: rename unstable into orphan
Don't touch unstable volatile set name, only the revset name. The volatile set
name will be updated in a later patch.

The renaming is done according to
https://www.mercurial-scm.org/wiki/CEDVocabulary.

Differential Revision: https://phab.mercurial-scm.org/D250
2017-08-03 13:48:39 +02:00
Yuya Nishihara
9955f11c5c revset: add experimental ancestors/descendants relation subscript
The relation name is 'generations' now, which may be changed in future.
2017-07-08 13:15:17 +09:00
Yuya Nishihara
ad66ada8bf revset: add experimental relation and subscript operators
The proposed syntax [1] was originally 'set{n rel}', but it seemed slightly
confusing if template is involved. On the other hand, we want to keep 'set[n]'
for future extension. So this patch introduces 'set#rel[n]' ternary operator.
I chose '#' just because it looks like applying an attribute.

This also adds stubs for 'set[n]' and 'set#rel' operators since these syntax
elements are fundamental for constructing 'set#rel[n]'.

 [1]: https://www.mercurial-scm.org/wiki/RevsetOperatorPlan#ideas_from_mpm
2017-07-08 13:07:59 +09:00
Jun Wu
573f8d2389 revset: define successors revset
This revset returns all successors, including transit nodes and the source
nodes (to be consistent with existing revsets like "ancestors").

To filter out transit nodes, use `successors(X)-obsolete()`.
To filter out divergent case, use `successors(X)-divergent()-obsolete()`.

The revset could be useful to define rebase destination, like:
`max(successors(BASE)-divergent()-obsolete())`. The `max` is to deal with
splits.

There are other implementations where `successors` returns just one level of
successors, and `allsuccessors` returns everything. I think `successors`
returning all successors by default is more user friendly. We have seen
cases in production where people use 1-level `successors` while they really
want `allsuccessors`. So it seems better to just have one single revset
returning all successors by default to avoid user errors.

In the future we might want to add `depth` keyword argument to it and for
other revsets like `ancestors` etc. Or even build some flexible indexing
syntax [1] to satisfy people having the depth limit requirement.

[1]: https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-July/101140.html
2017-07-10 10:56:40 -07:00
Jun Wu
f50841989e revset: make repo.anyrevs accept customized alias override (API)
Previously repo.anyrevs only expand aliases in [revsetalias] config. This
patch makes it more flexible to accept a customized dict defining aliases
without having to couple with ui.

revsetlang.expandaliases now has the signature (tree, aliases, warn=None)
which is more consistent with templater.expandaliases. revsetlang.py is now
free from "ui", which seems to be a good thing.
2017-06-24 15:29:42 -07:00
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
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
d2a35c3c21 help: clarify ancestors() and descendants() include given set (issue5594)
Also unified "a changeset" to "changesets".
2017-06-18 22:46:56 +09:00
Yuya Nishihara
e75a42ecc9 dagop: move blockancestors() and blockdescendants() from context
context.py seems not a good place to host these functions.

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

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

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

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

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

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