Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revset.py @ 35816:f6ca1e11d8b4 stable
revset: evaluate filesets against each revision for 'file()' (issue5778)
After f2aeff8a87b6, the fileset was evaluated to a set of files against the
working directory, and then those files were applied against each revision. The
result was nonsense. For example, `hg log -r 'file("set:exec()")'` on the
Mercurial repo listed revision 0 because it has the `hg` script, which is
currently +x. But that bit wasn't applied until revision 280 (which
'contains()' properly indicates).
This technique was borrowed from checkstatus(), which services adds(),
modifies(), and removes(), so it seems safe enough. The 'r:' case is explicitly
assigned to wdirrev, freeing up rev=None to mean "re-evaluate at each revision".
The distinction is important to avoid behavior changes with `hg log set:...`
(test-largefiles-misc.t and test-fileset-generated.t drop current log output
without this). I'm not sure what the right behavior for that is (1fd352aa08fc
explicitly enabled this behavior for graphlog), but the day before the release
isn't the time to experiment.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sun, 28 Jan 2018 14:08:59 -0500 |
parents | 134ef400cb11 |
children | 00a56c83ab64 |
comparison
equal
deleted
inserted
replaced
35815:b5df7fcf5d80 | 35816:f6ca1e11d8b4 |
---|---|
1063 exc.append(value) | 1063 exc.append(value) |
1064 elif prefix == 'r:': | 1064 elif prefix == 'r:': |
1065 if rev is not None: | 1065 if rev is not None: |
1066 raise error.ParseError('_matchfiles expected at most one ' | 1066 raise error.ParseError('_matchfiles expected at most one ' |
1067 'revision') | 1067 'revision') |
1068 if value != '': # empty means working directory; leave rev as None | 1068 if value == '': # empty means working directory |
1069 rev = node.wdirrev | |
1070 else: | |
1069 rev = value | 1071 rev = value |
1070 elif prefix == 'd:': | 1072 elif prefix == 'd:': |
1071 if default is not None: | 1073 if default is not None: |
1072 raise error.ParseError('_matchfiles expected at most one ' | 1074 raise error.ParseError('_matchfiles expected at most one ' |
1073 'default mode') | 1075 'default mode') |
1074 default = value | 1076 default = value |
1075 else: | 1077 else: |
1076 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix) | 1078 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix) |
1077 if not default: | 1079 if not default: |
1078 default = 'glob' | 1080 default = 'glob' |
1079 | 1081 hasset = any(matchmod.patkind(p) == 'set' for p in pats + inc + exc) |
1080 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc, | 1082 |
1081 exclude=exc, ctx=repo[rev], default=default) | 1083 mcache = [None] |
1082 | 1084 |
1083 # This directly read the changelog data as creating changectx for all | 1085 # This directly read the changelog data as creating changectx for all |
1084 # revisions is quite expensive. | 1086 # revisions is quite expensive. |
1085 getfiles = repo.changelog.readfiles | 1087 getfiles = repo.changelog.readfiles |
1086 wdirrev = node.wdirrev | 1088 wdirrev = node.wdirrev |
1087 def matches(x): | 1089 def matches(x): |
1088 if x == wdirrev: | 1090 if x == wdirrev: |
1089 files = repo[x].files() | 1091 files = repo[x].files() |
1090 else: | 1092 else: |
1091 files = getfiles(x) | 1093 files = getfiles(x) |
1094 | |
1095 if not mcache[0] or (hasset and rev is None): | |
1096 r = x if rev is None else rev | |
1097 mcache[0] = matchmod.match(repo.root, repo.getcwd(), pats, | |
1098 include=inc, exclude=exc, ctx=repo[r], | |
1099 default=default) | |
1100 m = mcache[0] | |
1101 | |
1092 for f in files: | 1102 for f in files: |
1093 if m(f): | 1103 if m(f): |
1094 return True | 1104 return True |
1095 return False | 1105 return False |
1096 | 1106 |