Commit Graph

272 Commits

Author SHA1 Message Date
FUJIWARA Katsunori
43338be810 revset: narrow scope of the variable referred only in specific code path
This patch narrows scope of the variable "m" in the function for
revset predicate "contains()", because it is referred only in "else"
code path of "if not matchmod.patkind(pat)" examination.
2014-01-17 23:42:12 +09:00
Yuya Nishihara
cb7a1dd14c fileset, revset: do not use global parser object for thread safety
parse() cannot be called at the same time because a parser object keeps its
states.  This is no problem for command-line hg client, but it would cause
strange errors in multi-threaded hgweb.

Creating parser object is not too expensive.

original:
% python -m timeit -s 'from mercurial import revset' 'revset.parse("0::tip")'
100000 loops, best of 3: 11.3 usec per loop

thread-safe:
% python -m timeit -s 'from mercurial import revset' 'revset.parse("0::tip")'
100000 loops, best of 3: 13.1 usec per loop
2013-12-21 12:44:19 +09:00
Alexander Plavin
d519eef8ec revset: add a whitelist of DoS-safe symbols
'Safe' here means that they can't be used for a DoS attack for any given input.
2013-09-06 13:30:56 +04:00
Alexander Plavin
75dc3d55d6 revset: add helper function to get functions used in a revset parse tree
Will be used to determine whether all functions used in a hgweb search query
are allowed there.
2013-08-07 01:21:31 +04:00
Alexander Plavin
573b3e69b6 revset: add helper function to get revset parse tree depth
Will be used to determine if a hgweb search query actually uses
any revset syntax.
2013-08-09 22:52:58 +04:00
Alexander Plavin
fd04e86dd0 revset: fix wrong keyword() behaviour for strings with spaces
Some changesets can be wrongly reported as matched by this predicate
due to searching in a string joined with spaces and not individually.
A test case added, which fails without this fix.
2013-08-06 00:52:06 +04:00
Alexander Plavin
829cf92d16 log: fix behavior with empty repositories (issue3497)
Make output in this special case consistent with general case one.
2013-04-17 00:29:54 +04:00
Kevin Bullock
8d329cb6b6 revset: don't abort when regex to tag() matches nothing (issue3850)
This makes the tag("re:...") revset consistent with branch("re:...").
2013-03-18 16:04:10 -05:00
Paul Cavallaro
4a3134830c revset: change ancestor to accept 0 or more arguments (issue3750)
Change ancestor to accept 0 or more arguments. The greatest common ancestor of a
single changeset is that changeset. If passed no arguments, the empty list is
returned.
2013-01-28 12:19:21 -08:00
Kevin Bullock
921b868783 bookmarks: don't use bookmarks.listbookmarks in local computations
bookmarks.listbookmarks is for wire-protocol use. The normal way to get
all the bookmarks on a local repository is repo._bookmarks.
2013-01-27 14:24:37 -06:00
FUJIWARA Katsunori
1fc2644404 revset: evaluate sub expressions correctly (issue3775)
Before this patch, sub expression may return unexpected result, if it
is joined with another expression by "or":

  - "^"/parentspec():
    "R or R^1" is not equal to "R^1 or R". the former returns only "R".

  - "~"/ancestorspec():
    "R or R~1" is not equal to "R~1 or R". the former returns only "R".

  - ":"/rangeset():
    "10 or (10 or 15):" is not equal to "(10 or 15): or 10". the
    former returns only 10 and 15 or grater (11 to 14 are not
    included).

In "or"-ed expression "A or B", the "subset" passed to evaluation of
"B" doesn't contain revisions gotten from evaluation of "A", for
efficiency.

In the other hand, "stringset()" fails to look corresponding revision
for specified string/symbol up, if "subset" doesn't contain that
revision.

So, predicates looking revisions up indirectly should evaluate sub
expressions of themselves not with passed "subset" but with "entire
revisions in the repository", to prevent "stringset()" from unexpected
failing to look symbols in them up.

But predicates in above example don't so. For example, in the case of
"R or R^1":

  1. "R^1" is evaluated with "subset" containing revisions other than
     "R", because "R" is already gotten by the former of "or"-ed
     expressions

  2. "parentspec()" evaluates "R" of "R^1" with such "subset"

  3. "stringset()" fails to look "R" up, because "R" is not contained
     in "subset"

  4. so, evaluation of "R^1" returns no revision

This patch evaluates sub expressions for predicates above with "entire
revisions in the repository".
2013-01-23 22:52:55 +09:00
Mads Kiilerich
7bc546e4e0 bundlerepo: improve performance for bundle() revset expression
Create the set of revision numbers directly instead of creating a list of nodes
first.
2013-01-16 20:41:34 +01:00
Kevin Bullock
93f9cb7f25 filtering: rename filters to their antonyms
Now that changelog filtering is in place, it's become evident that
naming the filters according to the set of revs _not_ included in the
filtered changelog is confusing. This is especially evident in the
collaborative branch cache scheme.

This changes the names of the filters to reflect the revs that _are_
included:

  hidden -> visible
  unserved -> served
  mutable -> immutable
  impactable -> base

repoview.filteredrevs is renamed to filterrevs, so that callers read a
bit more sensibly, e.g.:

  filterrevs('visible') # filter revs according to what's visible
2013-01-13 01:39:16 -06:00
Pierre-Yves David
10fc5e09ff revset: retrieve hidden from filteredrevs
This prepare the dropping of the `repo.hiddenrevs` property
2013-01-03 18:48:14 +01:00
Pierre-Yves David
f3faf259c5 obsolete: add revset and test for divergent changesets
This changesets add a new `divergent()` revset similar to `unstable()` and
`bumped()` one. Introducting this revset allows actuall test of the divergent
detection.
2012-12-12 03:12:55 +01:00
Siddharth Agarwal
86e87e5ede revset.children: ignore rev numbers that are too low
This replaces unnecessary parentrevs() calls with calculating min(parentset).
Even though the min operation is O(size of parentset), since parentrevs is
relatively expensive, this tradeoff almost always works in our favour. In a
repository with over 400,000 changesets, hg perfrevset "children(X)" takes:

       Set X       Before    After
       -1           0.51s    0.06s
    -1000:          0.55s    0.08s
   -10000:          0.56s    0.10s
  -100000:          0.60s    0.25s
  -100000:-99000    0.55s    0.19s
        0:100000    0.60s    0.61s
      all()         0.72s    0.74s

The relative performance is similar for Mercurial's own repository -- several
times faster in most cases, slightly slower for revisions close to 0 and
all().
2012-12-07 10:37:43 -08:00
Matt Mackall
cf4605492a merge with stable 2012-11-28 16:15:05 -06:00
Matt Mackall
d4deebc4f7 revset: backed out changeset 7a8dc9a35aa2
This was causing clones of the hg repo to go from 12.4s to 14.7s.
2012-11-26 13:44:11 -06:00
Durham Goode
6a6b8c49d1 commit: increase perf by avoiding checks against entire repo subsets
When commiting to a repo with lots of history (>400000 changesets)
checking the results of revset.py:descendants against the subset takes
some time.  Since the subset equals the entire changelog, the check
isn't necessary.  Avoiding it in that case saves 0.1 seconds off of
a 1.78 second commit. A 6% gain.

We use the length of the subset to determine if it is the entire repo.
There is precedence for this in revset.py:stringset.
2012-11-16 15:39:12 -08:00
Matt Mackall
e56ab4a814 revset: accept @ in unquoted symbols (issue3686) 2012-10-30 18:48:44 -05:00
Bryan O'Sullivan
e9f10aaaf1 Merge with crew-stable 2012-11-20 10:09:06 -08:00
Tomasz Kleczek
fab490ae63 bundle: add revset expression to show bundle contents (issue3487)
bundle() revset expression returns all changes that are present
in the bundle file (no matter whether they are in the repo or not).

Bundle file should be specified via -R option.
2012-10-31 16:23:23 -07:00
Pierre-Yves David
6f4d6c0cd4 revset: add a bumped revset
Select bumped changesets.
2012-10-19 00:39:06 +02:00
Pierre-Yves David
bc08c6dbf1 obsolete: rename getobscache into getrevs
The old name was not very good for two reasons:
- caller does not care about "cache",
- set of revision returned may not be obsolete at all.

The new name was suggested by Kevin Bullock.
2012-10-19 00:28:13 +02:00
Pierre-Yves David
99b5dd9737 clfilter: remove use of xrange in revset
For changelog level filtering to take effect it need to be used for any
iteration. Some remaining use of `xrange` in revset code is replace by proper
use of `changelog.revs` or direct iteration over changelog.
2012-10-08 15:54:53 +02:00
Pierre-Yves David
abf7ca7986 branchpoint: remove useless intermediate set creation
We don't need to compute the set of all branchpoints. We can just check the
number of children that element of subset have. The extra work did not seems to
had particular performance impact but the code is simpler this way.
2012-10-15 17:43:05 +02:00
Pierre-Yves David
dcd3550206 clfilter: use changelog to iterate over the repo in branchpoint
Otherwise filtered changesets may cause false positives in `branchpoint()`.
2012-10-15 17:42:40 +02:00
Ivan Andrus
3a1f5d9617 revsets: add branchpoint() function
The branchpoint() function returns changesets with more than one child.
Eventually I would like to be able to see only branch points and merge
points in a graphical log to see the topology of the repository.
2012-08-13 21:50:45 +02:00
Pierre-Yves David
df82aab75f clfilter: remove usage of range in favor of iteration over changelog
If we want to apply filtering at changelog level, we need to iterate over it.
See previous changeset description for details.
2012-09-20 19:01:53 +02:00
Pierre-Yves David
785d90eba0 obsolete: introduce caches for all meaningful sets
This changeset introduces caches on the `obsstore` that keeps track of sets of
revisions meaningful for obsolescence related logics. For now they are:

- obsolete: changesets used as precursors (and not public),
- extinct:  obsolete changesets with osbolete descendants only,
- unstable: non obsolete changesets with obsolete ancestors.

The cache is accessed using the `getobscache(repo, '<set-name>')` function which
builds the cache on demand. The `clearobscaches(repo)` function takes care of
clearing the caches if any.

Caches are cleared when one of these events happens:

- a new marker is added,
- a new changeset is added,
- some changesets are made public,
- some public changesets are demoted to draft or secret.

Declaration of more sets is made easy because we will have to handle at least
two other "troubles" (latecomer and conflicting).

Caches are now used by revset and changectx. It is usually not much more
expensive to compute the whole set than to check the property of a few elements.
The performance boost is welcome in case we apply obsolescence logic on a lot of
revisions. This makes the feature usable!
2012-08-28 20:52:04 +02:00
Mads Kiilerich
2f4504e446 fix trivial spelling errors 2012-08-15 22:38:42 +02:00
Patrick Mezard
7acf48f9a1 revset: add hidden() revset 2012-08-04 20:20:48 +02:00
Patrick Mezard
b5860803d6 revset: minor doc fixes on obsolete related revsets 2012-07-30 15:48:04 +02:00
FUJIWARA Katsunori
b4636b9d05 revset: fix the definition of "unstable changesets" for "unstable" predicate
unstable-ness of changesets should be determined by obsolete-ness of
not descendants but ancestors.
2012-07-28 23:51:57 +09:00
Greg Ward
9468b4b81c revset: polish explanation of the difference between file() and filelog() 2012-07-25 22:41:26 -04:00
FUJIWARA Katsunori
5f3de0edc0 i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py 2012-07-26 13:58:43 +09:00
FUJIWARA Katsunori
26c5c2b610 revset: use appropriate predicate name in error messages
"extinct" and "unstable" predicates use "obsolete" implementation
internally, but own predicate name should be used in error messages of
them instead of "obsolete".
2012-07-26 13:58:43 +09:00
FUJIWARA Katsunori
cc080612f7 revset: add explanation about difference between 'filelog()' and 'file()' 2012-07-25 16:15:28 +09:00
Matt Harbison
223186cb48 revset: add destination() predicate
This predicate is used to find csets that were created because of a graft,
transplant or rebase --keep.  An optional revset can be supplied, in which case
the result will be limited to those copies which specified one of the revs as
the source for the command.

    hg log -r destination()                 # csets copied from anywhere
    hg log -r destination(branch(default))  # all csets copied from default

    hg log -r origin(x) or destination(origin(x))  # all instances of x

This predicate will follow a cset through different types of copies.  Given a
repo with a cset 'S' that is grafted to create G(S), which itself is
transplanted to become T(G(S)):

    o-S
   /
  o-o-G(S)
   \
    o-T(G(S))

    hg log -r destination( S )    # { G(S), T(G(S)) }
    hg log -r destination( G(S) ) # { T(G(S)) }

The implementation differences between the three different copy commands (see
the origin() predicate) are not intentionally exposed, however if the
transplant was a graft instead:

	hg log -r destination( G(S) )   # {}

because the 'extra' field in G(G(S)) is S, not G(S).  The implementation cannot
correct this by following sources before G(S) and then select the csets that
reference those sources because the cset provided to the predicate would also
end up selected.  If there were more than two copies, sources of the argument
would also get selected.

Note that the convert extension does not currently update the 'extra' map in its
destination csets, and therefore copies made prior to the convert will be
missing from the resulting set.

Instead of the loop over 'subset', the following almost works, but does not
select a transplant of a transplant.  That is, 'destination(S)' will only
select T(S).

    dests = set([r for r in subset if _getrevsource(repo, r) in args])
2012-07-07 00:47:55 -04:00
Matt Harbison
f78efc8aa9 revset: add origin() predicate
This predicate is used to find the original source of csets created by a graft,
transplant or rebase --keep.  If a copied cset is itself copied, only the
source of the original copy is selected.

    hg log -r origin()                # all src csets, anywhere
    hg log -r origin(branch(default)) # all srcs of copies on default

By following through different types of copy commands and only selecting the
original cset, the implementation differences between the copy commands are
hidden.  (A graft of a graft preserves the original source in its 'extra' map,
while transplant and rebase use the immediate source specified for the
command).

Given a repo with a cset S that is grafted to create G(S), which itself is
grafted to become G(G(S))

    o-S
   /
  o-o-G(S)
   \
    o-G(G(S))

    hg log -r origin( G(S) )      # { S }
    hg log -r origin( G(G(S)) )   # { S }, NOT { G(S) }

Even if the last graft were a transplant

    hg log -r origin( T(G(S)) )   # { S }

A rebase without --keep essentially strips the source, so providing the cset
that results to this predicate will yield an empty set.

Note that the convert extension does not currently update the 'extra' map in
its destination csets, and therefore copies made prior to the convert will be
unable to find their source.
2012-07-07 00:47:30 -04:00
Pierre-Yves David
9e13d2931c obsolete: compute extinct changesets
`extinct` changesets are obsolete changesets with obsolete descendants only. They
are of no interest anymore and can be:

- exclude from exchange
- hidden to the user in most situation
- safely garbage collected

This changeset just allows mercurial to detect them.

The implementation is a bit naive, as for unstable changesets. We better use a
simple revset query and a cache, but simple version comes first.
2012-07-06 19:34:09 +02:00
Pierre-Yves David
2444c95546 obsolete: compute unstable changeset
An unstable changeset is a changeset *not* obsolete but with some obsolete
ancestors.

The current logic to decide if a changeset is unstable is naive and very
inefficient. A better solution is to compute the set of unstable changeset with
a simple revset and to cache the result. But this require cache invalidation
logic. Simpler version goes first.
2012-07-06 00:18:09 +02:00
Pierre-Yves David
940b30d287 revset: add an obsolete symbol
This predicate matches obsolete changesets.

This is a naive implementation to be improved later.
2012-07-06 19:29:10 +02:00
Angel Ezquerra
c386f40e4b revset: add "diff" field to "matching" keyword
The new "diff" field lets you use the matching revset keyword to find revisions
that apply the same change as the selected revisions.

The match must be exact (i.e. same additions, same deletions, same modified
lines and same change context, same file renames and copies).

Two revisions matching their diff must also match their files. Thus, to match
the diff much faster we will always check that the 'files' match first, and only
then check that the 'diff' matches as well.
2012-06-13 23:32:58 +02:00
Bryan O'Sullivan
513bd920fa revset: ensure we are reversing a list (issue3530) 2012-07-04 09:38:07 -07:00
Matt Harbison
524542016e revset: add a utility for obtaining the source of a given rev
graft, transplant and rebase all embed a different type of source marker in
extra, and each with a different name.  The current implementation of each is
such that there will never be more than one of these markers on a node.

Note that the rebase marker can only be resolved if the source is
still present, which excludes the typical rebase usage (without
--keep) from consideration (unless the resulting bundle in
strip-backup is overlayed). There probably isn't any reason to use
rebase --keep as a substitute for transplant or graft at this point,
but maybe there was at one point and there are even a few rebases in
the hg repo, so it may be of historical interest.
2012-06-05 20:35:34 -04:00
Matt Harbison
5c29c87aee revset: add a predicate for finding converted changesets
This selects changesets added because of repo conversions.  For example

    hg log -r "converted()"      # all csets created by a convertion
    hg log -r "converted(rev)"   # the cset converted from rev in the src repo

The converted(rev) form is analogous to remote(id), where the remote repo is
the source of the conversion.  This can be useful for cross referencing an old
repository into the current one.

The source revision may be the short changeset hash or the full hash from the
source repository.  The local identifier isn't useful.  An interesting
ramification of this is if a short revision is specified, it may cause more
than one changeset to be selected.  (e.g. converted(6) matches changesets with
a convert_revision field of 6e..e and 67..0)

The convert.hg.saverev option must have been specified when converting the hg
source repository for this to work.  The other sources automatically embed the
converted marker.
2012-05-13 01:12:26 -04:00
Bryan O'Sullivan
8585634f4d revset: introduce and use _revsbetween
This is similar in spirit to revlog.nodesbetween, but less ambitious,
much simpler, and ~2x faster.
2012-06-01 15:50:22 -07:00
Bryan O'Sullivan
609ea1623d revset: implement dagrange directly
This is much faster than the older implementation (~8x).
2012-06-01 15:50:22 -07:00
Bryan O'Sullivan
a5d8345282 revset: turn dagrange into a function 2012-06-01 15:50:22 -07:00
Bryan O'Sullivan
4fbcddec79 revset: drop unreachable code 2012-06-01 15:50:22 -07:00
Patrick Mezard
8870ba9d24 revset: cache alias expansions
Caching has no performance effect on the revset aliases which triggered
the recent recursive evaluation bug. I wrote it not to feel bad about
expanding several times the same complicated expression.
2012-05-24 13:05:06 +02:00
Bryan O'Sullivan
abdf4a8227 util: subclass deque for Python 2.4 backwards compatibility
It turns out that Python 2.4's deque type is lacking a remove method.
We can't implement remove in terms of find, because it doesn't have
find either.
2012-06-01 17:05:31 -07:00
Matt Mackall
acd12b376b revset: avoid validating all tag nodes for tag(x)
This generally causes the entire node->rev table to get built when
we're only interested in one node.
2012-06-01 15:13:05 -05:00
Simon King
099a5c925c revset: add pattern matching to 'extra' revset expression 2012-05-30 23:14:04 +01:00
Simon King
93954249b9 revset: add pattern matching to the 'user' revset expression 2012-05-30 23:13:58 +01:00
Simon King
e5e759a651 revset: add pattern matching to 'bookmarks' revset expression 2012-05-30 23:13:33 +01:00
Simon King
85110850a9 revset: add pattern matching to 'branch' revset expression 2012-05-30 23:13:33 +01:00
Simon King
9ecf845d55 revset: add pattern matching to 'tag' revset expression
If the string provided to the 'tag' predicate starts with 're:', the rest
of the string will be treated as a regular expression and matched against
all tags in the repository.

There is a slight backwards-compatibility problem for people who actually
have tags that start with 're:'. As a workaround, these tags can be matched
using a 'literal:' prefix.

If no tags match the pattern, an error is raised. This matches the behaviour
of the previous exact-match code.
2012-05-30 23:13:33 +01:00
Simon King
12ea13934c revset: add helper function for matching strings to patterns 2012-05-30 23:13:33 +01:00
Bryan O'Sullivan
bef5b61512 cleanup: use the deque type where appropriate
There have been quite a few places where we pop elements off the
front of a list.  This can turn O(n) algorithms into something more
like O(n**2).  Python has provided a deque type that can do this
efficiently since at least 2.4.

As an example of the difference a deque can make, it improves
perfancestors performance on a Linux repo from 0.50 seconds to 0.36.
2012-05-15 10:46:23 -07:00
Matt Mackall
8c3c80ff37 merge with stable 2012-05-22 14:37:20 -05:00
Patrick Mezard
139c15da66 revset: fix infinite alias expansion detection
The alias expansion code it changed from:
1- Get replacement tree
2- Substitute arguments in the replacement tree
3- Expand the replacement tree again

into:

1- Get the replacement tree
2- Expand the replacement tree
3- Expand the arguments
4- Substitute the expanded arguments in the replacement tree

and fixes cases like:

  [revsetalias]
  level1($1, $2) = $1 or $2
  level2($1, $2) = level1($2, $1)

  $ hg log -r "level2(level1(1, 2), 3)"

where the original version incorrectly aborted on infinite expansion
error, because it was confusing the expanded aliases with their
arguments.
2012-05-19 17:19:55 +02:00
Patrick Mezard
c7a80dee31 revset: explicitely tag alias arguments for expansion
The current revset alias expansion code works like:
1- Get the replacement tree
2- Substitute the variables in the replacement tree
3- Expand the replacement tree

It makes it easy to substitute alias arguments because the placeholders
are always replaced before the updated replacement tree is expanded
again. Unfortunately, to fix other alias expansion issues, we need to
reorder the sequence and delay the argument substitution. To solve this,
a new "virtual" construct called _aliasarg() is introduced and injected
when parsing the aliases definitions. Only _aliasarg() will be
substituted in the argument expansion phase instead of all regular
matching string. We also check user inputs do not contain unexpected
_aliasarg() instances to avoid argument injections.
2012-05-19 17:18:29 +02:00
FUJIWARA Katsunori
db8047a1c0 doc: add detail explanation for 'present()' predicate of revsets 2012-05-16 17:02:30 +09:00
Matt Harbison
353d5deeb2 revset: fix traceback for bogus revisions in id(rev)
hg log -r "id(1234567)" now returns an empty list like rev() does.
2012-05-14 19:25:13 -04:00
Matt Mackall
e0b2cc783f merge with stable 2012-05-20 14:40:36 -05:00
Matt Mackall
67c0680caa merge with stable 2012-05-17 15:52:14 -05:00
Brodie Rao
ab32f1721d context: add changectx.closesbranch() method
This removes the duplicated code for inspecting the 'close' extra field in
a changeset.
2012-05-13 14:04:06 +02:00
Brodie Rao
d6a6abf2b0 cleanup: eradicate long lines 2012-05-12 15:54:54 +02:00
Henrik Stuart
97ebbbffd1 revset: add function for matching extra data (issue2767) 2012-05-12 10:20:57 +02:00
Patrick Mezard
641ee7d3ba phases: introduce phasecache
The original motivation was changectx.phase() had special logic to
correctly lookup in repo._phaserev, including invalidating it when
necessary. And at other places, repo._phaserev was accessed directly.

This led to the discovery that phases state including _phaseroots,
_phaserev and _dirtyphase was manipulated in localrepository.py,
phases.py, repair.py, etc. phasecache helps encapsulating that.

This patch replaces all phase state in localrepo with phasecache and
adjust related code except for advance/retractboundary() in phases.
These still access to phasecache internals directly. This will be
addressed in a followup.
2012-05-12 00:24:07 +02:00
Bryan O'Sullivan
01cb9841ca bisect: track the current changeset (issue3382)
Introduce a new revset feature, bisect(current), that identifies
the changeset currently being bisected.
2012-05-08 15:29:09 -07:00
Patrick Mezard
1ecfe35e64 revset: make matching() preserve input revision order 2012-05-09 18:45:14 +02:00
Jesse Glick
33aa2b5c45 revset: documentation typo "metatadata" 2012-05-10 14:17:05 -04:00
FUJIWARA Katsunori
9fda466cef doc: flatten description of 'matching()' predicate to be formatted well
current description of 'matching()' revset predicate can't be
formatted well on "hg help revset" output.

each descriptions for revset predicates (or something like them) are
split-ed into lines, and spaces on left side of them are stripped
before minirst processing. so, bullet list can't be nested.

this patch just flattens description of 'matching()' predicate to be
formatted well.
2012-04-26 21:32:48 +09:00
Patrick Mezard
bed77ab945 revset: fix adds/modifies/removes and patterns (issue3403)
The fast path was triggered if the argument was not like "type:value", with
type a known pattern type. This is wrong for several reasons:
- path:value is valid for the fast path
- '*' is interpreted as a glob by default and is not valid for fast path

Fast path detection is now done after the pattern is parsed, and the normalized
path is extracted for direct comparison. All this seems a bit complicated, it
is tempting to drop the fast path completely. Also, the hasfile() revset does
something similar (only check .files()), without a fast path. If the fast path
is really that efficient maybe it should be used there too.

Note that:

  $ log 'modifies("set:modified()")'

is different from:

  $ log 'modifies("*")'

because of the usual merge ctx.files()/status(ctx.p1(), ctx) differences.

Reported by Steffen Eichenberg <steffen.eichenberg@msg-gillardon.de>
2012-04-26 14:24:46 +02:00
Bryan O'Sullivan
6dd793955c revset: fix O(n**2) behaviour of bisect() (issue3381) 2012-04-18 21:27:35 -07:00
Patrick Mezard
c57d92d67c revset: make matching() work on python 2.4
tuple.index() was apparently added to python 2.6:

  http://bugs.python.org/issue1696444

Also remove a trailing comma to make check-code.py happy.
2012-04-17 10:33:47 +02:00
Thomas Arendsen Hein
69b89489ab revset: use list instead of tuple for compatibility with python before 2.6
'string elements'.split() instead of explicitly typing a list of strings is
used. This is done in other parts of Mercurial code, too.
2012-04-17 15:10:33 +02:00
Angel Ezquerra
19cbf3a030 revset: speedup matching() by first matching fields that take less time to
match

This patch sorts the fields that are passed to the matching function so that it
always starts by matching those fields that take less time to match.

Not all fields take the same amount of time to match. I've done several
measurements running the following command:

hg --time log -r "matching(1, field)"

on the mercurial repository, and where 'field' was each one of the fields
accepted by match. In order to avoid the print overhead (which could be
different for different fields, given the different number of matches) I used a
modified version of the matching() function which always returns no matches.

These tests showed that different fields take wildly different amounts of time
to match. Particulary the substate field takes up to 25 seconds to match on my
machine, compared to the 0.3 seconds that takes to match the phase field or the
2 seconds (approx) that takes to match most fields. With this patch, matching
both the phase and the substate of a revision takes the same amount of time as
matching the phase.

The field match order introduced by this patch is as follows:

phase, parents, user, date, branch, summary, files, description, substate

An extra nice thing about this patch is that it makes the match time stable.
2012-04-14 01:41:03 +02:00
Angel Ezquerra
2b1f5fd344 revset: speedup matching() by stopping the match early if a field does not match
Rather than getting all the fields that are being matches from every revision
and then comparing them to those of the target revision, compare each field one
by one and stop the match as soon as there is a match failure.

This can greatly reduce the match time when matching multiple fields.
The impact on match time when matching a single field seems negligible
(according to my measurements).
2012-04-13 13:46:49 +02:00
Angel Ezquerra
806c38f88b revset: make matching keyword not match summary when matching for description 2012-04-13 13:35:45 +02:00
Matt Mackall
265f182101 revset: avoid demandimport bug
Apparently the "import x as xy" doesn't manage to update xy in the
current scope's dictionary after load, which causes nodemod.nullrev to do a huge amount of demandload magic in the inner loop.
2012-04-13 15:32:49 -05:00
Matt Mackall
af300e88ec merge with stable 2012-04-12 20:52:39 -05:00
Patrick Mezard
00224d1ac6 graphlog: correctly handle calls in subdirectories 2012-04-11 11:32:00 +02:00
Patrick Mezard
a07861a2e3 graphlog: fix --follow-first --rev combinations
This solves a similar problem than the previous --follow/--rev patch. This time
we need changelog.ancestors()/descendants() filtering on first parent.
Duplicating the code looked better than introducing keyword arguments. Besides,
the ancestors() version was already implemented in follow() revset.
2012-04-11 11:25:34 +02:00
Patrick Mezard
ef43384e07 revset: avoid set duplication in roots() 2012-04-08 11:14:56 +02:00
Patrick Mezard
af77d0083f revset: retrieve a bit less parents in roots() 2012-04-08 11:13:06 +02:00
Patrick Mezard
4bfe090298 revset: do not ignore input revisions in roots()
0233b606220f is also partially reverted to use the 'narrow' parameter again and
make less changesets parents lookups.
2012-04-08 11:11:30 +02:00
Angel Ezquerra
bfc07420f3 revset: add "matching" keyword
This keyword can be used to find revisions that "match" one or more fields of a
given set of revisions.

A revision matches another if all the selected fields (description, author,
branch, date, files, phase, parents, substate, user, summary and/or metadata)
match the corresponding values of those fields on the source revision.

By default this keyword looks for revisions that whose metadata match
(description, author and date) making it ideal to look for duplicate revisions.

matching takes 2 arguments (the second being optional):

1.- rev: a revset represeting a _single_ revision (e.g. tip, ., p1(.), etc)
2.- [field(s) to match]: an optional string containing the field or fields
(separated by spaces) to match.
    Valid fields are most regular context fields and some special fields:
    * regular fields:
      - description, author, branch, date, files, phase, parents,
      substate, user.
      Note that author and user are synonyms.
    * special fields: summary, metadata.
      - summary: matches the first line of the description.
      - metatadata: It is equivalent to matching 'description user date'
        (i.e. it matches the main metadata fields).

Examples:

1.- Look for revisions with the same metadata (author, description and date)
as the 11th revision:

hg log -r "matching(11)"

2.- Look for revisions with the same description as the 11th revision:

hg log -r "matching(11, description)"

3.- Look for revisions with the same 'summary' (i.e. same first line on their
description) as the 11th revision:

hg log -r "matching(11, summary)"

4.- Look for revisions with the same author as the current revision:

hg log -r "matching(., author)"

You could use 'user' rather than 'author' to get the same result.

5.- Look for revisions with the same description _AND_ author as the tip of the
repository:

hg log -r "matching(tip, 'author description')"

6.- Look for revisions touching the same files as the parent of the tip of the
repository

hg log -r "matching(p1(tip), files)"

7.- Look for revisions whose subrepos are on the same state as the tip of the
repository or its parent

hg log -r "matching(p1(tip):tip, substate)"

8.- Look for revisions whose author and subrepo states both match those of any
of the revisions on the stable branch:

hg log -r "matching(branch(stable), 'author substate')"
2012-04-01 14:12:14 +02:00
Patrick Mezard
e329a7b4ce debugrevspec: pretty print output
Before:

  ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('or',
  ('symbol', '2'), ('symbol', '3')), ('symbol', 'date'))))

After:

  (func
    ('symbol', 'reverse')
    (func
      ('symbol', 'sort')
      (list
        (or
          ('symbol', '2')
          ('symbol', '3'))
        ('symbol', 'date'))))

v2:
- Rebased on stable to avoid having to merge tests output
2012-02-24 11:02:21 +01:00
Patrick Mezard
57671f9108 context: add followfirst arg to filectx and workingfilectx
When _followfirst() revset was introduced it seemed to be the sole user of such
an argument, so filectx.ancestors() was duplicated and modified instead. It now
appears this argument could be used when computing the set of files to be
considered when --patch or --stat are passed along with --follow FILE.
2012-02-26 17:10:57 +01:00
Patrick Mezard
14c70f7752 graphlog: evaluate FILE/-I/-X filesets on the working dir
This subtlety is not documented yet but:
- pats/--include/--exclude filesets are evaluated against the working directory
- --rev filesets are reevaluated against every revisions
2012-02-26 17:10:51 +01:00
Patrick Mezard
38c46923b9 graphlog: implement --follow-first
log --graph --follow-first FILE cannot be compared with the regular version
because it never worked: --follow-first is not taken in account in
walkchangerevs() fast path and is explicitely bypassed in FILE case in
walkchangerevs() nested iterate() function.
2012-02-25 22:11:36 +01:00
Patrick Mezard
4dca114aca graphlog: paths/-I/-X handling requires a new revset
The filtering logic of match objects cannot be reproduced with the existing
revsets as it operates at changeset files level. A changeset touching "a" and
"b" is matched by "-I a -X b" but not by "file(a) and not file(b)".

To solve this, a new internal "_matchfiles(...)" revset is introduced. It works
like "file(x)" but accepts more than one argument and its arguments are
prefixed with "p:", "i:" and "x:" to be used as patterns, include patterns or
exclude patterns respectively.

The _matchfiles revset is kept private for now:
- There are probably smarter ways to pass the arguments in a user-friendly way
- A "rev:" argument is likely appear at some point to emulate log command
  behaviour with regard to filesets: they are evaluated for the parent revision
  and applied everywhere instead of being reevaluated for each revision.
2012-02-23 18:05:20 +01:00
FUJIWARA Katsunori
8e9263abed revset: fix documentation for 'remote()' predicate
current documentation for 'remote()' predicate is wrong about
specification of parameters.

there are 3 patterns:

  # of
  param:  id:              remote:
  - 0     current branch   "defult" remote
  - 1     specified        "defult" remote
  - 2     specified        specified
2012-01-27 22:29:58 +09:00
FUJIWARA Katsunori
fa22f7f531 revset: fix 'remote()' failure when remote repo has more revs than local
current 'remote()' implementation uses 'r' variable, even if it is not
initialized when 'if n in repo' is not true.

this causes unexpected exception.
2012-01-27 22:29:58 +09:00
Patrick Mezard
231c7be7bb revset: fix alias substitution recursion (issue3240)
The revset aliases expansion worked like:

  expr = "some revset"
  for alias in aliases:
      expr = alias.process(expr)

where "process" was replacing the alias with its *unexpanded* substitution,
recursively. So it only worked when aliases were applied in proper dependency
order.

This patch rewrites the expansion process so all aliases are expanded
recursively at every tree level, after parent alias rewriting and variable
expansion.
2012-02-09 21:03:07 +01:00
Matt Mackall
87fbd9f786 revset: include the correct first ancestor change for follow(file)
Previously we always included '.', which may not touch a file.
Instead, find the file revision present in '.' and add its linkrev.
This matches the results of 'hg log --follow file'.
2012-01-20 23:52:31 -06:00