##// END OF EJS Templates
obsfate: makes successorsetverb takes the markers as argument...
Boris Feld -
r35011:b81ad5b7 default
parent child Browse files
Show More
@@ -1,837 +1,838 b''
1 # obsutil.py - utility functions for obsolescence
1 # obsutil.py - utility functions for obsolescence
2 #
2 #
3 # Copyright 2017 Boris Feld <boris.feld@octobus.net>
3 # Copyright 2017 Boris Feld <boris.feld@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import re
10 import re
11
11
12 from . import (
12 from . import (
13 phases,
13 phases,
14 util
14 util
15 )
15 )
16
16
17 class marker(object):
17 class marker(object):
18 """Wrap obsolete marker raw data"""
18 """Wrap obsolete marker raw data"""
19
19
20 def __init__(self, repo, data):
20 def __init__(self, repo, data):
21 # the repo argument will be used to create changectx in later version
21 # the repo argument will be used to create changectx in later version
22 self._repo = repo
22 self._repo = repo
23 self._data = data
23 self._data = data
24 self._decodedmeta = None
24 self._decodedmeta = None
25
25
26 def __hash__(self):
26 def __hash__(self):
27 return hash(self._data)
27 return hash(self._data)
28
28
29 def __eq__(self, other):
29 def __eq__(self, other):
30 if type(other) != type(self):
30 if type(other) != type(self):
31 return False
31 return False
32 return self._data == other._data
32 return self._data == other._data
33
33
34 def precnode(self):
34 def precnode(self):
35 msg = ("'marker.precnode' is deprecated, "
35 msg = ("'marker.precnode' is deprecated, "
36 "use 'marker.prednode'")
36 "use 'marker.prednode'")
37 util.nouideprecwarn(msg, '4.4')
37 util.nouideprecwarn(msg, '4.4')
38 return self.prednode()
38 return self.prednode()
39
39
40 def prednode(self):
40 def prednode(self):
41 """Predecessor changeset node identifier"""
41 """Predecessor changeset node identifier"""
42 return self._data[0]
42 return self._data[0]
43
43
44 def succnodes(self):
44 def succnodes(self):
45 """List of successor changesets node identifiers"""
45 """List of successor changesets node identifiers"""
46 return self._data[1]
46 return self._data[1]
47
47
48 def parentnodes(self):
48 def parentnodes(self):
49 """Parents of the predecessors (None if not recorded)"""
49 """Parents of the predecessors (None if not recorded)"""
50 return self._data[5]
50 return self._data[5]
51
51
52 def metadata(self):
52 def metadata(self):
53 """Decoded metadata dictionary"""
53 """Decoded metadata dictionary"""
54 return dict(self._data[3])
54 return dict(self._data[3])
55
55
56 def date(self):
56 def date(self):
57 """Creation date as (unixtime, offset)"""
57 """Creation date as (unixtime, offset)"""
58 return self._data[4]
58 return self._data[4]
59
59
60 def flags(self):
60 def flags(self):
61 """The flags field of the marker"""
61 """The flags field of the marker"""
62 return self._data[2]
62 return self._data[2]
63
63
64 def getmarkers(repo, nodes=None, exclusive=False):
64 def getmarkers(repo, nodes=None, exclusive=False):
65 """returns markers known in a repository
65 """returns markers known in a repository
66
66
67 If <nodes> is specified, only markers "relevant" to those nodes are are
67 If <nodes> is specified, only markers "relevant" to those nodes are are
68 returned"""
68 returned"""
69 if nodes is None:
69 if nodes is None:
70 rawmarkers = repo.obsstore
70 rawmarkers = repo.obsstore
71 elif exclusive:
71 elif exclusive:
72 rawmarkers = exclusivemarkers(repo, nodes)
72 rawmarkers = exclusivemarkers(repo, nodes)
73 else:
73 else:
74 rawmarkers = repo.obsstore.relevantmarkers(nodes)
74 rawmarkers = repo.obsstore.relevantmarkers(nodes)
75
75
76 for markerdata in rawmarkers:
76 for markerdata in rawmarkers:
77 yield marker(repo, markerdata)
77 yield marker(repo, markerdata)
78
78
79 def closestpredecessors(repo, nodeid):
79 def closestpredecessors(repo, nodeid):
80 """yield the list of next predecessors pointing on visible changectx nodes
80 """yield the list of next predecessors pointing on visible changectx nodes
81
81
82 This function respect the repoview filtering, filtered revision will be
82 This function respect the repoview filtering, filtered revision will be
83 considered missing.
83 considered missing.
84 """
84 """
85
85
86 precursors = repo.obsstore.predecessors
86 precursors = repo.obsstore.predecessors
87 stack = [nodeid]
87 stack = [nodeid]
88 seen = set(stack)
88 seen = set(stack)
89
89
90 while stack:
90 while stack:
91 current = stack.pop()
91 current = stack.pop()
92 currentpreccs = precursors.get(current, ())
92 currentpreccs = precursors.get(current, ())
93
93
94 for prec in currentpreccs:
94 for prec in currentpreccs:
95 precnodeid = prec[0]
95 precnodeid = prec[0]
96
96
97 # Basic cycle protection
97 # Basic cycle protection
98 if precnodeid in seen:
98 if precnodeid in seen:
99 continue
99 continue
100 seen.add(precnodeid)
100 seen.add(precnodeid)
101
101
102 if precnodeid in repo:
102 if precnodeid in repo:
103 yield precnodeid
103 yield precnodeid
104 else:
104 else:
105 stack.append(precnodeid)
105 stack.append(precnodeid)
106
106
107 def allprecursors(*args, **kwargs):
107 def allprecursors(*args, **kwargs):
108 """ (DEPRECATED)
108 """ (DEPRECATED)
109 """
109 """
110 msg = ("'obsutil.allprecursors' is deprecated, "
110 msg = ("'obsutil.allprecursors' is deprecated, "
111 "use 'obsutil.allpredecessors'")
111 "use 'obsutil.allpredecessors'")
112 util.nouideprecwarn(msg, '4.4')
112 util.nouideprecwarn(msg, '4.4')
113
113
114 return allpredecessors(*args, **kwargs)
114 return allpredecessors(*args, **kwargs)
115
115
116 def allpredecessors(obsstore, nodes, ignoreflags=0):
116 def allpredecessors(obsstore, nodes, ignoreflags=0):
117 """Yield node for every precursors of <nodes>.
117 """Yield node for every precursors of <nodes>.
118
118
119 Some precursors may be unknown locally.
119 Some precursors may be unknown locally.
120
120
121 This is a linear yield unsuited to detecting folded changesets. It includes
121 This is a linear yield unsuited to detecting folded changesets. It includes
122 initial nodes too."""
122 initial nodes too."""
123
123
124 remaining = set(nodes)
124 remaining = set(nodes)
125 seen = set(remaining)
125 seen = set(remaining)
126 while remaining:
126 while remaining:
127 current = remaining.pop()
127 current = remaining.pop()
128 yield current
128 yield current
129 for mark in obsstore.predecessors.get(current, ()):
129 for mark in obsstore.predecessors.get(current, ()):
130 # ignore marker flagged with specified flag
130 # ignore marker flagged with specified flag
131 if mark[2] & ignoreflags:
131 if mark[2] & ignoreflags:
132 continue
132 continue
133 suc = mark[0]
133 suc = mark[0]
134 if suc not in seen:
134 if suc not in seen:
135 seen.add(suc)
135 seen.add(suc)
136 remaining.add(suc)
136 remaining.add(suc)
137
137
138 def allsuccessors(obsstore, nodes, ignoreflags=0):
138 def allsuccessors(obsstore, nodes, ignoreflags=0):
139 """Yield node for every successor of <nodes>.
139 """Yield node for every successor of <nodes>.
140
140
141 Some successors may be unknown locally.
141 Some successors may be unknown locally.
142
142
143 This is a linear yield unsuited to detecting split changesets. It includes
143 This is a linear yield unsuited to detecting split changesets. It includes
144 initial nodes too."""
144 initial nodes too."""
145 remaining = set(nodes)
145 remaining = set(nodes)
146 seen = set(remaining)
146 seen = set(remaining)
147 while remaining:
147 while remaining:
148 current = remaining.pop()
148 current = remaining.pop()
149 yield current
149 yield current
150 for mark in obsstore.successors.get(current, ()):
150 for mark in obsstore.successors.get(current, ()):
151 # ignore marker flagged with specified flag
151 # ignore marker flagged with specified flag
152 if mark[2] & ignoreflags:
152 if mark[2] & ignoreflags:
153 continue
153 continue
154 for suc in mark[1]:
154 for suc in mark[1]:
155 if suc not in seen:
155 if suc not in seen:
156 seen.add(suc)
156 seen.add(suc)
157 remaining.add(suc)
157 remaining.add(suc)
158
158
159 def _filterprunes(markers):
159 def _filterprunes(markers):
160 """return a set with no prune markers"""
160 """return a set with no prune markers"""
161 return set(m for m in markers if m[1])
161 return set(m for m in markers if m[1])
162
162
163 def exclusivemarkers(repo, nodes):
163 def exclusivemarkers(repo, nodes):
164 """set of markers relevant to "nodes" but no other locally-known nodes
164 """set of markers relevant to "nodes" but no other locally-known nodes
165
165
166 This function compute the set of markers "exclusive" to a locally-known
166 This function compute the set of markers "exclusive" to a locally-known
167 node. This means we walk the markers starting from <nodes> until we reach a
167 node. This means we walk the markers starting from <nodes> until we reach a
168 locally-known precursors outside of <nodes>. Element of <nodes> with
168 locally-known precursors outside of <nodes>. Element of <nodes> with
169 locally-known successors outside of <nodes> are ignored (since their
169 locally-known successors outside of <nodes> are ignored (since their
170 precursors markers are also relevant to these successors).
170 precursors markers are also relevant to these successors).
171
171
172 For example:
172 For example:
173
173
174 # (A0 rewritten as A1)
174 # (A0 rewritten as A1)
175 #
175 #
176 # A0 <-1- A1 # Marker "1" is exclusive to A1
176 # A0 <-1- A1 # Marker "1" is exclusive to A1
177
177
178 or
178 or
179
179
180 # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
180 # (A0 rewritten as AX; AX rewritten as A1; AX is unkown locally)
181 #
181 #
182 # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
182 # <-1- A0 <-2- AX <-3- A1 # Marker "2,3" are exclusive to A1
183
183
184 or
184 or
185
185
186 # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
186 # (A0 has unknown precursors, A0 rewritten as A1 and A2 (divergence))
187 #
187 #
188 # <-2- A1 # Marker "2" is exclusive to A0,A1
188 # <-2- A1 # Marker "2" is exclusive to A0,A1
189 # /
189 # /
190 # <-1- A0
190 # <-1- A0
191 # \
191 # \
192 # <-3- A2 # Marker "3" is exclusive to A0,A2
192 # <-3- A2 # Marker "3" is exclusive to A0,A2
193 #
193 #
194 # in addition:
194 # in addition:
195 #
195 #
196 # Markers "2,3" are exclusive to A1,A2
196 # Markers "2,3" are exclusive to A1,A2
197 # Markers "1,2,3" are exclusive to A0,A1,A2
197 # Markers "1,2,3" are exclusive to A0,A1,A2
198
198
199 See test/test-obsolete-bundle-strip.t for more examples.
199 See test/test-obsolete-bundle-strip.t for more examples.
200
200
201 An example usage is strip. When stripping a changeset, we also want to
201 An example usage is strip. When stripping a changeset, we also want to
202 strip the markers exclusive to this changeset. Otherwise we would have
202 strip the markers exclusive to this changeset. Otherwise we would have
203 "dangling"" obsolescence markers from its precursors: Obsolescence markers
203 "dangling"" obsolescence markers from its precursors: Obsolescence markers
204 marking a node as obsolete without any successors available locally.
204 marking a node as obsolete without any successors available locally.
205
205
206 As for relevant markers, the prune markers for children will be followed.
206 As for relevant markers, the prune markers for children will be followed.
207 Of course, they will only be followed if the pruned children is
207 Of course, they will only be followed if the pruned children is
208 locally-known. Since the prune markers are relevant to the pruned node.
208 locally-known. Since the prune markers are relevant to the pruned node.
209 However, while prune markers are considered relevant to the parent of the
209 However, while prune markers are considered relevant to the parent of the
210 pruned changesets, prune markers for locally-known changeset (with no
210 pruned changesets, prune markers for locally-known changeset (with no
211 successors) are considered exclusive to the pruned nodes. This allows
211 successors) are considered exclusive to the pruned nodes. This allows
212 to strip the prune markers (with the rest of the exclusive chain) alongside
212 to strip the prune markers (with the rest of the exclusive chain) alongside
213 the pruned changesets.
213 the pruned changesets.
214 """
214 """
215 # running on a filtered repository would be dangerous as markers could be
215 # running on a filtered repository would be dangerous as markers could be
216 # reported as exclusive when they are relevant for other filtered nodes.
216 # reported as exclusive when they are relevant for other filtered nodes.
217 unfi = repo.unfiltered()
217 unfi = repo.unfiltered()
218
218
219 # shortcut to various useful item
219 # shortcut to various useful item
220 nm = unfi.changelog.nodemap
220 nm = unfi.changelog.nodemap
221 precursorsmarkers = unfi.obsstore.predecessors
221 precursorsmarkers = unfi.obsstore.predecessors
222 successormarkers = unfi.obsstore.successors
222 successormarkers = unfi.obsstore.successors
223 childrenmarkers = unfi.obsstore.children
223 childrenmarkers = unfi.obsstore.children
224
224
225 # exclusive markers (return of the function)
225 # exclusive markers (return of the function)
226 exclmarkers = set()
226 exclmarkers = set()
227 # we need fast membership testing
227 # we need fast membership testing
228 nodes = set(nodes)
228 nodes = set(nodes)
229 # looking for head in the obshistory
229 # looking for head in the obshistory
230 #
230 #
231 # XXX we are ignoring all issues in regard with cycle for now.
231 # XXX we are ignoring all issues in regard with cycle for now.
232 stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
232 stack = [n for n in nodes if not _filterprunes(successormarkers.get(n, ()))]
233 stack.sort()
233 stack.sort()
234 # nodes already stacked
234 # nodes already stacked
235 seennodes = set(stack)
235 seennodes = set(stack)
236 while stack:
236 while stack:
237 current = stack.pop()
237 current = stack.pop()
238 # fetch precursors markers
238 # fetch precursors markers
239 markers = list(precursorsmarkers.get(current, ()))
239 markers = list(precursorsmarkers.get(current, ()))
240 # extend the list with prune markers
240 # extend the list with prune markers
241 for mark in successormarkers.get(current, ()):
241 for mark in successormarkers.get(current, ()):
242 if not mark[1]:
242 if not mark[1]:
243 markers.append(mark)
243 markers.append(mark)
244 # and markers from children (looking for prune)
244 # and markers from children (looking for prune)
245 for mark in childrenmarkers.get(current, ()):
245 for mark in childrenmarkers.get(current, ()):
246 if not mark[1]:
246 if not mark[1]:
247 markers.append(mark)
247 markers.append(mark)
248 # traverse the markers
248 # traverse the markers
249 for mark in markers:
249 for mark in markers:
250 if mark in exclmarkers:
250 if mark in exclmarkers:
251 # markers already selected
251 # markers already selected
252 continue
252 continue
253
253
254 # If the markers is about the current node, select it
254 # If the markers is about the current node, select it
255 #
255 #
256 # (this delay the addition of markers from children)
256 # (this delay the addition of markers from children)
257 if mark[1] or mark[0] == current:
257 if mark[1] or mark[0] == current:
258 exclmarkers.add(mark)
258 exclmarkers.add(mark)
259
259
260 # should we keep traversing through the precursors?
260 # should we keep traversing through the precursors?
261 prec = mark[0]
261 prec = mark[0]
262
262
263 # nodes in the stack or already processed
263 # nodes in the stack or already processed
264 if prec in seennodes:
264 if prec in seennodes:
265 continue
265 continue
266
266
267 # is this a locally known node ?
267 # is this a locally known node ?
268 known = prec in nm
268 known = prec in nm
269 # if locally-known and not in the <nodes> set the traversal
269 # if locally-known and not in the <nodes> set the traversal
270 # stop here.
270 # stop here.
271 if known and prec not in nodes:
271 if known and prec not in nodes:
272 continue
272 continue
273
273
274 # do not keep going if there are unselected markers pointing to this
274 # do not keep going if there are unselected markers pointing to this
275 # nodes. If we end up traversing these unselected markers later the
275 # nodes. If we end up traversing these unselected markers later the
276 # node will be taken care of at that point.
276 # node will be taken care of at that point.
277 precmarkers = _filterprunes(successormarkers.get(prec))
277 precmarkers = _filterprunes(successormarkers.get(prec))
278 if precmarkers.issubset(exclmarkers):
278 if precmarkers.issubset(exclmarkers):
279 seennodes.add(prec)
279 seennodes.add(prec)
280 stack.append(prec)
280 stack.append(prec)
281
281
282 return exclmarkers
282 return exclmarkers
283
283
284 def foreground(repo, nodes):
284 def foreground(repo, nodes):
285 """return all nodes in the "foreground" of other node
285 """return all nodes in the "foreground" of other node
286
286
287 The foreground of a revision is anything reachable using parent -> children
287 The foreground of a revision is anything reachable using parent -> children
288 or precursor -> successor relation. It is very similar to "descendant" but
288 or precursor -> successor relation. It is very similar to "descendant" but
289 augmented with obsolescence information.
289 augmented with obsolescence information.
290
290
291 Beware that possible obsolescence cycle may result if complex situation.
291 Beware that possible obsolescence cycle may result if complex situation.
292 """
292 """
293 repo = repo.unfiltered()
293 repo = repo.unfiltered()
294 foreground = set(repo.set('%ln::', nodes))
294 foreground = set(repo.set('%ln::', nodes))
295 if repo.obsstore:
295 if repo.obsstore:
296 # We only need this complicated logic if there is obsolescence
296 # We only need this complicated logic if there is obsolescence
297 # XXX will probably deserve an optimised revset.
297 # XXX will probably deserve an optimised revset.
298 nm = repo.changelog.nodemap
298 nm = repo.changelog.nodemap
299 plen = -1
299 plen = -1
300 # compute the whole set of successors or descendants
300 # compute the whole set of successors or descendants
301 while len(foreground) != plen:
301 while len(foreground) != plen:
302 plen = len(foreground)
302 plen = len(foreground)
303 succs = set(c.node() for c in foreground)
303 succs = set(c.node() for c in foreground)
304 mutable = [c.node() for c in foreground if c.mutable()]
304 mutable = [c.node() for c in foreground if c.mutable()]
305 succs.update(allsuccessors(repo.obsstore, mutable))
305 succs.update(allsuccessors(repo.obsstore, mutable))
306 known = (n for n in succs if n in nm)
306 known = (n for n in succs if n in nm)
307 foreground = set(repo.set('%ln::', known))
307 foreground = set(repo.set('%ln::', known))
308 return set(c.node() for c in foreground)
308 return set(c.node() for c in foreground)
309
309
310 # effectflag field
310 # effectflag field
311 #
311 #
312 # Effect-flag is a 1-byte bit field used to store what changed between a
312 # Effect-flag is a 1-byte bit field used to store what changed between a
313 # changeset and its successor(s).
313 # changeset and its successor(s).
314 #
314 #
315 # The effect flag is stored in obs-markers metadata while we iterate on the
315 # The effect flag is stored in obs-markers metadata while we iterate on the
316 # information design. That's why we have the EFFECTFLAGFIELD. If we come up
316 # information design. That's why we have the EFFECTFLAGFIELD. If we come up
317 # with an incompatible design for effect flag, we can store a new design under
317 # with an incompatible design for effect flag, we can store a new design under
318 # another field name so we don't break readers. We plan to extend the existing
318 # another field name so we don't break readers. We plan to extend the existing
319 # obsmarkers bit-field when the effect flag design will be stabilized.
319 # obsmarkers bit-field when the effect flag design will be stabilized.
320 #
320 #
321 # The effect-flag is placed behind an experimental flag
321 # The effect-flag is placed behind an experimental flag
322 # `effect-flags` set to off by default.
322 # `effect-flags` set to off by default.
323 #
323 #
324
324
325 EFFECTFLAGFIELD = "ef1"
325 EFFECTFLAGFIELD = "ef1"
326
326
327 DESCCHANGED = 1 << 0 # action changed the description
327 DESCCHANGED = 1 << 0 # action changed the description
328 METACHANGED = 1 << 1 # action change the meta
328 METACHANGED = 1 << 1 # action change the meta
329 DIFFCHANGED = 1 << 3 # action change diff introduced by the changeset
329 DIFFCHANGED = 1 << 3 # action change diff introduced by the changeset
330 PARENTCHANGED = 1 << 2 # action change the parent
330 PARENTCHANGED = 1 << 2 # action change the parent
331 USERCHANGED = 1 << 4 # the user changed
331 USERCHANGED = 1 << 4 # the user changed
332 DATECHANGED = 1 << 5 # the date changed
332 DATECHANGED = 1 << 5 # the date changed
333 BRANCHCHANGED = 1 << 6 # the branch changed
333 BRANCHCHANGED = 1 << 6 # the branch changed
334
334
335 METABLACKLIST = [
335 METABLACKLIST = [
336 re.compile('^branch$'),
336 re.compile('^branch$'),
337 re.compile('^.*-source$'),
337 re.compile('^.*-source$'),
338 re.compile('^.*_source$'),
338 re.compile('^.*_source$'),
339 re.compile('^source$'),
339 re.compile('^source$'),
340 ]
340 ]
341
341
342 def metanotblacklisted(metaitem):
342 def metanotblacklisted(metaitem):
343 """ Check that the key of a meta item (extrakey, extravalue) does not
343 """ Check that the key of a meta item (extrakey, extravalue) does not
344 match at least one of the blacklist pattern
344 match at least one of the blacklist pattern
345 """
345 """
346 metakey = metaitem[0]
346 metakey = metaitem[0]
347
347
348 return not any(pattern.match(metakey) for pattern in METABLACKLIST)
348 return not any(pattern.match(metakey) for pattern in METABLACKLIST)
349
349
350 def _prepare_hunk(hunk):
350 def _prepare_hunk(hunk):
351 """Drop all information but the username and patch"""
351 """Drop all information but the username and patch"""
352 cleanhunk = []
352 cleanhunk = []
353 for line in hunk.splitlines():
353 for line in hunk.splitlines():
354 if line.startswith(b'# User') or not line.startswith(b'#'):
354 if line.startswith(b'# User') or not line.startswith(b'#'):
355 if line.startswith(b'@@'):
355 if line.startswith(b'@@'):
356 line = b'@@\n'
356 line = b'@@\n'
357 cleanhunk.append(line)
357 cleanhunk.append(line)
358 return cleanhunk
358 return cleanhunk
359
359
360 def _getdifflines(iterdiff):
360 def _getdifflines(iterdiff):
361 """return a cleaned up lines"""
361 """return a cleaned up lines"""
362 lines = next(iterdiff, None)
362 lines = next(iterdiff, None)
363
363
364 if lines is None:
364 if lines is None:
365 return lines
365 return lines
366
366
367 return _prepare_hunk(lines)
367 return _prepare_hunk(lines)
368
368
369 def _cmpdiff(leftctx, rightctx):
369 def _cmpdiff(leftctx, rightctx):
370 """return True if both ctx introduce the "same diff"
370 """return True if both ctx introduce the "same diff"
371
371
372 This is a first and basic implementation, with many shortcoming.
372 This is a first and basic implementation, with many shortcoming.
373 """
373 """
374
374
375 # Leftctx or right ctx might be filtered, so we need to use the contexts
375 # Leftctx or right ctx might be filtered, so we need to use the contexts
376 # with an unfiltered repository to safely compute the diff
376 # with an unfiltered repository to safely compute the diff
377 leftunfi = leftctx._repo.unfiltered()[leftctx.rev()]
377 leftunfi = leftctx._repo.unfiltered()[leftctx.rev()]
378 leftdiff = leftunfi.diff(git=1)
378 leftdiff = leftunfi.diff(git=1)
379 rightunfi = rightctx._repo.unfiltered()[rightctx.rev()]
379 rightunfi = rightctx._repo.unfiltered()[rightctx.rev()]
380 rightdiff = rightunfi.diff(git=1)
380 rightdiff = rightunfi.diff(git=1)
381
381
382 left, right = (0, 0)
382 left, right = (0, 0)
383 while None not in (left, right):
383 while None not in (left, right):
384 left = _getdifflines(leftdiff)
384 left = _getdifflines(leftdiff)
385 right = _getdifflines(rightdiff)
385 right = _getdifflines(rightdiff)
386
386
387 if left != right:
387 if left != right:
388 return False
388 return False
389 return True
389 return True
390
390
391 def geteffectflag(relation):
391 def geteffectflag(relation):
392 """ From an obs-marker relation, compute what changed between the
392 """ From an obs-marker relation, compute what changed between the
393 predecessor and the successor.
393 predecessor and the successor.
394 """
394 """
395 effects = 0
395 effects = 0
396
396
397 source = relation[0]
397 source = relation[0]
398
398
399 for changectx in relation[1]:
399 for changectx in relation[1]:
400 # Check if description has changed
400 # Check if description has changed
401 if changectx.description() != source.description():
401 if changectx.description() != source.description():
402 effects |= DESCCHANGED
402 effects |= DESCCHANGED
403
403
404 # Check if user has changed
404 # Check if user has changed
405 if changectx.user() != source.user():
405 if changectx.user() != source.user():
406 effects |= USERCHANGED
406 effects |= USERCHANGED
407
407
408 # Check if date has changed
408 # Check if date has changed
409 if changectx.date() != source.date():
409 if changectx.date() != source.date():
410 effects |= DATECHANGED
410 effects |= DATECHANGED
411
411
412 # Check if branch has changed
412 # Check if branch has changed
413 if changectx.branch() != source.branch():
413 if changectx.branch() != source.branch():
414 effects |= BRANCHCHANGED
414 effects |= BRANCHCHANGED
415
415
416 # Check if at least one of the parent has changed
416 # Check if at least one of the parent has changed
417 if changectx.parents() != source.parents():
417 if changectx.parents() != source.parents():
418 effects |= PARENTCHANGED
418 effects |= PARENTCHANGED
419
419
420 # Check if other meta has changed
420 # Check if other meta has changed
421 changeextra = changectx.extra().items()
421 changeextra = changectx.extra().items()
422 ctxmeta = filter(metanotblacklisted, changeextra)
422 ctxmeta = filter(metanotblacklisted, changeextra)
423
423
424 sourceextra = source.extra().items()
424 sourceextra = source.extra().items()
425 srcmeta = filter(metanotblacklisted, sourceextra)
425 srcmeta = filter(metanotblacklisted, sourceextra)
426
426
427 if ctxmeta != srcmeta:
427 if ctxmeta != srcmeta:
428 effects |= METACHANGED
428 effects |= METACHANGED
429
429
430 # Check if the diff has changed
430 # Check if the diff has changed
431 if not _cmpdiff(source, changectx):
431 if not _cmpdiff(source, changectx):
432 effects |= DIFFCHANGED
432 effects |= DIFFCHANGED
433
433
434 return effects
434 return effects
435
435
436 def getobsoleted(repo, tr):
436 def getobsoleted(repo, tr):
437 """return the set of pre-existing revisions obsoleted by a transaction"""
437 """return the set of pre-existing revisions obsoleted by a transaction"""
438 torev = repo.unfiltered().changelog.nodemap.get
438 torev = repo.unfiltered().changelog.nodemap.get
439 phase = repo._phasecache.phase
439 phase = repo._phasecache.phase
440 succsmarkers = repo.obsstore.successors.get
440 succsmarkers = repo.obsstore.successors.get
441 public = phases.public
441 public = phases.public
442 addedmarkers = tr.changes.get('obsmarkers')
442 addedmarkers = tr.changes.get('obsmarkers')
443 addedrevs = tr.changes.get('revs')
443 addedrevs = tr.changes.get('revs')
444 seenrevs = set(addedrevs)
444 seenrevs = set(addedrevs)
445 obsoleted = set()
445 obsoleted = set()
446 for mark in addedmarkers:
446 for mark in addedmarkers:
447 node = mark[0]
447 node = mark[0]
448 rev = torev(node)
448 rev = torev(node)
449 if rev is None or rev in seenrevs:
449 if rev is None or rev in seenrevs:
450 continue
450 continue
451 seenrevs.add(rev)
451 seenrevs.add(rev)
452 if phase(repo, rev) == public:
452 if phase(repo, rev) == public:
453 continue
453 continue
454 if set(succsmarkers(node) or []).issubset(addedmarkers):
454 if set(succsmarkers(node) or []).issubset(addedmarkers):
455 obsoleted.add(rev)
455 obsoleted.add(rev)
456 return obsoleted
456 return obsoleted
457
457
458 class _succs(list):
458 class _succs(list):
459 """small class to represent a successors with some metadata about it"""
459 """small class to represent a successors with some metadata about it"""
460
460
461 def __init__(self, *args, **kwargs):
461 def __init__(self, *args, **kwargs):
462 super(_succs, self).__init__(*args, **kwargs)
462 super(_succs, self).__init__(*args, **kwargs)
463 self.markers = set()
463 self.markers = set()
464
464
465 def copy(self):
465 def copy(self):
466 new = _succs(self)
466 new = _succs(self)
467 new.markers = self.markers.copy()
467 new.markers = self.markers.copy()
468 return new
468 return new
469
469
470 @util.propertycache
470 @util.propertycache
471 def _set(self):
471 def _set(self):
472 # immutable
472 # immutable
473 return set(self)
473 return set(self)
474
474
475 def canmerge(self, other):
475 def canmerge(self, other):
476 return self._set.issubset(other._set)
476 return self._set.issubset(other._set)
477
477
478 def successorssets(repo, initialnode, closest=False, cache=None):
478 def successorssets(repo, initialnode, closest=False, cache=None):
479 """Return set of all latest successors of initial nodes
479 """Return set of all latest successors of initial nodes
480
480
481 The successors set of a changeset A are the group of revisions that succeed
481 The successors set of a changeset A are the group of revisions that succeed
482 A. It succeeds A as a consistent whole, each revision being only a partial
482 A. It succeeds A as a consistent whole, each revision being only a partial
483 replacement. By default, the successors set contains non-obsolete
483 replacement. By default, the successors set contains non-obsolete
484 changesets only, walking the obsolescence graph until reaching a leaf. If
484 changesets only, walking the obsolescence graph until reaching a leaf. If
485 'closest' is set to True, closest successors-sets are return (the
485 'closest' is set to True, closest successors-sets are return (the
486 obsolescence walk stops on known changesets).
486 obsolescence walk stops on known changesets).
487
487
488 This function returns the full list of successor sets which is why it
488 This function returns the full list of successor sets which is why it
489 returns a list of tuples and not just a single tuple. Each tuple is a valid
489 returns a list of tuples and not just a single tuple. Each tuple is a valid
490 successors set. Note that (A,) may be a valid successors set for changeset A
490 successors set. Note that (A,) may be a valid successors set for changeset A
491 (see below).
491 (see below).
492
492
493 In most cases, a changeset A will have a single element (e.g. the changeset
493 In most cases, a changeset A will have a single element (e.g. the changeset
494 A is replaced by A') in its successors set. Though, it is also common for a
494 A is replaced by A') in its successors set. Though, it is also common for a
495 changeset A to have no elements in its successor set (e.g. the changeset
495 changeset A to have no elements in its successor set (e.g. the changeset
496 has been pruned). Therefore, the returned list of successors sets will be
496 has been pruned). Therefore, the returned list of successors sets will be
497 [(A',)] or [], respectively.
497 [(A',)] or [], respectively.
498
498
499 When a changeset A is split into A' and B', however, it will result in a
499 When a changeset A is split into A' and B', however, it will result in a
500 successors set containing more than a single element, i.e. [(A',B')].
500 successors set containing more than a single element, i.e. [(A',B')].
501 Divergent changesets will result in multiple successors sets, i.e. [(A',),
501 Divergent changesets will result in multiple successors sets, i.e. [(A',),
502 (A'')].
502 (A'')].
503
503
504 If a changeset A is not obsolete, then it will conceptually have no
504 If a changeset A is not obsolete, then it will conceptually have no
505 successors set. To distinguish this from a pruned changeset, the successor
505 successors set. To distinguish this from a pruned changeset, the successor
506 set will contain itself only, i.e. [(A,)].
506 set will contain itself only, i.e. [(A,)].
507
507
508 Finally, final successors unknown locally are considered to be pruned
508 Finally, final successors unknown locally are considered to be pruned
509 (pruned: obsoleted without any successors). (Final: successors not affected
509 (pruned: obsoleted without any successors). (Final: successors not affected
510 by markers).
510 by markers).
511
511
512 The 'closest' mode respect the repoview filtering. For example, without
512 The 'closest' mode respect the repoview filtering. For example, without
513 filter it will stop at the first locally known changeset, with 'visible'
513 filter it will stop at the first locally known changeset, with 'visible'
514 filter it will stop on visible changesets).
514 filter it will stop on visible changesets).
515
515
516 The optional `cache` parameter is a dictionary that may contains
516 The optional `cache` parameter is a dictionary that may contains
517 precomputed successors sets. It is meant to reuse the computation of a
517 precomputed successors sets. It is meant to reuse the computation of a
518 previous call to `successorssets` when multiple calls are made at the same
518 previous call to `successorssets` when multiple calls are made at the same
519 time. The cache dictionary is updated in place. The caller is responsible
519 time. The cache dictionary is updated in place. The caller is responsible
520 for its life span. Code that makes multiple calls to `successorssets`
520 for its life span. Code that makes multiple calls to `successorssets`
521 *should* use this cache mechanism or risk a performance hit.
521 *should* use this cache mechanism or risk a performance hit.
522
522
523 Since results are different depending of the 'closest' most, the same cache
523 Since results are different depending of the 'closest' most, the same cache
524 cannot be reused for both mode.
524 cannot be reused for both mode.
525 """
525 """
526
526
527 succmarkers = repo.obsstore.successors
527 succmarkers = repo.obsstore.successors
528
528
529 # Stack of nodes we search successors sets for
529 # Stack of nodes we search successors sets for
530 toproceed = [initialnode]
530 toproceed = [initialnode]
531 # set version of above list for fast loop detection
531 # set version of above list for fast loop detection
532 # element added to "toproceed" must be added here
532 # element added to "toproceed" must be added here
533 stackedset = set(toproceed)
533 stackedset = set(toproceed)
534 if cache is None:
534 if cache is None:
535 cache = {}
535 cache = {}
536
536
537 # This while loop is the flattened version of a recursive search for
537 # This while loop is the flattened version of a recursive search for
538 # successors sets
538 # successors sets
539 #
539 #
540 # def successorssets(x):
540 # def successorssets(x):
541 # successors = directsuccessors(x)
541 # successors = directsuccessors(x)
542 # ss = [[]]
542 # ss = [[]]
543 # for succ in directsuccessors(x):
543 # for succ in directsuccessors(x):
544 # # product as in itertools cartesian product
544 # # product as in itertools cartesian product
545 # ss = product(ss, successorssets(succ))
545 # ss = product(ss, successorssets(succ))
546 # return ss
546 # return ss
547 #
547 #
548 # But we can not use plain recursive calls here:
548 # But we can not use plain recursive calls here:
549 # - that would blow the python call stack
549 # - that would blow the python call stack
550 # - obsolescence markers may have cycles, we need to handle them.
550 # - obsolescence markers may have cycles, we need to handle them.
551 #
551 #
552 # The `toproceed` list act as our call stack. Every node we search
552 # The `toproceed` list act as our call stack. Every node we search
553 # successors set for are stacked there.
553 # successors set for are stacked there.
554 #
554 #
555 # The `stackedset` is set version of this stack used to check if a node is
555 # The `stackedset` is set version of this stack used to check if a node is
556 # already stacked. This check is used to detect cycles and prevent infinite
556 # already stacked. This check is used to detect cycles and prevent infinite
557 # loop.
557 # loop.
558 #
558 #
559 # successors set of all nodes are stored in the `cache` dictionary.
559 # successors set of all nodes are stored in the `cache` dictionary.
560 #
560 #
561 # After this while loop ends we use the cache to return the successors sets
561 # After this while loop ends we use the cache to return the successors sets
562 # for the node requested by the caller.
562 # for the node requested by the caller.
563 while toproceed:
563 while toproceed:
564 # Every iteration tries to compute the successors sets of the topmost
564 # Every iteration tries to compute the successors sets of the topmost
565 # node of the stack: CURRENT.
565 # node of the stack: CURRENT.
566 #
566 #
567 # There are four possible outcomes:
567 # There are four possible outcomes:
568 #
568 #
569 # 1) We already know the successors sets of CURRENT:
569 # 1) We already know the successors sets of CURRENT:
570 # -> mission accomplished, pop it from the stack.
570 # -> mission accomplished, pop it from the stack.
571 # 2) Stop the walk:
571 # 2) Stop the walk:
572 # default case: Node is not obsolete
572 # default case: Node is not obsolete
573 # closest case: Node is known at this repo filter level
573 # closest case: Node is known at this repo filter level
574 # -> the node is its own successors sets. Add it to the cache.
574 # -> the node is its own successors sets. Add it to the cache.
575 # 3) We do not know successors set of direct successors of CURRENT:
575 # 3) We do not know successors set of direct successors of CURRENT:
576 # -> We add those successors to the stack.
576 # -> We add those successors to the stack.
577 # 4) We know successors sets of all direct successors of CURRENT:
577 # 4) We know successors sets of all direct successors of CURRENT:
578 # -> We can compute CURRENT successors set and add it to the
578 # -> We can compute CURRENT successors set and add it to the
579 # cache.
579 # cache.
580 #
580 #
581 current = toproceed[-1]
581 current = toproceed[-1]
582
582
583 # case 2 condition is a bit hairy because of closest,
583 # case 2 condition is a bit hairy because of closest,
584 # we compute it on its own
584 # we compute it on its own
585 case2condition = ((current not in succmarkers)
585 case2condition = ((current not in succmarkers)
586 or (closest and current != initialnode
586 or (closest and current != initialnode
587 and current in repo))
587 and current in repo))
588
588
589 if current in cache:
589 if current in cache:
590 # case (1): We already know the successors sets
590 # case (1): We already know the successors sets
591 stackedset.remove(toproceed.pop())
591 stackedset.remove(toproceed.pop())
592 elif case2condition:
592 elif case2condition:
593 # case (2): end of walk.
593 # case (2): end of walk.
594 if current in repo:
594 if current in repo:
595 # We have a valid successors.
595 # We have a valid successors.
596 cache[current] = [_succs((current,))]
596 cache[current] = [_succs((current,))]
597 else:
597 else:
598 # Final obsolete version is unknown locally.
598 # Final obsolete version is unknown locally.
599 # Do not count that as a valid successors
599 # Do not count that as a valid successors
600 cache[current] = []
600 cache[current] = []
601 else:
601 else:
602 # cases (3) and (4)
602 # cases (3) and (4)
603 #
603 #
604 # We proceed in two phases. Phase 1 aims to distinguish case (3)
604 # We proceed in two phases. Phase 1 aims to distinguish case (3)
605 # from case (4):
605 # from case (4):
606 #
606 #
607 # For each direct successors of CURRENT, we check whether its
607 # For each direct successors of CURRENT, we check whether its
608 # successors sets are known. If they are not, we stack the
608 # successors sets are known. If they are not, we stack the
609 # unknown node and proceed to the next iteration of the while
609 # unknown node and proceed to the next iteration of the while
610 # loop. (case 3)
610 # loop. (case 3)
611 #
611 #
612 # During this step, we may detect obsolescence cycles: a node
612 # During this step, we may detect obsolescence cycles: a node
613 # with unknown successors sets but already in the call stack.
613 # with unknown successors sets but already in the call stack.
614 # In such a situation, we arbitrary set the successors sets of
614 # In such a situation, we arbitrary set the successors sets of
615 # the node to nothing (node pruned) to break the cycle.
615 # the node to nothing (node pruned) to break the cycle.
616 #
616 #
617 # If no break was encountered we proceed to phase 2.
617 # If no break was encountered we proceed to phase 2.
618 #
618 #
619 # Phase 2 computes successors sets of CURRENT (case 4); see details
619 # Phase 2 computes successors sets of CURRENT (case 4); see details
620 # in phase 2 itself.
620 # in phase 2 itself.
621 #
621 #
622 # Note the two levels of iteration in each phase.
622 # Note the two levels of iteration in each phase.
623 # - The first one handles obsolescence markers using CURRENT as
623 # - The first one handles obsolescence markers using CURRENT as
624 # precursor (successors markers of CURRENT).
624 # precursor (successors markers of CURRENT).
625 #
625 #
626 # Having multiple entry here means divergence.
626 # Having multiple entry here means divergence.
627 #
627 #
628 # - The second one handles successors defined in each marker.
628 # - The second one handles successors defined in each marker.
629 #
629 #
630 # Having none means pruned node, multiple successors means split,
630 # Having none means pruned node, multiple successors means split,
631 # single successors are standard replacement.
631 # single successors are standard replacement.
632 #
632 #
633 for mark in sorted(succmarkers[current]):
633 for mark in sorted(succmarkers[current]):
634 for suc in mark[1]:
634 for suc in mark[1]:
635 if suc not in cache:
635 if suc not in cache:
636 if suc in stackedset:
636 if suc in stackedset:
637 # cycle breaking
637 # cycle breaking
638 cache[suc] = []
638 cache[suc] = []
639 else:
639 else:
640 # case (3) If we have not computed successors sets
640 # case (3) If we have not computed successors sets
641 # of one of those successors we add it to the
641 # of one of those successors we add it to the
642 # `toproceed` stack and stop all work for this
642 # `toproceed` stack and stop all work for this
643 # iteration.
643 # iteration.
644 toproceed.append(suc)
644 toproceed.append(suc)
645 stackedset.add(suc)
645 stackedset.add(suc)
646 break
646 break
647 else:
647 else:
648 continue
648 continue
649 break
649 break
650 else:
650 else:
651 # case (4): we know all successors sets of all direct
651 # case (4): we know all successors sets of all direct
652 # successors
652 # successors
653 #
653 #
654 # Successors set contributed by each marker depends on the
654 # Successors set contributed by each marker depends on the
655 # successors sets of all its "successors" node.
655 # successors sets of all its "successors" node.
656 #
656 #
657 # Each different marker is a divergence in the obsolescence
657 # Each different marker is a divergence in the obsolescence
658 # history. It contributes successors sets distinct from other
658 # history. It contributes successors sets distinct from other
659 # markers.
659 # markers.
660 #
660 #
661 # Within a marker, a successor may have divergent successors
661 # Within a marker, a successor may have divergent successors
662 # sets. In such a case, the marker will contribute multiple
662 # sets. In such a case, the marker will contribute multiple
663 # divergent successors sets. If multiple successors have
663 # divergent successors sets. If multiple successors have
664 # divergent successors sets, a Cartesian product is used.
664 # divergent successors sets, a Cartesian product is used.
665 #
665 #
666 # At the end we post-process successors sets to remove
666 # At the end we post-process successors sets to remove
667 # duplicated entry and successors set that are strict subset of
667 # duplicated entry and successors set that are strict subset of
668 # another one.
668 # another one.
669 succssets = []
669 succssets = []
670 for mark in sorted(succmarkers[current]):
670 for mark in sorted(succmarkers[current]):
671 # successors sets contributed by this marker
671 # successors sets contributed by this marker
672 base = _succs()
672 base = _succs()
673 base.markers.add(mark)
673 base.markers.add(mark)
674 markss = [base]
674 markss = [base]
675 for suc in mark[1]:
675 for suc in mark[1]:
676 # cardinal product with previous successors
676 # cardinal product with previous successors
677 productresult = []
677 productresult = []
678 for prefix in markss:
678 for prefix in markss:
679 for suffix in cache[suc]:
679 for suffix in cache[suc]:
680 newss = prefix.copy()
680 newss = prefix.copy()
681 newss.markers.update(suffix.markers)
681 newss.markers.update(suffix.markers)
682 for part in suffix:
682 for part in suffix:
683 # do not duplicated entry in successors set
683 # do not duplicated entry in successors set
684 # first entry wins.
684 # first entry wins.
685 if part not in newss:
685 if part not in newss:
686 newss.append(part)
686 newss.append(part)
687 productresult.append(newss)
687 productresult.append(newss)
688 markss = productresult
688 markss = productresult
689 succssets.extend(markss)
689 succssets.extend(markss)
690 # remove duplicated and subset
690 # remove duplicated and subset
691 seen = []
691 seen = []
692 final = []
692 final = []
693 candidates = sorted((s for s in succssets if s),
693 candidates = sorted((s for s in succssets if s),
694 key=len, reverse=True)
694 key=len, reverse=True)
695 for cand in candidates:
695 for cand in candidates:
696 for seensuccs in seen:
696 for seensuccs in seen:
697 if cand.canmerge(seensuccs):
697 if cand.canmerge(seensuccs):
698 seensuccs.markers.update(cand.markers)
698 seensuccs.markers.update(cand.markers)
699 break
699 break
700 else:
700 else:
701 final.append(cand)
701 final.append(cand)
702 seen.append(cand)
702 seen.append(cand)
703 final.reverse() # put small successors set first
703 final.reverse() # put small successors set first
704 cache[current] = final
704 cache[current] = final
705 return cache[initialnode]
705 return cache[initialnode]
706
706
707 def successorsandmarkers(repo, ctx):
707 def successorsandmarkers(repo, ctx):
708 """compute the raw data needed for computing obsfate
708 """compute the raw data needed for computing obsfate
709 Returns a list of dict, one dict per successors set
709 Returns a list of dict, one dict per successors set
710 """
710 """
711 if not ctx.obsolete():
711 if not ctx.obsolete():
712 return None
712 return None
713
713
714 ssets = successorssets(repo, ctx.node(), closest=True)
714 ssets = successorssets(repo, ctx.node(), closest=True)
715
715
716 # closestsuccessors returns an empty list for pruned revisions, remap it
716 # closestsuccessors returns an empty list for pruned revisions, remap it
717 # into a list containing an empty list for future processing
717 # into a list containing an empty list for future processing
718 if ssets == []:
718 if ssets == []:
719 ssets = [[]]
719 ssets = [[]]
720
720
721 # Try to recover pruned markers
721 # Try to recover pruned markers
722 succsmap = repo.obsstore.successors
722 succsmap = repo.obsstore.successors
723 fullsuccessorsets = [] # successor set + markers
723 fullsuccessorsets = [] # successor set + markers
724 for sset in ssets:
724 for sset in ssets:
725 if sset:
725 if sset:
726 fullsuccessorsets.append(sset)
726 fullsuccessorsets.append(sset)
727 else:
727 else:
728 # successorsset return an empty set() when ctx or one of its
728 # successorsset return an empty set() when ctx or one of its
729 # successors is pruned.
729 # successors is pruned.
730 # In this case, walk the obs-markers tree again starting with ctx
730 # In this case, walk the obs-markers tree again starting with ctx
731 # and find the relevant pruning obs-makers, the ones without
731 # and find the relevant pruning obs-makers, the ones without
732 # successors.
732 # successors.
733 # Having these markers allow us to compute some information about
733 # Having these markers allow us to compute some information about
734 # its fate, like who pruned this changeset and when.
734 # its fate, like who pruned this changeset and when.
735
735
736 # XXX we do not catch all prune markers (eg rewritten then pruned)
736 # XXX we do not catch all prune markers (eg rewritten then pruned)
737 # (fix me later)
737 # (fix me later)
738 foundany = False
738 foundany = False
739 for mark in succsmap.get(ctx.node(), ()):
739 for mark in succsmap.get(ctx.node(), ()):
740 if not mark[1]:
740 if not mark[1]:
741 foundany = True
741 foundany = True
742 sset = _succs()
742 sset = _succs()
743 sset.markers.add(mark)
743 sset.markers.add(mark)
744 fullsuccessorsets.append(sset)
744 fullsuccessorsets.append(sset)
745 if not foundany:
745 if not foundany:
746 fullsuccessorsets.append(_succs())
746 fullsuccessorsets.append(_succs())
747
747
748 values = []
748 values = []
749 for sset in fullsuccessorsets:
749 for sset in fullsuccessorsets:
750 values.append({'successors': sset, 'markers': sset.markers})
750 values.append({'successors': sset, 'markers': sset.markers})
751
751
752 return values
752 return values
753
753
754 def successorsetverb(successorset):
754 def obsfateverb(successorset, markers):
755 """ Return the verb summarizing the successorset
755 """ Return the verb summarizing the successorset and potentially using
756 information from the markers
756 """
757 """
757 if not successorset:
758 if not successorset:
758 verb = 'pruned'
759 verb = 'pruned'
759 elif len(successorset) == 1:
760 elif len(successorset) == 1:
760 verb = 'rewritten'
761 verb = 'rewritten'
761 else:
762 else:
762 verb = 'split'
763 verb = 'split'
763 return verb
764 return verb
764
765
765 def markersdates(markers):
766 def markersdates(markers):
766 """returns the list of dates for a list of markers
767 """returns the list of dates for a list of markers
767 """
768 """
768 return [m[4] for m in markers]
769 return [m[4] for m in markers]
769
770
770 def markersusers(markers):
771 def markersusers(markers):
771 """ Returns a sorted list of markers users without duplicates
772 """ Returns a sorted list of markers users without duplicates
772 """
773 """
773 markersmeta = [dict(m[3]) for m in markers]
774 markersmeta = [dict(m[3]) for m in markers]
774 users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
775 users = set(meta.get('user') for meta in markersmeta if meta.get('user'))
775
776
776 return sorted(users)
777 return sorted(users)
777
778
778 def markersoperations(markers):
779 def markersoperations(markers):
779 """ Returns a sorted list of markers operations without duplicates
780 """ Returns a sorted list of markers operations without duplicates
780 """
781 """
781 markersmeta = [dict(m[3]) for m in markers]
782 markersmeta = [dict(m[3]) for m in markers]
782 operations = set(meta.get('operation') for meta in markersmeta
783 operations = set(meta.get('operation') for meta in markersmeta
783 if meta.get('operation'))
784 if meta.get('operation'))
784
785
785 return sorted(operations)
786 return sorted(operations)
786
787
787 def obsfateprinter(successors, markers, ui):
788 def obsfateprinter(successors, markers, ui):
788 """ Build a obsfate string for a single successorset using all obsfate
789 """ Build a obsfate string for a single successorset using all obsfate
789 related function defined in obsutil
790 related function defined in obsutil
790 """
791 """
791 quiet = ui.quiet
792 quiet = ui.quiet
792 verbose = ui.verbose
793 verbose = ui.verbose
793 normal = not verbose and not quiet
794 normal = not verbose and not quiet
794
795
795 line = []
796 line = []
796
797
797 # Verb
798 # Verb
798 line.append(successorsetverb(successors))
799 line.append(obsfateverb(successors, markers))
799
800
800 # Operations
801 # Operations
801 operations = markersoperations(markers)
802 operations = markersoperations(markers)
802 if operations:
803 if operations:
803 line.append(" using %s" % ", ".join(operations))
804 line.append(" using %s" % ", ".join(operations))
804
805
805 # Successors
806 # Successors
806 if successors:
807 if successors:
807 fmtsuccessors = [successors.joinfmt(succ) for succ in successors]
808 fmtsuccessors = [successors.joinfmt(succ) for succ in successors]
808 line.append(" as %s" % ", ".join(fmtsuccessors))
809 line.append(" as %s" % ", ".join(fmtsuccessors))
809
810
810 # Users
811 # Users
811 users = markersusers(markers)
812 users = markersusers(markers)
812 # Filter out current user in not verbose mode to reduce amount of
813 # Filter out current user in not verbose mode to reduce amount of
813 # information
814 # information
814 if not verbose:
815 if not verbose:
815 currentuser = ui.username(acceptempty=True)
816 currentuser = ui.username(acceptempty=True)
816 if len(users) == 1 and currentuser in users:
817 if len(users) == 1 and currentuser in users:
817 users = None
818 users = None
818
819
819 if (verbose or normal) and users:
820 if (verbose or normal) and users:
820 line.append(" by %s" % ", ".join(users))
821 line.append(" by %s" % ", ".join(users))
821
822
822 # Date
823 # Date
823 dates = markersdates(markers)
824 dates = markersdates(markers)
824
825
825 if dates and verbose:
826 if dates and verbose:
826 min_date = min(dates)
827 min_date = min(dates)
827 max_date = max(dates)
828 max_date = max(dates)
828
829
829 if min_date == max_date:
830 if min_date == max_date:
830 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
831 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
831 line.append(" (at %s)" % fmtmin_date)
832 line.append(" (at %s)" % fmtmin_date)
832 else:
833 else:
833 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
834 fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2')
834 fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2')
835 fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2')
835 line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date))
836 line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date))
836
837
837 return "".join(line)
838 return "".join(line)
@@ -1,1525 +1,1526 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 color,
16 color,
17 config,
17 config,
18 encoding,
18 encoding,
19 error,
19 error,
20 minirst,
20 minirst,
21 obsutil,
21 obsutil,
22 parser,
22 parser,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 revset as revsetmod,
25 revset as revsetmod,
26 revsetlang,
26 revsetlang,
27 scmutil,
27 scmutil,
28 templatefilters,
28 templatefilters,
29 templatekw,
29 templatekw,
30 util,
30 util,
31 )
31 )
32
32
33 # template parsing
33 # template parsing
34
34
35 elements = {
35 elements = {
36 # token-type: binding-strength, primary, prefix, infix, suffix
36 # token-type: binding-strength, primary, prefix, infix, suffix
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
38 ".": (18, None, None, (".", 18), None),
38 ".": (18, None, None, (".", 18), None),
39 "%": (15, None, None, ("%", 15), None),
39 "%": (15, None, None, ("%", 15), None),
40 "|": (15, None, None, ("|", 15), None),
40 "|": (15, None, None, ("|", 15), None),
41 "*": (5, None, None, ("*", 5), None),
41 "*": (5, None, None, ("*", 5), None),
42 "/": (5, None, None, ("/", 5), None),
42 "/": (5, None, None, ("/", 5), None),
43 "+": (4, None, None, ("+", 4), None),
43 "+": (4, None, None, ("+", 4), None),
44 "-": (4, None, ("negate", 19), ("-", 4), None),
44 "-": (4, None, ("negate", 19), ("-", 4), None),
45 "=": (3, None, None, ("keyvalue", 3), None),
45 "=": (3, None, None, ("keyvalue", 3), None),
46 ",": (2, None, None, ("list", 2), None),
46 ",": (2, None, None, ("list", 2), None),
47 ")": (0, None, None, None, None),
47 ")": (0, None, None, None, None),
48 "integer": (0, "integer", None, None, None),
48 "integer": (0, "integer", None, None, None),
49 "symbol": (0, "symbol", None, None, None),
49 "symbol": (0, "symbol", None, None, None),
50 "string": (0, "string", None, None, None),
50 "string": (0, "string", None, None, None),
51 "template": (0, "template", None, None, None),
51 "template": (0, "template", None, None, None),
52 "end": (0, None, None, None, None),
52 "end": (0, None, None, None, None),
53 }
53 }
54
54
55 def tokenize(program, start, end, term=None):
55 def tokenize(program, start, end, term=None):
56 """Parse a template expression into a stream of tokens, which must end
56 """Parse a template expression into a stream of tokens, which must end
57 with term if specified"""
57 with term if specified"""
58 pos = start
58 pos = start
59 program = pycompat.bytestr(program)
59 program = pycompat.bytestr(program)
60 while pos < end:
60 while pos < end:
61 c = program[pos]
61 c = program[pos]
62 if c.isspace(): # skip inter-token whitespace
62 if c.isspace(): # skip inter-token whitespace
63 pass
63 pass
64 elif c in "(=,).%|+-*/": # handle simple operators
64 elif c in "(=,).%|+-*/": # handle simple operators
65 yield (c, None, pos)
65 yield (c, None, pos)
66 elif c in '"\'': # handle quoted templates
66 elif c in '"\'': # handle quoted templates
67 s = pos + 1
67 s = pos + 1
68 data, pos = _parsetemplate(program, s, end, c)
68 data, pos = _parsetemplate(program, s, end, c)
69 yield ('template', data, s)
69 yield ('template', data, s)
70 pos -= 1
70 pos -= 1
71 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
71 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
72 # handle quoted strings
72 # handle quoted strings
73 c = program[pos + 1]
73 c = program[pos + 1]
74 s = pos = pos + 2
74 s = pos = pos + 2
75 while pos < end: # find closing quote
75 while pos < end: # find closing quote
76 d = program[pos]
76 d = program[pos]
77 if d == '\\': # skip over escaped characters
77 if d == '\\': # skip over escaped characters
78 pos += 2
78 pos += 2
79 continue
79 continue
80 if d == c:
80 if d == c:
81 yield ('string', program[s:pos], s)
81 yield ('string', program[s:pos], s)
82 break
82 break
83 pos += 1
83 pos += 1
84 else:
84 else:
85 raise error.ParseError(_("unterminated string"), s)
85 raise error.ParseError(_("unterminated string"), s)
86 elif c.isdigit():
86 elif c.isdigit():
87 s = pos
87 s = pos
88 while pos < end:
88 while pos < end:
89 d = program[pos]
89 d = program[pos]
90 if not d.isdigit():
90 if not d.isdigit():
91 break
91 break
92 pos += 1
92 pos += 1
93 yield ('integer', program[s:pos], s)
93 yield ('integer', program[s:pos], s)
94 pos -= 1
94 pos -= 1
95 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
95 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
96 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
96 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
97 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
97 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
98 # where some of nested templates were preprocessed as strings and
98 # where some of nested templates were preprocessed as strings and
99 # then compiled. therefore, \"...\" was allowed. (issue4733)
99 # then compiled. therefore, \"...\" was allowed. (issue4733)
100 #
100 #
101 # processing flow of _evalifliteral() at 5ab28a2e9962:
101 # processing flow of _evalifliteral() at 5ab28a2e9962:
102 # outer template string -> stringify() -> compiletemplate()
102 # outer template string -> stringify() -> compiletemplate()
103 # ------------------------ ------------ ------------------
103 # ------------------------ ------------ ------------------
104 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
104 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
105 # ~~~~~~~~
105 # ~~~~~~~~
106 # escaped quoted string
106 # escaped quoted string
107 if c == 'r':
107 if c == 'r':
108 pos += 1
108 pos += 1
109 token = 'string'
109 token = 'string'
110 else:
110 else:
111 token = 'template'
111 token = 'template'
112 quote = program[pos:pos + 2]
112 quote = program[pos:pos + 2]
113 s = pos = pos + 2
113 s = pos = pos + 2
114 while pos < end: # find closing escaped quote
114 while pos < end: # find closing escaped quote
115 if program.startswith('\\\\\\', pos, end):
115 if program.startswith('\\\\\\', pos, end):
116 pos += 4 # skip over double escaped characters
116 pos += 4 # skip over double escaped characters
117 continue
117 continue
118 if program.startswith(quote, pos, end):
118 if program.startswith(quote, pos, end):
119 # interpret as if it were a part of an outer string
119 # interpret as if it were a part of an outer string
120 data = parser.unescapestr(program[s:pos])
120 data = parser.unescapestr(program[s:pos])
121 if token == 'template':
121 if token == 'template':
122 data = _parsetemplate(data, 0, len(data))[0]
122 data = _parsetemplate(data, 0, len(data))[0]
123 yield (token, data, s)
123 yield (token, data, s)
124 pos += 1
124 pos += 1
125 break
125 break
126 pos += 1
126 pos += 1
127 else:
127 else:
128 raise error.ParseError(_("unterminated string"), s)
128 raise error.ParseError(_("unterminated string"), s)
129 elif c.isalnum() or c in '_':
129 elif c.isalnum() or c in '_':
130 s = pos
130 s = pos
131 pos += 1
131 pos += 1
132 while pos < end: # find end of symbol
132 while pos < end: # find end of symbol
133 d = program[pos]
133 d = program[pos]
134 if not (d.isalnum() or d == "_"):
134 if not (d.isalnum() or d == "_"):
135 break
135 break
136 pos += 1
136 pos += 1
137 sym = program[s:pos]
137 sym = program[s:pos]
138 yield ('symbol', sym, s)
138 yield ('symbol', sym, s)
139 pos -= 1
139 pos -= 1
140 elif c == term:
140 elif c == term:
141 yield ('end', None, pos + 1)
141 yield ('end', None, pos + 1)
142 return
142 return
143 else:
143 else:
144 raise error.ParseError(_("syntax error"), pos)
144 raise error.ParseError(_("syntax error"), pos)
145 pos += 1
145 pos += 1
146 if term:
146 if term:
147 raise error.ParseError(_("unterminated template expansion"), start)
147 raise error.ParseError(_("unterminated template expansion"), start)
148 yield ('end', None, pos)
148 yield ('end', None, pos)
149
149
150 def _parsetemplate(tmpl, start, stop, quote=''):
150 def _parsetemplate(tmpl, start, stop, quote=''):
151 r"""
151 r"""
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
152 >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
153 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
153 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
154 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
154 >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
155 ([('string', 'foo'), ('symbol', 'bar')], 9)
155 ([('string', 'foo'), ('symbol', 'bar')], 9)
156 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
156 >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
157 ([('string', 'foo')], 4)
157 ([('string', 'foo')], 4)
158 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
158 >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
159 ([('string', 'foo"'), ('string', 'bar')], 9)
159 ([('string', 'foo"'), ('string', 'bar')], 9)
160 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
160 >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
161 ([('string', 'foo\\')], 6)
161 ([('string', 'foo\\')], 6)
162 """
162 """
163 parsed = []
163 parsed = []
164 sepchars = '{' + quote
164 sepchars = '{' + quote
165 pos = start
165 pos = start
166 p = parser.parser(elements)
166 p = parser.parser(elements)
167 while pos < stop:
167 while pos < stop:
168 n = min((tmpl.find(c, pos, stop) for c in sepchars),
168 n = min((tmpl.find(c, pos, stop) for c in sepchars),
169 key=lambda n: (n < 0, n))
169 key=lambda n: (n < 0, n))
170 if n < 0:
170 if n < 0:
171 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
171 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
172 pos = stop
172 pos = stop
173 break
173 break
174 c = tmpl[n:n + 1]
174 c = tmpl[n:n + 1]
175 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
175 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
176 if bs % 2 == 1:
176 if bs % 2 == 1:
177 # escaped (e.g. '\{', '\\\{', but not '\\{')
177 # escaped (e.g. '\{', '\\\{', but not '\\{')
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
178 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
179 pos = n + 1
179 pos = n + 1
180 continue
180 continue
181 if n > pos:
181 if n > pos:
182 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
182 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
183 if c == quote:
183 if c == quote:
184 return parsed, n + 1
184 return parsed, n + 1
185
185
186 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
186 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
187 parsed.append(parseres)
187 parsed.append(parseres)
188
188
189 if quote:
189 if quote:
190 raise error.ParseError(_("unterminated string"), start)
190 raise error.ParseError(_("unterminated string"), start)
191 return parsed, pos
191 return parsed, pos
192
192
193 def _unnesttemplatelist(tree):
193 def _unnesttemplatelist(tree):
194 """Expand list of templates to node tuple
194 """Expand list of templates to node tuple
195
195
196 >>> def f(tree):
196 >>> def f(tree):
197 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
197 ... print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
198 >>> f((b'template', []))
198 >>> f((b'template', []))
199 (string '')
199 (string '')
200 >>> f((b'template', [(b'string', b'foo')]))
200 >>> f((b'template', [(b'string', b'foo')]))
201 (string 'foo')
201 (string 'foo')
202 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
202 >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
203 (template
203 (template
204 (string 'foo')
204 (string 'foo')
205 (symbol 'rev'))
205 (symbol 'rev'))
206 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
206 >>> f((b'template', [(b'symbol', b'rev')])) # template(rev) -> str
207 (template
207 (template
208 (symbol 'rev'))
208 (symbol 'rev'))
209 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
209 >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
210 (string 'foo')
210 (string 'foo')
211 """
211 """
212 if not isinstance(tree, tuple):
212 if not isinstance(tree, tuple):
213 return tree
213 return tree
214 op = tree[0]
214 op = tree[0]
215 if op != 'template':
215 if op != 'template':
216 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
216 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
217
217
218 assert len(tree) == 2
218 assert len(tree) == 2
219 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
219 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
220 if not xs:
220 if not xs:
221 return ('string', '') # empty template ""
221 return ('string', '') # empty template ""
222 elif len(xs) == 1 and xs[0][0] == 'string':
222 elif len(xs) == 1 and xs[0][0] == 'string':
223 return xs[0] # fast path for string with no template fragment "x"
223 return xs[0] # fast path for string with no template fragment "x"
224 else:
224 else:
225 return (op,) + xs
225 return (op,) + xs
226
226
227 def parse(tmpl):
227 def parse(tmpl):
228 """Parse template string into tree"""
228 """Parse template string into tree"""
229 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
229 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
230 assert pos == len(tmpl), 'unquoted template should be consumed'
230 assert pos == len(tmpl), 'unquoted template should be consumed'
231 return _unnesttemplatelist(('template', parsed))
231 return _unnesttemplatelist(('template', parsed))
232
232
233 def _parseexpr(expr):
233 def _parseexpr(expr):
234 """Parse a template expression into tree
234 """Parse a template expression into tree
235
235
236 >>> _parseexpr(b'"foo"')
236 >>> _parseexpr(b'"foo"')
237 ('string', 'foo')
237 ('string', 'foo')
238 >>> _parseexpr(b'foo(bar)')
238 >>> _parseexpr(b'foo(bar)')
239 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
239 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
240 >>> _parseexpr(b'foo(')
240 >>> _parseexpr(b'foo(')
241 Traceback (most recent call last):
241 Traceback (most recent call last):
242 ...
242 ...
243 ParseError: ('not a prefix: end', 4)
243 ParseError: ('not a prefix: end', 4)
244 >>> _parseexpr(b'"foo" "bar"')
244 >>> _parseexpr(b'"foo" "bar"')
245 Traceback (most recent call last):
245 Traceback (most recent call last):
246 ...
246 ...
247 ParseError: ('invalid token', 7)
247 ParseError: ('invalid token', 7)
248 """
248 """
249 p = parser.parser(elements)
249 p = parser.parser(elements)
250 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
250 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
251 if pos != len(expr):
251 if pos != len(expr):
252 raise error.ParseError(_('invalid token'), pos)
252 raise error.ParseError(_('invalid token'), pos)
253 return _unnesttemplatelist(tree)
253 return _unnesttemplatelist(tree)
254
254
255 def prettyformat(tree):
255 def prettyformat(tree):
256 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
256 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
257
257
258 def compileexp(exp, context, curmethods):
258 def compileexp(exp, context, curmethods):
259 """Compile parsed template tree to (func, data) pair"""
259 """Compile parsed template tree to (func, data) pair"""
260 t = exp[0]
260 t = exp[0]
261 if t in curmethods:
261 if t in curmethods:
262 return curmethods[t](exp, context)
262 return curmethods[t](exp, context)
263 raise error.ParseError(_("unknown method '%s'") % t)
263 raise error.ParseError(_("unknown method '%s'") % t)
264
264
265 # template evaluation
265 # template evaluation
266
266
267 def getsymbol(exp):
267 def getsymbol(exp):
268 if exp[0] == 'symbol':
268 if exp[0] == 'symbol':
269 return exp[1]
269 return exp[1]
270 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
270 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
271
271
272 def getlist(x):
272 def getlist(x):
273 if not x:
273 if not x:
274 return []
274 return []
275 if x[0] == 'list':
275 if x[0] == 'list':
276 return getlist(x[1]) + [x[2]]
276 return getlist(x[1]) + [x[2]]
277 return [x]
277 return [x]
278
278
279 def gettemplate(exp, context):
279 def gettemplate(exp, context):
280 """Compile given template tree or load named template from map file;
280 """Compile given template tree or load named template from map file;
281 returns (func, data) pair"""
281 returns (func, data) pair"""
282 if exp[0] in ('template', 'string'):
282 if exp[0] in ('template', 'string'):
283 return compileexp(exp, context, methods)
283 return compileexp(exp, context, methods)
284 if exp[0] == 'symbol':
284 if exp[0] == 'symbol':
285 # unlike runsymbol(), here 'symbol' is always taken as template name
285 # unlike runsymbol(), here 'symbol' is always taken as template name
286 # even if it exists in mapping. this allows us to override mapping
286 # even if it exists in mapping. this allows us to override mapping
287 # by web templates, e.g. 'changelogtag' is redefined in map file.
287 # by web templates, e.g. 'changelogtag' is redefined in map file.
288 return context._load(exp[1])
288 return context._load(exp[1])
289 raise error.ParseError(_("expected template specifier"))
289 raise error.ParseError(_("expected template specifier"))
290
290
291 def findsymbolicname(arg):
291 def findsymbolicname(arg):
292 """Find symbolic name for the given compiled expression; returns None
292 """Find symbolic name for the given compiled expression; returns None
293 if nothing found reliably"""
293 if nothing found reliably"""
294 while True:
294 while True:
295 func, data = arg
295 func, data = arg
296 if func is runsymbol:
296 if func is runsymbol:
297 return data
297 return data
298 elif func is runfilter:
298 elif func is runfilter:
299 arg = data[0]
299 arg = data[0]
300 else:
300 else:
301 return None
301 return None
302
302
303 def evalrawexp(context, mapping, arg):
303 def evalrawexp(context, mapping, arg):
304 """Evaluate given argument as a bare template object which may require
304 """Evaluate given argument as a bare template object which may require
305 further processing (such as folding generator of strings)"""
305 further processing (such as folding generator of strings)"""
306 func, data = arg
306 func, data = arg
307 return func(context, mapping, data)
307 return func(context, mapping, data)
308
308
309 def evalfuncarg(context, mapping, arg):
309 def evalfuncarg(context, mapping, arg):
310 """Evaluate given argument as value type"""
310 """Evaluate given argument as value type"""
311 thing = evalrawexp(context, mapping, arg)
311 thing = evalrawexp(context, mapping, arg)
312 thing = templatekw.unwrapvalue(thing)
312 thing = templatekw.unwrapvalue(thing)
313 # evalrawexp() may return string, generator of strings or arbitrary object
313 # evalrawexp() may return string, generator of strings or arbitrary object
314 # such as date tuple, but filter does not want generator.
314 # such as date tuple, but filter does not want generator.
315 if isinstance(thing, types.GeneratorType):
315 if isinstance(thing, types.GeneratorType):
316 thing = stringify(thing)
316 thing = stringify(thing)
317 return thing
317 return thing
318
318
319 def evalboolean(context, mapping, arg):
319 def evalboolean(context, mapping, arg):
320 """Evaluate given argument as boolean, but also takes boolean literals"""
320 """Evaluate given argument as boolean, but also takes boolean literals"""
321 func, data = arg
321 func, data = arg
322 if func is runsymbol:
322 if func is runsymbol:
323 thing = func(context, mapping, data, default=None)
323 thing = func(context, mapping, data, default=None)
324 if thing is None:
324 if thing is None:
325 # not a template keyword, takes as a boolean literal
325 # not a template keyword, takes as a boolean literal
326 thing = util.parsebool(data)
326 thing = util.parsebool(data)
327 else:
327 else:
328 thing = func(context, mapping, data)
328 thing = func(context, mapping, data)
329 thing = templatekw.unwrapvalue(thing)
329 thing = templatekw.unwrapvalue(thing)
330 if isinstance(thing, bool):
330 if isinstance(thing, bool):
331 return thing
331 return thing
332 # other objects are evaluated as strings, which means 0 is True, but
332 # other objects are evaluated as strings, which means 0 is True, but
333 # empty dict/list should be False as they are expected to be ''
333 # empty dict/list should be False as they are expected to be ''
334 return bool(stringify(thing))
334 return bool(stringify(thing))
335
335
336 def evalinteger(context, mapping, arg, err=None):
336 def evalinteger(context, mapping, arg, err=None):
337 v = evalfuncarg(context, mapping, arg)
337 v = evalfuncarg(context, mapping, arg)
338 try:
338 try:
339 return int(v)
339 return int(v)
340 except (TypeError, ValueError):
340 except (TypeError, ValueError):
341 raise error.ParseError(err or _('not an integer'))
341 raise error.ParseError(err or _('not an integer'))
342
342
343 def evalstring(context, mapping, arg):
343 def evalstring(context, mapping, arg):
344 return stringify(evalrawexp(context, mapping, arg))
344 return stringify(evalrawexp(context, mapping, arg))
345
345
346 def evalstringliteral(context, mapping, arg):
346 def evalstringliteral(context, mapping, arg):
347 """Evaluate given argument as string template, but returns symbol name
347 """Evaluate given argument as string template, but returns symbol name
348 if it is unknown"""
348 if it is unknown"""
349 func, data = arg
349 func, data = arg
350 if func is runsymbol:
350 if func is runsymbol:
351 thing = func(context, mapping, data, default=data)
351 thing = func(context, mapping, data, default=data)
352 else:
352 else:
353 thing = func(context, mapping, data)
353 thing = func(context, mapping, data)
354 return stringify(thing)
354 return stringify(thing)
355
355
356 _evalfuncbytype = {
356 _evalfuncbytype = {
357 bool: evalboolean,
357 bool: evalboolean,
358 bytes: evalstring,
358 bytes: evalstring,
359 int: evalinteger,
359 int: evalinteger,
360 }
360 }
361
361
362 def evalastype(context, mapping, arg, typ):
362 def evalastype(context, mapping, arg, typ):
363 """Evaluate given argument and coerce its type"""
363 """Evaluate given argument and coerce its type"""
364 try:
364 try:
365 f = _evalfuncbytype[typ]
365 f = _evalfuncbytype[typ]
366 except KeyError:
366 except KeyError:
367 raise error.ProgrammingError('invalid type specified: %r' % typ)
367 raise error.ProgrammingError('invalid type specified: %r' % typ)
368 return f(context, mapping, arg)
368 return f(context, mapping, arg)
369
369
370 def runinteger(context, mapping, data):
370 def runinteger(context, mapping, data):
371 return int(data)
371 return int(data)
372
372
373 def runstring(context, mapping, data):
373 def runstring(context, mapping, data):
374 return data
374 return data
375
375
376 def _recursivesymbolblocker(key):
376 def _recursivesymbolblocker(key):
377 def showrecursion(**args):
377 def showrecursion(**args):
378 raise error.Abort(_("recursive reference '%s' in template") % key)
378 raise error.Abort(_("recursive reference '%s' in template") % key)
379 return showrecursion
379 return showrecursion
380
380
381 def _runrecursivesymbol(context, mapping, key):
381 def _runrecursivesymbol(context, mapping, key):
382 raise error.Abort(_("recursive reference '%s' in template") % key)
382 raise error.Abort(_("recursive reference '%s' in template") % key)
383
383
384 def runsymbol(context, mapping, key, default=''):
384 def runsymbol(context, mapping, key, default=''):
385 v = mapping.get(key)
385 v = mapping.get(key)
386 if v is None:
386 if v is None:
387 v = context._defaults.get(key)
387 v = context._defaults.get(key)
388 if v is None:
388 if v is None:
389 # put poison to cut recursion. we can't move this to parsing phase
389 # put poison to cut recursion. we can't move this to parsing phase
390 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
390 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
391 safemapping = mapping.copy()
391 safemapping = mapping.copy()
392 safemapping[key] = _recursivesymbolblocker(key)
392 safemapping[key] = _recursivesymbolblocker(key)
393 try:
393 try:
394 v = context.process(key, safemapping)
394 v = context.process(key, safemapping)
395 except TemplateNotFound:
395 except TemplateNotFound:
396 v = default
396 v = default
397 if callable(v):
397 if callable(v):
398 return v(**pycompat.strkwargs(mapping))
398 return v(**pycompat.strkwargs(mapping))
399 return v
399 return v
400
400
401 def buildtemplate(exp, context):
401 def buildtemplate(exp, context):
402 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
402 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
403 return (runtemplate, ctmpl)
403 return (runtemplate, ctmpl)
404
404
405 def runtemplate(context, mapping, template):
405 def runtemplate(context, mapping, template):
406 for arg in template:
406 for arg in template:
407 yield evalrawexp(context, mapping, arg)
407 yield evalrawexp(context, mapping, arg)
408
408
409 def buildfilter(exp, context):
409 def buildfilter(exp, context):
410 n = getsymbol(exp[2])
410 n = getsymbol(exp[2])
411 if n in context._filters:
411 if n in context._filters:
412 filt = context._filters[n]
412 filt = context._filters[n]
413 arg = compileexp(exp[1], context, methods)
413 arg = compileexp(exp[1], context, methods)
414 return (runfilter, (arg, filt))
414 return (runfilter, (arg, filt))
415 if n in funcs:
415 if n in funcs:
416 f = funcs[n]
416 f = funcs[n]
417 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
417 args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
418 return (f, args)
418 return (f, args)
419 raise error.ParseError(_("unknown function '%s'") % n)
419 raise error.ParseError(_("unknown function '%s'") % n)
420
420
421 def runfilter(context, mapping, data):
421 def runfilter(context, mapping, data):
422 arg, filt = data
422 arg, filt = data
423 thing = evalfuncarg(context, mapping, arg)
423 thing = evalfuncarg(context, mapping, arg)
424 try:
424 try:
425 return filt(thing)
425 return filt(thing)
426 except (ValueError, AttributeError, TypeError):
426 except (ValueError, AttributeError, TypeError):
427 sym = findsymbolicname(arg)
427 sym = findsymbolicname(arg)
428 if sym:
428 if sym:
429 msg = (_("template filter '%s' is not compatible with keyword '%s'")
429 msg = (_("template filter '%s' is not compatible with keyword '%s'")
430 % (pycompat.sysbytes(filt.__name__), sym))
430 % (pycompat.sysbytes(filt.__name__), sym))
431 else:
431 else:
432 msg = (_("incompatible use of template filter '%s'")
432 msg = (_("incompatible use of template filter '%s'")
433 % pycompat.sysbytes(filt.__name__))
433 % pycompat.sysbytes(filt.__name__))
434 raise error.Abort(msg)
434 raise error.Abort(msg)
435
435
436 def buildmap(exp, context):
436 def buildmap(exp, context):
437 darg = compileexp(exp[1], context, methods)
437 darg = compileexp(exp[1], context, methods)
438 targ = gettemplate(exp[2], context)
438 targ = gettemplate(exp[2], context)
439 return (runmap, (darg, targ))
439 return (runmap, (darg, targ))
440
440
441 def runmap(context, mapping, data):
441 def runmap(context, mapping, data):
442 darg, targ = data
442 darg, targ = data
443 d = evalrawexp(context, mapping, darg)
443 d = evalrawexp(context, mapping, darg)
444 if util.safehasattr(d, 'itermaps'):
444 if util.safehasattr(d, 'itermaps'):
445 diter = d.itermaps()
445 diter = d.itermaps()
446 else:
446 else:
447 try:
447 try:
448 diter = iter(d)
448 diter = iter(d)
449 except TypeError:
449 except TypeError:
450 sym = findsymbolicname(darg)
450 sym = findsymbolicname(darg)
451 if sym:
451 if sym:
452 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
452 raise error.ParseError(_("keyword '%s' is not iterable") % sym)
453 else:
453 else:
454 raise error.ParseError(_("%r is not iterable") % d)
454 raise error.ParseError(_("%r is not iterable") % d)
455
455
456 for i, v in enumerate(diter):
456 for i, v in enumerate(diter):
457 lm = mapping.copy()
457 lm = mapping.copy()
458 lm['index'] = i
458 lm['index'] = i
459 if isinstance(v, dict):
459 if isinstance(v, dict):
460 lm.update(v)
460 lm.update(v)
461 lm['originalnode'] = mapping.get('node')
461 lm['originalnode'] = mapping.get('node')
462 yield evalrawexp(context, lm, targ)
462 yield evalrawexp(context, lm, targ)
463 else:
463 else:
464 # v is not an iterable of dicts, this happen when 'key'
464 # v is not an iterable of dicts, this happen when 'key'
465 # has been fully expanded already and format is useless.
465 # has been fully expanded already and format is useless.
466 # If so, return the expanded value.
466 # If so, return the expanded value.
467 yield v
467 yield v
468
468
469 def buildmember(exp, context):
469 def buildmember(exp, context):
470 darg = compileexp(exp[1], context, methods)
470 darg = compileexp(exp[1], context, methods)
471 memb = getsymbol(exp[2])
471 memb = getsymbol(exp[2])
472 return (runmember, (darg, memb))
472 return (runmember, (darg, memb))
473
473
474 def runmember(context, mapping, data):
474 def runmember(context, mapping, data):
475 darg, memb = data
475 darg, memb = data
476 d = evalrawexp(context, mapping, darg)
476 d = evalrawexp(context, mapping, darg)
477 if util.safehasattr(d, 'tomap'):
477 if util.safehasattr(d, 'tomap'):
478 lm = mapping.copy()
478 lm = mapping.copy()
479 lm.update(d.tomap())
479 lm.update(d.tomap())
480 return runsymbol(context, lm, memb)
480 return runsymbol(context, lm, memb)
481 if util.safehasattr(d, 'get'):
481 if util.safehasattr(d, 'get'):
482 return _getdictitem(d, memb)
482 return _getdictitem(d, memb)
483
483
484 sym = findsymbolicname(darg)
484 sym = findsymbolicname(darg)
485 if sym:
485 if sym:
486 raise error.ParseError(_("keyword '%s' has no member") % sym)
486 raise error.ParseError(_("keyword '%s' has no member") % sym)
487 else:
487 else:
488 raise error.ParseError(_("%r has no member") % d)
488 raise error.ParseError(_("%r has no member") % d)
489
489
490 def buildnegate(exp, context):
490 def buildnegate(exp, context):
491 arg = compileexp(exp[1], context, exprmethods)
491 arg = compileexp(exp[1], context, exprmethods)
492 return (runnegate, arg)
492 return (runnegate, arg)
493
493
494 def runnegate(context, mapping, data):
494 def runnegate(context, mapping, data):
495 data = evalinteger(context, mapping, data,
495 data = evalinteger(context, mapping, data,
496 _('negation needs an integer argument'))
496 _('negation needs an integer argument'))
497 return -data
497 return -data
498
498
499 def buildarithmetic(exp, context, func):
499 def buildarithmetic(exp, context, func):
500 left = compileexp(exp[1], context, exprmethods)
500 left = compileexp(exp[1], context, exprmethods)
501 right = compileexp(exp[2], context, exprmethods)
501 right = compileexp(exp[2], context, exprmethods)
502 return (runarithmetic, (func, left, right))
502 return (runarithmetic, (func, left, right))
503
503
504 def runarithmetic(context, mapping, data):
504 def runarithmetic(context, mapping, data):
505 func, left, right = data
505 func, left, right = data
506 left = evalinteger(context, mapping, left,
506 left = evalinteger(context, mapping, left,
507 _('arithmetic only defined on integers'))
507 _('arithmetic only defined on integers'))
508 right = evalinteger(context, mapping, right,
508 right = evalinteger(context, mapping, right,
509 _('arithmetic only defined on integers'))
509 _('arithmetic only defined on integers'))
510 try:
510 try:
511 return func(left, right)
511 return func(left, right)
512 except ZeroDivisionError:
512 except ZeroDivisionError:
513 raise error.Abort(_('division by zero is not defined'))
513 raise error.Abort(_('division by zero is not defined'))
514
514
515 def buildfunc(exp, context):
515 def buildfunc(exp, context):
516 n = getsymbol(exp[1])
516 n = getsymbol(exp[1])
517 if n in funcs:
517 if n in funcs:
518 f = funcs[n]
518 f = funcs[n]
519 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
519 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
520 return (f, args)
520 return (f, args)
521 if n in context._filters:
521 if n in context._filters:
522 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
522 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
523 if len(args) != 1:
523 if len(args) != 1:
524 raise error.ParseError(_("filter %s expects one argument") % n)
524 raise error.ParseError(_("filter %s expects one argument") % n)
525 f = context._filters[n]
525 f = context._filters[n]
526 return (runfilter, (args[0], f))
526 return (runfilter, (args[0], f))
527 raise error.ParseError(_("unknown function '%s'") % n)
527 raise error.ParseError(_("unknown function '%s'") % n)
528
528
529 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
529 def _buildfuncargs(exp, context, curmethods, funcname, argspec):
530 """Compile parsed tree of function arguments into list or dict of
530 """Compile parsed tree of function arguments into list or dict of
531 (func, data) pairs
531 (func, data) pairs
532
532
533 >>> context = engine(lambda t: (runsymbol, t))
533 >>> context = engine(lambda t: (runsymbol, t))
534 >>> def fargs(expr, argspec):
534 >>> def fargs(expr, argspec):
535 ... x = _parseexpr(expr)
535 ... x = _parseexpr(expr)
536 ... n = getsymbol(x[1])
536 ... n = getsymbol(x[1])
537 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
537 ... return _buildfuncargs(x[2], context, exprmethods, n, argspec)
538 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
538 >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
539 ['l', 'k']
539 ['l', 'k']
540 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
540 >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
541 >>> list(args.keys()), list(args[b'opts'].keys())
541 >>> list(args.keys()), list(args[b'opts'].keys())
542 (['opts'], ['opts', 'k'])
542 (['opts'], ['opts', 'k'])
543 """
543 """
544 def compiledict(xs):
544 def compiledict(xs):
545 return util.sortdict((k, compileexp(x, context, curmethods))
545 return util.sortdict((k, compileexp(x, context, curmethods))
546 for k, x in xs.iteritems())
546 for k, x in xs.iteritems())
547 def compilelist(xs):
547 def compilelist(xs):
548 return [compileexp(x, context, curmethods) for x in xs]
548 return [compileexp(x, context, curmethods) for x in xs]
549
549
550 if not argspec:
550 if not argspec:
551 # filter or function with no argspec: return list of positional args
551 # filter or function with no argspec: return list of positional args
552 return compilelist(getlist(exp))
552 return compilelist(getlist(exp))
553
553
554 # function with argspec: return dict of named args
554 # function with argspec: return dict of named args
555 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
555 _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
556 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
556 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
557 keyvaluenode='keyvalue', keynode='symbol')
557 keyvaluenode='keyvalue', keynode='symbol')
558 compargs = util.sortdict()
558 compargs = util.sortdict()
559 if varkey:
559 if varkey:
560 compargs[varkey] = compilelist(treeargs.pop(varkey))
560 compargs[varkey] = compilelist(treeargs.pop(varkey))
561 if optkey:
561 if optkey:
562 compargs[optkey] = compiledict(treeargs.pop(optkey))
562 compargs[optkey] = compiledict(treeargs.pop(optkey))
563 compargs.update(compiledict(treeargs))
563 compargs.update(compiledict(treeargs))
564 return compargs
564 return compargs
565
565
566 def buildkeyvaluepair(exp, content):
566 def buildkeyvaluepair(exp, content):
567 raise error.ParseError(_("can't use a key-value pair in this context"))
567 raise error.ParseError(_("can't use a key-value pair in this context"))
568
568
569 # dict of template built-in functions
569 # dict of template built-in functions
570 funcs = {}
570 funcs = {}
571
571
572 templatefunc = registrar.templatefunc(funcs)
572 templatefunc = registrar.templatefunc(funcs)
573
573
574 @templatefunc('date(date[, fmt])')
574 @templatefunc('date(date[, fmt])')
575 def date(context, mapping, args):
575 def date(context, mapping, args):
576 """Format a date. See :hg:`help dates` for formatting
576 """Format a date. See :hg:`help dates` for formatting
577 strings. The default is a Unix date format, including the timezone:
577 strings. The default is a Unix date format, including the timezone:
578 "Mon Sep 04 15:13:13 2006 0700"."""
578 "Mon Sep 04 15:13:13 2006 0700"."""
579 if not (1 <= len(args) <= 2):
579 if not (1 <= len(args) <= 2):
580 # i18n: "date" is a keyword
580 # i18n: "date" is a keyword
581 raise error.ParseError(_("date expects one or two arguments"))
581 raise error.ParseError(_("date expects one or two arguments"))
582
582
583 date = evalfuncarg(context, mapping, args[0])
583 date = evalfuncarg(context, mapping, args[0])
584 fmt = None
584 fmt = None
585 if len(args) == 2:
585 if len(args) == 2:
586 fmt = evalstring(context, mapping, args[1])
586 fmt = evalstring(context, mapping, args[1])
587 try:
587 try:
588 if fmt is None:
588 if fmt is None:
589 return util.datestr(date)
589 return util.datestr(date)
590 else:
590 else:
591 return util.datestr(date, fmt)
591 return util.datestr(date, fmt)
592 except (TypeError, ValueError):
592 except (TypeError, ValueError):
593 # i18n: "date" is a keyword
593 # i18n: "date" is a keyword
594 raise error.ParseError(_("date expects a date information"))
594 raise error.ParseError(_("date expects a date information"))
595
595
596 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
596 @templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
597 def dict_(context, mapping, args):
597 def dict_(context, mapping, args):
598 """Construct a dict from key-value pairs. A key may be omitted if
598 """Construct a dict from key-value pairs. A key may be omitted if
599 a value expression can provide an unambiguous name."""
599 a value expression can provide an unambiguous name."""
600 data = util.sortdict()
600 data = util.sortdict()
601
601
602 for v in args['args']:
602 for v in args['args']:
603 k = findsymbolicname(v)
603 k = findsymbolicname(v)
604 if not k:
604 if not k:
605 raise error.ParseError(_('dict key cannot be inferred'))
605 raise error.ParseError(_('dict key cannot be inferred'))
606 if k in data or k in args['kwargs']:
606 if k in data or k in args['kwargs']:
607 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
607 raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
608 data[k] = evalfuncarg(context, mapping, v)
608 data[k] = evalfuncarg(context, mapping, v)
609
609
610 data.update((k, evalfuncarg(context, mapping, v))
610 data.update((k, evalfuncarg(context, mapping, v))
611 for k, v in args['kwargs'].iteritems())
611 for k, v in args['kwargs'].iteritems())
612 return templatekw.hybriddict(data)
612 return templatekw.hybriddict(data)
613
613
614 @templatefunc('diff([includepattern [, excludepattern]])')
614 @templatefunc('diff([includepattern [, excludepattern]])')
615 def diff(context, mapping, args):
615 def diff(context, mapping, args):
616 """Show a diff, optionally
616 """Show a diff, optionally
617 specifying files to include or exclude."""
617 specifying files to include or exclude."""
618 if len(args) > 2:
618 if len(args) > 2:
619 # i18n: "diff" is a keyword
619 # i18n: "diff" is a keyword
620 raise error.ParseError(_("diff expects zero, one, or two arguments"))
620 raise error.ParseError(_("diff expects zero, one, or two arguments"))
621
621
622 def getpatterns(i):
622 def getpatterns(i):
623 if i < len(args):
623 if i < len(args):
624 s = evalstring(context, mapping, args[i]).strip()
624 s = evalstring(context, mapping, args[i]).strip()
625 if s:
625 if s:
626 return [s]
626 return [s]
627 return []
627 return []
628
628
629 ctx = mapping['ctx']
629 ctx = mapping['ctx']
630 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
630 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
631
631
632 return ''.join(chunks)
632 return ''.join(chunks)
633
633
634 @templatefunc('extdata(source)', argspec='source')
634 @templatefunc('extdata(source)', argspec='source')
635 def extdata(context, mapping, args):
635 def extdata(context, mapping, args):
636 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
636 """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
637 if 'source' not in args:
637 if 'source' not in args:
638 # i18n: "extdata" is a keyword
638 # i18n: "extdata" is a keyword
639 raise error.ParseError(_('extdata expects one argument'))
639 raise error.ParseError(_('extdata expects one argument'))
640
640
641 source = evalstring(context, mapping, args['source'])
641 source = evalstring(context, mapping, args['source'])
642 cache = mapping['cache'].setdefault('extdata', {})
642 cache = mapping['cache'].setdefault('extdata', {})
643 ctx = mapping['ctx']
643 ctx = mapping['ctx']
644 if source in cache:
644 if source in cache:
645 data = cache[source]
645 data = cache[source]
646 else:
646 else:
647 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
647 data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
648 return data.get(ctx.rev(), '')
648 return data.get(ctx.rev(), '')
649
649
650 @templatefunc('files(pattern)')
650 @templatefunc('files(pattern)')
651 def files(context, mapping, args):
651 def files(context, mapping, args):
652 """All files of the current changeset matching the pattern. See
652 """All files of the current changeset matching the pattern. See
653 :hg:`help patterns`."""
653 :hg:`help patterns`."""
654 if not len(args) == 1:
654 if not len(args) == 1:
655 # i18n: "files" is a keyword
655 # i18n: "files" is a keyword
656 raise error.ParseError(_("files expects one argument"))
656 raise error.ParseError(_("files expects one argument"))
657
657
658 raw = evalstring(context, mapping, args[0])
658 raw = evalstring(context, mapping, args[0])
659 ctx = mapping['ctx']
659 ctx = mapping['ctx']
660 m = ctx.match([raw])
660 m = ctx.match([raw])
661 files = list(ctx.matches(m))
661 files = list(ctx.matches(m))
662 return templatekw.showlist("file", files, mapping)
662 return templatekw.showlist("file", files, mapping)
663
663
664 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
664 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
665 def fill(context, mapping, args):
665 def fill(context, mapping, args):
666 """Fill many
666 """Fill many
667 paragraphs with optional indentation. See the "fill" filter."""
667 paragraphs with optional indentation. See the "fill" filter."""
668 if not (1 <= len(args) <= 4):
668 if not (1 <= len(args) <= 4):
669 # i18n: "fill" is a keyword
669 # i18n: "fill" is a keyword
670 raise error.ParseError(_("fill expects one to four arguments"))
670 raise error.ParseError(_("fill expects one to four arguments"))
671
671
672 text = evalstring(context, mapping, args[0])
672 text = evalstring(context, mapping, args[0])
673 width = 76
673 width = 76
674 initindent = ''
674 initindent = ''
675 hangindent = ''
675 hangindent = ''
676 if 2 <= len(args) <= 4:
676 if 2 <= len(args) <= 4:
677 width = evalinteger(context, mapping, args[1],
677 width = evalinteger(context, mapping, args[1],
678 # i18n: "fill" is a keyword
678 # i18n: "fill" is a keyword
679 _("fill expects an integer width"))
679 _("fill expects an integer width"))
680 try:
680 try:
681 initindent = evalstring(context, mapping, args[2])
681 initindent = evalstring(context, mapping, args[2])
682 hangindent = evalstring(context, mapping, args[3])
682 hangindent = evalstring(context, mapping, args[3])
683 except IndexError:
683 except IndexError:
684 pass
684 pass
685
685
686 return templatefilters.fill(text, width, initindent, hangindent)
686 return templatefilters.fill(text, width, initindent, hangindent)
687
687
688 @templatefunc('formatnode(node)')
688 @templatefunc('formatnode(node)')
689 def formatnode(context, mapping, args):
689 def formatnode(context, mapping, args):
690 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
690 """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
691 if len(args) != 1:
691 if len(args) != 1:
692 # i18n: "formatnode" is a keyword
692 # i18n: "formatnode" is a keyword
693 raise error.ParseError(_("formatnode expects one argument"))
693 raise error.ParseError(_("formatnode expects one argument"))
694
694
695 ui = mapping['ui']
695 ui = mapping['ui']
696 node = evalstring(context, mapping, args[0])
696 node = evalstring(context, mapping, args[0])
697 if ui.debugflag:
697 if ui.debugflag:
698 return node
698 return node
699 return templatefilters.short(node)
699 return templatefilters.short(node)
700
700
701 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
701 @templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
702 argspec='text width fillchar left')
702 argspec='text width fillchar left')
703 def pad(context, mapping, args):
703 def pad(context, mapping, args):
704 """Pad text with a
704 """Pad text with a
705 fill character."""
705 fill character."""
706 if 'text' not in args or 'width' not in args:
706 if 'text' not in args or 'width' not in args:
707 # i18n: "pad" is a keyword
707 # i18n: "pad" is a keyword
708 raise error.ParseError(_("pad() expects two to four arguments"))
708 raise error.ParseError(_("pad() expects two to four arguments"))
709
709
710 width = evalinteger(context, mapping, args['width'],
710 width = evalinteger(context, mapping, args['width'],
711 # i18n: "pad" is a keyword
711 # i18n: "pad" is a keyword
712 _("pad() expects an integer width"))
712 _("pad() expects an integer width"))
713
713
714 text = evalstring(context, mapping, args['text'])
714 text = evalstring(context, mapping, args['text'])
715
715
716 left = False
716 left = False
717 fillchar = ' '
717 fillchar = ' '
718 if 'fillchar' in args:
718 if 'fillchar' in args:
719 fillchar = evalstring(context, mapping, args['fillchar'])
719 fillchar = evalstring(context, mapping, args['fillchar'])
720 if len(color.stripeffects(fillchar)) != 1:
720 if len(color.stripeffects(fillchar)) != 1:
721 # i18n: "pad" is a keyword
721 # i18n: "pad" is a keyword
722 raise error.ParseError(_("pad() expects a single fill character"))
722 raise error.ParseError(_("pad() expects a single fill character"))
723 if 'left' in args:
723 if 'left' in args:
724 left = evalboolean(context, mapping, args['left'])
724 left = evalboolean(context, mapping, args['left'])
725
725
726 fillwidth = width - encoding.colwidth(color.stripeffects(text))
726 fillwidth = width - encoding.colwidth(color.stripeffects(text))
727 if fillwidth <= 0:
727 if fillwidth <= 0:
728 return text
728 return text
729 if left:
729 if left:
730 return fillchar * fillwidth + text
730 return fillchar * fillwidth + text
731 else:
731 else:
732 return text + fillchar * fillwidth
732 return text + fillchar * fillwidth
733
733
734 @templatefunc('indent(text, indentchars[, firstline])')
734 @templatefunc('indent(text, indentchars[, firstline])')
735 def indent(context, mapping, args):
735 def indent(context, mapping, args):
736 """Indents all non-empty lines
736 """Indents all non-empty lines
737 with the characters given in the indentchars string. An optional
737 with the characters given in the indentchars string. An optional
738 third parameter will override the indent for the first line only
738 third parameter will override the indent for the first line only
739 if present."""
739 if present."""
740 if not (2 <= len(args) <= 3):
740 if not (2 <= len(args) <= 3):
741 # i18n: "indent" is a keyword
741 # i18n: "indent" is a keyword
742 raise error.ParseError(_("indent() expects two or three arguments"))
742 raise error.ParseError(_("indent() expects two or three arguments"))
743
743
744 text = evalstring(context, mapping, args[0])
744 text = evalstring(context, mapping, args[0])
745 indent = evalstring(context, mapping, args[1])
745 indent = evalstring(context, mapping, args[1])
746
746
747 if len(args) == 3:
747 if len(args) == 3:
748 firstline = evalstring(context, mapping, args[2])
748 firstline = evalstring(context, mapping, args[2])
749 else:
749 else:
750 firstline = indent
750 firstline = indent
751
751
752 # the indent function doesn't indent the first line, so we do it here
752 # the indent function doesn't indent the first line, so we do it here
753 return templatefilters.indent(firstline + text, indent)
753 return templatefilters.indent(firstline + text, indent)
754
754
755 @templatefunc('get(dict, key)')
755 @templatefunc('get(dict, key)')
756 def get(context, mapping, args):
756 def get(context, mapping, args):
757 """Get an attribute/key from an object. Some keywords
757 """Get an attribute/key from an object. Some keywords
758 are complex types. This function allows you to obtain the value of an
758 are complex types. This function allows you to obtain the value of an
759 attribute on these types."""
759 attribute on these types."""
760 if len(args) != 2:
760 if len(args) != 2:
761 # i18n: "get" is a keyword
761 # i18n: "get" is a keyword
762 raise error.ParseError(_("get() expects two arguments"))
762 raise error.ParseError(_("get() expects two arguments"))
763
763
764 dictarg = evalfuncarg(context, mapping, args[0])
764 dictarg = evalfuncarg(context, mapping, args[0])
765 if not util.safehasattr(dictarg, 'get'):
765 if not util.safehasattr(dictarg, 'get'):
766 # i18n: "get" is a keyword
766 # i18n: "get" is a keyword
767 raise error.ParseError(_("get() expects a dict as first argument"))
767 raise error.ParseError(_("get() expects a dict as first argument"))
768
768
769 key = evalfuncarg(context, mapping, args[1])
769 key = evalfuncarg(context, mapping, args[1])
770 return _getdictitem(dictarg, key)
770 return _getdictitem(dictarg, key)
771
771
772 def _getdictitem(dictarg, key):
772 def _getdictitem(dictarg, key):
773 val = dictarg.get(key)
773 val = dictarg.get(key)
774 if val is None:
774 if val is None:
775 return
775 return
776 return templatekw.wraphybridvalue(dictarg, key, val)
776 return templatekw.wraphybridvalue(dictarg, key, val)
777
777
778 @templatefunc('if(expr, then[, else])')
778 @templatefunc('if(expr, then[, else])')
779 def if_(context, mapping, args):
779 def if_(context, mapping, args):
780 """Conditionally execute based on the result of
780 """Conditionally execute based on the result of
781 an expression."""
781 an expression."""
782 if not (2 <= len(args) <= 3):
782 if not (2 <= len(args) <= 3):
783 # i18n: "if" is a keyword
783 # i18n: "if" is a keyword
784 raise error.ParseError(_("if expects two or three arguments"))
784 raise error.ParseError(_("if expects two or three arguments"))
785
785
786 test = evalboolean(context, mapping, args[0])
786 test = evalboolean(context, mapping, args[0])
787 if test:
787 if test:
788 yield evalrawexp(context, mapping, args[1])
788 yield evalrawexp(context, mapping, args[1])
789 elif len(args) == 3:
789 elif len(args) == 3:
790 yield evalrawexp(context, mapping, args[2])
790 yield evalrawexp(context, mapping, args[2])
791
791
792 @templatefunc('ifcontains(needle, haystack, then[, else])')
792 @templatefunc('ifcontains(needle, haystack, then[, else])')
793 def ifcontains(context, mapping, args):
793 def ifcontains(context, mapping, args):
794 """Conditionally execute based
794 """Conditionally execute based
795 on whether the item "needle" is in "haystack"."""
795 on whether the item "needle" is in "haystack"."""
796 if not (3 <= len(args) <= 4):
796 if not (3 <= len(args) <= 4):
797 # i18n: "ifcontains" is a keyword
797 # i18n: "ifcontains" is a keyword
798 raise error.ParseError(_("ifcontains expects three or four arguments"))
798 raise error.ParseError(_("ifcontains expects three or four arguments"))
799
799
800 haystack = evalfuncarg(context, mapping, args[1])
800 haystack = evalfuncarg(context, mapping, args[1])
801 try:
801 try:
802 needle = evalastype(context, mapping, args[0],
802 needle = evalastype(context, mapping, args[0],
803 getattr(haystack, 'keytype', None) or bytes)
803 getattr(haystack, 'keytype', None) or bytes)
804 found = (needle in haystack)
804 found = (needle in haystack)
805 except error.ParseError:
805 except error.ParseError:
806 found = False
806 found = False
807
807
808 if found:
808 if found:
809 yield evalrawexp(context, mapping, args[2])
809 yield evalrawexp(context, mapping, args[2])
810 elif len(args) == 4:
810 elif len(args) == 4:
811 yield evalrawexp(context, mapping, args[3])
811 yield evalrawexp(context, mapping, args[3])
812
812
813 @templatefunc('ifeq(expr1, expr2, then[, else])')
813 @templatefunc('ifeq(expr1, expr2, then[, else])')
814 def ifeq(context, mapping, args):
814 def ifeq(context, mapping, args):
815 """Conditionally execute based on
815 """Conditionally execute based on
816 whether 2 items are equivalent."""
816 whether 2 items are equivalent."""
817 if not (3 <= len(args) <= 4):
817 if not (3 <= len(args) <= 4):
818 # i18n: "ifeq" is a keyword
818 # i18n: "ifeq" is a keyword
819 raise error.ParseError(_("ifeq expects three or four arguments"))
819 raise error.ParseError(_("ifeq expects three or four arguments"))
820
820
821 test = evalstring(context, mapping, args[0])
821 test = evalstring(context, mapping, args[0])
822 match = evalstring(context, mapping, args[1])
822 match = evalstring(context, mapping, args[1])
823 if test == match:
823 if test == match:
824 yield evalrawexp(context, mapping, args[2])
824 yield evalrawexp(context, mapping, args[2])
825 elif len(args) == 4:
825 elif len(args) == 4:
826 yield evalrawexp(context, mapping, args[3])
826 yield evalrawexp(context, mapping, args[3])
827
827
828 @templatefunc('join(list, sep)')
828 @templatefunc('join(list, sep)')
829 def join(context, mapping, args):
829 def join(context, mapping, args):
830 """Join items in a list with a delimiter."""
830 """Join items in a list with a delimiter."""
831 if not (1 <= len(args) <= 2):
831 if not (1 <= len(args) <= 2):
832 # i18n: "join" is a keyword
832 # i18n: "join" is a keyword
833 raise error.ParseError(_("join expects one or two arguments"))
833 raise error.ParseError(_("join expects one or two arguments"))
834
834
835 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
835 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
836 # abuses generator as a keyword that returns a list of dicts.
836 # abuses generator as a keyword that returns a list of dicts.
837 joinset = evalrawexp(context, mapping, args[0])
837 joinset = evalrawexp(context, mapping, args[0])
838 joinset = templatekw.unwrapvalue(joinset)
838 joinset = templatekw.unwrapvalue(joinset)
839 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
839 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
840 joiner = " "
840 joiner = " "
841 if len(args) > 1:
841 if len(args) > 1:
842 joiner = evalstring(context, mapping, args[1])
842 joiner = evalstring(context, mapping, args[1])
843
843
844 first = True
844 first = True
845 for x in joinset:
845 for x in joinset:
846 if first:
846 if first:
847 first = False
847 first = False
848 else:
848 else:
849 yield joiner
849 yield joiner
850 yield joinfmt(x)
850 yield joinfmt(x)
851
851
852 @templatefunc('label(label, expr)')
852 @templatefunc('label(label, expr)')
853 def label(context, mapping, args):
853 def label(context, mapping, args):
854 """Apply a label to generated content. Content with
854 """Apply a label to generated content. Content with
855 a label applied can result in additional post-processing, such as
855 a label applied can result in additional post-processing, such as
856 automatic colorization."""
856 automatic colorization."""
857 if len(args) != 2:
857 if len(args) != 2:
858 # i18n: "label" is a keyword
858 # i18n: "label" is a keyword
859 raise error.ParseError(_("label expects two arguments"))
859 raise error.ParseError(_("label expects two arguments"))
860
860
861 ui = mapping['ui']
861 ui = mapping['ui']
862 thing = evalstring(context, mapping, args[1])
862 thing = evalstring(context, mapping, args[1])
863 # preserve unknown symbol as literal so effects like 'red', 'bold',
863 # preserve unknown symbol as literal so effects like 'red', 'bold',
864 # etc. don't need to be quoted
864 # etc. don't need to be quoted
865 label = evalstringliteral(context, mapping, args[0])
865 label = evalstringliteral(context, mapping, args[0])
866
866
867 return ui.label(thing, label)
867 return ui.label(thing, label)
868
868
869 @templatefunc('latesttag([pattern])')
869 @templatefunc('latesttag([pattern])')
870 def latesttag(context, mapping, args):
870 def latesttag(context, mapping, args):
871 """The global tags matching the given pattern on the
871 """The global tags matching the given pattern on the
872 most recent globally tagged ancestor of this changeset.
872 most recent globally tagged ancestor of this changeset.
873 If no such tags exist, the "{tag}" template resolves to
873 If no such tags exist, the "{tag}" template resolves to
874 the string "null"."""
874 the string "null"."""
875 if len(args) > 1:
875 if len(args) > 1:
876 # i18n: "latesttag" is a keyword
876 # i18n: "latesttag" is a keyword
877 raise error.ParseError(_("latesttag expects at most one argument"))
877 raise error.ParseError(_("latesttag expects at most one argument"))
878
878
879 pattern = None
879 pattern = None
880 if len(args) == 1:
880 if len(args) == 1:
881 pattern = evalstring(context, mapping, args[0])
881 pattern = evalstring(context, mapping, args[0])
882
882
883 return templatekw.showlatesttags(pattern, **mapping)
883 return templatekw.showlatesttags(pattern, **mapping)
884
884
885 @templatefunc('localdate(date[, tz])')
885 @templatefunc('localdate(date[, tz])')
886 def localdate(context, mapping, args):
886 def localdate(context, mapping, args):
887 """Converts a date to the specified timezone.
887 """Converts a date to the specified timezone.
888 The default is local date."""
888 The default is local date."""
889 if not (1 <= len(args) <= 2):
889 if not (1 <= len(args) <= 2):
890 # i18n: "localdate" is a keyword
890 # i18n: "localdate" is a keyword
891 raise error.ParseError(_("localdate expects one or two arguments"))
891 raise error.ParseError(_("localdate expects one or two arguments"))
892
892
893 date = evalfuncarg(context, mapping, args[0])
893 date = evalfuncarg(context, mapping, args[0])
894 try:
894 try:
895 date = util.parsedate(date)
895 date = util.parsedate(date)
896 except AttributeError: # not str nor date tuple
896 except AttributeError: # not str nor date tuple
897 # i18n: "localdate" is a keyword
897 # i18n: "localdate" is a keyword
898 raise error.ParseError(_("localdate expects a date information"))
898 raise error.ParseError(_("localdate expects a date information"))
899 if len(args) >= 2:
899 if len(args) >= 2:
900 tzoffset = None
900 tzoffset = None
901 tz = evalfuncarg(context, mapping, args[1])
901 tz = evalfuncarg(context, mapping, args[1])
902 if isinstance(tz, str):
902 if isinstance(tz, str):
903 tzoffset, remainder = util.parsetimezone(tz)
903 tzoffset, remainder = util.parsetimezone(tz)
904 if remainder:
904 if remainder:
905 tzoffset = None
905 tzoffset = None
906 if tzoffset is None:
906 if tzoffset is None:
907 try:
907 try:
908 tzoffset = int(tz)
908 tzoffset = int(tz)
909 except (TypeError, ValueError):
909 except (TypeError, ValueError):
910 # i18n: "localdate" is a keyword
910 # i18n: "localdate" is a keyword
911 raise error.ParseError(_("localdate expects a timezone"))
911 raise error.ParseError(_("localdate expects a timezone"))
912 else:
912 else:
913 tzoffset = util.makedate()[1]
913 tzoffset = util.makedate()[1]
914 return (date[0], tzoffset)
914 return (date[0], tzoffset)
915
915
916 @templatefunc('max(iterable)')
916 @templatefunc('max(iterable)')
917 def max_(context, mapping, args, **kwargs):
917 def max_(context, mapping, args, **kwargs):
918 """Return the max of an iterable"""
918 """Return the max of an iterable"""
919 if len(args) != 1:
919 if len(args) != 1:
920 # i18n: "max" is a keyword
920 # i18n: "max" is a keyword
921 raise error.ParseError(_("max expects one arguments"))
921 raise error.ParseError(_("max expects one arguments"))
922
922
923 iterable = evalfuncarg(context, mapping, args[0])
923 iterable = evalfuncarg(context, mapping, args[0])
924 try:
924 try:
925 x = max(iterable)
925 x = max(iterable)
926 except (TypeError, ValueError):
926 except (TypeError, ValueError):
927 # i18n: "max" is a keyword
927 # i18n: "max" is a keyword
928 raise error.ParseError(_("max first argument should be an iterable"))
928 raise error.ParseError(_("max first argument should be an iterable"))
929 return templatekw.wraphybridvalue(iterable, x, x)
929 return templatekw.wraphybridvalue(iterable, x, x)
930
930
931 @templatefunc('min(iterable)')
931 @templatefunc('min(iterable)')
932 def min_(context, mapping, args, **kwargs):
932 def min_(context, mapping, args, **kwargs):
933 """Return the min of an iterable"""
933 """Return the min of an iterable"""
934 if len(args) != 1:
934 if len(args) != 1:
935 # i18n: "min" is a keyword
935 # i18n: "min" is a keyword
936 raise error.ParseError(_("min expects one arguments"))
936 raise error.ParseError(_("min expects one arguments"))
937
937
938 iterable = evalfuncarg(context, mapping, args[0])
938 iterable = evalfuncarg(context, mapping, args[0])
939 try:
939 try:
940 x = min(iterable)
940 x = min(iterable)
941 except (TypeError, ValueError):
941 except (TypeError, ValueError):
942 # i18n: "min" is a keyword
942 # i18n: "min" is a keyword
943 raise error.ParseError(_("min first argument should be an iterable"))
943 raise error.ParseError(_("min first argument should be an iterable"))
944 return templatekw.wraphybridvalue(iterable, x, x)
944 return templatekw.wraphybridvalue(iterable, x, x)
945
945
946 @templatefunc('mod(a, b)')
946 @templatefunc('mod(a, b)')
947 def mod(context, mapping, args):
947 def mod(context, mapping, args):
948 """Calculate a mod b such that a / b + a mod b == a"""
948 """Calculate a mod b such that a / b + a mod b == a"""
949 if not len(args) == 2:
949 if not len(args) == 2:
950 # i18n: "mod" is a keyword
950 # i18n: "mod" is a keyword
951 raise error.ParseError(_("mod expects two arguments"))
951 raise error.ParseError(_("mod expects two arguments"))
952
952
953 func = lambda a, b: a % b
953 func = lambda a, b: a % b
954 return runarithmetic(context, mapping, (func, args[0], args[1]))
954 return runarithmetic(context, mapping, (func, args[0], args[1]))
955
955
956 @templatefunc('obsfateoperations(markers)')
956 @templatefunc('obsfateoperations(markers)')
957 def obsfateoperations(context, mapping, args):
957 def obsfateoperations(context, mapping, args):
958 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
958 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
959 if len(args) != 1:
959 if len(args) != 1:
960 # i18n: "obsfateoperations" is a keyword
960 # i18n: "obsfateoperations" is a keyword
961 raise error.ParseError(_("obsfateoperations expects one arguments"))
961 raise error.ParseError(_("obsfateoperations expects one arguments"))
962
962
963 markers = evalfuncarg(context, mapping, args[0])
963 markers = evalfuncarg(context, mapping, args[0])
964
964
965 try:
965 try:
966 data = obsutil.markersoperations(markers)
966 data = obsutil.markersoperations(markers)
967 return templatekw.hybridlist(data, name='operation')
967 return templatekw.hybridlist(data, name='operation')
968 except (TypeError, KeyError):
968 except (TypeError, KeyError):
969 # i18n: "obsfateoperations" is a keyword
969 # i18n: "obsfateoperations" is a keyword
970 errmsg = _("obsfateoperations first argument should be an iterable")
970 errmsg = _("obsfateoperations first argument should be an iterable")
971 raise error.ParseError(errmsg)
971 raise error.ParseError(errmsg)
972
972
973 @templatefunc('obsfatedate(markers)')
973 @templatefunc('obsfatedate(markers)')
974 def obsfatedate(context, mapping, args):
974 def obsfatedate(context, mapping, args):
975 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
975 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
976 if len(args) != 1:
976 if len(args) != 1:
977 # i18n: "obsfatedate" is a keyword
977 # i18n: "obsfatedate" is a keyword
978 raise error.ParseError(_("obsfatedate expects one arguments"))
978 raise error.ParseError(_("obsfatedate expects one arguments"))
979
979
980 markers = evalfuncarg(context, mapping, args[0])
980 markers = evalfuncarg(context, mapping, args[0])
981
981
982 try:
982 try:
983 data = obsutil.markersdates(markers)
983 data = obsutil.markersdates(markers)
984 return templatekw.hybridlist(data, name='date', fmt='%d %d')
984 return templatekw.hybridlist(data, name='date', fmt='%d %d')
985 except (TypeError, KeyError):
985 except (TypeError, KeyError):
986 # i18n: "obsfatedate" is a keyword
986 # i18n: "obsfatedate" is a keyword
987 errmsg = _("obsfatedate first argument should be an iterable")
987 errmsg = _("obsfatedate first argument should be an iterable")
988 raise error.ParseError(errmsg)
988 raise error.ParseError(errmsg)
989
989
990 @templatefunc('obsfateusers(markers)')
990 @templatefunc('obsfateusers(markers)')
991 def obsfateusers(context, mapping, args):
991 def obsfateusers(context, mapping, args):
992 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
992 """Compute obsfate related information based on markers (EXPERIMENTAL)"""
993 if len(args) != 1:
993 if len(args) != 1:
994 # i18n: "obsfateusers" is a keyword
994 # i18n: "obsfateusers" is a keyword
995 raise error.ParseError(_("obsfateusers expects one arguments"))
995 raise error.ParseError(_("obsfateusers expects one arguments"))
996
996
997 markers = evalfuncarg(context, mapping, args[0])
997 markers = evalfuncarg(context, mapping, args[0])
998
998
999 try:
999 try:
1000 data = obsutil.markersusers(markers)
1000 data = obsutil.markersusers(markers)
1001 return templatekw.hybridlist(data, name='user')
1001 return templatekw.hybridlist(data, name='user')
1002 except (TypeError, KeyError, ValueError):
1002 except (TypeError, KeyError, ValueError):
1003 # i18n: "obsfateusers" is a keyword
1003 # i18n: "obsfateusers" is a keyword
1004 msg = _("obsfateusers first argument should be an iterable of "
1004 msg = _("obsfateusers first argument should be an iterable of "
1005 "obsmakers")
1005 "obsmakers")
1006 raise error.ParseError(msg)
1006 raise error.ParseError(msg)
1007
1007
1008 @templatefunc('obsfateverb(successors)')
1008 @templatefunc('obsfateverb(successors, markers)')
1009 def obsfateverb(context, mapping, args):
1009 def obsfateverb(context, mapping, args):
1010 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
1010 """Compute obsfate related information based on successors (EXPERIMENTAL)"""
1011 if len(args) != 1:
1011 if len(args) != 2:
1012 # i18n: "obsfateverb" is a keyword
1012 # i18n: "obsfateverb" is a keyword
1013 raise error.ParseError(_("obsfateverb expects one arguments"))
1013 raise error.ParseError(_("obsfateverb expects two arguments"))
1014
1014
1015 successors = evalfuncarg(context, mapping, args[0])
1015 successors = evalfuncarg(context, mapping, args[0])
1016 markers = evalfuncarg(context, mapping, args[1])
1016
1017
1017 try:
1018 try:
1018 return obsutil.successorsetverb(successors)
1019 return obsutil.obsfateverb(successors, markers)
1019 except TypeError:
1020 except TypeError:
1020 # i18n: "obsfateverb" is a keyword
1021 # i18n: "obsfateverb" is a keyword
1021 errmsg = _("obsfateverb first argument should be countable")
1022 errmsg = _("obsfateverb first argument should be countable")
1022 raise error.ParseError(errmsg)
1023 raise error.ParseError(errmsg)
1023
1024
1024 @templatefunc('relpath(path)')
1025 @templatefunc('relpath(path)')
1025 def relpath(context, mapping, args):
1026 def relpath(context, mapping, args):
1026 """Convert a repository-absolute path into a filesystem path relative to
1027 """Convert a repository-absolute path into a filesystem path relative to
1027 the current working directory."""
1028 the current working directory."""
1028 if len(args) != 1:
1029 if len(args) != 1:
1029 # i18n: "relpath" is a keyword
1030 # i18n: "relpath" is a keyword
1030 raise error.ParseError(_("relpath expects one argument"))
1031 raise error.ParseError(_("relpath expects one argument"))
1031
1032
1032 repo = mapping['ctx'].repo()
1033 repo = mapping['ctx'].repo()
1033 path = evalstring(context, mapping, args[0])
1034 path = evalstring(context, mapping, args[0])
1034 return repo.pathto(path)
1035 return repo.pathto(path)
1035
1036
1036 @templatefunc('revset(query[, formatargs...])')
1037 @templatefunc('revset(query[, formatargs...])')
1037 def revset(context, mapping, args):
1038 def revset(context, mapping, args):
1038 """Execute a revision set query. See
1039 """Execute a revision set query. See
1039 :hg:`help revset`."""
1040 :hg:`help revset`."""
1040 if not len(args) > 0:
1041 if not len(args) > 0:
1041 # i18n: "revset" is a keyword
1042 # i18n: "revset" is a keyword
1042 raise error.ParseError(_("revset expects one or more arguments"))
1043 raise error.ParseError(_("revset expects one or more arguments"))
1043
1044
1044 raw = evalstring(context, mapping, args[0])
1045 raw = evalstring(context, mapping, args[0])
1045 ctx = mapping['ctx']
1046 ctx = mapping['ctx']
1046 repo = ctx.repo()
1047 repo = ctx.repo()
1047
1048
1048 def query(expr):
1049 def query(expr):
1049 m = revsetmod.match(repo.ui, expr, repo=repo)
1050 m = revsetmod.match(repo.ui, expr, repo=repo)
1050 return m(repo)
1051 return m(repo)
1051
1052
1052 if len(args) > 1:
1053 if len(args) > 1:
1053 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
1054 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
1054 revs = query(revsetlang.formatspec(raw, *formatargs))
1055 revs = query(revsetlang.formatspec(raw, *formatargs))
1055 revs = list(revs)
1056 revs = list(revs)
1056 else:
1057 else:
1057 revsetcache = mapping['cache'].setdefault("revsetcache", {})
1058 revsetcache = mapping['cache'].setdefault("revsetcache", {})
1058 if raw in revsetcache:
1059 if raw in revsetcache:
1059 revs = revsetcache[raw]
1060 revs = revsetcache[raw]
1060 else:
1061 else:
1061 revs = query(raw)
1062 revs = query(raw)
1062 revs = list(revs)
1063 revs = list(revs)
1063 revsetcache[raw] = revs
1064 revsetcache[raw] = revs
1064
1065
1065 return templatekw.showrevslist("revision", revs, **mapping)
1066 return templatekw.showrevslist("revision", revs, **mapping)
1066
1067
1067 @templatefunc('rstdoc(text, style)')
1068 @templatefunc('rstdoc(text, style)')
1068 def rstdoc(context, mapping, args):
1069 def rstdoc(context, mapping, args):
1069 """Format reStructuredText."""
1070 """Format reStructuredText."""
1070 if len(args) != 2:
1071 if len(args) != 2:
1071 # i18n: "rstdoc" is a keyword
1072 # i18n: "rstdoc" is a keyword
1072 raise error.ParseError(_("rstdoc expects two arguments"))
1073 raise error.ParseError(_("rstdoc expects two arguments"))
1073
1074
1074 text = evalstring(context, mapping, args[0])
1075 text = evalstring(context, mapping, args[0])
1075 style = evalstring(context, mapping, args[1])
1076 style = evalstring(context, mapping, args[1])
1076
1077
1077 return minirst.format(text, style=style, keep=['verbose'])
1078 return minirst.format(text, style=style, keep=['verbose'])
1078
1079
1079 @templatefunc('separate(sep, args)', argspec='sep *args')
1080 @templatefunc('separate(sep, args)', argspec='sep *args')
1080 def separate(context, mapping, args):
1081 def separate(context, mapping, args):
1081 """Add a separator between non-empty arguments."""
1082 """Add a separator between non-empty arguments."""
1082 if 'sep' not in args:
1083 if 'sep' not in args:
1083 # i18n: "separate" is a keyword
1084 # i18n: "separate" is a keyword
1084 raise error.ParseError(_("separate expects at least one argument"))
1085 raise error.ParseError(_("separate expects at least one argument"))
1085
1086
1086 sep = evalstring(context, mapping, args['sep'])
1087 sep = evalstring(context, mapping, args['sep'])
1087 first = True
1088 first = True
1088 for arg in args['args']:
1089 for arg in args['args']:
1089 argstr = evalstring(context, mapping, arg)
1090 argstr = evalstring(context, mapping, arg)
1090 if not argstr:
1091 if not argstr:
1091 continue
1092 continue
1092 if first:
1093 if first:
1093 first = False
1094 first = False
1094 else:
1095 else:
1095 yield sep
1096 yield sep
1096 yield argstr
1097 yield argstr
1097
1098
1098 @templatefunc('shortest(node, minlength=4)')
1099 @templatefunc('shortest(node, minlength=4)')
1099 def shortest(context, mapping, args):
1100 def shortest(context, mapping, args):
1100 """Obtain the shortest representation of
1101 """Obtain the shortest representation of
1101 a node."""
1102 a node."""
1102 if not (1 <= len(args) <= 2):
1103 if not (1 <= len(args) <= 2):
1103 # i18n: "shortest" is a keyword
1104 # i18n: "shortest" is a keyword
1104 raise error.ParseError(_("shortest() expects one or two arguments"))
1105 raise error.ParseError(_("shortest() expects one or two arguments"))
1105
1106
1106 node = evalstring(context, mapping, args[0])
1107 node = evalstring(context, mapping, args[0])
1107
1108
1108 minlength = 4
1109 minlength = 4
1109 if len(args) > 1:
1110 if len(args) > 1:
1110 minlength = evalinteger(context, mapping, args[1],
1111 minlength = evalinteger(context, mapping, args[1],
1111 # i18n: "shortest" is a keyword
1112 # i18n: "shortest" is a keyword
1112 _("shortest() expects an integer minlength"))
1113 _("shortest() expects an integer minlength"))
1113
1114
1114 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1115 # _partialmatch() of filtered changelog could take O(len(repo)) time,
1115 # which would be unacceptably slow. so we look for hash collision in
1116 # which would be unacceptably slow. so we look for hash collision in
1116 # unfiltered space, which means some hashes may be slightly longer.
1117 # unfiltered space, which means some hashes may be slightly longer.
1117 cl = mapping['ctx']._repo.unfiltered().changelog
1118 cl = mapping['ctx']._repo.unfiltered().changelog
1118 return cl.shortest(node, minlength)
1119 return cl.shortest(node, minlength)
1119
1120
1120 @templatefunc('strip(text[, chars])')
1121 @templatefunc('strip(text[, chars])')
1121 def strip(context, mapping, args):
1122 def strip(context, mapping, args):
1122 """Strip characters from a string. By default,
1123 """Strip characters from a string. By default,
1123 strips all leading and trailing whitespace."""
1124 strips all leading and trailing whitespace."""
1124 if not (1 <= len(args) <= 2):
1125 if not (1 <= len(args) <= 2):
1125 # i18n: "strip" is a keyword
1126 # i18n: "strip" is a keyword
1126 raise error.ParseError(_("strip expects one or two arguments"))
1127 raise error.ParseError(_("strip expects one or two arguments"))
1127
1128
1128 text = evalstring(context, mapping, args[0])
1129 text = evalstring(context, mapping, args[0])
1129 if len(args) == 2:
1130 if len(args) == 2:
1130 chars = evalstring(context, mapping, args[1])
1131 chars = evalstring(context, mapping, args[1])
1131 return text.strip(chars)
1132 return text.strip(chars)
1132 return text.strip()
1133 return text.strip()
1133
1134
1134 @templatefunc('sub(pattern, replacement, expression)')
1135 @templatefunc('sub(pattern, replacement, expression)')
1135 def sub(context, mapping, args):
1136 def sub(context, mapping, args):
1136 """Perform text substitution
1137 """Perform text substitution
1137 using regular expressions."""
1138 using regular expressions."""
1138 if len(args) != 3:
1139 if len(args) != 3:
1139 # i18n: "sub" is a keyword
1140 # i18n: "sub" is a keyword
1140 raise error.ParseError(_("sub expects three arguments"))
1141 raise error.ParseError(_("sub expects three arguments"))
1141
1142
1142 pat = evalstring(context, mapping, args[0])
1143 pat = evalstring(context, mapping, args[0])
1143 rpl = evalstring(context, mapping, args[1])
1144 rpl = evalstring(context, mapping, args[1])
1144 src = evalstring(context, mapping, args[2])
1145 src = evalstring(context, mapping, args[2])
1145 try:
1146 try:
1146 patre = re.compile(pat)
1147 patre = re.compile(pat)
1147 except re.error:
1148 except re.error:
1148 # i18n: "sub" is a keyword
1149 # i18n: "sub" is a keyword
1149 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1150 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
1150 try:
1151 try:
1151 yield patre.sub(rpl, src)
1152 yield patre.sub(rpl, src)
1152 except re.error:
1153 except re.error:
1153 # i18n: "sub" is a keyword
1154 # i18n: "sub" is a keyword
1154 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1155 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
1155
1156
1156 @templatefunc('startswith(pattern, text)')
1157 @templatefunc('startswith(pattern, text)')
1157 def startswith(context, mapping, args):
1158 def startswith(context, mapping, args):
1158 """Returns the value from the "text" argument
1159 """Returns the value from the "text" argument
1159 if it begins with the content from the "pattern" argument."""
1160 if it begins with the content from the "pattern" argument."""
1160 if len(args) != 2:
1161 if len(args) != 2:
1161 # i18n: "startswith" is a keyword
1162 # i18n: "startswith" is a keyword
1162 raise error.ParseError(_("startswith expects two arguments"))
1163 raise error.ParseError(_("startswith expects two arguments"))
1163
1164
1164 patn = evalstring(context, mapping, args[0])
1165 patn = evalstring(context, mapping, args[0])
1165 text = evalstring(context, mapping, args[1])
1166 text = evalstring(context, mapping, args[1])
1166 if text.startswith(patn):
1167 if text.startswith(patn):
1167 return text
1168 return text
1168 return ''
1169 return ''
1169
1170
1170 @templatefunc('word(number, text[, separator])')
1171 @templatefunc('word(number, text[, separator])')
1171 def word(context, mapping, args):
1172 def word(context, mapping, args):
1172 """Return the nth word from a string."""
1173 """Return the nth word from a string."""
1173 if not (2 <= len(args) <= 3):
1174 if not (2 <= len(args) <= 3):
1174 # i18n: "word" is a keyword
1175 # i18n: "word" is a keyword
1175 raise error.ParseError(_("word expects two or three arguments, got %d")
1176 raise error.ParseError(_("word expects two or three arguments, got %d")
1176 % len(args))
1177 % len(args))
1177
1178
1178 num = evalinteger(context, mapping, args[0],
1179 num = evalinteger(context, mapping, args[0],
1179 # i18n: "word" is a keyword
1180 # i18n: "word" is a keyword
1180 _("word expects an integer index"))
1181 _("word expects an integer index"))
1181 text = evalstring(context, mapping, args[1])
1182 text = evalstring(context, mapping, args[1])
1182 if len(args) == 3:
1183 if len(args) == 3:
1183 splitter = evalstring(context, mapping, args[2])
1184 splitter = evalstring(context, mapping, args[2])
1184 else:
1185 else:
1185 splitter = None
1186 splitter = None
1186
1187
1187 tokens = text.split(splitter)
1188 tokens = text.split(splitter)
1188 if num >= len(tokens) or num < -len(tokens):
1189 if num >= len(tokens) or num < -len(tokens):
1189 return ''
1190 return ''
1190 else:
1191 else:
1191 return tokens[num]
1192 return tokens[num]
1192
1193
1193 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1194 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
1194 exprmethods = {
1195 exprmethods = {
1195 "integer": lambda e, c: (runinteger, e[1]),
1196 "integer": lambda e, c: (runinteger, e[1]),
1196 "string": lambda e, c: (runstring, e[1]),
1197 "string": lambda e, c: (runstring, e[1]),
1197 "symbol": lambda e, c: (runsymbol, e[1]),
1198 "symbol": lambda e, c: (runsymbol, e[1]),
1198 "template": buildtemplate,
1199 "template": buildtemplate,
1199 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1200 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1200 ".": buildmember,
1201 ".": buildmember,
1201 "|": buildfilter,
1202 "|": buildfilter,
1202 "%": buildmap,
1203 "%": buildmap,
1203 "func": buildfunc,
1204 "func": buildfunc,
1204 "keyvalue": buildkeyvaluepair,
1205 "keyvalue": buildkeyvaluepair,
1205 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1206 "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
1206 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1207 "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
1207 "negate": buildnegate,
1208 "negate": buildnegate,
1208 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1209 "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
1209 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1210 "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
1210 }
1211 }
1211
1212
1212 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1213 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
1213 methods = exprmethods.copy()
1214 methods = exprmethods.copy()
1214 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1215 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
1215
1216
1216 class _aliasrules(parser.basealiasrules):
1217 class _aliasrules(parser.basealiasrules):
1217 """Parsing and expansion rule set of template aliases"""
1218 """Parsing and expansion rule set of template aliases"""
1218 _section = _('template alias')
1219 _section = _('template alias')
1219 _parse = staticmethod(_parseexpr)
1220 _parse = staticmethod(_parseexpr)
1220
1221
1221 @staticmethod
1222 @staticmethod
1222 def _trygetfunc(tree):
1223 def _trygetfunc(tree):
1223 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1224 """Return (name, args) if tree is func(...) or ...|filter; otherwise
1224 None"""
1225 None"""
1225 if tree[0] == 'func' and tree[1][0] == 'symbol':
1226 if tree[0] == 'func' and tree[1][0] == 'symbol':
1226 return tree[1][1], getlist(tree[2])
1227 return tree[1][1], getlist(tree[2])
1227 if tree[0] == '|' and tree[2][0] == 'symbol':
1228 if tree[0] == '|' and tree[2][0] == 'symbol':
1228 return tree[2][1], [tree[1]]
1229 return tree[2][1], [tree[1]]
1229
1230
1230 def expandaliases(tree, aliases):
1231 def expandaliases(tree, aliases):
1231 """Return new tree of aliases are expanded"""
1232 """Return new tree of aliases are expanded"""
1232 aliasmap = _aliasrules.buildmap(aliases)
1233 aliasmap = _aliasrules.buildmap(aliases)
1233 return _aliasrules.expand(aliasmap, tree)
1234 return _aliasrules.expand(aliasmap, tree)
1234
1235
1235 # template engine
1236 # template engine
1236
1237
1237 stringify = templatefilters.stringify
1238 stringify = templatefilters.stringify
1238
1239
1239 def _flatten(thing):
1240 def _flatten(thing):
1240 '''yield a single stream from a possibly nested set of iterators'''
1241 '''yield a single stream from a possibly nested set of iterators'''
1241 thing = templatekw.unwraphybrid(thing)
1242 thing = templatekw.unwraphybrid(thing)
1242 if isinstance(thing, bytes):
1243 if isinstance(thing, bytes):
1243 yield thing
1244 yield thing
1244 elif isinstance(thing, str):
1245 elif isinstance(thing, str):
1245 # We can only hit this on Python 3, and it's here to guard
1246 # We can only hit this on Python 3, and it's here to guard
1246 # against infinite recursion.
1247 # against infinite recursion.
1247 raise error.ProgrammingError('Mercurial IO including templates is done'
1248 raise error.ProgrammingError('Mercurial IO including templates is done'
1248 ' with bytes, not strings')
1249 ' with bytes, not strings')
1249 elif thing is None:
1250 elif thing is None:
1250 pass
1251 pass
1251 elif not util.safehasattr(thing, '__iter__'):
1252 elif not util.safehasattr(thing, '__iter__'):
1252 yield pycompat.bytestr(thing)
1253 yield pycompat.bytestr(thing)
1253 else:
1254 else:
1254 for i in thing:
1255 for i in thing:
1255 i = templatekw.unwraphybrid(i)
1256 i = templatekw.unwraphybrid(i)
1256 if isinstance(i, bytes):
1257 if isinstance(i, bytes):
1257 yield i
1258 yield i
1258 elif i is None:
1259 elif i is None:
1259 pass
1260 pass
1260 elif not util.safehasattr(i, '__iter__'):
1261 elif not util.safehasattr(i, '__iter__'):
1261 yield pycompat.bytestr(i)
1262 yield pycompat.bytestr(i)
1262 else:
1263 else:
1263 for j in _flatten(i):
1264 for j in _flatten(i):
1264 yield j
1265 yield j
1265
1266
1266 def unquotestring(s):
1267 def unquotestring(s):
1267 '''unwrap quotes if any; otherwise returns unmodified string'''
1268 '''unwrap quotes if any; otherwise returns unmodified string'''
1268 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1269 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
1269 return s
1270 return s
1270 return s[1:-1]
1271 return s[1:-1]
1271
1272
1272 class engine(object):
1273 class engine(object):
1273 '''template expansion engine.
1274 '''template expansion engine.
1274
1275
1275 template expansion works like this. a map file contains key=value
1276 template expansion works like this. a map file contains key=value
1276 pairs. if value is quoted, it is treated as string. otherwise, it
1277 pairs. if value is quoted, it is treated as string. otherwise, it
1277 is treated as name of template file.
1278 is treated as name of template file.
1278
1279
1279 templater is asked to expand a key in map. it looks up key, and
1280 templater is asked to expand a key in map. it looks up key, and
1280 looks for strings like this: {foo}. it expands {foo} by looking up
1281 looks for strings like this: {foo}. it expands {foo} by looking up
1281 foo in map, and substituting it. expansion is recursive: it stops
1282 foo in map, and substituting it. expansion is recursive: it stops
1282 when there is no more {foo} to replace.
1283 when there is no more {foo} to replace.
1283
1284
1284 expansion also allows formatting and filtering.
1285 expansion also allows formatting and filtering.
1285
1286
1286 format uses key to expand each item in list. syntax is
1287 format uses key to expand each item in list. syntax is
1287 {key%format}.
1288 {key%format}.
1288
1289
1289 filter uses function to transform value. syntax is
1290 filter uses function to transform value. syntax is
1290 {key|filter1|filter2|...}.'''
1291 {key|filter1|filter2|...}.'''
1291
1292
1292 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1293 def __init__(self, loader, filters=None, defaults=None, aliases=()):
1293 self._loader = loader
1294 self._loader = loader
1294 if filters is None:
1295 if filters is None:
1295 filters = {}
1296 filters = {}
1296 self._filters = filters
1297 self._filters = filters
1297 if defaults is None:
1298 if defaults is None:
1298 defaults = {}
1299 defaults = {}
1299 self._defaults = defaults
1300 self._defaults = defaults
1300 self._aliasmap = _aliasrules.buildmap(aliases)
1301 self._aliasmap = _aliasrules.buildmap(aliases)
1301 self._cache = {} # key: (func, data)
1302 self._cache = {} # key: (func, data)
1302
1303
1303 def _load(self, t):
1304 def _load(self, t):
1304 '''load, parse, and cache a template'''
1305 '''load, parse, and cache a template'''
1305 if t not in self._cache:
1306 if t not in self._cache:
1306 # put poison to cut recursion while compiling 't'
1307 # put poison to cut recursion while compiling 't'
1307 self._cache[t] = (_runrecursivesymbol, t)
1308 self._cache[t] = (_runrecursivesymbol, t)
1308 try:
1309 try:
1309 x = parse(self._loader(t))
1310 x = parse(self._loader(t))
1310 if self._aliasmap:
1311 if self._aliasmap:
1311 x = _aliasrules.expand(self._aliasmap, x)
1312 x = _aliasrules.expand(self._aliasmap, x)
1312 self._cache[t] = compileexp(x, self, methods)
1313 self._cache[t] = compileexp(x, self, methods)
1313 except: # re-raises
1314 except: # re-raises
1314 del self._cache[t]
1315 del self._cache[t]
1315 raise
1316 raise
1316 return self._cache[t]
1317 return self._cache[t]
1317
1318
1318 def process(self, t, mapping):
1319 def process(self, t, mapping):
1319 '''Perform expansion. t is name of map element to expand.
1320 '''Perform expansion. t is name of map element to expand.
1320 mapping contains added elements for use during expansion. Is a
1321 mapping contains added elements for use during expansion. Is a
1321 generator.'''
1322 generator.'''
1322 func, data = self._load(t)
1323 func, data = self._load(t)
1323 return _flatten(func(self, mapping, data))
1324 return _flatten(func(self, mapping, data))
1324
1325
1325 engines = {'default': engine}
1326 engines = {'default': engine}
1326
1327
1327 def stylelist():
1328 def stylelist():
1328 paths = templatepaths()
1329 paths = templatepaths()
1329 if not paths:
1330 if not paths:
1330 return _('no templates found, try `hg debuginstall` for more info')
1331 return _('no templates found, try `hg debuginstall` for more info')
1331 dirlist = os.listdir(paths[0])
1332 dirlist = os.listdir(paths[0])
1332 stylelist = []
1333 stylelist = []
1333 for file in dirlist:
1334 for file in dirlist:
1334 split = file.split(".")
1335 split = file.split(".")
1335 if split[-1] in ('orig', 'rej'):
1336 if split[-1] in ('orig', 'rej'):
1336 continue
1337 continue
1337 if split[0] == "map-cmdline":
1338 if split[0] == "map-cmdline":
1338 stylelist.append(split[1])
1339 stylelist.append(split[1])
1339 return ", ".join(sorted(stylelist))
1340 return ", ".join(sorted(stylelist))
1340
1341
1341 def _readmapfile(mapfile):
1342 def _readmapfile(mapfile):
1342 """Load template elements from the given map file"""
1343 """Load template elements from the given map file"""
1343 if not os.path.exists(mapfile):
1344 if not os.path.exists(mapfile):
1344 raise error.Abort(_("style '%s' not found") % mapfile,
1345 raise error.Abort(_("style '%s' not found") % mapfile,
1345 hint=_("available styles: %s") % stylelist())
1346 hint=_("available styles: %s") % stylelist())
1346
1347
1347 base = os.path.dirname(mapfile)
1348 base = os.path.dirname(mapfile)
1348 conf = config.config(includepaths=templatepaths())
1349 conf = config.config(includepaths=templatepaths())
1349 conf.read(mapfile, remap={'': 'templates'})
1350 conf.read(mapfile, remap={'': 'templates'})
1350
1351
1351 cache = {}
1352 cache = {}
1352 tmap = {}
1353 tmap = {}
1353 aliases = []
1354 aliases = []
1354
1355
1355 val = conf.get('templates', '__base__')
1356 val = conf.get('templates', '__base__')
1356 if val and val[0] not in "'\"":
1357 if val and val[0] not in "'\"":
1357 # treat as a pointer to a base class for this style
1358 # treat as a pointer to a base class for this style
1358 path = util.normpath(os.path.join(base, val))
1359 path = util.normpath(os.path.join(base, val))
1359
1360
1360 # fallback check in template paths
1361 # fallback check in template paths
1361 if not os.path.exists(path):
1362 if not os.path.exists(path):
1362 for p in templatepaths():
1363 for p in templatepaths():
1363 p2 = util.normpath(os.path.join(p, val))
1364 p2 = util.normpath(os.path.join(p, val))
1364 if os.path.isfile(p2):
1365 if os.path.isfile(p2):
1365 path = p2
1366 path = p2
1366 break
1367 break
1367 p3 = util.normpath(os.path.join(p2, "map"))
1368 p3 = util.normpath(os.path.join(p2, "map"))
1368 if os.path.isfile(p3):
1369 if os.path.isfile(p3):
1369 path = p3
1370 path = p3
1370 break
1371 break
1371
1372
1372 cache, tmap, aliases = _readmapfile(path)
1373 cache, tmap, aliases = _readmapfile(path)
1373
1374
1374 for key, val in conf['templates'].items():
1375 for key, val in conf['templates'].items():
1375 if not val:
1376 if not val:
1376 raise error.ParseError(_('missing value'),
1377 raise error.ParseError(_('missing value'),
1377 conf.source('templates', key))
1378 conf.source('templates', key))
1378 if val[0] in "'\"":
1379 if val[0] in "'\"":
1379 if val[0] != val[-1]:
1380 if val[0] != val[-1]:
1380 raise error.ParseError(_('unmatched quotes'),
1381 raise error.ParseError(_('unmatched quotes'),
1381 conf.source('templates', key))
1382 conf.source('templates', key))
1382 cache[key] = unquotestring(val)
1383 cache[key] = unquotestring(val)
1383 elif key != '__base__':
1384 elif key != '__base__':
1384 val = 'default', val
1385 val = 'default', val
1385 if ':' in val[1]:
1386 if ':' in val[1]:
1386 val = val[1].split(':', 1)
1387 val = val[1].split(':', 1)
1387 tmap[key] = val[0], os.path.join(base, val[1])
1388 tmap[key] = val[0], os.path.join(base, val[1])
1388 aliases.extend(conf['templatealias'].items())
1389 aliases.extend(conf['templatealias'].items())
1389 return cache, tmap, aliases
1390 return cache, tmap, aliases
1390
1391
1391 class TemplateNotFound(error.Abort):
1392 class TemplateNotFound(error.Abort):
1392 pass
1393 pass
1393
1394
1394 class templater(object):
1395 class templater(object):
1395
1396
1396 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1397 def __init__(self, filters=None, defaults=None, cache=None, aliases=(),
1397 minchunk=1024, maxchunk=65536):
1398 minchunk=1024, maxchunk=65536):
1398 '''set up template engine.
1399 '''set up template engine.
1399 filters is dict of functions. each transforms a value into another.
1400 filters is dict of functions. each transforms a value into another.
1400 defaults is dict of default map definitions.
1401 defaults is dict of default map definitions.
1401 aliases is list of alias (name, replacement) pairs.
1402 aliases is list of alias (name, replacement) pairs.
1402 '''
1403 '''
1403 if filters is None:
1404 if filters is None:
1404 filters = {}
1405 filters = {}
1405 if defaults is None:
1406 if defaults is None:
1406 defaults = {}
1407 defaults = {}
1407 if cache is None:
1408 if cache is None:
1408 cache = {}
1409 cache = {}
1409 self.cache = cache.copy()
1410 self.cache = cache.copy()
1410 self.map = {}
1411 self.map = {}
1411 self.filters = templatefilters.filters.copy()
1412 self.filters = templatefilters.filters.copy()
1412 self.filters.update(filters)
1413 self.filters.update(filters)
1413 self.defaults = defaults
1414 self.defaults = defaults
1414 self._aliases = aliases
1415 self._aliases = aliases
1415 self.minchunk, self.maxchunk = minchunk, maxchunk
1416 self.minchunk, self.maxchunk = minchunk, maxchunk
1416 self.ecache = {}
1417 self.ecache = {}
1417
1418
1418 @classmethod
1419 @classmethod
1419 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1420 def frommapfile(cls, mapfile, filters=None, defaults=None, cache=None,
1420 minchunk=1024, maxchunk=65536):
1421 minchunk=1024, maxchunk=65536):
1421 """Create templater from the specified map file"""
1422 """Create templater from the specified map file"""
1422 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1423 t = cls(filters, defaults, cache, [], minchunk, maxchunk)
1423 cache, tmap, aliases = _readmapfile(mapfile)
1424 cache, tmap, aliases = _readmapfile(mapfile)
1424 t.cache.update(cache)
1425 t.cache.update(cache)
1425 t.map = tmap
1426 t.map = tmap
1426 t._aliases = aliases
1427 t._aliases = aliases
1427 return t
1428 return t
1428
1429
1429 def __contains__(self, key):
1430 def __contains__(self, key):
1430 return key in self.cache or key in self.map
1431 return key in self.cache or key in self.map
1431
1432
1432 def load(self, t):
1433 def load(self, t):
1433 '''Get the template for the given template name. Use a local cache.'''
1434 '''Get the template for the given template name. Use a local cache.'''
1434 if t not in self.cache:
1435 if t not in self.cache:
1435 try:
1436 try:
1436 self.cache[t] = util.readfile(self.map[t][1])
1437 self.cache[t] = util.readfile(self.map[t][1])
1437 except KeyError as inst:
1438 except KeyError as inst:
1438 raise TemplateNotFound(_('"%s" not in template map') %
1439 raise TemplateNotFound(_('"%s" not in template map') %
1439 inst.args[0])
1440 inst.args[0])
1440 except IOError as inst:
1441 except IOError as inst:
1441 raise IOError(inst.args[0], _('template file %s: %s') %
1442 raise IOError(inst.args[0], _('template file %s: %s') %
1442 (self.map[t][1], inst.args[1]))
1443 (self.map[t][1], inst.args[1]))
1443 return self.cache[t]
1444 return self.cache[t]
1444
1445
1445 def render(self, mapping):
1446 def render(self, mapping):
1446 """Render the default unnamed template and return result as string"""
1447 """Render the default unnamed template and return result as string"""
1447 mapping = pycompat.strkwargs(mapping)
1448 mapping = pycompat.strkwargs(mapping)
1448 return stringify(self('', **mapping))
1449 return stringify(self('', **mapping))
1449
1450
1450 def __call__(self, t, **mapping):
1451 def __call__(self, t, **mapping):
1451 mapping = pycompat.byteskwargs(mapping)
1452 mapping = pycompat.byteskwargs(mapping)
1452 ttype = t in self.map and self.map[t][0] or 'default'
1453 ttype = t in self.map and self.map[t][0] or 'default'
1453 if ttype not in self.ecache:
1454 if ttype not in self.ecache:
1454 try:
1455 try:
1455 ecls = engines[ttype]
1456 ecls = engines[ttype]
1456 except KeyError:
1457 except KeyError:
1457 raise error.Abort(_('invalid template engine: %s') % ttype)
1458 raise error.Abort(_('invalid template engine: %s') % ttype)
1458 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1459 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
1459 self._aliases)
1460 self._aliases)
1460 proc = self.ecache[ttype]
1461 proc = self.ecache[ttype]
1461
1462
1462 stream = proc.process(t, mapping)
1463 stream = proc.process(t, mapping)
1463 if self.minchunk:
1464 if self.minchunk:
1464 stream = util.increasingchunks(stream, min=self.minchunk,
1465 stream = util.increasingchunks(stream, min=self.minchunk,
1465 max=self.maxchunk)
1466 max=self.maxchunk)
1466 return stream
1467 return stream
1467
1468
1468 def templatepaths():
1469 def templatepaths():
1469 '''return locations used for template files.'''
1470 '''return locations used for template files.'''
1470 pathsrel = ['templates']
1471 pathsrel = ['templates']
1471 paths = [os.path.normpath(os.path.join(util.datapath, f))
1472 paths = [os.path.normpath(os.path.join(util.datapath, f))
1472 for f in pathsrel]
1473 for f in pathsrel]
1473 return [p for p in paths if os.path.isdir(p)]
1474 return [p for p in paths if os.path.isdir(p)]
1474
1475
1475 def templatepath(name):
1476 def templatepath(name):
1476 '''return location of template file. returns None if not found.'''
1477 '''return location of template file. returns None if not found.'''
1477 for p in templatepaths():
1478 for p in templatepaths():
1478 f = os.path.join(p, name)
1479 f = os.path.join(p, name)
1479 if os.path.exists(f):
1480 if os.path.exists(f):
1480 return f
1481 return f
1481 return None
1482 return None
1482
1483
1483 def stylemap(styles, paths=None):
1484 def stylemap(styles, paths=None):
1484 """Return path to mapfile for a given style.
1485 """Return path to mapfile for a given style.
1485
1486
1486 Searches mapfile in the following locations:
1487 Searches mapfile in the following locations:
1487 1. templatepath/style/map
1488 1. templatepath/style/map
1488 2. templatepath/map-style
1489 2. templatepath/map-style
1489 3. templatepath/map
1490 3. templatepath/map
1490 """
1491 """
1491
1492
1492 if paths is None:
1493 if paths is None:
1493 paths = templatepaths()
1494 paths = templatepaths()
1494 elif isinstance(paths, str):
1495 elif isinstance(paths, str):
1495 paths = [paths]
1496 paths = [paths]
1496
1497
1497 if isinstance(styles, str):
1498 if isinstance(styles, str):
1498 styles = [styles]
1499 styles = [styles]
1499
1500
1500 for style in styles:
1501 for style in styles:
1501 # only plain name is allowed to honor template paths
1502 # only plain name is allowed to honor template paths
1502 if (not style
1503 if (not style
1503 or style in (os.curdir, os.pardir)
1504 or style in (os.curdir, os.pardir)
1504 or pycompat.ossep in style
1505 or pycompat.ossep in style
1505 or pycompat.osaltsep and pycompat.osaltsep in style):
1506 or pycompat.osaltsep and pycompat.osaltsep in style):
1506 continue
1507 continue
1507 locations = [os.path.join(style, 'map'), 'map-' + style]
1508 locations = [os.path.join(style, 'map'), 'map-' + style]
1508 locations.append('map')
1509 locations.append('map')
1509
1510
1510 for path in paths:
1511 for path in paths:
1511 for location in locations:
1512 for location in locations:
1512 mapfile = os.path.join(path, location)
1513 mapfile = os.path.join(path, location)
1513 if os.path.isfile(mapfile):
1514 if os.path.isfile(mapfile):
1514 return style, mapfile
1515 return style, mapfile
1515
1516
1516 raise RuntimeError("No hgweb templates found in %r" % paths)
1517 raise RuntimeError("No hgweb templates found in %r" % paths)
1517
1518
1518 def loadfunction(ui, extname, registrarobj):
1519 def loadfunction(ui, extname, registrarobj):
1519 """Load template function from specified registrarobj
1520 """Load template function from specified registrarobj
1520 """
1521 """
1521 for name, func in registrarobj._table.iteritems():
1522 for name, func in registrarobj._table.iteritems():
1522 funcs[name] = func
1523 funcs[name] = func
1523
1524
1524 # tell hggettext to extract docstrings from these functions:
1525 # tell hggettext to extract docstrings from these functions:
1525 i18nfunctions = funcs.values()
1526 i18nfunctions = funcs.values()
@@ -1,2545 +1,2545 b''
1 This test file test the various templates related to obsmarkers.
1 This test file test the various templates related to obsmarkers.
2
2
3 Global setup
3 Global setup
4 ============
4 ============
5
5
6 $ . $TESTDIR/testlib/obsmarker-common.sh
6 $ . $TESTDIR/testlib/obsmarker-common.sh
7 $ cat >> $HGRCPATH <<EOF
7 $ cat >> $HGRCPATH <<EOF
8 > [ui]
8 > [ui]
9 > interactive = true
9 > interactive = true
10 > [phases]
10 > [phases]
11 > publish=False
11 > publish=False
12 > [experimental]
12 > [experimental]
13 > evolution=true
13 > evolution=true
14 > [templates]
14 > [templates]
15 > obsfatesuccessors = "{if(successors, " as ")}{join(successors, ", ")}"
15 > obsfatesuccessors = "{if(successors, " as ")}{join(successors, ", ")}"
16 > obsfateverb = "{obsfateverb(successors)}"
16 > obsfateverb = "{obsfateverb(successors, markers)}"
17 > obsfateoperations = "{if(obsfateoperations(markers), " using {join(obsfateoperations(markers), ", ")}")}"
17 > obsfateoperations = "{if(obsfateoperations(markers), " using {join(obsfateoperations(markers), ", ")}")}"
18 > obsfateusers = "{if(obsfateusers(markers), " by {join(obsfateusers(markers), ", ")}")}"
18 > obsfateusers = "{if(obsfateusers(markers), " by {join(obsfateusers(markers), ", ")}")}"
19 > obsfatedate = "{if(obsfatedate(markers), "{ifeq(min(obsfatedate(markers)), max(obsfatedate(markers)), " (at {min(obsfatedate(markers))|isodate})", " (between {min(obsfatedate(markers))|isodate} and {max(obsfatedate(markers))|isodate})")}")}"
19 > obsfatedate = "{if(obsfatedate(markers), "{ifeq(min(obsfatedate(markers)), max(obsfatedate(markers)), " (at {min(obsfatedate(markers))|isodate})", " (between {min(obsfatedate(markers))|isodate} and {max(obsfatedate(markers))|isodate})")}")}"
20 > obsfatetempl = "{obsfateverb}{obsfateoperations}{obsfatesuccessors}{obsfateusers}{obsfatedate}; "
20 > obsfatetempl = "{obsfateverb}{obsfateoperations}{obsfatesuccessors}{obsfateusers}{obsfatedate}; "
21 > [alias]
21 > [alias]
22 > tlog = log -G -T '{node|short}\
22 > tlog = log -G -T '{node|short}\
23 > {if(predecessors, "\n Predecessors: {predecessors}")}\
23 > {if(predecessors, "\n Predecessors: {predecessors}")}\
24 > {if(predecessors, "\n semi-colon: {join(predecessors, "; ")}")}\
24 > {if(predecessors, "\n semi-colon: {join(predecessors, "; ")}")}\
25 > {if(predecessors, "\n json: {predecessors|json}")}\
25 > {if(predecessors, "\n json: {predecessors|json}")}\
26 > {if(predecessors, "\n map: {join(predecessors % "{rev}:{node}", " ")}")}\
26 > {if(predecessors, "\n map: {join(predecessors % "{rev}:{node}", " ")}")}\
27 > {if(successorssets, "\n Successors: {successorssets}")}\
27 > {if(successorssets, "\n Successors: {successorssets}")}\
28 > {if(successorssets, "\n multi-line: {join(successorssets, "\n multi-line: ")}")}\
28 > {if(successorssets, "\n multi-line: {join(successorssets, "\n multi-line: ")}")}\
29 > {if(successorssets, "\n json: {successorssets|json}")}\n'
29 > {if(successorssets, "\n json: {successorssets|json}")}\n'
30 > fatelog = log -G -T '{node|short}\n{if(succsandmarkers, " Obsfate: {succsandmarkers % "{obsfatetempl}"} \n" )}'
30 > fatelog = log -G -T '{node|short}\n{if(succsandmarkers, " Obsfate: {succsandmarkers % "{obsfatetempl}"} \n" )}'
31 > fatelogjson = log -G -T '{node|short}\n{if(succsandmarkers, " Obsfate: {succsandmarkers|json}\n")}'
31 > fatelogjson = log -G -T '{node|short}\n{if(succsandmarkers, " Obsfate: {succsandmarkers|json}\n")}'
32 > fatelogkw = log -G -T '{node|short}\n{if(obsfate, "{obsfate % " Obsfate: {fate}\n"}")}'
32 > fatelogkw = log -G -T '{node|short}\n{if(obsfate, "{obsfate % " Obsfate: {fate}\n"}")}'
33 > EOF
33 > EOF
34
34
35 Test templates on amended commit
35 Test templates on amended commit
36 ================================
36 ================================
37
37
38 Test setup
38 Test setup
39 ----------
39 ----------
40
40
41 $ hg init $TESTTMP/templates-local-amend
41 $ hg init $TESTTMP/templates-local-amend
42 $ cd $TESTTMP/templates-local-amend
42 $ cd $TESTTMP/templates-local-amend
43 $ mkcommit ROOT
43 $ mkcommit ROOT
44 $ mkcommit A0
44 $ mkcommit A0
45 $ echo 42 >> A0
45 $ echo 42 >> A0
46 $ hg commit --amend -m "A1" --config devel.default-date="1234567890 0"
46 $ hg commit --amend -m "A1" --config devel.default-date="1234567890 0"
47 $ hg commit --amend -m "A2" --config devel.default-date="987654321 0" --config devel.user.obsmarker=test2
47 $ hg commit --amend -m "A2" --config devel.default-date="987654321 0" --config devel.user.obsmarker=test2
48
48
49 $ hg log --hidden -G
49 $ hg log --hidden -G
50 @ changeset: 3:d004c8f274b9
50 @ changeset: 3:d004c8f274b9
51 | tag: tip
51 | tag: tip
52 | parent: 0:ea207398892e
52 | parent: 0:ea207398892e
53 | user: test
53 | user: test
54 | date: Thu Jan 01 00:00:00 1970 +0000
54 | date: Thu Jan 01 00:00:00 1970 +0000
55 | summary: A2
55 | summary: A2
56 |
56 |
57 | x changeset: 2:a468dc9b3633
57 | x changeset: 2:a468dc9b3633
58 |/ parent: 0:ea207398892e
58 |/ parent: 0:ea207398892e
59 | user: test
59 | user: test
60 | date: Thu Jan 01 00:00:00 1970 +0000
60 | date: Thu Jan 01 00:00:00 1970 +0000
61 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2
61 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2
62 | summary: A1
62 | summary: A1
63 |
63 |
64 | x changeset: 1:471f378eab4c
64 | x changeset: 1:471f378eab4c
65 |/ user: test
65 |/ user: test
66 | date: Thu Jan 01 00:00:00 1970 +0000
66 | date: Thu Jan 01 00:00:00 1970 +0000
67 | obsolete: rewritten using amend as 2:a468dc9b3633
67 | obsolete: rewritten using amend as 2:a468dc9b3633
68 | summary: A0
68 | summary: A0
69 |
69 |
70 o changeset: 0:ea207398892e
70 o changeset: 0:ea207398892e
71 user: test
71 user: test
72 date: Thu Jan 01 00:00:00 1970 +0000
72 date: Thu Jan 01 00:00:00 1970 +0000
73 summary: ROOT
73 summary: ROOT
74
74
75 Check templates
75 Check templates
76 ---------------
76 ---------------
77 $ hg up 'desc(A0)' --hidden
77 $ hg up 'desc(A0)' --hidden
78 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
79
79
80 Predecessors template should show current revision as it is the working copy
80 Predecessors template should show current revision as it is the working copy
81 $ hg tlog
81 $ hg tlog
82 o d004c8f274b9
82 o d004c8f274b9
83 | Predecessors: 1:471f378eab4c
83 | Predecessors: 1:471f378eab4c
84 | semi-colon: 1:471f378eab4c
84 | semi-colon: 1:471f378eab4c
85 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
85 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
86 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
86 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
87 | @ 471f378eab4c
87 | @ 471f378eab4c
88 |/ Successors: 3:d004c8f274b9
88 |/ Successors: 3:d004c8f274b9
89 | multi-line: 3:d004c8f274b9
89 | multi-line: 3:d004c8f274b9
90 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
90 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
91 o ea207398892e
91 o ea207398892e
92
92
93 $ hg fatelog
93 $ hg fatelog
94 o d004c8f274b9
94 o d004c8f274b9
95 |
95 |
96 | @ 471f378eab4c
96 | @ 471f378eab4c
97 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test, test2 (between 2001-04-19 04:25 +0000 and 2009-02-13 23:31 +0000);
97 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test, test2 (between 2001-04-19 04:25 +0000 and 2009-02-13 23:31 +0000);
98 o ea207398892e
98 o ea207398892e
99
99
100
100
101 $ hg fatelogkw
101 $ hg fatelogkw
102 o d004c8f274b9
102 o d004c8f274b9
103 |
103 |
104 | @ 471f378eab4c
104 | @ 471f378eab4c
105 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test, test2
105 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test, test2
106 o ea207398892e
106 o ea207398892e
107
107
108
108
109 $ hg log -G --config ui.logtemplate=
109 $ hg log -G --config ui.logtemplate=
110 o changeset: 3:d004c8f274b9
110 o changeset: 3:d004c8f274b9
111 | tag: tip
111 | tag: tip
112 | parent: 0:ea207398892e
112 | parent: 0:ea207398892e
113 | user: test
113 | user: test
114 | date: Thu Jan 01 00:00:00 1970 +0000
114 | date: Thu Jan 01 00:00:00 1970 +0000
115 | summary: A2
115 | summary: A2
116 |
116 |
117 | @ changeset: 1:471f378eab4c
117 | @ changeset: 1:471f378eab4c
118 |/ user: test
118 |/ user: test
119 | date: Thu Jan 01 00:00:00 1970 +0000
119 | date: Thu Jan 01 00:00:00 1970 +0000
120 | obsolete: rewritten using amend as 3:d004c8f274b9 by test, test2
120 | obsolete: rewritten using amend as 3:d004c8f274b9 by test, test2
121 | summary: A0
121 | summary: A0
122 |
122 |
123 o changeset: 0:ea207398892e
123 o changeset: 0:ea207398892e
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:00 1970 +0000
125 date: Thu Jan 01 00:00:00 1970 +0000
126 summary: ROOT
126 summary: ROOT
127
127
128
128
129 $ hg log -G -T "default"
129 $ hg log -G -T "default"
130 o changeset: 3:d004c8f274b9
130 o changeset: 3:d004c8f274b9
131 | tag: tip
131 | tag: tip
132 | parent: 0:ea207398892e
132 | parent: 0:ea207398892e
133 | user: test
133 | user: test
134 | date: Thu Jan 01 00:00:00 1970 +0000
134 | date: Thu Jan 01 00:00:00 1970 +0000
135 | summary: A2
135 | summary: A2
136 |
136 |
137 | @ changeset: 1:471f378eab4c
137 | @ changeset: 1:471f378eab4c
138 |/ user: test
138 |/ user: test
139 | date: Thu Jan 01 00:00:00 1970 +0000
139 | date: Thu Jan 01 00:00:00 1970 +0000
140 | obsolete: rewritten using amend as 3:d004c8f274b9 by test, test2
140 | obsolete: rewritten using amend as 3:d004c8f274b9 by test, test2
141 | summary: A0
141 | summary: A0
142 |
142 |
143 o changeset: 0:ea207398892e
143 o changeset: 0:ea207398892e
144 user: test
144 user: test
145 date: Thu Jan 01 00:00:00 1970 +0000
145 date: Thu Jan 01 00:00:00 1970 +0000
146 summary: ROOT
146 summary: ROOT
147
147
148 $ hg up 'desc(A1)' --hidden
148 $ hg up 'desc(A1)' --hidden
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150
150
151 Predecessors template should show current revision as it is the working copy
151 Predecessors template should show current revision as it is the working copy
152 $ hg tlog
152 $ hg tlog
153 o d004c8f274b9
153 o d004c8f274b9
154 | Predecessors: 2:a468dc9b3633
154 | Predecessors: 2:a468dc9b3633
155 | semi-colon: 2:a468dc9b3633
155 | semi-colon: 2:a468dc9b3633
156 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
156 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
157 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
157 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
158 | @ a468dc9b3633
158 | @ a468dc9b3633
159 |/ Successors: 3:d004c8f274b9
159 |/ Successors: 3:d004c8f274b9
160 | multi-line: 3:d004c8f274b9
160 | multi-line: 3:d004c8f274b9
161 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
161 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
162 o ea207398892e
162 o ea207398892e
163
163
164 $ hg fatelog
164 $ hg fatelog
165 o d004c8f274b9
165 o d004c8f274b9
166 |
166 |
167 | @ a468dc9b3633
167 | @ a468dc9b3633
168 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
168 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
169 o ea207398892e
169 o ea207398892e
170
170
171 Predecessors template should show all the predecessors as we force their display
171 Predecessors template should show all the predecessors as we force their display
172 with --hidden
172 with --hidden
173 $ hg tlog --hidden
173 $ hg tlog --hidden
174 o d004c8f274b9
174 o d004c8f274b9
175 | Predecessors: 2:a468dc9b3633
175 | Predecessors: 2:a468dc9b3633
176 | semi-colon: 2:a468dc9b3633
176 | semi-colon: 2:a468dc9b3633
177 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
177 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
178 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
178 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
179 | @ a468dc9b3633
179 | @ a468dc9b3633
180 |/ Predecessors: 1:471f378eab4c
180 |/ Predecessors: 1:471f378eab4c
181 | semi-colon: 1:471f378eab4c
181 | semi-colon: 1:471f378eab4c
182 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
182 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
183 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
183 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
184 | Successors: 3:d004c8f274b9
184 | Successors: 3:d004c8f274b9
185 | multi-line: 3:d004c8f274b9
185 | multi-line: 3:d004c8f274b9
186 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
186 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
187 | x 471f378eab4c
187 | x 471f378eab4c
188 |/ Successors: 2:a468dc9b3633
188 |/ Successors: 2:a468dc9b3633
189 | multi-line: 2:a468dc9b3633
189 | multi-line: 2:a468dc9b3633
190 | json: [["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]]
190 | json: [["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]]
191 o ea207398892e
191 o ea207398892e
192
192
193 $ hg fatelog --hidden
193 $ hg fatelog --hidden
194 o d004c8f274b9
194 o d004c8f274b9
195 |
195 |
196 | @ a468dc9b3633
196 | @ a468dc9b3633
197 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
197 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
198 | x 471f378eab4c
198 | x 471f378eab4c
199 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000);
199 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000);
200 o ea207398892e
200 o ea207398892e
201
201
202
202
203 Predecessors template shouldn't show anything as all obsolete commit are not
203 Predecessors template shouldn't show anything as all obsolete commit are not
204 visible.
204 visible.
205 $ hg up 'desc(A2)'
205 $ hg up 'desc(A2)'
206 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 $ hg tlog
207 $ hg tlog
208 @ d004c8f274b9
208 @ d004c8f274b9
209 |
209 |
210 o ea207398892e
210 o ea207398892e
211
211
212 $ hg tlog --hidden
212 $ hg tlog --hidden
213 @ d004c8f274b9
213 @ d004c8f274b9
214 | Predecessors: 2:a468dc9b3633
214 | Predecessors: 2:a468dc9b3633
215 | semi-colon: 2:a468dc9b3633
215 | semi-colon: 2:a468dc9b3633
216 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
216 | json: ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]
217 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
217 | map: 2:a468dc9b36338b14fdb7825f55ce3df4e71517ad
218 | x a468dc9b3633
218 | x a468dc9b3633
219 |/ Predecessors: 1:471f378eab4c
219 |/ Predecessors: 1:471f378eab4c
220 | semi-colon: 1:471f378eab4c
220 | semi-colon: 1:471f378eab4c
221 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
221 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
222 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
222 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
223 | Successors: 3:d004c8f274b9
223 | Successors: 3:d004c8f274b9
224 | multi-line: 3:d004c8f274b9
224 | multi-line: 3:d004c8f274b9
225 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
225 | json: [["d004c8f274b9ec480a47a93c10dac5eee63adb78"]]
226 | x 471f378eab4c
226 | x 471f378eab4c
227 |/ Successors: 2:a468dc9b3633
227 |/ Successors: 2:a468dc9b3633
228 | multi-line: 2:a468dc9b3633
228 | multi-line: 2:a468dc9b3633
229 | json: [["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]]
229 | json: [["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]]
230 o ea207398892e
230 o ea207398892e
231
231
232 $ hg fatelog
232 $ hg fatelog
233 @ d004c8f274b9
233 @ d004c8f274b9
234 |
234 |
235 o ea207398892e
235 o ea207398892e
236
236
237
237
238 $ hg fatelog --hidden
238 $ hg fatelog --hidden
239 @ d004c8f274b9
239 @ d004c8f274b9
240 |
240 |
241 | x a468dc9b3633
241 | x a468dc9b3633
242 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
242 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000);
243 | x 471f378eab4c
243 | x 471f378eab4c
244 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000);
244 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000);
245 o ea207398892e
245 o ea207398892e
246
246
247 $ hg fatelogjson --hidden
247 $ hg fatelogjson --hidden
248 @ d004c8f274b9
248 @ d004c8f274b9
249 |
249 |
250 | x a468dc9b3633
250 | x a468dc9b3633
251 |/ Obsfate: [{"markers": [["a468dc9b36338b14fdb7825f55ce3df4e71517ad", ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test2"]], [987654321.0, 0], null]], "successors": ["d004c8f274b9ec480a47a93c10dac5eee63adb78"]}]
251 |/ Obsfate: [{"markers": [["a468dc9b36338b14fdb7825f55ce3df4e71517ad", ["d004c8f274b9ec480a47a93c10dac5eee63adb78"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test2"]], [987654321.0, 0], null]], "successors": ["d004c8f274b9ec480a47a93c10dac5eee63adb78"]}]
252 | x 471f378eab4c
252 | x 471f378eab4c
253 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], 0, [["ef1", "9"], ["operation", "amend"], ["user", "test"]], [1234567890.0, 0], null]], "successors": ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]}]
253 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"], 0, [["ef1", "9"], ["operation", "amend"], ["user", "test"]], [1234567890.0, 0], null]], "successors": ["a468dc9b36338b14fdb7825f55ce3df4e71517ad"]}]
254 o ea207398892e
254 o ea207398892e
255
255
256
256
257 Check other fatelog implementations
257 Check other fatelog implementations
258 -----------------------------------
258 -----------------------------------
259
259
260 $ hg fatelogkw --hidden -q
260 $ hg fatelogkw --hidden -q
261 @ d004c8f274b9
261 @ d004c8f274b9
262 |
262 |
263 | x a468dc9b3633
263 | x a468dc9b3633
264 |/ Obsfate: rewritten using amend as 3:d004c8f274b9
264 |/ Obsfate: rewritten using amend as 3:d004c8f274b9
265 | x 471f378eab4c
265 | x 471f378eab4c
266 |/ Obsfate: rewritten using amend as 2:a468dc9b3633
266 |/ Obsfate: rewritten using amend as 2:a468dc9b3633
267 o ea207398892e
267 o ea207398892e
268
268
269 $ hg fatelogkw --hidden
269 $ hg fatelogkw --hidden
270 @ d004c8f274b9
270 @ d004c8f274b9
271 |
271 |
272 | x a468dc9b3633
272 | x a468dc9b3633
273 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2
273 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2
274 | x 471f378eab4c
274 | x 471f378eab4c
275 |/ Obsfate: rewritten using amend as 2:a468dc9b3633
275 |/ Obsfate: rewritten using amend as 2:a468dc9b3633
276 o ea207398892e
276 o ea207398892e
277
277
278 $ hg fatelogkw --hidden -v
278 $ hg fatelogkw --hidden -v
279 @ d004c8f274b9
279 @ d004c8f274b9
280 |
280 |
281 | x a468dc9b3633
281 | x a468dc9b3633
282 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000)
282 |/ Obsfate: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000)
283 | x 471f378eab4c
283 | x 471f378eab4c
284 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000)
284 |/ Obsfate: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000)
285 o ea207398892e
285 o ea207398892e
286
286
287
287
288 $ hg log -G -T "default" --hidden
288 $ hg log -G -T "default" --hidden
289 @ changeset: 3:d004c8f274b9
289 @ changeset: 3:d004c8f274b9
290 | tag: tip
290 | tag: tip
291 | parent: 0:ea207398892e
291 | parent: 0:ea207398892e
292 | user: test
292 | user: test
293 | date: Thu Jan 01 00:00:00 1970 +0000
293 | date: Thu Jan 01 00:00:00 1970 +0000
294 | summary: A2
294 | summary: A2
295 |
295 |
296 | x changeset: 2:a468dc9b3633
296 | x changeset: 2:a468dc9b3633
297 |/ parent: 0:ea207398892e
297 |/ parent: 0:ea207398892e
298 | user: test
298 | user: test
299 | date: Thu Jan 01 00:00:00 1970 +0000
299 | date: Thu Jan 01 00:00:00 1970 +0000
300 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2
300 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2
301 | summary: A1
301 | summary: A1
302 |
302 |
303 | x changeset: 1:471f378eab4c
303 | x changeset: 1:471f378eab4c
304 |/ user: test
304 |/ user: test
305 | date: Thu Jan 01 00:00:00 1970 +0000
305 | date: Thu Jan 01 00:00:00 1970 +0000
306 | obsolete: rewritten using amend as 2:a468dc9b3633
306 | obsolete: rewritten using amend as 2:a468dc9b3633
307 | summary: A0
307 | summary: A0
308 |
308 |
309 o changeset: 0:ea207398892e
309 o changeset: 0:ea207398892e
310 user: test
310 user: test
311 date: Thu Jan 01 00:00:00 1970 +0000
311 date: Thu Jan 01 00:00:00 1970 +0000
312 summary: ROOT
312 summary: ROOT
313
313
314 $ hg log -G -T "default" --hidden -v
314 $ hg log -G -T "default" --hidden -v
315 @ changeset: 3:d004c8f274b9
315 @ changeset: 3:d004c8f274b9
316 | tag: tip
316 | tag: tip
317 | parent: 0:ea207398892e
317 | parent: 0:ea207398892e
318 | user: test
318 | user: test
319 | date: Thu Jan 01 00:00:00 1970 +0000
319 | date: Thu Jan 01 00:00:00 1970 +0000
320 | files: A0
320 | files: A0
321 | description:
321 | description:
322 | A2
322 | A2
323 |
323 |
324 |
324 |
325 | x changeset: 2:a468dc9b3633
325 | x changeset: 2:a468dc9b3633
326 |/ parent: 0:ea207398892e
326 |/ parent: 0:ea207398892e
327 | user: test
327 | user: test
328 | date: Thu Jan 01 00:00:00 1970 +0000
328 | date: Thu Jan 01 00:00:00 1970 +0000
329 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000)
329 | obsolete: rewritten using amend as 3:d004c8f274b9 by test2 (at 2001-04-19 04:25 +0000)
330 | files: A0
330 | files: A0
331 | description:
331 | description:
332 | A1
332 | A1
333 |
333 |
334 |
334 |
335 | x changeset: 1:471f378eab4c
335 | x changeset: 1:471f378eab4c
336 |/ user: test
336 |/ user: test
337 | date: Thu Jan 01 00:00:00 1970 +0000
337 | date: Thu Jan 01 00:00:00 1970 +0000
338 | obsolete: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000)
338 | obsolete: rewritten using amend as 2:a468dc9b3633 by test (at 2009-02-13 23:31 +0000)
339 | files: A0
339 | files: A0
340 | description:
340 | description:
341 | A0
341 | A0
342 |
342 |
343 |
343 |
344 o changeset: 0:ea207398892e
344 o changeset: 0:ea207398892e
345 user: test
345 user: test
346 date: Thu Jan 01 00:00:00 1970 +0000
346 date: Thu Jan 01 00:00:00 1970 +0000
347 files: ROOT
347 files: ROOT
348 description:
348 description:
349 ROOT
349 ROOT
350
350
351
351
352 Test templates with splitted commit
352 Test templates with splitted commit
353 ===================================
353 ===================================
354
354
355 $ hg init $TESTTMP/templates-local-split
355 $ hg init $TESTTMP/templates-local-split
356 $ cd $TESTTMP/templates-local-split
356 $ cd $TESTTMP/templates-local-split
357 $ mkcommit ROOT
357 $ mkcommit ROOT
358 $ echo 42 >> a
358 $ echo 42 >> a
359 $ echo 43 >> b
359 $ echo 43 >> b
360 $ hg commit -A -m "A0"
360 $ hg commit -A -m "A0"
361 adding a
361 adding a
362 adding b
362 adding b
363 $ hg log --hidden -G
363 $ hg log --hidden -G
364 @ changeset: 1:471597cad322
364 @ changeset: 1:471597cad322
365 | tag: tip
365 | tag: tip
366 | user: test
366 | user: test
367 | date: Thu Jan 01 00:00:00 1970 +0000
367 | date: Thu Jan 01 00:00:00 1970 +0000
368 | summary: A0
368 | summary: A0
369 |
369 |
370 o changeset: 0:ea207398892e
370 o changeset: 0:ea207398892e
371 user: test
371 user: test
372 date: Thu Jan 01 00:00:00 1970 +0000
372 date: Thu Jan 01 00:00:00 1970 +0000
373 summary: ROOT
373 summary: ROOT
374
374
375 # Simulate split
375 # Simulate split
376 $ hg up -r "desc(ROOT)"
376 $ hg up -r "desc(ROOT)"
377 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
377 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
378 $ echo 42 >> a
378 $ echo 42 >> a
379 $ hg commit -A -m "A0"
379 $ hg commit -A -m "A0"
380 adding a
380 adding a
381 created new head
381 created new head
382 $ echo 43 >> b
382 $ echo 43 >> b
383 $ hg commit -A -m "A0"
383 $ hg commit -A -m "A0"
384 adding b
384 adding b
385 $ hg debugobsolete `getid "1"` `getid "2"` `getid "3"`
385 $ hg debugobsolete `getid "1"` `getid "2"` `getid "3"`
386 obsoleted 1 changesets
386 obsoleted 1 changesets
387
387
388 $ hg log --hidden -G
388 $ hg log --hidden -G
389 @ changeset: 3:f257fde29c7a
389 @ changeset: 3:f257fde29c7a
390 | tag: tip
390 | tag: tip
391 | user: test
391 | user: test
392 | date: Thu Jan 01 00:00:00 1970 +0000
392 | date: Thu Jan 01 00:00:00 1970 +0000
393 | summary: A0
393 | summary: A0
394 |
394 |
395 o changeset: 2:337fec4d2edc
395 o changeset: 2:337fec4d2edc
396 | parent: 0:ea207398892e
396 | parent: 0:ea207398892e
397 | user: test
397 | user: test
398 | date: Thu Jan 01 00:00:00 1970 +0000
398 | date: Thu Jan 01 00:00:00 1970 +0000
399 | summary: A0
399 | summary: A0
400 |
400 |
401 | x changeset: 1:471597cad322
401 | x changeset: 1:471597cad322
402 |/ user: test
402 |/ user: test
403 | date: Thu Jan 01 00:00:00 1970 +0000
403 | date: Thu Jan 01 00:00:00 1970 +0000
404 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a
404 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a
405 | summary: A0
405 | summary: A0
406 |
406 |
407 o changeset: 0:ea207398892e
407 o changeset: 0:ea207398892e
408 user: test
408 user: test
409 date: Thu Jan 01 00:00:00 1970 +0000
409 date: Thu Jan 01 00:00:00 1970 +0000
410 summary: ROOT
410 summary: ROOT
411
411
412 Check templates
412 Check templates
413 ---------------
413 ---------------
414
414
415 $ hg up 'obsolete()' --hidden
415 $ hg up 'obsolete()' --hidden
416 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
417
417
418 Predecessors template should show current revision as it is the working copy
418 Predecessors template should show current revision as it is the working copy
419 $ hg tlog
419 $ hg tlog
420 o f257fde29c7a
420 o f257fde29c7a
421 | Predecessors: 1:471597cad322
421 | Predecessors: 1:471597cad322
422 | semi-colon: 1:471597cad322
422 | semi-colon: 1:471597cad322
423 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
423 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
424 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
424 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
425 o 337fec4d2edc
425 o 337fec4d2edc
426 | Predecessors: 1:471597cad322
426 | Predecessors: 1:471597cad322
427 | semi-colon: 1:471597cad322
427 | semi-colon: 1:471597cad322
428 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
428 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
429 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
429 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
430 | @ 471597cad322
430 | @ 471597cad322
431 |/ Successors: 2:337fec4d2edc 3:f257fde29c7a
431 |/ Successors: 2:337fec4d2edc 3:f257fde29c7a
432 | multi-line: 2:337fec4d2edc 3:f257fde29c7a
432 | multi-line: 2:337fec4d2edc 3:f257fde29c7a
433 | json: [["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]]
433 | json: [["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]]
434 o ea207398892e
434 o ea207398892e
435
435
436
436
437 $ hg fatelog
437 $ hg fatelog
438 o f257fde29c7a
438 o f257fde29c7a
439 |
439 |
440 o 337fec4d2edc
440 o 337fec4d2edc
441 |
441 |
442 | @ 471597cad322
442 | @ 471597cad322
443 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000);
443 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000);
444 o ea207398892e
444 o ea207398892e
445
445
446 $ hg up f257fde29c7a
446 $ hg up f257fde29c7a
447 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
447 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
448
448
449 Predecessors template should not show a predecessor as it's not displayed in
449 Predecessors template should not show a predecessor as it's not displayed in
450 the log
450 the log
451 $ hg tlog
451 $ hg tlog
452 @ f257fde29c7a
452 @ f257fde29c7a
453 |
453 |
454 o 337fec4d2edc
454 o 337fec4d2edc
455 |
455 |
456 o ea207398892e
456 o ea207398892e
457
457
458 Predecessors template should show both predecessors as we force their display
458 Predecessors template should show both predecessors as we force their display
459 with --hidden
459 with --hidden
460 $ hg tlog --hidden
460 $ hg tlog --hidden
461 @ f257fde29c7a
461 @ f257fde29c7a
462 | Predecessors: 1:471597cad322
462 | Predecessors: 1:471597cad322
463 | semi-colon: 1:471597cad322
463 | semi-colon: 1:471597cad322
464 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
464 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
465 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
465 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
466 o 337fec4d2edc
466 o 337fec4d2edc
467 | Predecessors: 1:471597cad322
467 | Predecessors: 1:471597cad322
468 | semi-colon: 1:471597cad322
468 | semi-colon: 1:471597cad322
469 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
469 | json: ["471597cad322d1f659bb169751be9133dad92ef3"]
470 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
470 | map: 1:471597cad322d1f659bb169751be9133dad92ef3
471 | x 471597cad322
471 | x 471597cad322
472 |/ Successors: 2:337fec4d2edc 3:f257fde29c7a
472 |/ Successors: 2:337fec4d2edc 3:f257fde29c7a
473 | multi-line: 2:337fec4d2edc 3:f257fde29c7a
473 | multi-line: 2:337fec4d2edc 3:f257fde29c7a
474 | json: [["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]]
474 | json: [["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]]
475 o ea207398892e
475 o ea207398892e
476
476
477
477
478 $ hg fatelog --hidden
478 $ hg fatelog --hidden
479 @ f257fde29c7a
479 @ f257fde29c7a
480 |
480 |
481 o 337fec4d2edc
481 o 337fec4d2edc
482 |
482 |
483 | x 471597cad322
483 | x 471597cad322
484 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000);
484 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000);
485 o ea207398892e
485 o ea207398892e
486
486
487 $ hg fatelogjson --hidden
487 $ hg fatelogjson --hidden
488 @ f257fde29c7a
488 @ f257fde29c7a
489 |
489 |
490 o 337fec4d2edc
490 o 337fec4d2edc
491 |
491 |
492 | x 471597cad322
492 | x 471597cad322
493 |/ Obsfate: [{"markers": [["471597cad322d1f659bb169751be9133dad92ef3", ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]}]
493 |/ Obsfate: [{"markers": [["471597cad322d1f659bb169751be9133dad92ef3", ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["337fec4d2edcf0e7a467e35f818234bc620068b5", "f257fde29c7a847c9b607f6e958656d0df0fb15c"]}]
494 o ea207398892e
494 o ea207398892e
495
495
496 Check other fatelog implementations
496 Check other fatelog implementations
497 -----------------------------------
497 -----------------------------------
498
498
499 $ hg fatelogkw --hidden -q
499 $ hg fatelogkw --hidden -q
500 @ f257fde29c7a
500 @ f257fde29c7a
501 |
501 |
502 o 337fec4d2edc
502 o 337fec4d2edc
503 |
503 |
504 | x 471597cad322
504 | x 471597cad322
505 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a
505 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a
506 o ea207398892e
506 o ea207398892e
507
507
508 $ hg fatelogkw --hidden
508 $ hg fatelogkw --hidden
509 @ f257fde29c7a
509 @ f257fde29c7a
510 |
510 |
511 o 337fec4d2edc
511 o 337fec4d2edc
512 |
512 |
513 | x 471597cad322
513 | x 471597cad322
514 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a
514 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a
515 o ea207398892e
515 o ea207398892e
516
516
517 $ hg fatelogkw --hidden -v
517 $ hg fatelogkw --hidden -v
518 @ f257fde29c7a
518 @ f257fde29c7a
519 |
519 |
520 o 337fec4d2edc
520 o 337fec4d2edc
521 |
521 |
522 | x 471597cad322
522 | x 471597cad322
523 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000)
523 |/ Obsfate: split as 2:337fec4d2edc, 3:f257fde29c7a by test (at 1970-01-01 00:00 +0000)
524 o ea207398892e
524 o ea207398892e
525
525
526
526
527 $ hg log -G -T "default" --hidden
527 $ hg log -G -T "default" --hidden
528 @ changeset: 3:f257fde29c7a
528 @ changeset: 3:f257fde29c7a
529 | tag: tip
529 | tag: tip
530 | user: test
530 | user: test
531 | date: Thu Jan 01 00:00:00 1970 +0000
531 | date: Thu Jan 01 00:00:00 1970 +0000
532 | summary: A0
532 | summary: A0
533 |
533 |
534 o changeset: 2:337fec4d2edc
534 o changeset: 2:337fec4d2edc
535 | parent: 0:ea207398892e
535 | parent: 0:ea207398892e
536 | user: test
536 | user: test
537 | date: Thu Jan 01 00:00:00 1970 +0000
537 | date: Thu Jan 01 00:00:00 1970 +0000
538 | summary: A0
538 | summary: A0
539 |
539 |
540 | x changeset: 1:471597cad322
540 | x changeset: 1:471597cad322
541 |/ user: test
541 |/ user: test
542 | date: Thu Jan 01 00:00:00 1970 +0000
542 | date: Thu Jan 01 00:00:00 1970 +0000
543 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a
543 | obsolete: split as 2:337fec4d2edc, 3:f257fde29c7a
544 | summary: A0
544 | summary: A0
545 |
545 |
546 o changeset: 0:ea207398892e
546 o changeset: 0:ea207398892e
547 user: test
547 user: test
548 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
549 summary: ROOT
549 summary: ROOT
550
550
551
551
552 Test templates with folded commit
552 Test templates with folded commit
553 =================================
553 =================================
554
554
555 Test setup
555 Test setup
556 ----------
556 ----------
557
557
558 $ hg init $TESTTMP/templates-local-fold
558 $ hg init $TESTTMP/templates-local-fold
559 $ cd $TESTTMP/templates-local-fold
559 $ cd $TESTTMP/templates-local-fold
560 $ mkcommit ROOT
560 $ mkcommit ROOT
561 $ mkcommit A0
561 $ mkcommit A0
562 $ mkcommit B0
562 $ mkcommit B0
563 $ hg log --hidden -G
563 $ hg log --hidden -G
564 @ changeset: 2:0dec01379d3b
564 @ changeset: 2:0dec01379d3b
565 | tag: tip
565 | tag: tip
566 | user: test
566 | user: test
567 | date: Thu Jan 01 00:00:00 1970 +0000
567 | date: Thu Jan 01 00:00:00 1970 +0000
568 | summary: B0
568 | summary: B0
569 |
569 |
570 o changeset: 1:471f378eab4c
570 o changeset: 1:471f378eab4c
571 | user: test
571 | user: test
572 | date: Thu Jan 01 00:00:00 1970 +0000
572 | date: Thu Jan 01 00:00:00 1970 +0000
573 | summary: A0
573 | summary: A0
574 |
574 |
575 o changeset: 0:ea207398892e
575 o changeset: 0:ea207398892e
576 user: test
576 user: test
577 date: Thu Jan 01 00:00:00 1970 +0000
577 date: Thu Jan 01 00:00:00 1970 +0000
578 summary: ROOT
578 summary: ROOT
579
579
580 Simulate a fold
580 Simulate a fold
581 $ hg up -r "desc(ROOT)"
581 $ hg up -r "desc(ROOT)"
582 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
582 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
583 $ echo "A0" > A0
583 $ echo "A0" > A0
584 $ echo "B0" > B0
584 $ echo "B0" > B0
585 $ hg commit -A -m "C0"
585 $ hg commit -A -m "C0"
586 adding A0
586 adding A0
587 adding B0
587 adding B0
588 created new head
588 created new head
589 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(C0)"`
589 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(C0)"`
590 obsoleted 1 changesets
590 obsoleted 1 changesets
591 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(C0)"`
591 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(C0)"`
592 obsoleted 1 changesets
592 obsoleted 1 changesets
593
593
594 $ hg log --hidden -G
594 $ hg log --hidden -G
595 @ changeset: 3:eb5a0daa2192
595 @ changeset: 3:eb5a0daa2192
596 | tag: tip
596 | tag: tip
597 | parent: 0:ea207398892e
597 | parent: 0:ea207398892e
598 | user: test
598 | user: test
599 | date: Thu Jan 01 00:00:00 1970 +0000
599 | date: Thu Jan 01 00:00:00 1970 +0000
600 | summary: C0
600 | summary: C0
601 |
601 |
602 | x changeset: 2:0dec01379d3b
602 | x changeset: 2:0dec01379d3b
603 | | user: test
603 | | user: test
604 | | date: Thu Jan 01 00:00:00 1970 +0000
604 | | date: Thu Jan 01 00:00:00 1970 +0000
605 | | obsolete: rewritten as 3:eb5a0daa2192
605 | | obsolete: rewritten as 3:eb5a0daa2192
606 | | summary: B0
606 | | summary: B0
607 | |
607 | |
608 | x changeset: 1:471f378eab4c
608 | x changeset: 1:471f378eab4c
609 |/ user: test
609 |/ user: test
610 | date: Thu Jan 01 00:00:00 1970 +0000
610 | date: Thu Jan 01 00:00:00 1970 +0000
611 | obsolete: rewritten as 3:eb5a0daa2192
611 | obsolete: rewritten as 3:eb5a0daa2192
612 | summary: A0
612 | summary: A0
613 |
613 |
614 o changeset: 0:ea207398892e
614 o changeset: 0:ea207398892e
615 user: test
615 user: test
616 date: Thu Jan 01 00:00:00 1970 +0000
616 date: Thu Jan 01 00:00:00 1970 +0000
617 summary: ROOT
617 summary: ROOT
618
618
619 Check templates
619 Check templates
620 ---------------
620 ---------------
621
621
622 $ hg up 'desc(A0)' --hidden
622 $ hg up 'desc(A0)' --hidden
623 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
623 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
624
624
625 Predecessors template should show current revision as it is the working copy
625 Predecessors template should show current revision as it is the working copy
626 $ hg tlog
626 $ hg tlog
627 o eb5a0daa2192
627 o eb5a0daa2192
628 | Predecessors: 1:471f378eab4c
628 | Predecessors: 1:471f378eab4c
629 | semi-colon: 1:471f378eab4c
629 | semi-colon: 1:471f378eab4c
630 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
630 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
631 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
631 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
632 | @ 471f378eab4c
632 | @ 471f378eab4c
633 |/ Successors: 3:eb5a0daa2192
633 |/ Successors: 3:eb5a0daa2192
634 | multi-line: 3:eb5a0daa2192
634 | multi-line: 3:eb5a0daa2192
635 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
635 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
636 o ea207398892e
636 o ea207398892e
637
637
638
638
639 $ hg fatelog
639 $ hg fatelog
640 o eb5a0daa2192
640 o eb5a0daa2192
641 |
641 |
642 | @ 471f378eab4c
642 | @ 471f378eab4c
643 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
643 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
644 o ea207398892e
644 o ea207398892e
645
645
646 $ hg up 'desc(B0)' --hidden
646 $ hg up 'desc(B0)' --hidden
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
648
648
649 Predecessors template should show both predecessors as they should be both
649 Predecessors template should show both predecessors as they should be both
650 displayed
650 displayed
651 $ hg tlog
651 $ hg tlog
652 o eb5a0daa2192
652 o eb5a0daa2192
653 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
653 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
654 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
654 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
655 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
655 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
656 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
656 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
657 | @ 0dec01379d3b
657 | @ 0dec01379d3b
658 | | Successors: 3:eb5a0daa2192
658 | | Successors: 3:eb5a0daa2192
659 | | multi-line: 3:eb5a0daa2192
659 | | multi-line: 3:eb5a0daa2192
660 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
660 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
661 | x 471f378eab4c
661 | x 471f378eab4c
662 |/ Successors: 3:eb5a0daa2192
662 |/ Successors: 3:eb5a0daa2192
663 | multi-line: 3:eb5a0daa2192
663 | multi-line: 3:eb5a0daa2192
664 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
664 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
665 o ea207398892e
665 o ea207398892e
666
666
667
667
668 $ hg fatelog
668 $ hg fatelog
669 o eb5a0daa2192
669 o eb5a0daa2192
670 |
670 |
671 | @ 0dec01379d3b
671 | @ 0dec01379d3b
672 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
672 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
673 | x 471f378eab4c
673 | x 471f378eab4c
674 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
674 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
675 o ea207398892e
675 o ea207398892e
676
676
677 $ hg up 'desc(C0)'
677 $ hg up 'desc(C0)'
678 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
678 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
679
679
680 Predecessors template should not show predecessors as they are not displayed in
680 Predecessors template should not show predecessors as they are not displayed in
681 the log
681 the log
682 $ hg tlog
682 $ hg tlog
683 @ eb5a0daa2192
683 @ eb5a0daa2192
684 |
684 |
685 o ea207398892e
685 o ea207398892e
686
686
687 Predecessors template should show both predecessors as we force their display
687 Predecessors template should show both predecessors as we force their display
688 with --hidden
688 with --hidden
689 $ hg tlog --hidden
689 $ hg tlog --hidden
690 @ eb5a0daa2192
690 @ eb5a0daa2192
691 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
691 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
692 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
692 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
693 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
693 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
694 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
694 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
695 | x 0dec01379d3b
695 | x 0dec01379d3b
696 | | Successors: 3:eb5a0daa2192
696 | | Successors: 3:eb5a0daa2192
697 | | multi-line: 3:eb5a0daa2192
697 | | multi-line: 3:eb5a0daa2192
698 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
698 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
699 | x 471f378eab4c
699 | x 471f378eab4c
700 |/ Successors: 3:eb5a0daa2192
700 |/ Successors: 3:eb5a0daa2192
701 | multi-line: 3:eb5a0daa2192
701 | multi-line: 3:eb5a0daa2192
702 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
702 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
703 o ea207398892e
703 o ea207398892e
704
704
705
705
706 $ hg fatelog --hidden
706 $ hg fatelog --hidden
707 @ eb5a0daa2192
707 @ eb5a0daa2192
708 |
708 |
709 | x 0dec01379d3b
709 | x 0dec01379d3b
710 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
710 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
711 | x 471f378eab4c
711 | x 471f378eab4c
712 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
712 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
713 o ea207398892e
713 o ea207398892e
714
714
715
715
716 $ hg fatelogjson --hidden
716 $ hg fatelogjson --hidden
717 @ eb5a0daa2192
717 @ eb5a0daa2192
718 |
718 |
719 | x 0dec01379d3b
719 | x 0dec01379d3b
720 | | Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
720 | | Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
721 | x 471f378eab4c
721 | x 471f378eab4c
722 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
722 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
723 o ea207398892e
723 o ea207398892e
724
724
725 Check other fatelog implementations
725 Check other fatelog implementations
726 -----------------------------------
726 -----------------------------------
727
727
728 $ hg fatelogkw --hidden -q
728 $ hg fatelogkw --hidden -q
729 @ eb5a0daa2192
729 @ eb5a0daa2192
730 |
730 |
731 | x 0dec01379d3b
731 | x 0dec01379d3b
732 | | Obsfate: rewritten as 3:eb5a0daa2192
732 | | Obsfate: rewritten as 3:eb5a0daa2192
733 | x 471f378eab4c
733 | x 471f378eab4c
734 |/ Obsfate: rewritten as 3:eb5a0daa2192
734 |/ Obsfate: rewritten as 3:eb5a0daa2192
735 o ea207398892e
735 o ea207398892e
736
736
737 $ hg fatelogkw --hidden
737 $ hg fatelogkw --hidden
738 @ eb5a0daa2192
738 @ eb5a0daa2192
739 |
739 |
740 | x 0dec01379d3b
740 | x 0dec01379d3b
741 | | Obsfate: rewritten as 3:eb5a0daa2192
741 | | Obsfate: rewritten as 3:eb5a0daa2192
742 | x 471f378eab4c
742 | x 471f378eab4c
743 |/ Obsfate: rewritten as 3:eb5a0daa2192
743 |/ Obsfate: rewritten as 3:eb5a0daa2192
744 o ea207398892e
744 o ea207398892e
745
745
746 $ hg fatelogkw --hidden -v
746 $ hg fatelogkw --hidden -v
747 @ eb5a0daa2192
747 @ eb5a0daa2192
748 |
748 |
749 | x 0dec01379d3b
749 | x 0dec01379d3b
750 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
750 | | Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
751 | x 471f378eab4c
751 | x 471f378eab4c
752 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
752 |/ Obsfate: rewritten as 3:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
753 o ea207398892e
753 o ea207398892e
754
754
755 $ hg log -G -T "default" --hidden
755 $ hg log -G -T "default" --hidden
756 @ changeset: 3:eb5a0daa2192
756 @ changeset: 3:eb5a0daa2192
757 | tag: tip
757 | tag: tip
758 | parent: 0:ea207398892e
758 | parent: 0:ea207398892e
759 | user: test
759 | user: test
760 | date: Thu Jan 01 00:00:00 1970 +0000
760 | date: Thu Jan 01 00:00:00 1970 +0000
761 | summary: C0
761 | summary: C0
762 |
762 |
763 | x changeset: 2:0dec01379d3b
763 | x changeset: 2:0dec01379d3b
764 | | user: test
764 | | user: test
765 | | date: Thu Jan 01 00:00:00 1970 +0000
765 | | date: Thu Jan 01 00:00:00 1970 +0000
766 | | obsolete: rewritten as 3:eb5a0daa2192
766 | | obsolete: rewritten as 3:eb5a0daa2192
767 | | summary: B0
767 | | summary: B0
768 | |
768 | |
769 | x changeset: 1:471f378eab4c
769 | x changeset: 1:471f378eab4c
770 |/ user: test
770 |/ user: test
771 | date: Thu Jan 01 00:00:00 1970 +0000
771 | date: Thu Jan 01 00:00:00 1970 +0000
772 | obsolete: rewritten as 3:eb5a0daa2192
772 | obsolete: rewritten as 3:eb5a0daa2192
773 | summary: A0
773 | summary: A0
774 |
774 |
775 o changeset: 0:ea207398892e
775 o changeset: 0:ea207398892e
776 user: test
776 user: test
777 date: Thu Jan 01 00:00:00 1970 +0000
777 date: Thu Jan 01 00:00:00 1970 +0000
778 summary: ROOT
778 summary: ROOT
779
779
780
780
781 Test templates with divergence
781 Test templates with divergence
782 ==============================
782 ==============================
783
783
784 Test setup
784 Test setup
785 ----------
785 ----------
786
786
787 $ hg init $TESTTMP/templates-local-divergence
787 $ hg init $TESTTMP/templates-local-divergence
788 $ cd $TESTTMP/templates-local-divergence
788 $ cd $TESTTMP/templates-local-divergence
789 $ mkcommit ROOT
789 $ mkcommit ROOT
790 $ mkcommit A0
790 $ mkcommit A0
791 $ hg commit --amend -m "A1"
791 $ hg commit --amend -m "A1"
792 $ hg log --hidden -G
792 $ hg log --hidden -G
793 @ changeset: 2:fdf9bde5129a
793 @ changeset: 2:fdf9bde5129a
794 | tag: tip
794 | tag: tip
795 | parent: 0:ea207398892e
795 | parent: 0:ea207398892e
796 | user: test
796 | user: test
797 | date: Thu Jan 01 00:00:00 1970 +0000
797 | date: Thu Jan 01 00:00:00 1970 +0000
798 | summary: A1
798 | summary: A1
799 |
799 |
800 | x changeset: 1:471f378eab4c
800 | x changeset: 1:471f378eab4c
801 |/ user: test
801 |/ user: test
802 | date: Thu Jan 01 00:00:00 1970 +0000
802 | date: Thu Jan 01 00:00:00 1970 +0000
803 | obsolete: rewritten using amend as 2:fdf9bde5129a
803 | obsolete: rewritten using amend as 2:fdf9bde5129a
804 | summary: A0
804 | summary: A0
805 |
805 |
806 o changeset: 0:ea207398892e
806 o changeset: 0:ea207398892e
807 user: test
807 user: test
808 date: Thu Jan 01 00:00:00 1970 +0000
808 date: Thu Jan 01 00:00:00 1970 +0000
809 summary: ROOT
809 summary: ROOT
810
810
811 $ hg update --hidden 'desc(A0)'
811 $ hg update --hidden 'desc(A0)'
812 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
812 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
813 $ hg commit --amend -m "A2"
813 $ hg commit --amend -m "A2"
814 $ hg log --hidden -G
814 $ hg log --hidden -G
815 @ changeset: 3:65b757b745b9
815 @ changeset: 3:65b757b745b9
816 | tag: tip
816 | tag: tip
817 | parent: 0:ea207398892e
817 | parent: 0:ea207398892e
818 | user: test
818 | user: test
819 | date: Thu Jan 01 00:00:00 1970 +0000
819 | date: Thu Jan 01 00:00:00 1970 +0000
820 | instability: content-divergent
820 | instability: content-divergent
821 | summary: A2
821 | summary: A2
822 |
822 |
823 | o changeset: 2:fdf9bde5129a
823 | o changeset: 2:fdf9bde5129a
824 |/ parent: 0:ea207398892e
824 |/ parent: 0:ea207398892e
825 | user: test
825 | user: test
826 | date: Thu Jan 01 00:00:00 1970 +0000
826 | date: Thu Jan 01 00:00:00 1970 +0000
827 | instability: content-divergent
827 | instability: content-divergent
828 | summary: A1
828 | summary: A1
829 |
829 |
830 | x changeset: 1:471f378eab4c
830 | x changeset: 1:471f378eab4c
831 |/ user: test
831 |/ user: test
832 | date: Thu Jan 01 00:00:00 1970 +0000
832 | date: Thu Jan 01 00:00:00 1970 +0000
833 | obsolete: rewritten using amend as 2:fdf9bde5129a
833 | obsolete: rewritten using amend as 2:fdf9bde5129a
834 | obsolete: rewritten using amend as 3:65b757b745b9
834 | obsolete: rewritten using amend as 3:65b757b745b9
835 | summary: A0
835 | summary: A0
836 |
836 |
837 o changeset: 0:ea207398892e
837 o changeset: 0:ea207398892e
838 user: test
838 user: test
839 date: Thu Jan 01 00:00:00 1970 +0000
839 date: Thu Jan 01 00:00:00 1970 +0000
840 summary: ROOT
840 summary: ROOT
841
841
842 $ hg commit --amend -m 'A3'
842 $ hg commit --amend -m 'A3'
843 $ hg log --hidden -G
843 $ hg log --hidden -G
844 @ changeset: 4:019fadeab383
844 @ changeset: 4:019fadeab383
845 | tag: tip
845 | tag: tip
846 | parent: 0:ea207398892e
846 | parent: 0:ea207398892e
847 | user: test
847 | user: test
848 | date: Thu Jan 01 00:00:00 1970 +0000
848 | date: Thu Jan 01 00:00:00 1970 +0000
849 | instability: content-divergent
849 | instability: content-divergent
850 | summary: A3
850 | summary: A3
851 |
851 |
852 | x changeset: 3:65b757b745b9
852 | x changeset: 3:65b757b745b9
853 |/ parent: 0:ea207398892e
853 |/ parent: 0:ea207398892e
854 | user: test
854 | user: test
855 | date: Thu Jan 01 00:00:00 1970 +0000
855 | date: Thu Jan 01 00:00:00 1970 +0000
856 | obsolete: rewritten using amend as 4:019fadeab383
856 | obsolete: rewritten using amend as 4:019fadeab383
857 | summary: A2
857 | summary: A2
858 |
858 |
859 | o changeset: 2:fdf9bde5129a
859 | o changeset: 2:fdf9bde5129a
860 |/ parent: 0:ea207398892e
860 |/ parent: 0:ea207398892e
861 | user: test
861 | user: test
862 | date: Thu Jan 01 00:00:00 1970 +0000
862 | date: Thu Jan 01 00:00:00 1970 +0000
863 | instability: content-divergent
863 | instability: content-divergent
864 | summary: A1
864 | summary: A1
865 |
865 |
866 | x changeset: 1:471f378eab4c
866 | x changeset: 1:471f378eab4c
867 |/ user: test
867 |/ user: test
868 | date: Thu Jan 01 00:00:00 1970 +0000
868 | date: Thu Jan 01 00:00:00 1970 +0000
869 | obsolete: rewritten using amend as 2:fdf9bde5129a
869 | obsolete: rewritten using amend as 2:fdf9bde5129a
870 | obsolete: rewritten using amend as 3:65b757b745b9
870 | obsolete: rewritten using amend as 3:65b757b745b9
871 | summary: A0
871 | summary: A0
872 |
872 |
873 o changeset: 0:ea207398892e
873 o changeset: 0:ea207398892e
874 user: test
874 user: test
875 date: Thu Jan 01 00:00:00 1970 +0000
875 date: Thu Jan 01 00:00:00 1970 +0000
876 summary: ROOT
876 summary: ROOT
877
877
878
878
879 Check templates
879 Check templates
880 ---------------
880 ---------------
881
881
882 $ hg up 'desc(A0)' --hidden
882 $ hg up 'desc(A0)' --hidden
883 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
883 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
884
884
885 Predecessors template should show current revision as it is the working copy
885 Predecessors template should show current revision as it is the working copy
886 $ hg tlog
886 $ hg tlog
887 o 019fadeab383
887 o 019fadeab383
888 | Predecessors: 1:471f378eab4c
888 | Predecessors: 1:471f378eab4c
889 | semi-colon: 1:471f378eab4c
889 | semi-colon: 1:471f378eab4c
890 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
890 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
891 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
891 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
892 | o fdf9bde5129a
892 | o fdf9bde5129a
893 |/ Predecessors: 1:471f378eab4c
893 |/ Predecessors: 1:471f378eab4c
894 | semi-colon: 1:471f378eab4c
894 | semi-colon: 1:471f378eab4c
895 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
895 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
896 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
896 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
897 | @ 471f378eab4c
897 | @ 471f378eab4c
898 |/ Successors: 2:fdf9bde5129a; 4:019fadeab383
898 |/ Successors: 2:fdf9bde5129a; 4:019fadeab383
899 | multi-line: 2:fdf9bde5129a
899 | multi-line: 2:fdf9bde5129a
900 | multi-line: 4:019fadeab383
900 | multi-line: 4:019fadeab383
901 | json: [["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]]
901 | json: [["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]]
902 o ea207398892e
902 o ea207398892e
903
903
904 $ hg fatelog
904 $ hg fatelog
905 o 019fadeab383
905 o 019fadeab383
906 |
906 |
907 | o fdf9bde5129a
907 | o fdf9bde5129a
908 |/
908 |/
909 | @ 471f378eab4c
909 | @ 471f378eab4c
910 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000);
910 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000);
911 o ea207398892e
911 o ea207398892e
912
912
913 $ hg up 'desc(A1)'
913 $ hg up 'desc(A1)'
914 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
914 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
915
915
916 Predecessors template should not show predecessors as they are not displayed in
916 Predecessors template should not show predecessors as they are not displayed in
917 the log
917 the log
918 $ hg tlog
918 $ hg tlog
919 o 019fadeab383
919 o 019fadeab383
920 |
920 |
921 | @ fdf9bde5129a
921 | @ fdf9bde5129a
922 |/
922 |/
923 o ea207398892e
923 o ea207398892e
924
924
925
925
926 $ hg fatelog
926 $ hg fatelog
927 o 019fadeab383
927 o 019fadeab383
928 |
928 |
929 | @ fdf9bde5129a
929 | @ fdf9bde5129a
930 |/
930 |/
931 o ea207398892e
931 o ea207398892e
932
932
933 Predecessors template should the predecessors as we force their display with
933 Predecessors template should the predecessors as we force their display with
934 --hidden
934 --hidden
935 $ hg tlog --hidden
935 $ hg tlog --hidden
936 o 019fadeab383
936 o 019fadeab383
937 | Predecessors: 3:65b757b745b9
937 | Predecessors: 3:65b757b745b9
938 | semi-colon: 3:65b757b745b9
938 | semi-colon: 3:65b757b745b9
939 | json: ["65b757b745b935093c87a2bccd877521cccffcbd"]
939 | json: ["65b757b745b935093c87a2bccd877521cccffcbd"]
940 | map: 3:65b757b745b935093c87a2bccd877521cccffcbd
940 | map: 3:65b757b745b935093c87a2bccd877521cccffcbd
941 | x 65b757b745b9
941 | x 65b757b745b9
942 |/ Predecessors: 1:471f378eab4c
942 |/ Predecessors: 1:471f378eab4c
943 | semi-colon: 1:471f378eab4c
943 | semi-colon: 1:471f378eab4c
944 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
944 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
945 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
945 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
946 | Successors: 4:019fadeab383
946 | Successors: 4:019fadeab383
947 | multi-line: 4:019fadeab383
947 | multi-line: 4:019fadeab383
948 | json: [["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]]
948 | json: [["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]]
949 | @ fdf9bde5129a
949 | @ fdf9bde5129a
950 |/ Predecessors: 1:471f378eab4c
950 |/ Predecessors: 1:471f378eab4c
951 | semi-colon: 1:471f378eab4c
951 | semi-colon: 1:471f378eab4c
952 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
952 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
953 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
953 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
954 | x 471f378eab4c
954 | x 471f378eab4c
955 |/ Successors: 2:fdf9bde5129a; 3:65b757b745b9
955 |/ Successors: 2:fdf9bde5129a; 3:65b757b745b9
956 | multi-line: 2:fdf9bde5129a
956 | multi-line: 2:fdf9bde5129a
957 | multi-line: 3:65b757b745b9
957 | multi-line: 3:65b757b745b9
958 | json: [["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], ["65b757b745b935093c87a2bccd877521cccffcbd"]]
958 | json: [["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], ["65b757b745b935093c87a2bccd877521cccffcbd"]]
959 o ea207398892e
959 o ea207398892e
960
960
961
961
962 $ hg fatelog --hidden
962 $ hg fatelog --hidden
963 o 019fadeab383
963 o 019fadeab383
964 |
964 |
965 | x 65b757b745b9
965 | x 65b757b745b9
966 |/ Obsfate: rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000);
966 |/ Obsfate: rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000);
967 | @ fdf9bde5129a
967 | @ fdf9bde5129a
968 |/
968 |/
969 | x 471f378eab4c
969 | x 471f378eab4c
970 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000);
970 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000);
971 o ea207398892e
971 o ea207398892e
972
972
973
973
974 $ hg fatelogjson --hidden
974 $ hg fatelogjson --hidden
975 o 019fadeab383
975 o 019fadeab383
976 |
976 |
977 | x 65b757b745b9
977 | x 65b757b745b9
978 |/ Obsfate: [{"markers": [["65b757b745b935093c87a2bccd877521cccffcbd", ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]}]
978 |/ Obsfate: [{"markers": [["65b757b745b935093c87a2bccd877521cccffcbd", ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["019fadeab383f6699fa83ad7bdb4d82ed2c0e5ab"]}]
979 | @ fdf9bde5129a
979 | @ fdf9bde5129a
980 |/
980 |/
981 | x 471f378eab4c
981 | x 471f378eab4c
982 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"]}, {"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["65b757b745b935093c87a2bccd877521cccffcbd"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["65b757b745b935093c87a2bccd877521cccffcbd"]}]
982 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e"]}, {"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["65b757b745b935093c87a2bccd877521cccffcbd"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["65b757b745b935093c87a2bccd877521cccffcbd"]}]
983 o ea207398892e
983 o ea207398892e
984
984
985
985
986 Check other fatelog implementations
986 Check other fatelog implementations
987 -----------------------------------
987 -----------------------------------
988
988
989 $ hg fatelogkw --hidden -q
989 $ hg fatelogkw --hidden -q
990 o 019fadeab383
990 o 019fadeab383
991 |
991 |
992 | x 65b757b745b9
992 | x 65b757b745b9
993 |/ Obsfate: rewritten using amend as 4:019fadeab383
993 |/ Obsfate: rewritten using amend as 4:019fadeab383
994 | @ fdf9bde5129a
994 | @ fdf9bde5129a
995 |/
995 |/
996 | x 471f378eab4c
996 | x 471f378eab4c
997 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
997 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
998 | Obsfate: rewritten using amend as 3:65b757b745b9
998 | Obsfate: rewritten using amend as 3:65b757b745b9
999 o ea207398892e
999 o ea207398892e
1000
1000
1001 $ hg fatelogkw --hidden
1001 $ hg fatelogkw --hidden
1002 o 019fadeab383
1002 o 019fadeab383
1003 |
1003 |
1004 | x 65b757b745b9
1004 | x 65b757b745b9
1005 |/ Obsfate: rewritten using amend as 4:019fadeab383
1005 |/ Obsfate: rewritten using amend as 4:019fadeab383
1006 | @ fdf9bde5129a
1006 | @ fdf9bde5129a
1007 |/
1007 |/
1008 | x 471f378eab4c
1008 | x 471f378eab4c
1009 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
1009 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
1010 | Obsfate: rewritten using amend as 3:65b757b745b9
1010 | Obsfate: rewritten using amend as 3:65b757b745b9
1011 o ea207398892e
1011 o ea207398892e
1012
1012
1013 $ hg fatelogkw --hidden -v
1013 $ hg fatelogkw --hidden -v
1014 o 019fadeab383
1014 o 019fadeab383
1015 |
1015 |
1016 | x 65b757b745b9
1016 | x 65b757b745b9
1017 |/ Obsfate: rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000)
1017 |/ Obsfate: rewritten using amend as 4:019fadeab383 by test (at 1970-01-01 00:00 +0000)
1018 | @ fdf9bde5129a
1018 | @ fdf9bde5129a
1019 |/
1019 |/
1020 | x 471f378eab4c
1020 | x 471f378eab4c
1021 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000)
1021 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000)
1022 | Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000)
1022 | Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000)
1023 o ea207398892e
1023 o ea207398892e
1024
1024
1025 $ hg log -G -T "default" --hidden
1025 $ hg log -G -T "default" --hidden
1026 o changeset: 4:019fadeab383
1026 o changeset: 4:019fadeab383
1027 | tag: tip
1027 | tag: tip
1028 | parent: 0:ea207398892e
1028 | parent: 0:ea207398892e
1029 | user: test
1029 | user: test
1030 | date: Thu Jan 01 00:00:00 1970 +0000
1030 | date: Thu Jan 01 00:00:00 1970 +0000
1031 | instability: content-divergent
1031 | instability: content-divergent
1032 | summary: A3
1032 | summary: A3
1033 |
1033 |
1034 | x changeset: 3:65b757b745b9
1034 | x changeset: 3:65b757b745b9
1035 |/ parent: 0:ea207398892e
1035 |/ parent: 0:ea207398892e
1036 | user: test
1036 | user: test
1037 | date: Thu Jan 01 00:00:00 1970 +0000
1037 | date: Thu Jan 01 00:00:00 1970 +0000
1038 | obsolete: rewritten using amend as 4:019fadeab383
1038 | obsolete: rewritten using amend as 4:019fadeab383
1039 | summary: A2
1039 | summary: A2
1040 |
1040 |
1041 | @ changeset: 2:fdf9bde5129a
1041 | @ changeset: 2:fdf9bde5129a
1042 |/ parent: 0:ea207398892e
1042 |/ parent: 0:ea207398892e
1043 | user: test
1043 | user: test
1044 | date: Thu Jan 01 00:00:00 1970 +0000
1044 | date: Thu Jan 01 00:00:00 1970 +0000
1045 | instability: content-divergent
1045 | instability: content-divergent
1046 | summary: A1
1046 | summary: A1
1047 |
1047 |
1048 | x changeset: 1:471f378eab4c
1048 | x changeset: 1:471f378eab4c
1049 |/ user: test
1049 |/ user: test
1050 | date: Thu Jan 01 00:00:00 1970 +0000
1050 | date: Thu Jan 01 00:00:00 1970 +0000
1051 | obsolete: rewritten using amend as 2:fdf9bde5129a
1051 | obsolete: rewritten using amend as 2:fdf9bde5129a
1052 | obsolete: rewritten using amend as 3:65b757b745b9
1052 | obsolete: rewritten using amend as 3:65b757b745b9
1053 | summary: A0
1053 | summary: A0
1054 |
1054 |
1055 o changeset: 0:ea207398892e
1055 o changeset: 0:ea207398892e
1056 user: test
1056 user: test
1057 date: Thu Jan 01 00:00:00 1970 +0000
1057 date: Thu Jan 01 00:00:00 1970 +0000
1058 summary: ROOT
1058 summary: ROOT
1059
1059
1060
1060
1061 Test templates with amended + folded commit
1061 Test templates with amended + folded commit
1062 ===========================================
1062 ===========================================
1063
1063
1064 Test setup
1064 Test setup
1065 ----------
1065 ----------
1066
1066
1067 $ hg init $TESTTMP/templates-local-amend-fold
1067 $ hg init $TESTTMP/templates-local-amend-fold
1068 $ cd $TESTTMP/templates-local-amend-fold
1068 $ cd $TESTTMP/templates-local-amend-fold
1069 $ mkcommit ROOT
1069 $ mkcommit ROOT
1070 $ mkcommit A0
1070 $ mkcommit A0
1071 $ mkcommit B0
1071 $ mkcommit B0
1072 $ hg commit --amend -m "B1"
1072 $ hg commit --amend -m "B1"
1073 $ hg log --hidden -G
1073 $ hg log --hidden -G
1074 @ changeset: 3:b7ea6d14e664
1074 @ changeset: 3:b7ea6d14e664
1075 | tag: tip
1075 | tag: tip
1076 | parent: 1:471f378eab4c
1076 | parent: 1:471f378eab4c
1077 | user: test
1077 | user: test
1078 | date: Thu Jan 01 00:00:00 1970 +0000
1078 | date: Thu Jan 01 00:00:00 1970 +0000
1079 | summary: B1
1079 | summary: B1
1080 |
1080 |
1081 | x changeset: 2:0dec01379d3b
1081 | x changeset: 2:0dec01379d3b
1082 |/ user: test
1082 |/ user: test
1083 | date: Thu Jan 01 00:00:00 1970 +0000
1083 | date: Thu Jan 01 00:00:00 1970 +0000
1084 | obsolete: rewritten using amend as 3:b7ea6d14e664
1084 | obsolete: rewritten using amend as 3:b7ea6d14e664
1085 | summary: B0
1085 | summary: B0
1086 |
1086 |
1087 o changeset: 1:471f378eab4c
1087 o changeset: 1:471f378eab4c
1088 | user: test
1088 | user: test
1089 | date: Thu Jan 01 00:00:00 1970 +0000
1089 | date: Thu Jan 01 00:00:00 1970 +0000
1090 | summary: A0
1090 | summary: A0
1091 |
1091 |
1092 o changeset: 0:ea207398892e
1092 o changeset: 0:ea207398892e
1093 user: test
1093 user: test
1094 date: Thu Jan 01 00:00:00 1970 +0000
1094 date: Thu Jan 01 00:00:00 1970 +0000
1095 summary: ROOT
1095 summary: ROOT
1096
1096
1097 # Simulate a fold
1097 # Simulate a fold
1098 $ hg up -r "desc(ROOT)"
1098 $ hg up -r "desc(ROOT)"
1099 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1099 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1100 $ echo "A0" > A0
1100 $ echo "A0" > A0
1101 $ echo "B0" > B0
1101 $ echo "B0" > B0
1102 $ hg commit -A -m "C0"
1102 $ hg commit -A -m "C0"
1103 adding A0
1103 adding A0
1104 adding B0
1104 adding B0
1105 created new head
1105 created new head
1106 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(C0)"`
1106 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(C0)"`
1107 obsoleted 1 changesets
1107 obsoleted 1 changesets
1108 $ hg debugobsolete `getid "desc(B1)"` `getid "desc(C0)"`
1108 $ hg debugobsolete `getid "desc(B1)"` `getid "desc(C0)"`
1109 obsoleted 1 changesets
1109 obsoleted 1 changesets
1110
1110
1111 $ hg log --hidden -G
1111 $ hg log --hidden -G
1112 @ changeset: 4:eb5a0daa2192
1112 @ changeset: 4:eb5a0daa2192
1113 | tag: tip
1113 | tag: tip
1114 | parent: 0:ea207398892e
1114 | parent: 0:ea207398892e
1115 | user: test
1115 | user: test
1116 | date: Thu Jan 01 00:00:00 1970 +0000
1116 | date: Thu Jan 01 00:00:00 1970 +0000
1117 | summary: C0
1117 | summary: C0
1118 |
1118 |
1119 | x changeset: 3:b7ea6d14e664
1119 | x changeset: 3:b7ea6d14e664
1120 | | parent: 1:471f378eab4c
1120 | | parent: 1:471f378eab4c
1121 | | user: test
1121 | | user: test
1122 | | date: Thu Jan 01 00:00:00 1970 +0000
1122 | | date: Thu Jan 01 00:00:00 1970 +0000
1123 | | obsolete: rewritten as 4:eb5a0daa2192
1123 | | obsolete: rewritten as 4:eb5a0daa2192
1124 | | summary: B1
1124 | | summary: B1
1125 | |
1125 | |
1126 | | x changeset: 2:0dec01379d3b
1126 | | x changeset: 2:0dec01379d3b
1127 | |/ user: test
1127 | |/ user: test
1128 | | date: Thu Jan 01 00:00:00 1970 +0000
1128 | | date: Thu Jan 01 00:00:00 1970 +0000
1129 | | obsolete: rewritten using amend as 3:b7ea6d14e664
1129 | | obsolete: rewritten using amend as 3:b7ea6d14e664
1130 | | summary: B0
1130 | | summary: B0
1131 | |
1131 | |
1132 | x changeset: 1:471f378eab4c
1132 | x changeset: 1:471f378eab4c
1133 |/ user: test
1133 |/ user: test
1134 | date: Thu Jan 01 00:00:00 1970 +0000
1134 | date: Thu Jan 01 00:00:00 1970 +0000
1135 | obsolete: rewritten as 4:eb5a0daa2192
1135 | obsolete: rewritten as 4:eb5a0daa2192
1136 | summary: A0
1136 | summary: A0
1137 |
1137 |
1138 o changeset: 0:ea207398892e
1138 o changeset: 0:ea207398892e
1139 user: test
1139 user: test
1140 date: Thu Jan 01 00:00:00 1970 +0000
1140 date: Thu Jan 01 00:00:00 1970 +0000
1141 summary: ROOT
1141 summary: ROOT
1142
1142
1143 Check templates
1143 Check templates
1144 ---------------
1144 ---------------
1145
1145
1146 $ hg up 'desc(A0)' --hidden
1146 $ hg up 'desc(A0)' --hidden
1147 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1147 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1148
1148
1149 Predecessors template should show current revision as it is the working copy
1149 Predecessors template should show current revision as it is the working copy
1150 $ hg tlog
1150 $ hg tlog
1151 o eb5a0daa2192
1151 o eb5a0daa2192
1152 | Predecessors: 1:471f378eab4c
1152 | Predecessors: 1:471f378eab4c
1153 | semi-colon: 1:471f378eab4c
1153 | semi-colon: 1:471f378eab4c
1154 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1154 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1155 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1155 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1156 | @ 471f378eab4c
1156 | @ 471f378eab4c
1157 |/ Successors: 4:eb5a0daa2192
1157 |/ Successors: 4:eb5a0daa2192
1158 | multi-line: 4:eb5a0daa2192
1158 | multi-line: 4:eb5a0daa2192
1159 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1159 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1160 o ea207398892e
1160 o ea207398892e
1161
1161
1162
1162
1163 $ hg fatelog
1163 $ hg fatelog
1164 o eb5a0daa2192
1164 o eb5a0daa2192
1165 |
1165 |
1166 | @ 471f378eab4c
1166 | @ 471f378eab4c
1167 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1167 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1168 o ea207398892e
1168 o ea207398892e
1169
1169
1170 $ hg up 'desc(B0)' --hidden
1170 $ hg up 'desc(B0)' --hidden
1171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1172
1172
1173 Predecessors template should both predecessors as they are visible
1173 Predecessors template should both predecessors as they are visible
1174 $ hg tlog
1174 $ hg tlog
1175 o eb5a0daa2192
1175 o eb5a0daa2192
1176 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
1176 | Predecessors: 2:0dec01379d3b 1:471f378eab4c
1177 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
1177 | semi-colon: 2:0dec01379d3b; 1:471f378eab4c
1178 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
1178 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", "471f378eab4c5e25f6c77f785b27c936efb22874"]
1179 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
1179 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5 1:471f378eab4c5e25f6c77f785b27c936efb22874
1180 | @ 0dec01379d3b
1180 | @ 0dec01379d3b
1181 | | Successors: 4:eb5a0daa2192
1181 | | Successors: 4:eb5a0daa2192
1182 | | multi-line: 4:eb5a0daa2192
1182 | | multi-line: 4:eb5a0daa2192
1183 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1183 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1184 | x 471f378eab4c
1184 | x 471f378eab4c
1185 |/ Successors: 4:eb5a0daa2192
1185 |/ Successors: 4:eb5a0daa2192
1186 | multi-line: 4:eb5a0daa2192
1186 | multi-line: 4:eb5a0daa2192
1187 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1187 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1188 o ea207398892e
1188 o ea207398892e
1189
1189
1190
1190
1191 $ hg fatelog
1191 $ hg fatelog
1192 o eb5a0daa2192
1192 o eb5a0daa2192
1193 |
1193 |
1194 | @ 0dec01379d3b
1194 | @ 0dec01379d3b
1195 | | Obsfate: rewritten using amend as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1195 | | Obsfate: rewritten using amend as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1196 | x 471f378eab4c
1196 | x 471f378eab4c
1197 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1197 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1198 o ea207398892e
1198 o ea207398892e
1199
1199
1200 $ hg up 'desc(B1)' --hidden
1200 $ hg up 'desc(B1)' --hidden
1201 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1201 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1202
1202
1203 Predecessors template should both predecessors as they are visible
1203 Predecessors template should both predecessors as they are visible
1204 $ hg tlog
1204 $ hg tlog
1205 o eb5a0daa2192
1205 o eb5a0daa2192
1206 | Predecessors: 1:471f378eab4c 3:b7ea6d14e664
1206 | Predecessors: 1:471f378eab4c 3:b7ea6d14e664
1207 | semi-colon: 1:471f378eab4c; 3:b7ea6d14e664
1207 | semi-colon: 1:471f378eab4c; 3:b7ea6d14e664
1208 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874", "b7ea6d14e664bdc8922221f7992631b50da3fb07"]
1208 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874", "b7ea6d14e664bdc8922221f7992631b50da3fb07"]
1209 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874 3:b7ea6d14e664bdc8922221f7992631b50da3fb07
1209 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874 3:b7ea6d14e664bdc8922221f7992631b50da3fb07
1210 | @ b7ea6d14e664
1210 | @ b7ea6d14e664
1211 | | Successors: 4:eb5a0daa2192
1211 | | Successors: 4:eb5a0daa2192
1212 | | multi-line: 4:eb5a0daa2192
1212 | | multi-line: 4:eb5a0daa2192
1213 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1213 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1214 | x 471f378eab4c
1214 | x 471f378eab4c
1215 |/ Successors: 4:eb5a0daa2192
1215 |/ Successors: 4:eb5a0daa2192
1216 | multi-line: 4:eb5a0daa2192
1216 | multi-line: 4:eb5a0daa2192
1217 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1217 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1218 o ea207398892e
1218 o ea207398892e
1219
1219
1220
1220
1221 $ hg fatelog
1221 $ hg fatelog
1222 o eb5a0daa2192
1222 o eb5a0daa2192
1223 |
1223 |
1224 | @ b7ea6d14e664
1224 | @ b7ea6d14e664
1225 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1225 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1226 | x 471f378eab4c
1226 | x 471f378eab4c
1227 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1227 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1228 o ea207398892e
1228 o ea207398892e
1229
1229
1230 $ hg up 'desc(C0)'
1230 $ hg up 'desc(C0)'
1231 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1231 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1232
1232
1233 Predecessors template should show no predecessors as they are both non visible
1233 Predecessors template should show no predecessors as they are both non visible
1234 $ hg tlog
1234 $ hg tlog
1235 @ eb5a0daa2192
1235 @ eb5a0daa2192
1236 |
1236 |
1237 o ea207398892e
1237 o ea207398892e
1238
1238
1239
1239
1240 $ hg fatelog
1240 $ hg fatelog
1241 @ eb5a0daa2192
1241 @ eb5a0daa2192
1242 |
1242 |
1243 o ea207398892e
1243 o ea207398892e
1244
1244
1245 Predecessors template should show all predecessors as we force their display
1245 Predecessors template should show all predecessors as we force their display
1246 with --hidden
1246 with --hidden
1247 $ hg tlog --hidden
1247 $ hg tlog --hidden
1248 @ eb5a0daa2192
1248 @ eb5a0daa2192
1249 | Predecessors: 1:471f378eab4c 3:b7ea6d14e664
1249 | Predecessors: 1:471f378eab4c 3:b7ea6d14e664
1250 | semi-colon: 1:471f378eab4c; 3:b7ea6d14e664
1250 | semi-colon: 1:471f378eab4c; 3:b7ea6d14e664
1251 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874", "b7ea6d14e664bdc8922221f7992631b50da3fb07"]
1251 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874", "b7ea6d14e664bdc8922221f7992631b50da3fb07"]
1252 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874 3:b7ea6d14e664bdc8922221f7992631b50da3fb07
1252 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874 3:b7ea6d14e664bdc8922221f7992631b50da3fb07
1253 | x b7ea6d14e664
1253 | x b7ea6d14e664
1254 | | Predecessors: 2:0dec01379d3b
1254 | | Predecessors: 2:0dec01379d3b
1255 | | semi-colon: 2:0dec01379d3b
1255 | | semi-colon: 2:0dec01379d3b
1256 | | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1256 | | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1257 | | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1257 | | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1258 | | Successors: 4:eb5a0daa2192
1258 | | Successors: 4:eb5a0daa2192
1259 | | multi-line: 4:eb5a0daa2192
1259 | | multi-line: 4:eb5a0daa2192
1260 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1260 | | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1261 | | x 0dec01379d3b
1261 | | x 0dec01379d3b
1262 | |/ Successors: 3:b7ea6d14e664
1262 | |/ Successors: 3:b7ea6d14e664
1263 | | multi-line: 3:b7ea6d14e664
1263 | | multi-line: 3:b7ea6d14e664
1264 | | json: [["b7ea6d14e664bdc8922221f7992631b50da3fb07"]]
1264 | | json: [["b7ea6d14e664bdc8922221f7992631b50da3fb07"]]
1265 | x 471f378eab4c
1265 | x 471f378eab4c
1266 |/ Successors: 4:eb5a0daa2192
1266 |/ Successors: 4:eb5a0daa2192
1267 | multi-line: 4:eb5a0daa2192
1267 | multi-line: 4:eb5a0daa2192
1268 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1268 | json: [["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]]
1269 o ea207398892e
1269 o ea207398892e
1270
1270
1271
1271
1272 $ hg fatelog --hidden
1272 $ hg fatelog --hidden
1273 @ eb5a0daa2192
1273 @ eb5a0daa2192
1274 |
1274 |
1275 | x b7ea6d14e664
1275 | x b7ea6d14e664
1276 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1276 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1277 | | x 0dec01379d3b
1277 | | x 0dec01379d3b
1278 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664 by test (at 1970-01-01 00:00 +0000);
1278 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664 by test (at 1970-01-01 00:00 +0000);
1279 | x 471f378eab4c
1279 | x 471f378eab4c
1280 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1280 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000);
1281 o ea207398892e
1281 o ea207398892e
1282
1282
1283
1283
1284 $ hg fatelogjson --hidden
1284 $ hg fatelogjson --hidden
1285 @ eb5a0daa2192
1285 @ eb5a0daa2192
1286 |
1286 |
1287 | x b7ea6d14e664
1287 | x b7ea6d14e664
1288 | | Obsfate: [{"markers": [["b7ea6d14e664bdc8922221f7992631b50da3fb07", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
1288 | | Obsfate: [{"markers": [["b7ea6d14e664bdc8922221f7992631b50da3fb07", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
1289 | | x 0dec01379d3b
1289 | | x 0dec01379d3b
1290 | |/ Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["b7ea6d14e664bdc8922221f7992631b50da3fb07"]}]
1290 | |/ Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["b7ea6d14e664bdc8922221f7992631b50da3fb07"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["b7ea6d14e664bdc8922221f7992631b50da3fb07"]}]
1291 | x 471f378eab4c
1291 | x 471f378eab4c
1292 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
1292 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["eb5a0daa21923bbf8caeb2c42085b9e463861fd0"]}]
1293 o ea207398892e
1293 o ea207398892e
1294
1294
1295
1295
1296 Check other fatelog implementations
1296 Check other fatelog implementations
1297 -----------------------------------
1297 -----------------------------------
1298
1298
1299 $ hg fatelogkw --hidden -q
1299 $ hg fatelogkw --hidden -q
1300 @ eb5a0daa2192
1300 @ eb5a0daa2192
1301 |
1301 |
1302 | x b7ea6d14e664
1302 | x b7ea6d14e664
1303 | | Obsfate: rewritten as 4:eb5a0daa2192
1303 | | Obsfate: rewritten as 4:eb5a0daa2192
1304 | | x 0dec01379d3b
1304 | | x 0dec01379d3b
1305 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664
1305 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664
1306 | x 471f378eab4c
1306 | x 471f378eab4c
1307 |/ Obsfate: rewritten as 4:eb5a0daa2192
1307 |/ Obsfate: rewritten as 4:eb5a0daa2192
1308 o ea207398892e
1308 o ea207398892e
1309
1309
1310 $ hg fatelogkw --hidden
1310 $ hg fatelogkw --hidden
1311 @ eb5a0daa2192
1311 @ eb5a0daa2192
1312 |
1312 |
1313 | x b7ea6d14e664
1313 | x b7ea6d14e664
1314 | | Obsfate: rewritten as 4:eb5a0daa2192
1314 | | Obsfate: rewritten as 4:eb5a0daa2192
1315 | | x 0dec01379d3b
1315 | | x 0dec01379d3b
1316 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664
1316 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664
1317 | x 471f378eab4c
1317 | x 471f378eab4c
1318 |/ Obsfate: rewritten as 4:eb5a0daa2192
1318 |/ Obsfate: rewritten as 4:eb5a0daa2192
1319 o ea207398892e
1319 o ea207398892e
1320
1320
1321 $ hg fatelogkw --hidden -v
1321 $ hg fatelogkw --hidden -v
1322 @ eb5a0daa2192
1322 @ eb5a0daa2192
1323 |
1323 |
1324 | x b7ea6d14e664
1324 | x b7ea6d14e664
1325 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
1325 | | Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
1326 | | x 0dec01379d3b
1326 | | x 0dec01379d3b
1327 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664 by test (at 1970-01-01 00:00 +0000)
1327 | |/ Obsfate: rewritten using amend as 3:b7ea6d14e664 by test (at 1970-01-01 00:00 +0000)
1328 | x 471f378eab4c
1328 | x 471f378eab4c
1329 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
1329 |/ Obsfate: rewritten as 4:eb5a0daa2192 by test (at 1970-01-01 00:00 +0000)
1330 o ea207398892e
1330 o ea207398892e
1331
1331
1332 $ hg log -G -T "default" --hidden
1332 $ hg log -G -T "default" --hidden
1333 @ changeset: 4:eb5a0daa2192
1333 @ changeset: 4:eb5a0daa2192
1334 | tag: tip
1334 | tag: tip
1335 | parent: 0:ea207398892e
1335 | parent: 0:ea207398892e
1336 | user: test
1336 | user: test
1337 | date: Thu Jan 01 00:00:00 1970 +0000
1337 | date: Thu Jan 01 00:00:00 1970 +0000
1338 | summary: C0
1338 | summary: C0
1339 |
1339 |
1340 | x changeset: 3:b7ea6d14e664
1340 | x changeset: 3:b7ea6d14e664
1341 | | parent: 1:471f378eab4c
1341 | | parent: 1:471f378eab4c
1342 | | user: test
1342 | | user: test
1343 | | date: Thu Jan 01 00:00:00 1970 +0000
1343 | | date: Thu Jan 01 00:00:00 1970 +0000
1344 | | obsolete: rewritten as 4:eb5a0daa2192
1344 | | obsolete: rewritten as 4:eb5a0daa2192
1345 | | summary: B1
1345 | | summary: B1
1346 | |
1346 | |
1347 | | x changeset: 2:0dec01379d3b
1347 | | x changeset: 2:0dec01379d3b
1348 | |/ user: test
1348 | |/ user: test
1349 | | date: Thu Jan 01 00:00:00 1970 +0000
1349 | | date: Thu Jan 01 00:00:00 1970 +0000
1350 | | obsolete: rewritten using amend as 3:b7ea6d14e664
1350 | | obsolete: rewritten using amend as 3:b7ea6d14e664
1351 | | summary: B0
1351 | | summary: B0
1352 | |
1352 | |
1353 | x changeset: 1:471f378eab4c
1353 | x changeset: 1:471f378eab4c
1354 |/ user: test
1354 |/ user: test
1355 | date: Thu Jan 01 00:00:00 1970 +0000
1355 | date: Thu Jan 01 00:00:00 1970 +0000
1356 | obsolete: rewritten as 4:eb5a0daa2192
1356 | obsolete: rewritten as 4:eb5a0daa2192
1357 | summary: A0
1357 | summary: A0
1358 |
1358 |
1359 o changeset: 0:ea207398892e
1359 o changeset: 0:ea207398892e
1360 user: test
1360 user: test
1361 date: Thu Jan 01 00:00:00 1970 +0000
1361 date: Thu Jan 01 00:00:00 1970 +0000
1362 summary: ROOT
1362 summary: ROOT
1363
1363
1364
1364
1365 Test template with pushed and pulled obs markers
1365 Test template with pushed and pulled obs markers
1366 ================================================
1366 ================================================
1367
1367
1368 Test setup
1368 Test setup
1369 ----------
1369 ----------
1370
1370
1371 $ hg init $TESTTMP/templates-local-remote-markers-1
1371 $ hg init $TESTTMP/templates-local-remote-markers-1
1372 $ cd $TESTTMP/templates-local-remote-markers-1
1372 $ cd $TESTTMP/templates-local-remote-markers-1
1373 $ mkcommit ROOT
1373 $ mkcommit ROOT
1374 $ mkcommit A0
1374 $ mkcommit A0
1375 $ hg clone $TESTTMP/templates-local-remote-markers-1 $TESTTMP/templates-local-remote-markers-2
1375 $ hg clone $TESTTMP/templates-local-remote-markers-1 $TESTTMP/templates-local-remote-markers-2
1376 updating to branch default
1376 updating to branch default
1377 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1377 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1378 $ cd $TESTTMP/templates-local-remote-markers-2
1378 $ cd $TESTTMP/templates-local-remote-markers-2
1379 $ hg log --hidden -G
1379 $ hg log --hidden -G
1380 @ changeset: 1:471f378eab4c
1380 @ changeset: 1:471f378eab4c
1381 | tag: tip
1381 | tag: tip
1382 | user: test
1382 | user: test
1383 | date: Thu Jan 01 00:00:00 1970 +0000
1383 | date: Thu Jan 01 00:00:00 1970 +0000
1384 | summary: A0
1384 | summary: A0
1385 |
1385 |
1386 o changeset: 0:ea207398892e
1386 o changeset: 0:ea207398892e
1387 user: test
1387 user: test
1388 date: Thu Jan 01 00:00:00 1970 +0000
1388 date: Thu Jan 01 00:00:00 1970 +0000
1389 summary: ROOT
1389 summary: ROOT
1390
1390
1391 $ cd $TESTTMP/templates-local-remote-markers-1
1391 $ cd $TESTTMP/templates-local-remote-markers-1
1392 $ hg commit --amend -m "A1"
1392 $ hg commit --amend -m "A1"
1393 $ hg commit --amend -m "A2"
1393 $ hg commit --amend -m "A2"
1394 $ hg log --hidden -G
1394 $ hg log --hidden -G
1395 @ changeset: 3:7a230b46bf61
1395 @ changeset: 3:7a230b46bf61
1396 | tag: tip
1396 | tag: tip
1397 | parent: 0:ea207398892e
1397 | parent: 0:ea207398892e
1398 | user: test
1398 | user: test
1399 | date: Thu Jan 01 00:00:00 1970 +0000
1399 | date: Thu Jan 01 00:00:00 1970 +0000
1400 | summary: A2
1400 | summary: A2
1401 |
1401 |
1402 | x changeset: 2:fdf9bde5129a
1402 | x changeset: 2:fdf9bde5129a
1403 |/ parent: 0:ea207398892e
1403 |/ parent: 0:ea207398892e
1404 | user: test
1404 | user: test
1405 | date: Thu Jan 01 00:00:00 1970 +0000
1405 | date: Thu Jan 01 00:00:00 1970 +0000
1406 | obsolete: rewritten using amend as 3:7a230b46bf61
1406 | obsolete: rewritten using amend as 3:7a230b46bf61
1407 | summary: A1
1407 | summary: A1
1408 |
1408 |
1409 | x changeset: 1:471f378eab4c
1409 | x changeset: 1:471f378eab4c
1410 |/ user: test
1410 |/ user: test
1411 | date: Thu Jan 01 00:00:00 1970 +0000
1411 | date: Thu Jan 01 00:00:00 1970 +0000
1412 | obsolete: rewritten using amend as 2:fdf9bde5129a
1412 | obsolete: rewritten using amend as 2:fdf9bde5129a
1413 | summary: A0
1413 | summary: A0
1414 |
1414 |
1415 o changeset: 0:ea207398892e
1415 o changeset: 0:ea207398892e
1416 user: test
1416 user: test
1417 date: Thu Jan 01 00:00:00 1970 +0000
1417 date: Thu Jan 01 00:00:00 1970 +0000
1418 summary: ROOT
1418 summary: ROOT
1419
1419
1420 $ cd $TESTTMP/templates-local-remote-markers-2
1420 $ cd $TESTTMP/templates-local-remote-markers-2
1421 $ hg pull
1421 $ hg pull
1422 pulling from $TESTTMP/templates-local-remote-markers-1 (glob)
1422 pulling from $TESTTMP/templates-local-remote-markers-1 (glob)
1423 searching for changes
1423 searching for changes
1424 adding changesets
1424 adding changesets
1425 adding manifests
1425 adding manifests
1426 adding file changes
1426 adding file changes
1427 added 1 changesets with 0 changes to 1 files (+1 heads)
1427 added 1 changesets with 0 changes to 1 files (+1 heads)
1428 2 new obsolescence markers
1428 2 new obsolescence markers
1429 obsoleted 1 changesets
1429 obsoleted 1 changesets
1430 new changesets 7a230b46bf61
1430 new changesets 7a230b46bf61
1431 (run 'hg heads' to see heads, 'hg merge' to merge)
1431 (run 'hg heads' to see heads, 'hg merge' to merge)
1432 $ hg log --hidden -G
1432 $ hg log --hidden -G
1433 o changeset: 2:7a230b46bf61
1433 o changeset: 2:7a230b46bf61
1434 | tag: tip
1434 | tag: tip
1435 | parent: 0:ea207398892e
1435 | parent: 0:ea207398892e
1436 | user: test
1436 | user: test
1437 | date: Thu Jan 01 00:00:00 1970 +0000
1437 | date: Thu Jan 01 00:00:00 1970 +0000
1438 | summary: A2
1438 | summary: A2
1439 |
1439 |
1440 | @ changeset: 1:471f378eab4c
1440 | @ changeset: 1:471f378eab4c
1441 |/ user: test
1441 |/ user: test
1442 | date: Thu Jan 01 00:00:00 1970 +0000
1442 | date: Thu Jan 01 00:00:00 1970 +0000
1443 | obsolete: rewritten using amend as 2:7a230b46bf61
1443 | obsolete: rewritten using amend as 2:7a230b46bf61
1444 | summary: A0
1444 | summary: A0
1445 |
1445 |
1446 o changeset: 0:ea207398892e
1446 o changeset: 0:ea207398892e
1447 user: test
1447 user: test
1448 date: Thu Jan 01 00:00:00 1970 +0000
1448 date: Thu Jan 01 00:00:00 1970 +0000
1449 summary: ROOT
1449 summary: ROOT
1450
1450
1451
1451
1452 $ hg debugobsolete
1452 $ hg debugobsolete
1453 471f378eab4c5e25f6c77f785b27c936efb22874 fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1453 471f378eab4c5e25f6c77f785b27c936efb22874 fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1454 fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e 7a230b46bf61e50b30308c6cfd7bd1269ef54702 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1454 fdf9bde5129a28d4548fadd3f62b265cdd3b7a2e 7a230b46bf61e50b30308c6cfd7bd1269ef54702 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1455
1455
1456 Check templates
1456 Check templates
1457 ---------------
1457 ---------------
1458
1458
1459 Predecessors template should show current revision as it is the working copy
1459 Predecessors template should show current revision as it is the working copy
1460 $ hg tlog
1460 $ hg tlog
1461 o 7a230b46bf61
1461 o 7a230b46bf61
1462 | Predecessors: 1:471f378eab4c
1462 | Predecessors: 1:471f378eab4c
1463 | semi-colon: 1:471f378eab4c
1463 | semi-colon: 1:471f378eab4c
1464 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1464 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1465 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1465 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1466 | @ 471f378eab4c
1466 | @ 471f378eab4c
1467 |/ Successors: 2:7a230b46bf61
1467 |/ Successors: 2:7a230b46bf61
1468 | multi-line: 2:7a230b46bf61
1468 | multi-line: 2:7a230b46bf61
1469 | json: [["7a230b46bf61e50b30308c6cfd7bd1269ef54702"]]
1469 | json: [["7a230b46bf61e50b30308c6cfd7bd1269ef54702"]]
1470 o ea207398892e
1470 o ea207398892e
1471
1471
1472
1472
1473 $ hg fatelog
1473 $ hg fatelog
1474 o 7a230b46bf61
1474 o 7a230b46bf61
1475 |
1475 |
1476 | @ 471f378eab4c
1476 | @ 471f378eab4c
1477 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000);
1477 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000);
1478 o ea207398892e
1478 o ea207398892e
1479
1479
1480 $ hg up 'desc(A2)'
1480 $ hg up 'desc(A2)'
1481 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1481 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1482
1482
1483 Predecessors template should show no predecessors as they are non visible
1483 Predecessors template should show no predecessors as they are non visible
1484 $ hg tlog
1484 $ hg tlog
1485 @ 7a230b46bf61
1485 @ 7a230b46bf61
1486 |
1486 |
1487 o ea207398892e
1487 o ea207398892e
1488
1488
1489
1489
1490 $ hg fatelog
1490 $ hg fatelog
1491 @ 7a230b46bf61
1491 @ 7a230b46bf61
1492 |
1492 |
1493 o ea207398892e
1493 o ea207398892e
1494
1494
1495 Predecessors template should show all predecessors as we force their display
1495 Predecessors template should show all predecessors as we force their display
1496 with --hidden
1496 with --hidden
1497 $ hg tlog --hidden
1497 $ hg tlog --hidden
1498 @ 7a230b46bf61
1498 @ 7a230b46bf61
1499 | Predecessors: 1:471f378eab4c
1499 | Predecessors: 1:471f378eab4c
1500 | semi-colon: 1:471f378eab4c
1500 | semi-colon: 1:471f378eab4c
1501 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1501 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1502 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1502 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1503 | x 471f378eab4c
1503 | x 471f378eab4c
1504 |/ Successors: 2:7a230b46bf61
1504 |/ Successors: 2:7a230b46bf61
1505 | multi-line: 2:7a230b46bf61
1505 | multi-line: 2:7a230b46bf61
1506 | json: [["7a230b46bf61e50b30308c6cfd7bd1269ef54702"]]
1506 | json: [["7a230b46bf61e50b30308c6cfd7bd1269ef54702"]]
1507 o ea207398892e
1507 o ea207398892e
1508
1508
1509
1509
1510 $ hg fatelog --hidden
1510 $ hg fatelog --hidden
1511 @ 7a230b46bf61
1511 @ 7a230b46bf61
1512 |
1512 |
1513 | x 471f378eab4c
1513 | x 471f378eab4c
1514 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000);
1514 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000);
1515 o ea207398892e
1515 o ea207398892e
1516
1516
1517
1517
1518 Check other fatelog implementations
1518 Check other fatelog implementations
1519 -----------------------------------
1519 -----------------------------------
1520
1520
1521 $ hg fatelogkw --hidden -q
1521 $ hg fatelogkw --hidden -q
1522 @ 7a230b46bf61
1522 @ 7a230b46bf61
1523 |
1523 |
1524 | x 471f378eab4c
1524 | x 471f378eab4c
1525 |/ Obsfate: rewritten using amend as 2:7a230b46bf61
1525 |/ Obsfate: rewritten using amend as 2:7a230b46bf61
1526 o ea207398892e
1526 o ea207398892e
1527
1527
1528 $ hg fatelogkw --hidden
1528 $ hg fatelogkw --hidden
1529 @ 7a230b46bf61
1529 @ 7a230b46bf61
1530 |
1530 |
1531 | x 471f378eab4c
1531 | x 471f378eab4c
1532 |/ Obsfate: rewritten using amend as 2:7a230b46bf61
1532 |/ Obsfate: rewritten using amend as 2:7a230b46bf61
1533 o ea207398892e
1533 o ea207398892e
1534
1534
1535 $ hg fatelogkw --hidden -v
1535 $ hg fatelogkw --hidden -v
1536 @ 7a230b46bf61
1536 @ 7a230b46bf61
1537 |
1537 |
1538 | x 471f378eab4c
1538 | x 471f378eab4c
1539 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000)
1539 |/ Obsfate: rewritten using amend as 2:7a230b46bf61 by test (at 1970-01-01 00:00 +0000)
1540 o ea207398892e
1540 o ea207398892e
1541
1541
1542 $ hg log -G -T "default" --hidden
1542 $ hg log -G -T "default" --hidden
1543 @ changeset: 2:7a230b46bf61
1543 @ changeset: 2:7a230b46bf61
1544 | tag: tip
1544 | tag: tip
1545 | parent: 0:ea207398892e
1545 | parent: 0:ea207398892e
1546 | user: test
1546 | user: test
1547 | date: Thu Jan 01 00:00:00 1970 +0000
1547 | date: Thu Jan 01 00:00:00 1970 +0000
1548 | summary: A2
1548 | summary: A2
1549 |
1549 |
1550 | x changeset: 1:471f378eab4c
1550 | x changeset: 1:471f378eab4c
1551 |/ user: test
1551 |/ user: test
1552 | date: Thu Jan 01 00:00:00 1970 +0000
1552 | date: Thu Jan 01 00:00:00 1970 +0000
1553 | obsolete: rewritten using amend as 2:7a230b46bf61
1553 | obsolete: rewritten using amend as 2:7a230b46bf61
1554 | summary: A0
1554 | summary: A0
1555 |
1555 |
1556 o changeset: 0:ea207398892e
1556 o changeset: 0:ea207398892e
1557 user: test
1557 user: test
1558 date: Thu Jan 01 00:00:00 1970 +0000
1558 date: Thu Jan 01 00:00:00 1970 +0000
1559 summary: ROOT
1559 summary: ROOT
1560
1560
1561
1561
1562 Test template with obsmarkers cycle
1562 Test template with obsmarkers cycle
1563 ===================================
1563 ===================================
1564
1564
1565 Test setup
1565 Test setup
1566 ----------
1566 ----------
1567
1567
1568 $ hg init $TESTTMP/templates-local-cycle
1568 $ hg init $TESTTMP/templates-local-cycle
1569 $ cd $TESTTMP/templates-local-cycle
1569 $ cd $TESTTMP/templates-local-cycle
1570 $ mkcommit ROOT
1570 $ mkcommit ROOT
1571 $ mkcommit A0
1571 $ mkcommit A0
1572 $ mkcommit B0
1572 $ mkcommit B0
1573 $ hg up -r 0
1573 $ hg up -r 0
1574 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1574 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1575 $ mkcommit C0
1575 $ mkcommit C0
1576 created new head
1576 created new head
1577
1577
1578 Create the cycle
1578 Create the cycle
1579
1579
1580 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(B0)"`
1580 $ hg debugobsolete `getid "desc(A0)"` `getid "desc(B0)"`
1581 obsoleted 1 changesets
1581 obsoleted 1 changesets
1582 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(C0)"`
1582 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(C0)"`
1583 obsoleted 1 changesets
1583 obsoleted 1 changesets
1584 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(A0)"`
1584 $ hg debugobsolete `getid "desc(B0)"` `getid "desc(A0)"`
1585
1585
1586 Check templates
1586 Check templates
1587 ---------------
1587 ---------------
1588
1588
1589 $ hg tlog
1589 $ hg tlog
1590 @ f897c6137566
1590 @ f897c6137566
1591 |
1591 |
1592 o ea207398892e
1592 o ea207398892e
1593
1593
1594
1594
1595 $ hg fatelog
1595 $ hg fatelog
1596 @ f897c6137566
1596 @ f897c6137566
1597 |
1597 |
1598 o ea207398892e
1598 o ea207398892e
1599
1599
1600
1600
1601 $ hg up -r "desc(B0)" --hidden
1601 $ hg up -r "desc(B0)" --hidden
1602 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1602 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1603 $ hg tlog
1603 $ hg tlog
1604 o f897c6137566
1604 o f897c6137566
1605 | Predecessors: 2:0dec01379d3b
1605 | Predecessors: 2:0dec01379d3b
1606 | semi-colon: 2:0dec01379d3b
1606 | semi-colon: 2:0dec01379d3b
1607 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1607 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1608 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1608 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1609 | @ 0dec01379d3b
1609 | @ 0dec01379d3b
1610 | | Predecessors: 1:471f378eab4c
1610 | | Predecessors: 1:471f378eab4c
1611 | | semi-colon: 1:471f378eab4c
1611 | | semi-colon: 1:471f378eab4c
1612 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1612 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1613 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1613 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1614 | | Successors: 3:f897c6137566; 1:471f378eab4c
1614 | | Successors: 3:f897c6137566; 1:471f378eab4c
1615 | | multi-line: 3:f897c6137566
1615 | | multi-line: 3:f897c6137566
1616 | | multi-line: 1:471f378eab4c
1616 | | multi-line: 1:471f378eab4c
1617 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
1617 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
1618 | x 471f378eab4c
1618 | x 471f378eab4c
1619 |/ Predecessors: 2:0dec01379d3b
1619 |/ Predecessors: 2:0dec01379d3b
1620 | semi-colon: 2:0dec01379d3b
1620 | semi-colon: 2:0dec01379d3b
1621 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1621 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1622 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1622 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1623 | Successors: 2:0dec01379d3b
1623 | Successors: 2:0dec01379d3b
1624 | multi-line: 2:0dec01379d3b
1624 | multi-line: 2:0dec01379d3b
1625 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
1625 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
1626 o ea207398892e
1626 o ea207398892e
1627
1627
1628
1628
1629 $ hg fatelog
1629 $ hg fatelog
1630 o f897c6137566
1630 o f897c6137566
1631 |
1631 |
1632 | @ 0dec01379d3b
1632 | @ 0dec01379d3b
1633 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000); rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000);
1633 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000); rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000);
1634 | x 471f378eab4c
1634 | x 471f378eab4c
1635 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000);
1635 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000);
1636 o ea207398892e
1636 o ea207398892e
1637
1637
1638
1638
1639 $ hg up -r "desc(A0)" --hidden
1639 $ hg up -r "desc(A0)" --hidden
1640 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1640 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1641 $ hg tlog
1641 $ hg tlog
1642 o f897c6137566
1642 o f897c6137566
1643 | Predecessors: 1:471f378eab4c
1643 | Predecessors: 1:471f378eab4c
1644 | semi-colon: 1:471f378eab4c
1644 | semi-colon: 1:471f378eab4c
1645 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1645 | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1646 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1646 | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1647 | @ 471f378eab4c
1647 | @ 471f378eab4c
1648 |/
1648 |/
1649 o ea207398892e
1649 o ea207398892e
1650
1650
1651
1651
1652 $ hg fatelog
1652 $ hg fatelog
1653 o f897c6137566
1653 o f897c6137566
1654 |
1654 |
1655 | @ 471f378eab4c
1655 | @ 471f378eab4c
1656 |/ Obsfate: pruned;
1656 |/ Obsfate: pruned;
1657 o ea207398892e
1657 o ea207398892e
1658
1658
1659
1659
1660 $ hg up -r "desc(ROOT)" --hidden
1660 $ hg up -r "desc(ROOT)" --hidden
1661 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1661 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1662 $ hg tlog
1662 $ hg tlog
1663 o f897c6137566
1663 o f897c6137566
1664 |
1664 |
1665 @ ea207398892e
1665 @ ea207398892e
1666
1666
1667
1667
1668 $ hg fatelog
1668 $ hg fatelog
1669 o f897c6137566
1669 o f897c6137566
1670 |
1670 |
1671 @ ea207398892e
1671 @ ea207398892e
1672
1672
1673
1673
1674 $ hg tlog --hidden
1674 $ hg tlog --hidden
1675 o f897c6137566
1675 o f897c6137566
1676 | Predecessors: 2:0dec01379d3b
1676 | Predecessors: 2:0dec01379d3b
1677 | semi-colon: 2:0dec01379d3b
1677 | semi-colon: 2:0dec01379d3b
1678 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1678 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1679 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1679 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1680 | x 0dec01379d3b
1680 | x 0dec01379d3b
1681 | | Predecessors: 1:471f378eab4c
1681 | | Predecessors: 1:471f378eab4c
1682 | | semi-colon: 1:471f378eab4c
1682 | | semi-colon: 1:471f378eab4c
1683 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1683 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
1684 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1684 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
1685 | | Successors: 3:f897c6137566; 1:471f378eab4c
1685 | | Successors: 3:f897c6137566; 1:471f378eab4c
1686 | | multi-line: 3:f897c6137566
1686 | | multi-line: 3:f897c6137566
1687 | | multi-line: 1:471f378eab4c
1687 | | multi-line: 1:471f378eab4c
1688 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
1688 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
1689 | x 471f378eab4c
1689 | x 471f378eab4c
1690 |/ Predecessors: 2:0dec01379d3b
1690 |/ Predecessors: 2:0dec01379d3b
1691 | semi-colon: 2:0dec01379d3b
1691 | semi-colon: 2:0dec01379d3b
1692 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1692 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1693 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1693 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1694 | Successors: 2:0dec01379d3b
1694 | Successors: 2:0dec01379d3b
1695 | multi-line: 2:0dec01379d3b
1695 | multi-line: 2:0dec01379d3b
1696 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
1696 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
1697 @ ea207398892e
1697 @ ea207398892e
1698
1698
1699
1699
1700 Check other fatelog implementations
1700 Check other fatelog implementations
1701 -----------------------------------
1701 -----------------------------------
1702
1702
1703 $ hg fatelogkw --hidden -q
1703 $ hg fatelogkw --hidden -q
1704 o f897c6137566
1704 o f897c6137566
1705 |
1705 |
1706 | x 0dec01379d3b
1706 | x 0dec01379d3b
1707 | | Obsfate: rewritten as 3:f897c6137566
1707 | | Obsfate: rewritten as 3:f897c6137566
1708 | | Obsfate: rewritten as 1:471f378eab4c
1708 | | Obsfate: rewritten as 1:471f378eab4c
1709 | x 471f378eab4c
1709 | x 471f378eab4c
1710 |/ Obsfate: rewritten as 2:0dec01379d3b
1710 |/ Obsfate: rewritten as 2:0dec01379d3b
1711 @ ea207398892e
1711 @ ea207398892e
1712
1712
1713 $ hg fatelogkw --hidden
1713 $ hg fatelogkw --hidden
1714 o f897c6137566
1714 o f897c6137566
1715 |
1715 |
1716 | x 0dec01379d3b
1716 | x 0dec01379d3b
1717 | | Obsfate: rewritten as 3:f897c6137566
1717 | | Obsfate: rewritten as 3:f897c6137566
1718 | | Obsfate: rewritten as 1:471f378eab4c
1718 | | Obsfate: rewritten as 1:471f378eab4c
1719 | x 471f378eab4c
1719 | x 471f378eab4c
1720 |/ Obsfate: rewritten as 2:0dec01379d3b
1720 |/ Obsfate: rewritten as 2:0dec01379d3b
1721 @ ea207398892e
1721 @ ea207398892e
1722
1722
1723 $ hg fatelogkw --hidden -v
1723 $ hg fatelogkw --hidden -v
1724 o f897c6137566
1724 o f897c6137566
1725 |
1725 |
1726 | x 0dec01379d3b
1726 | x 0dec01379d3b
1727 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000)
1727 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000)
1728 | | Obsfate: rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000)
1728 | | Obsfate: rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000)
1729 | x 471f378eab4c
1729 | x 471f378eab4c
1730 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000)
1730 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000)
1731 @ ea207398892e
1731 @ ea207398892e
1732
1732
1733 $ hg log -G -T "default" --hidden
1733 $ hg log -G -T "default" --hidden
1734 o changeset: 3:f897c6137566
1734 o changeset: 3:f897c6137566
1735 | tag: tip
1735 | tag: tip
1736 | parent: 0:ea207398892e
1736 | parent: 0:ea207398892e
1737 | user: test
1737 | user: test
1738 | date: Thu Jan 01 00:00:00 1970 +0000
1738 | date: Thu Jan 01 00:00:00 1970 +0000
1739 | summary: C0
1739 | summary: C0
1740 |
1740 |
1741 | x changeset: 2:0dec01379d3b
1741 | x changeset: 2:0dec01379d3b
1742 | | user: test
1742 | | user: test
1743 | | date: Thu Jan 01 00:00:00 1970 +0000
1743 | | date: Thu Jan 01 00:00:00 1970 +0000
1744 | | obsolete: rewritten as 3:f897c6137566
1744 | | obsolete: rewritten as 3:f897c6137566
1745 | | obsolete: rewritten as 1:471f378eab4c
1745 | | obsolete: rewritten as 1:471f378eab4c
1746 | | summary: B0
1746 | | summary: B0
1747 | |
1747 | |
1748 | x changeset: 1:471f378eab4c
1748 | x changeset: 1:471f378eab4c
1749 |/ user: test
1749 |/ user: test
1750 | date: Thu Jan 01 00:00:00 1970 +0000
1750 | date: Thu Jan 01 00:00:00 1970 +0000
1751 | obsolete: rewritten as 2:0dec01379d3b
1751 | obsolete: rewritten as 2:0dec01379d3b
1752 | summary: A0
1752 | summary: A0
1753 |
1753 |
1754 @ changeset: 0:ea207398892e
1754 @ changeset: 0:ea207398892e
1755 user: test
1755 user: test
1756 date: Thu Jan 01 00:00:00 1970 +0000
1756 date: Thu Jan 01 00:00:00 1970 +0000
1757 summary: ROOT
1757 summary: ROOT
1758
1758
1759
1759
1760 Test template with split + divergence with cycles
1760 Test template with split + divergence with cycles
1761 =================================================
1761 =================================================
1762
1762
1763 $ hg log -G
1763 $ hg log -G
1764 o changeset: 3:f897c6137566
1764 o changeset: 3:f897c6137566
1765 | tag: tip
1765 | tag: tip
1766 | parent: 0:ea207398892e
1766 | parent: 0:ea207398892e
1767 | user: test
1767 | user: test
1768 | date: Thu Jan 01 00:00:00 1970 +0000
1768 | date: Thu Jan 01 00:00:00 1970 +0000
1769 | summary: C0
1769 | summary: C0
1770 |
1770 |
1771 @ changeset: 0:ea207398892e
1771 @ changeset: 0:ea207398892e
1772 user: test
1772 user: test
1773 date: Thu Jan 01 00:00:00 1970 +0000
1773 date: Thu Jan 01 00:00:00 1970 +0000
1774 summary: ROOT
1774 summary: ROOT
1775
1775
1776 $ hg up
1776 $ hg up
1777 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1777 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1778
1778
1779 Create a commit with three files
1779 Create a commit with three files
1780 $ touch A B C
1780 $ touch A B C
1781 $ hg commit -A -m "Add A,B,C" A B C
1781 $ hg commit -A -m "Add A,B,C" A B C
1782
1782
1783 Split it
1783 Split it
1784 $ hg up 3
1784 $ hg up 3
1785 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
1785 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
1786 $ touch A
1786 $ touch A
1787 $ hg commit -A -m "Add A,B,C" A
1787 $ hg commit -A -m "Add A,B,C" A
1788 created new head
1788 created new head
1789
1789
1790 $ touch B
1790 $ touch B
1791 $ hg commit -A -m "Add A,B,C" B
1791 $ hg commit -A -m "Add A,B,C" B
1792
1792
1793 $ touch C
1793 $ touch C
1794 $ hg commit -A -m "Add A,B,C" C
1794 $ hg commit -A -m "Add A,B,C" C
1795
1795
1796 $ hg log -G
1796 $ hg log -G
1797 @ changeset: 7:ba2ed02b0c9a
1797 @ changeset: 7:ba2ed02b0c9a
1798 | tag: tip
1798 | tag: tip
1799 | user: test
1799 | user: test
1800 | date: Thu Jan 01 00:00:00 1970 +0000
1800 | date: Thu Jan 01 00:00:00 1970 +0000
1801 | summary: Add A,B,C
1801 | summary: Add A,B,C
1802 |
1802 |
1803 o changeset: 6:4a004186e638
1803 o changeset: 6:4a004186e638
1804 | user: test
1804 | user: test
1805 | date: Thu Jan 01 00:00:00 1970 +0000
1805 | date: Thu Jan 01 00:00:00 1970 +0000
1806 | summary: Add A,B,C
1806 | summary: Add A,B,C
1807 |
1807 |
1808 o changeset: 5:dd800401bd8c
1808 o changeset: 5:dd800401bd8c
1809 | parent: 3:f897c6137566
1809 | parent: 3:f897c6137566
1810 | user: test
1810 | user: test
1811 | date: Thu Jan 01 00:00:00 1970 +0000
1811 | date: Thu Jan 01 00:00:00 1970 +0000
1812 | summary: Add A,B,C
1812 | summary: Add A,B,C
1813 |
1813 |
1814 | o changeset: 4:9bd10a0775e4
1814 | o changeset: 4:9bd10a0775e4
1815 |/ user: test
1815 |/ user: test
1816 | date: Thu Jan 01 00:00:00 1970 +0000
1816 | date: Thu Jan 01 00:00:00 1970 +0000
1817 | summary: Add A,B,C
1817 | summary: Add A,B,C
1818 |
1818 |
1819 o changeset: 3:f897c6137566
1819 o changeset: 3:f897c6137566
1820 | parent: 0:ea207398892e
1820 | parent: 0:ea207398892e
1821 | user: test
1821 | user: test
1822 | date: Thu Jan 01 00:00:00 1970 +0000
1822 | date: Thu Jan 01 00:00:00 1970 +0000
1823 | summary: C0
1823 | summary: C0
1824 |
1824 |
1825 o changeset: 0:ea207398892e
1825 o changeset: 0:ea207398892e
1826 user: test
1826 user: test
1827 date: Thu Jan 01 00:00:00 1970 +0000
1827 date: Thu Jan 01 00:00:00 1970 +0000
1828 summary: ROOT
1828 summary: ROOT
1829
1829
1830 $ hg debugobsolete `getid "4"` `getid "5"` `getid "6"` `getid "7"`
1830 $ hg debugobsolete `getid "4"` `getid "5"` `getid "6"` `getid "7"`
1831 obsoleted 1 changesets
1831 obsoleted 1 changesets
1832 $ hg log -G
1832 $ hg log -G
1833 @ changeset: 7:ba2ed02b0c9a
1833 @ changeset: 7:ba2ed02b0c9a
1834 | tag: tip
1834 | tag: tip
1835 | user: test
1835 | user: test
1836 | date: Thu Jan 01 00:00:00 1970 +0000
1836 | date: Thu Jan 01 00:00:00 1970 +0000
1837 | summary: Add A,B,C
1837 | summary: Add A,B,C
1838 |
1838 |
1839 o changeset: 6:4a004186e638
1839 o changeset: 6:4a004186e638
1840 | user: test
1840 | user: test
1841 | date: Thu Jan 01 00:00:00 1970 +0000
1841 | date: Thu Jan 01 00:00:00 1970 +0000
1842 | summary: Add A,B,C
1842 | summary: Add A,B,C
1843 |
1843 |
1844 o changeset: 5:dd800401bd8c
1844 o changeset: 5:dd800401bd8c
1845 | parent: 3:f897c6137566
1845 | parent: 3:f897c6137566
1846 | user: test
1846 | user: test
1847 | date: Thu Jan 01 00:00:00 1970 +0000
1847 | date: Thu Jan 01 00:00:00 1970 +0000
1848 | summary: Add A,B,C
1848 | summary: Add A,B,C
1849 |
1849 |
1850 o changeset: 3:f897c6137566
1850 o changeset: 3:f897c6137566
1851 | parent: 0:ea207398892e
1851 | parent: 0:ea207398892e
1852 | user: test
1852 | user: test
1853 | date: Thu Jan 01 00:00:00 1970 +0000
1853 | date: Thu Jan 01 00:00:00 1970 +0000
1854 | summary: C0
1854 | summary: C0
1855 |
1855 |
1856 o changeset: 0:ea207398892e
1856 o changeset: 0:ea207398892e
1857 user: test
1857 user: test
1858 date: Thu Jan 01 00:00:00 1970 +0000
1858 date: Thu Jan 01 00:00:00 1970 +0000
1859 summary: ROOT
1859 summary: ROOT
1860
1860
1861 Diverge one of the splitted commit
1861 Diverge one of the splitted commit
1862
1862
1863 $ hg up 6
1863 $ hg up 6
1864 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1864 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1865 $ hg commit --amend -m "Add only B"
1865 $ hg commit --amend -m "Add only B"
1866
1866
1867 $ hg up 6 --hidden
1867 $ hg up 6 --hidden
1868 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1868 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1869 $ hg commit --amend -m "Add B only"
1869 $ hg commit --amend -m "Add B only"
1870
1870
1871 $ hg log -G
1871 $ hg log -G
1872 @ changeset: 9:0b997eb7ceee
1872 @ changeset: 9:0b997eb7ceee
1873 | tag: tip
1873 | tag: tip
1874 | parent: 5:dd800401bd8c
1874 | parent: 5:dd800401bd8c
1875 | user: test
1875 | user: test
1876 | date: Thu Jan 01 00:00:00 1970 +0000
1876 | date: Thu Jan 01 00:00:00 1970 +0000
1877 | instability: content-divergent
1877 | instability: content-divergent
1878 | summary: Add B only
1878 | summary: Add B only
1879 |
1879 |
1880 | o changeset: 8:b18bc8331526
1880 | o changeset: 8:b18bc8331526
1881 |/ parent: 5:dd800401bd8c
1881 |/ parent: 5:dd800401bd8c
1882 | user: test
1882 | user: test
1883 | date: Thu Jan 01 00:00:00 1970 +0000
1883 | date: Thu Jan 01 00:00:00 1970 +0000
1884 | instability: content-divergent
1884 | instability: content-divergent
1885 | summary: Add only B
1885 | summary: Add only B
1886 |
1886 |
1887 | o changeset: 7:ba2ed02b0c9a
1887 | o changeset: 7:ba2ed02b0c9a
1888 | | user: test
1888 | | user: test
1889 | | date: Thu Jan 01 00:00:00 1970 +0000
1889 | | date: Thu Jan 01 00:00:00 1970 +0000
1890 | | instability: orphan, content-divergent
1890 | | instability: orphan, content-divergent
1891 | | summary: Add A,B,C
1891 | | summary: Add A,B,C
1892 | |
1892 | |
1893 | x changeset: 6:4a004186e638
1893 | x changeset: 6:4a004186e638
1894 |/ user: test
1894 |/ user: test
1895 | date: Thu Jan 01 00:00:00 1970 +0000
1895 | date: Thu Jan 01 00:00:00 1970 +0000
1896 | obsolete: rewritten using amend as 8:b18bc8331526
1896 | obsolete: rewritten using amend as 8:b18bc8331526
1897 | obsolete: rewritten using amend as 9:0b997eb7ceee
1897 | obsolete: rewritten using amend as 9:0b997eb7ceee
1898 | summary: Add A,B,C
1898 | summary: Add A,B,C
1899 |
1899 |
1900 o changeset: 5:dd800401bd8c
1900 o changeset: 5:dd800401bd8c
1901 | parent: 3:f897c6137566
1901 | parent: 3:f897c6137566
1902 | user: test
1902 | user: test
1903 | date: Thu Jan 01 00:00:00 1970 +0000
1903 | date: Thu Jan 01 00:00:00 1970 +0000
1904 | instability: content-divergent
1904 | instability: content-divergent
1905 | summary: Add A,B,C
1905 | summary: Add A,B,C
1906 |
1906 |
1907 o changeset: 3:f897c6137566
1907 o changeset: 3:f897c6137566
1908 | parent: 0:ea207398892e
1908 | parent: 0:ea207398892e
1909 | user: test
1909 | user: test
1910 | date: Thu Jan 01 00:00:00 1970 +0000
1910 | date: Thu Jan 01 00:00:00 1970 +0000
1911 | summary: C0
1911 | summary: C0
1912 |
1912 |
1913 o changeset: 0:ea207398892e
1913 o changeset: 0:ea207398892e
1914 user: test
1914 user: test
1915 date: Thu Jan 01 00:00:00 1970 +0000
1915 date: Thu Jan 01 00:00:00 1970 +0000
1916 summary: ROOT
1916 summary: ROOT
1917
1917
1918
1918
1919 Check templates
1919 Check templates
1920 ---------------
1920 ---------------
1921
1921
1922 $ hg tlog
1922 $ hg tlog
1923 @ 0b997eb7ceee
1923 @ 0b997eb7ceee
1924 | Predecessors: 6:4a004186e638
1924 | Predecessors: 6:4a004186e638
1925 | semi-colon: 6:4a004186e638
1925 | semi-colon: 6:4a004186e638
1926 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1926 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1927 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1927 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1928 | o b18bc8331526
1928 | o b18bc8331526
1929 |/ Predecessors: 6:4a004186e638
1929 |/ Predecessors: 6:4a004186e638
1930 | semi-colon: 6:4a004186e638
1930 | semi-colon: 6:4a004186e638
1931 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1931 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1932 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1932 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1933 | o ba2ed02b0c9a
1933 | o ba2ed02b0c9a
1934 | |
1934 | |
1935 | x 4a004186e638
1935 | x 4a004186e638
1936 |/ Successors: 8:b18bc8331526; 9:0b997eb7ceee
1936 |/ Successors: 8:b18bc8331526; 9:0b997eb7ceee
1937 | multi-line: 8:b18bc8331526
1937 | multi-line: 8:b18bc8331526
1938 | multi-line: 9:0b997eb7ceee
1938 | multi-line: 9:0b997eb7ceee
1939 | json: [["b18bc8331526a22cbb1801022bd1555bf291c48b"], ["0b997eb7ceeee06200a02f8aab185979092d514e"]]
1939 | json: [["b18bc8331526a22cbb1801022bd1555bf291c48b"], ["0b997eb7ceeee06200a02f8aab185979092d514e"]]
1940 o dd800401bd8c
1940 o dd800401bd8c
1941 |
1941 |
1942 o f897c6137566
1942 o f897c6137566
1943 |
1943 |
1944 o ea207398892e
1944 o ea207398892e
1945
1945
1946 $ hg fatelog
1946 $ hg fatelog
1947 @ 0b997eb7ceee
1947 @ 0b997eb7ceee
1948 |
1948 |
1949 | o b18bc8331526
1949 | o b18bc8331526
1950 |/
1950 |/
1951 | o ba2ed02b0c9a
1951 | o ba2ed02b0c9a
1952 | |
1952 | |
1953 | x 4a004186e638
1953 | x 4a004186e638
1954 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000); rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000);
1954 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000); rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000);
1955 o dd800401bd8c
1955 o dd800401bd8c
1956 |
1956 |
1957 o f897c6137566
1957 o f897c6137566
1958 |
1958 |
1959 o ea207398892e
1959 o ea207398892e
1960
1960
1961 $ hg tlog --hidden
1961 $ hg tlog --hidden
1962 @ 0b997eb7ceee
1962 @ 0b997eb7ceee
1963 | Predecessors: 6:4a004186e638
1963 | Predecessors: 6:4a004186e638
1964 | semi-colon: 6:4a004186e638
1964 | semi-colon: 6:4a004186e638
1965 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1965 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1966 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1966 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1967 | o b18bc8331526
1967 | o b18bc8331526
1968 |/ Predecessors: 6:4a004186e638
1968 |/ Predecessors: 6:4a004186e638
1969 | semi-colon: 6:4a004186e638
1969 | semi-colon: 6:4a004186e638
1970 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1970 | json: ["4a004186e63889f20cb16434fcbd72220bd1eace"]
1971 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1971 | map: 6:4a004186e63889f20cb16434fcbd72220bd1eace
1972 | o ba2ed02b0c9a
1972 | o ba2ed02b0c9a
1973 | | Predecessors: 4:9bd10a0775e4
1973 | | Predecessors: 4:9bd10a0775e4
1974 | | semi-colon: 4:9bd10a0775e4
1974 | | semi-colon: 4:9bd10a0775e4
1975 | | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1975 | | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1976 | | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1976 | | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1977 | x 4a004186e638
1977 | x 4a004186e638
1978 |/ Predecessors: 4:9bd10a0775e4
1978 |/ Predecessors: 4:9bd10a0775e4
1979 | semi-colon: 4:9bd10a0775e4
1979 | semi-colon: 4:9bd10a0775e4
1980 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1980 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1981 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1981 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1982 | Successors: 8:b18bc8331526; 9:0b997eb7ceee
1982 | Successors: 8:b18bc8331526; 9:0b997eb7ceee
1983 | multi-line: 8:b18bc8331526
1983 | multi-line: 8:b18bc8331526
1984 | multi-line: 9:0b997eb7ceee
1984 | multi-line: 9:0b997eb7ceee
1985 | json: [["b18bc8331526a22cbb1801022bd1555bf291c48b"], ["0b997eb7ceeee06200a02f8aab185979092d514e"]]
1985 | json: [["b18bc8331526a22cbb1801022bd1555bf291c48b"], ["0b997eb7ceeee06200a02f8aab185979092d514e"]]
1986 o dd800401bd8c
1986 o dd800401bd8c
1987 | Predecessors: 4:9bd10a0775e4
1987 | Predecessors: 4:9bd10a0775e4
1988 | semi-colon: 4:9bd10a0775e4
1988 | semi-colon: 4:9bd10a0775e4
1989 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1989 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
1990 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1990 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
1991 | x 9bd10a0775e4
1991 | x 9bd10a0775e4
1992 |/ Successors: 5:dd800401bd8c 6:4a004186e638 7:ba2ed02b0c9a
1992 |/ Successors: 5:dd800401bd8c 6:4a004186e638 7:ba2ed02b0c9a
1993 | multi-line: 5:dd800401bd8c 6:4a004186e638 7:ba2ed02b0c9a
1993 | multi-line: 5:dd800401bd8c 6:4a004186e638 7:ba2ed02b0c9a
1994 | json: [["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"]]
1994 | json: [["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"]]
1995 o f897c6137566
1995 o f897c6137566
1996 | Predecessors: 2:0dec01379d3b
1996 | Predecessors: 2:0dec01379d3b
1997 | semi-colon: 2:0dec01379d3b
1997 | semi-colon: 2:0dec01379d3b
1998 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1998 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
1999 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
1999 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
2000 | x 0dec01379d3b
2000 | x 0dec01379d3b
2001 | | Predecessors: 1:471f378eab4c
2001 | | Predecessors: 1:471f378eab4c
2002 | | semi-colon: 1:471f378eab4c
2002 | | semi-colon: 1:471f378eab4c
2003 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
2003 | | json: ["471f378eab4c5e25f6c77f785b27c936efb22874"]
2004 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
2004 | | map: 1:471f378eab4c5e25f6c77f785b27c936efb22874
2005 | | Successors: 3:f897c6137566; 1:471f378eab4c
2005 | | Successors: 3:f897c6137566; 1:471f378eab4c
2006 | | multi-line: 3:f897c6137566
2006 | | multi-line: 3:f897c6137566
2007 | | multi-line: 1:471f378eab4c
2007 | | multi-line: 1:471f378eab4c
2008 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
2008 | | json: [["f897c6137566320b081514b4c7227ecc3d384b39"], ["471f378eab4c5e25f6c77f785b27c936efb22874"]]
2009 | x 471f378eab4c
2009 | x 471f378eab4c
2010 |/ Predecessors: 2:0dec01379d3b
2010 |/ Predecessors: 2:0dec01379d3b
2011 | semi-colon: 2:0dec01379d3b
2011 | semi-colon: 2:0dec01379d3b
2012 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
2012 | json: ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]
2013 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
2013 | map: 2:0dec01379d3be6318c470ead31b1fe7ae7cb53d5
2014 | Successors: 2:0dec01379d3b
2014 | Successors: 2:0dec01379d3b
2015 | multi-line: 2:0dec01379d3b
2015 | multi-line: 2:0dec01379d3b
2016 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
2016 | json: [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]]
2017 o ea207398892e
2017 o ea207398892e
2018
2018
2019 $ hg fatelog --hidden
2019 $ hg fatelog --hidden
2020 @ 0b997eb7ceee
2020 @ 0b997eb7ceee
2021 |
2021 |
2022 | o b18bc8331526
2022 | o b18bc8331526
2023 |/
2023 |/
2024 | o ba2ed02b0c9a
2024 | o ba2ed02b0c9a
2025 | |
2025 | |
2026 | x 4a004186e638
2026 | x 4a004186e638
2027 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000); rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000);
2027 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000); rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000);
2028 o dd800401bd8c
2028 o dd800401bd8c
2029 |
2029 |
2030 | x 9bd10a0775e4
2030 | x 9bd10a0775e4
2031 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a by test (at 1970-01-01 00:00 +0000);
2031 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a by test (at 1970-01-01 00:00 +0000);
2032 o f897c6137566
2032 o f897c6137566
2033 |
2033 |
2034 | x 0dec01379d3b
2034 | x 0dec01379d3b
2035 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000); rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000);
2035 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000); rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000);
2036 | x 471f378eab4c
2036 | x 471f378eab4c
2037 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000);
2037 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000);
2038 o ea207398892e
2038 o ea207398892e
2039
2039
2040 $ hg fatelogjson --hidden
2040 $ hg fatelogjson --hidden
2041 @ 0b997eb7ceee
2041 @ 0b997eb7ceee
2042 |
2042 |
2043 | o b18bc8331526
2043 | o b18bc8331526
2044 |/
2044 |/
2045 | o ba2ed02b0c9a
2045 | o ba2ed02b0c9a
2046 | |
2046 | |
2047 | x 4a004186e638
2047 | x 4a004186e638
2048 |/ Obsfate: [{"markers": [["4a004186e63889f20cb16434fcbd72220bd1eace", ["b18bc8331526a22cbb1801022bd1555bf291c48b"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["b18bc8331526a22cbb1801022bd1555bf291c48b"]}, {"markers": [["4a004186e63889f20cb16434fcbd72220bd1eace", ["0b997eb7ceeee06200a02f8aab185979092d514e"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["0b997eb7ceeee06200a02f8aab185979092d514e"]}]
2048 |/ Obsfate: [{"markers": [["4a004186e63889f20cb16434fcbd72220bd1eace", ["b18bc8331526a22cbb1801022bd1555bf291c48b"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["b18bc8331526a22cbb1801022bd1555bf291c48b"]}, {"markers": [["4a004186e63889f20cb16434fcbd72220bd1eace", ["0b997eb7ceeee06200a02f8aab185979092d514e"], 0, [["ef1", "1"], ["operation", "amend"], ["user", "test"]], [0.0, 0], null]], "successors": ["0b997eb7ceeee06200a02f8aab185979092d514e"]}]
2049 o dd800401bd8c
2049 o dd800401bd8c
2050 |
2050 |
2051 | x 9bd10a0775e4
2051 | x 9bd10a0775e4
2052 |/ Obsfate: [{"markers": [["9bd10a0775e478708cada5f176ec6de654359ce7", ["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"]}]
2052 |/ Obsfate: [{"markers": [["9bd10a0775e478708cada5f176ec6de654359ce7", ["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["dd800401bd8c79d815329277739e433e883f784e", "4a004186e63889f20cb16434fcbd72220bd1eace", "ba2ed02b0c9a56b9fdbc4e79c7e57866984d8a1f"]}]
2053 o f897c6137566
2053 o f897c6137566
2054 |
2054 |
2055 | x 0dec01379d3b
2055 | x 0dec01379d3b
2056 | | Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["f897c6137566320b081514b4c7227ecc3d384b39"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["f897c6137566320b081514b4c7227ecc3d384b39"]}, {"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["471f378eab4c5e25f6c77f785b27c936efb22874"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["471f378eab4c5e25f6c77f785b27c936efb22874"]}]
2056 | | Obsfate: [{"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["f897c6137566320b081514b4c7227ecc3d384b39"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["f897c6137566320b081514b4c7227ecc3d384b39"]}, {"markers": [["0dec01379d3be6318c470ead31b1fe7ae7cb53d5", ["471f378eab4c5e25f6c77f785b27c936efb22874"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["471f378eab4c5e25f6c77f785b27c936efb22874"]}]
2057 | x 471f378eab4c
2057 | x 471f378eab4c
2058 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]}]
2058 |/ Obsfate: [{"markers": [["471f378eab4c5e25f6c77f785b27c936efb22874", ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"], 0, [["user", "test"]], [0.0, 0], null]], "successors": ["0dec01379d3be6318c470ead31b1fe7ae7cb53d5"]}]
2059 o ea207398892e
2059 o ea207398892e
2060
2060
2061 $ hg up --hidden 4
2061 $ hg up --hidden 4
2062 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2062 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
2063 $ hg rebase -r 7 -d 8 --config extensions.rebase=
2063 $ hg rebase -r 7 -d 8 --config extensions.rebase=
2064 rebasing 7:ba2ed02b0c9a "Add A,B,C"
2064 rebasing 7:ba2ed02b0c9a "Add A,B,C"
2065 $ hg tlog
2065 $ hg tlog
2066 o eceed8f98ffc
2066 o eceed8f98ffc
2067 | Predecessors: 4:9bd10a0775e4
2067 | Predecessors: 4:9bd10a0775e4
2068 | semi-colon: 4:9bd10a0775e4
2068 | semi-colon: 4:9bd10a0775e4
2069 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2069 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2070 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2070 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2071 | o 0b997eb7ceee
2071 | o 0b997eb7ceee
2072 | | Predecessors: 4:9bd10a0775e4
2072 | | Predecessors: 4:9bd10a0775e4
2073 | | semi-colon: 4:9bd10a0775e4
2073 | | semi-colon: 4:9bd10a0775e4
2074 | | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2074 | | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2075 | | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2075 | | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2076 o | b18bc8331526
2076 o | b18bc8331526
2077 |/ Predecessors: 4:9bd10a0775e4
2077 |/ Predecessors: 4:9bd10a0775e4
2078 | semi-colon: 4:9bd10a0775e4
2078 | semi-colon: 4:9bd10a0775e4
2079 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2079 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2080 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2080 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2081 o dd800401bd8c
2081 o dd800401bd8c
2082 | Predecessors: 4:9bd10a0775e4
2082 | Predecessors: 4:9bd10a0775e4
2083 | semi-colon: 4:9bd10a0775e4
2083 | semi-colon: 4:9bd10a0775e4
2084 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2084 | json: ["9bd10a0775e478708cada5f176ec6de654359ce7"]
2085 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2085 | map: 4:9bd10a0775e478708cada5f176ec6de654359ce7
2086 | @ 9bd10a0775e4
2086 | @ 9bd10a0775e4
2087 |/ Successors: 5:dd800401bd8c 9:0b997eb7ceee 10:eceed8f98ffc; 5:dd800401bd8c 8:b18bc8331526 10:eceed8f98ffc
2087 |/ Successors: 5:dd800401bd8c 9:0b997eb7ceee 10:eceed8f98ffc; 5:dd800401bd8c 8:b18bc8331526 10:eceed8f98ffc
2088 | multi-line: 5:dd800401bd8c 9:0b997eb7ceee 10:eceed8f98ffc
2088 | multi-line: 5:dd800401bd8c 9:0b997eb7ceee 10:eceed8f98ffc
2089 | multi-line: 5:dd800401bd8c 8:b18bc8331526 10:eceed8f98ffc
2089 | multi-line: 5:dd800401bd8c 8:b18bc8331526 10:eceed8f98ffc
2090 | json: [["dd800401bd8c79d815329277739e433e883f784e", "0b997eb7ceeee06200a02f8aab185979092d514e", "eceed8f98ffc4186032e29a6542ab98888ebf68d"], ["dd800401bd8c79d815329277739e433e883f784e", "b18bc8331526a22cbb1801022bd1555bf291c48b", "eceed8f98ffc4186032e29a6542ab98888ebf68d"]]
2090 | json: [["dd800401bd8c79d815329277739e433e883f784e", "0b997eb7ceeee06200a02f8aab185979092d514e", "eceed8f98ffc4186032e29a6542ab98888ebf68d"], ["dd800401bd8c79d815329277739e433e883f784e", "b18bc8331526a22cbb1801022bd1555bf291c48b", "eceed8f98ffc4186032e29a6542ab98888ebf68d"]]
2091 o f897c6137566
2091 o f897c6137566
2092 |
2092 |
2093 o ea207398892e
2093 o ea207398892e
2094
2094
2095
2095
2096 $ hg fatelog
2096 $ hg fatelog
2097 o eceed8f98ffc
2097 o eceed8f98ffc
2098 |
2098 |
2099 | o 0b997eb7ceee
2099 | o 0b997eb7ceee
2100 | |
2100 | |
2101 o | b18bc8331526
2101 o | b18bc8331526
2102 |/
2102 |/
2103 o dd800401bd8c
2103 o dd800401bd8c
2104 |
2104 |
2105 | @ 9bd10a0775e4
2105 | @ 9bd10a0775e4
2106 |/ Obsfate: split using amend, rebase as 5:dd800401bd8c, 9:0b997eb7ceee, 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000); split using amend, rebase as 5:dd800401bd8c, 8:b18bc8331526, 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000);
2106 |/ Obsfate: split using amend, rebase as 5:dd800401bd8c, 9:0b997eb7ceee, 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000); split using amend, rebase as 5:dd800401bd8c, 8:b18bc8331526, 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000);
2107 o f897c6137566
2107 o f897c6137566
2108 |
2108 |
2109 o ea207398892e
2109 o ea207398892e
2110
2110
2111 Check other fatelog implementations
2111 Check other fatelog implementations
2112 -----------------------------------
2112 -----------------------------------
2113
2113
2114 $ hg fatelogkw --hidden -q
2114 $ hg fatelogkw --hidden -q
2115 o eceed8f98ffc
2115 o eceed8f98ffc
2116 |
2116 |
2117 | o 0b997eb7ceee
2117 | o 0b997eb7ceee
2118 | |
2118 | |
2119 o | b18bc8331526
2119 o | b18bc8331526
2120 |/
2120 |/
2121 | x ba2ed02b0c9a
2121 | x ba2ed02b0c9a
2122 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc
2122 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc
2123 | x 4a004186e638
2123 | x 4a004186e638
2124 |/ Obsfate: rewritten using amend as 8:b18bc8331526
2124 |/ Obsfate: rewritten using amend as 8:b18bc8331526
2125 | Obsfate: rewritten using amend as 9:0b997eb7ceee
2125 | Obsfate: rewritten using amend as 9:0b997eb7ceee
2126 o dd800401bd8c
2126 o dd800401bd8c
2127 |
2127 |
2128 | @ 9bd10a0775e4
2128 | @ 9bd10a0775e4
2129 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2129 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2130 o f897c6137566
2130 o f897c6137566
2131 |
2131 |
2132 | x 0dec01379d3b
2132 | x 0dec01379d3b
2133 | | Obsfate: rewritten as 3:f897c6137566
2133 | | Obsfate: rewritten as 3:f897c6137566
2134 | | Obsfate: rewritten as 1:471f378eab4c
2134 | | Obsfate: rewritten as 1:471f378eab4c
2135 | x 471f378eab4c
2135 | x 471f378eab4c
2136 |/ Obsfate: rewritten as 2:0dec01379d3b
2136 |/ Obsfate: rewritten as 2:0dec01379d3b
2137 o ea207398892e
2137 o ea207398892e
2138
2138
2139 $ hg fatelogkw --hidden
2139 $ hg fatelogkw --hidden
2140 o eceed8f98ffc
2140 o eceed8f98ffc
2141 |
2141 |
2142 | o 0b997eb7ceee
2142 | o 0b997eb7ceee
2143 | |
2143 | |
2144 o | b18bc8331526
2144 o | b18bc8331526
2145 |/
2145 |/
2146 | x ba2ed02b0c9a
2146 | x ba2ed02b0c9a
2147 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc
2147 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc
2148 | x 4a004186e638
2148 | x 4a004186e638
2149 |/ Obsfate: rewritten using amend as 8:b18bc8331526
2149 |/ Obsfate: rewritten using amend as 8:b18bc8331526
2150 | Obsfate: rewritten using amend as 9:0b997eb7ceee
2150 | Obsfate: rewritten using amend as 9:0b997eb7ceee
2151 o dd800401bd8c
2151 o dd800401bd8c
2152 |
2152 |
2153 | @ 9bd10a0775e4
2153 | @ 9bd10a0775e4
2154 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2154 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2155 o f897c6137566
2155 o f897c6137566
2156 |
2156 |
2157 | x 0dec01379d3b
2157 | x 0dec01379d3b
2158 | | Obsfate: rewritten as 3:f897c6137566
2158 | | Obsfate: rewritten as 3:f897c6137566
2159 | | Obsfate: rewritten as 1:471f378eab4c
2159 | | Obsfate: rewritten as 1:471f378eab4c
2160 | x 471f378eab4c
2160 | x 471f378eab4c
2161 |/ Obsfate: rewritten as 2:0dec01379d3b
2161 |/ Obsfate: rewritten as 2:0dec01379d3b
2162 o ea207398892e
2162 o ea207398892e
2163
2163
2164 $ hg fatelogkw --hidden -v
2164 $ hg fatelogkw --hidden -v
2165 o eceed8f98ffc
2165 o eceed8f98ffc
2166 |
2166 |
2167 | o 0b997eb7ceee
2167 | o 0b997eb7ceee
2168 | |
2168 | |
2169 o | b18bc8331526
2169 o | b18bc8331526
2170 |/
2170 |/
2171 | x ba2ed02b0c9a
2171 | x ba2ed02b0c9a
2172 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000)
2172 | | Obsfate: rewritten using rebase as 10:eceed8f98ffc by test (at 1970-01-01 00:00 +0000)
2173 | x 4a004186e638
2173 | x 4a004186e638
2174 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000)
2174 |/ Obsfate: rewritten using amend as 8:b18bc8331526 by test (at 1970-01-01 00:00 +0000)
2175 | Obsfate: rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000)
2175 | Obsfate: rewritten using amend as 9:0b997eb7ceee by test (at 1970-01-01 00:00 +0000)
2176 o dd800401bd8c
2176 o dd800401bd8c
2177 |
2177 |
2178 | @ 9bd10a0775e4
2178 | @ 9bd10a0775e4
2179 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a by test (at 1970-01-01 00:00 +0000)
2179 |/ Obsfate: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a by test (at 1970-01-01 00:00 +0000)
2180 o f897c6137566
2180 o f897c6137566
2181 |
2181 |
2182 | x 0dec01379d3b
2182 | x 0dec01379d3b
2183 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000)
2183 | | Obsfate: rewritten as 3:f897c6137566 by test (at 1970-01-01 00:00 +0000)
2184 | | Obsfate: rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000)
2184 | | Obsfate: rewritten as 1:471f378eab4c by test (at 1970-01-01 00:00 +0000)
2185 | x 471f378eab4c
2185 | x 471f378eab4c
2186 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000)
2186 |/ Obsfate: rewritten as 2:0dec01379d3b by test (at 1970-01-01 00:00 +0000)
2187 o ea207398892e
2187 o ea207398892e
2188
2188
2189 $ hg log -G -T "default" --hidden
2189 $ hg log -G -T "default" --hidden
2190 o changeset: 10:eceed8f98ffc
2190 o changeset: 10:eceed8f98ffc
2191 | tag: tip
2191 | tag: tip
2192 | parent: 8:b18bc8331526
2192 | parent: 8:b18bc8331526
2193 | user: test
2193 | user: test
2194 | date: Thu Jan 01 00:00:00 1970 +0000
2194 | date: Thu Jan 01 00:00:00 1970 +0000
2195 | instability: content-divergent
2195 | instability: content-divergent
2196 | summary: Add A,B,C
2196 | summary: Add A,B,C
2197 |
2197 |
2198 | o changeset: 9:0b997eb7ceee
2198 | o changeset: 9:0b997eb7ceee
2199 | | parent: 5:dd800401bd8c
2199 | | parent: 5:dd800401bd8c
2200 | | user: test
2200 | | user: test
2201 | | date: Thu Jan 01 00:00:00 1970 +0000
2201 | | date: Thu Jan 01 00:00:00 1970 +0000
2202 | | instability: content-divergent
2202 | | instability: content-divergent
2203 | | summary: Add B only
2203 | | summary: Add B only
2204 | |
2204 | |
2205 o | changeset: 8:b18bc8331526
2205 o | changeset: 8:b18bc8331526
2206 |/ parent: 5:dd800401bd8c
2206 |/ parent: 5:dd800401bd8c
2207 | user: test
2207 | user: test
2208 | date: Thu Jan 01 00:00:00 1970 +0000
2208 | date: Thu Jan 01 00:00:00 1970 +0000
2209 | instability: content-divergent
2209 | instability: content-divergent
2210 | summary: Add only B
2210 | summary: Add only B
2211 |
2211 |
2212 | x changeset: 7:ba2ed02b0c9a
2212 | x changeset: 7:ba2ed02b0c9a
2213 | | user: test
2213 | | user: test
2214 | | date: Thu Jan 01 00:00:00 1970 +0000
2214 | | date: Thu Jan 01 00:00:00 1970 +0000
2215 | | obsolete: rewritten using rebase as 10:eceed8f98ffc
2215 | | obsolete: rewritten using rebase as 10:eceed8f98ffc
2216 | | summary: Add A,B,C
2216 | | summary: Add A,B,C
2217 | |
2217 | |
2218 | x changeset: 6:4a004186e638
2218 | x changeset: 6:4a004186e638
2219 |/ user: test
2219 |/ user: test
2220 | date: Thu Jan 01 00:00:00 1970 +0000
2220 | date: Thu Jan 01 00:00:00 1970 +0000
2221 | obsolete: rewritten using amend as 8:b18bc8331526
2221 | obsolete: rewritten using amend as 8:b18bc8331526
2222 | obsolete: rewritten using amend as 9:0b997eb7ceee
2222 | obsolete: rewritten using amend as 9:0b997eb7ceee
2223 | summary: Add A,B,C
2223 | summary: Add A,B,C
2224 |
2224 |
2225 o changeset: 5:dd800401bd8c
2225 o changeset: 5:dd800401bd8c
2226 | parent: 3:f897c6137566
2226 | parent: 3:f897c6137566
2227 | user: test
2227 | user: test
2228 | date: Thu Jan 01 00:00:00 1970 +0000
2228 | date: Thu Jan 01 00:00:00 1970 +0000
2229 | instability: content-divergent
2229 | instability: content-divergent
2230 | summary: Add A,B,C
2230 | summary: Add A,B,C
2231 |
2231 |
2232 | @ changeset: 4:9bd10a0775e4
2232 | @ changeset: 4:9bd10a0775e4
2233 |/ user: test
2233 |/ user: test
2234 | date: Thu Jan 01 00:00:00 1970 +0000
2234 | date: Thu Jan 01 00:00:00 1970 +0000
2235 | obsolete: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2235 | obsolete: split as 5:dd800401bd8c, 6:4a004186e638, 7:ba2ed02b0c9a
2236 | summary: Add A,B,C
2236 | summary: Add A,B,C
2237 |
2237 |
2238 o changeset: 3:f897c6137566
2238 o changeset: 3:f897c6137566
2239 | parent: 0:ea207398892e
2239 | parent: 0:ea207398892e
2240 | user: test
2240 | user: test
2241 | date: Thu Jan 01 00:00:00 1970 +0000
2241 | date: Thu Jan 01 00:00:00 1970 +0000
2242 | summary: C0
2242 | summary: C0
2243 |
2243 |
2244 | x changeset: 2:0dec01379d3b
2244 | x changeset: 2:0dec01379d3b
2245 | | user: test
2245 | | user: test
2246 | | date: Thu Jan 01 00:00:00 1970 +0000
2246 | | date: Thu Jan 01 00:00:00 1970 +0000
2247 | | obsolete: rewritten as 3:f897c6137566
2247 | | obsolete: rewritten as 3:f897c6137566
2248 | | obsolete: rewritten as 1:471f378eab4c
2248 | | obsolete: rewritten as 1:471f378eab4c
2249 | | summary: B0
2249 | | summary: B0
2250 | |
2250 | |
2251 | x changeset: 1:471f378eab4c
2251 | x changeset: 1:471f378eab4c
2252 |/ user: test
2252 |/ user: test
2253 | date: Thu Jan 01 00:00:00 1970 +0000
2253 | date: Thu Jan 01 00:00:00 1970 +0000
2254 | obsolete: rewritten as 2:0dec01379d3b
2254 | obsolete: rewritten as 2:0dec01379d3b
2255 | summary: A0
2255 | summary: A0
2256 |
2256 |
2257 o changeset: 0:ea207398892e
2257 o changeset: 0:ea207398892e
2258 user: test
2258 user: test
2259 date: Thu Jan 01 00:00:00 1970 +0000
2259 date: Thu Jan 01 00:00:00 1970 +0000
2260 summary: ROOT
2260 summary: ROOT
2261
2261
2262
2262
2263 Test templates with pruned commits
2263 Test templates with pruned commits
2264 ==================================
2264 ==================================
2265
2265
2266 Test setup
2266 Test setup
2267 ----------
2267 ----------
2268
2268
2269 $ hg init $TESTTMP/templates-local-prune
2269 $ hg init $TESTTMP/templates-local-prune
2270 $ cd $TESTTMP/templates-local-prune
2270 $ cd $TESTTMP/templates-local-prune
2271 $ mkcommit ROOT
2271 $ mkcommit ROOT
2272 $ mkcommit A0
2272 $ mkcommit A0
2273 $ hg debugobsolete --record-parent `getid "."`
2273 $ hg debugobsolete --record-parent `getid "."`
2274 obsoleted 1 changesets
2274 obsoleted 1 changesets
2275
2275
2276 Check output
2276 Check output
2277 ------------
2277 ------------
2278
2278
2279 $ hg up "desc(A0)" --hidden
2279 $ hg up "desc(A0)" --hidden
2280 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2280 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2281 $ hg tlog
2281 $ hg tlog
2282 @ 471f378eab4c
2282 @ 471f378eab4c
2283 |
2283 |
2284 o ea207398892e
2284 o ea207398892e
2285
2285
2286 $ hg fatelog
2286 $ hg fatelog
2287 @ 471f378eab4c
2287 @ 471f378eab4c
2288 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2288 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2289 o ea207398892e
2289 o ea207398892e
2290
2290
2291 Test templates with multiple pruned commits
2291 Test templates with multiple pruned commits
2292 ===========================================
2292 ===========================================
2293
2293
2294 Test setup
2294 Test setup
2295 ----------
2295 ----------
2296
2296
2297 $ hg init $TESTTMP/multiple-local-prune
2297 $ hg init $TESTTMP/multiple-local-prune
2298 $ cd $TESTTMP/multiple-local-prune
2298 $ cd $TESTTMP/multiple-local-prune
2299 $ mkcommit ROOT
2299 $ mkcommit ROOT
2300 $ mkcommit A0
2300 $ mkcommit A0
2301 $ hg commit --amend -m "A1"
2301 $ hg commit --amend -m "A1"
2302 $ hg debugobsolete --record-parent `getid "."`
2302 $ hg debugobsolete --record-parent `getid "."`
2303 obsoleted 1 changesets
2303 obsoleted 1 changesets
2304
2304
2305 $ hg up -r "desc(A0)" --hidden
2305 $ hg up -r "desc(A0)" --hidden
2306 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2306 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2307 $ hg commit --amend -m "A2"
2307 $ hg commit --amend -m "A2"
2308 $ hg debugobsolete --record-parent `getid "."`
2308 $ hg debugobsolete --record-parent `getid "."`
2309 obsoleted 1 changesets
2309 obsoleted 1 changesets
2310
2310
2311 Check output
2311 Check output
2312 ------------
2312 ------------
2313
2313
2314 $ hg up "desc(A0)" --hidden
2314 $ hg up "desc(A0)" --hidden
2315 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2315 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2316 $ hg tlog
2316 $ hg tlog
2317 @ 471f378eab4c
2317 @ 471f378eab4c
2318 |
2318 |
2319 o ea207398892e
2319 o ea207398892e
2320
2320
2321 # todo: the obsfate output is not ideal
2321 # todo: the obsfate output is not ideal
2322 $ hg fatelog
2322 $ hg fatelog
2323 @ 471f378eab4c
2323 @ 471f378eab4c
2324 | Obsfate: pruned;
2324 | Obsfate: pruned;
2325 o ea207398892e
2325 o ea207398892e
2326
2326
2327 $ hg fatelog --hidden
2327 $ hg fatelog --hidden
2328 x 65b757b745b9
2328 x 65b757b745b9
2329 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2329 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2330 | x fdf9bde5129a
2330 | x fdf9bde5129a
2331 |/ Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2331 |/ Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2332 | @ 471f378eab4c
2332 | @ 471f378eab4c
2333 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000);
2333 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000); rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000);
2334 o ea207398892e
2334 o ea207398892e
2335
2335
2336 Check other fatelog implementations
2336 Check other fatelog implementations
2337 -----------------------------------
2337 -----------------------------------
2338
2338
2339 $ hg fatelogkw --hidden -q
2339 $ hg fatelogkw --hidden -q
2340 x 65b757b745b9
2340 x 65b757b745b9
2341 | Obsfate: pruned
2341 | Obsfate: pruned
2342 | x fdf9bde5129a
2342 | x fdf9bde5129a
2343 |/ Obsfate: pruned
2343 |/ Obsfate: pruned
2344 | @ 471f378eab4c
2344 | @ 471f378eab4c
2345 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
2345 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
2346 | Obsfate: rewritten using amend as 3:65b757b745b9
2346 | Obsfate: rewritten using amend as 3:65b757b745b9
2347 o ea207398892e
2347 o ea207398892e
2348
2348
2349 $ hg fatelogkw --hidden
2349 $ hg fatelogkw --hidden
2350 x 65b757b745b9
2350 x 65b757b745b9
2351 | Obsfate: pruned
2351 | Obsfate: pruned
2352 | x fdf9bde5129a
2352 | x fdf9bde5129a
2353 |/ Obsfate: pruned
2353 |/ Obsfate: pruned
2354 | @ 471f378eab4c
2354 | @ 471f378eab4c
2355 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
2355 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a
2356 | Obsfate: rewritten using amend as 3:65b757b745b9
2356 | Obsfate: rewritten using amend as 3:65b757b745b9
2357 o ea207398892e
2357 o ea207398892e
2358
2358
2359 $ hg fatelogkw --hidden -v
2359 $ hg fatelogkw --hidden -v
2360 x 65b757b745b9
2360 x 65b757b745b9
2361 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2361 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2362 | x fdf9bde5129a
2362 | x fdf9bde5129a
2363 |/ Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2363 |/ Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2364 | @ 471f378eab4c
2364 | @ 471f378eab4c
2365 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000)
2365 |/ Obsfate: rewritten using amend as 2:fdf9bde5129a by test (at 1970-01-01 00:00 +0000)
2366 | Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000)
2366 | Obsfate: rewritten using amend as 3:65b757b745b9 by test (at 1970-01-01 00:00 +0000)
2367 o ea207398892e
2367 o ea207398892e
2368
2368
2369
2369
2370 $ hg log -G -T "default" --hidden
2370 $ hg log -G -T "default" --hidden
2371 x changeset: 3:65b757b745b9
2371 x changeset: 3:65b757b745b9
2372 | tag: tip
2372 | tag: tip
2373 | parent: 0:ea207398892e
2373 | parent: 0:ea207398892e
2374 | user: test
2374 | user: test
2375 | date: Thu Jan 01 00:00:00 1970 +0000
2375 | date: Thu Jan 01 00:00:00 1970 +0000
2376 | obsolete: pruned
2376 | obsolete: pruned
2377 | summary: A2
2377 | summary: A2
2378 |
2378 |
2379 | x changeset: 2:fdf9bde5129a
2379 | x changeset: 2:fdf9bde5129a
2380 |/ parent: 0:ea207398892e
2380 |/ parent: 0:ea207398892e
2381 | user: test
2381 | user: test
2382 | date: Thu Jan 01 00:00:00 1970 +0000
2382 | date: Thu Jan 01 00:00:00 1970 +0000
2383 | obsolete: pruned
2383 | obsolete: pruned
2384 | summary: A1
2384 | summary: A1
2385 |
2385 |
2386 | @ changeset: 1:471f378eab4c
2386 | @ changeset: 1:471f378eab4c
2387 |/ user: test
2387 |/ user: test
2388 | date: Thu Jan 01 00:00:00 1970 +0000
2388 | date: Thu Jan 01 00:00:00 1970 +0000
2389 | obsolete: rewritten using amend as 2:fdf9bde5129a
2389 | obsolete: rewritten using amend as 2:fdf9bde5129a
2390 | obsolete: rewritten using amend as 3:65b757b745b9
2390 | obsolete: rewritten using amend as 3:65b757b745b9
2391 | summary: A0
2391 | summary: A0
2392 |
2392 |
2393 o changeset: 0:ea207398892e
2393 o changeset: 0:ea207398892e
2394 user: test
2394 user: test
2395 date: Thu Jan 01 00:00:00 1970 +0000
2395 date: Thu Jan 01 00:00:00 1970 +0000
2396 summary: ROOT
2396 summary: ROOT
2397
2397
2398
2398
2399 Test templates with splitted and pruned commit
2399 Test templates with splitted and pruned commit
2400 ==============================================
2400 ==============================================
2401
2401
2402 $ hg init $TESTTMP/templates-local-split-prune
2402 $ hg init $TESTTMP/templates-local-split-prune
2403 $ cd $TESTTMP/templates-local-split-prune
2403 $ cd $TESTTMP/templates-local-split-prune
2404 $ mkcommit ROOT
2404 $ mkcommit ROOT
2405 $ echo 42 >> a
2405 $ echo 42 >> a
2406 $ echo 43 >> b
2406 $ echo 43 >> b
2407 $ hg commit -A -m "A0"
2407 $ hg commit -A -m "A0"
2408 adding a
2408 adding a
2409 adding b
2409 adding b
2410 $ hg log --hidden -G
2410 $ hg log --hidden -G
2411 @ changeset: 1:471597cad322
2411 @ changeset: 1:471597cad322
2412 | tag: tip
2412 | tag: tip
2413 | user: test
2413 | user: test
2414 | date: Thu Jan 01 00:00:00 1970 +0000
2414 | date: Thu Jan 01 00:00:00 1970 +0000
2415 | summary: A0
2415 | summary: A0
2416 |
2416 |
2417 o changeset: 0:ea207398892e
2417 o changeset: 0:ea207398892e
2418 user: test
2418 user: test
2419 date: Thu Jan 01 00:00:00 1970 +0000
2419 date: Thu Jan 01 00:00:00 1970 +0000
2420 summary: ROOT
2420 summary: ROOT
2421
2421
2422 # Simulate split
2422 # Simulate split
2423 $ hg up -r "desc(ROOT)"
2423 $ hg up -r "desc(ROOT)"
2424 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
2424 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
2425 $ echo 42 >> a
2425 $ echo 42 >> a
2426 $ hg commit -A -m "A1"
2426 $ hg commit -A -m "A1"
2427 adding a
2427 adding a
2428 created new head
2428 created new head
2429 $ echo 43 >> b
2429 $ echo 43 >> b
2430 $ hg commit -A -m "A2"
2430 $ hg commit -A -m "A2"
2431 adding b
2431 adding b
2432 $ hg debugobsolete `getid "1"` `getid "2"` `getid "3"`
2432 $ hg debugobsolete `getid "1"` `getid "2"` `getid "3"`
2433 obsoleted 1 changesets
2433 obsoleted 1 changesets
2434
2434
2435 # Simulate prune
2435 # Simulate prune
2436 $ hg debugobsolete --record-parent `getid "."`
2436 $ hg debugobsolete --record-parent `getid "."`
2437 obsoleted 1 changesets
2437 obsoleted 1 changesets
2438
2438
2439 $ hg log --hidden -G
2439 $ hg log --hidden -G
2440 @ changeset: 3:0d0ef4bdf70e
2440 @ changeset: 3:0d0ef4bdf70e
2441 | tag: tip
2441 | tag: tip
2442 | user: test
2442 | user: test
2443 | date: Thu Jan 01 00:00:00 1970 +0000
2443 | date: Thu Jan 01 00:00:00 1970 +0000
2444 | obsolete: pruned
2444 | obsolete: pruned
2445 | summary: A2
2445 | summary: A2
2446 |
2446 |
2447 o changeset: 2:617adc3a144c
2447 o changeset: 2:617adc3a144c
2448 | parent: 0:ea207398892e
2448 | parent: 0:ea207398892e
2449 | user: test
2449 | user: test
2450 | date: Thu Jan 01 00:00:00 1970 +0000
2450 | date: Thu Jan 01 00:00:00 1970 +0000
2451 | summary: A1
2451 | summary: A1
2452 |
2452 |
2453 | x changeset: 1:471597cad322
2453 | x changeset: 1:471597cad322
2454 |/ user: test
2454 |/ user: test
2455 | date: Thu Jan 01 00:00:00 1970 +0000
2455 | date: Thu Jan 01 00:00:00 1970 +0000
2456 | obsolete: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2456 | obsolete: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2457 | summary: A0
2457 | summary: A0
2458 |
2458 |
2459 o changeset: 0:ea207398892e
2459 o changeset: 0:ea207398892e
2460 user: test
2460 user: test
2461 date: Thu Jan 01 00:00:00 1970 +0000
2461 date: Thu Jan 01 00:00:00 1970 +0000
2462 summary: ROOT
2462 summary: ROOT
2463
2463
2464 Check templates
2464 Check templates
2465 ---------------
2465 ---------------
2466
2466
2467 $ hg up 'desc("A0")' --hidden
2467 $ hg up 'desc("A0")' --hidden
2468 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2468 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2469
2469
2470 # todo: the obsfate output is not ideal
2470 # todo: the obsfate output is not ideal
2471 $ hg fatelog
2471 $ hg fatelog
2472 o 617adc3a144c
2472 o 617adc3a144c
2473 |
2473 |
2474 | @ 471597cad322
2474 | @ 471597cad322
2475 |/ Obsfate: pruned;
2475 |/ Obsfate: pruned;
2476 o ea207398892e
2476 o ea207398892e
2477
2477
2478 $ hg up -r 'desc("A2")' --hidden
2478 $ hg up -r 'desc("A2")' --hidden
2479 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2479 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2480
2480
2481 $ hg fatelog --hidden
2481 $ hg fatelog --hidden
2482 @ 0d0ef4bdf70e
2482 @ 0d0ef4bdf70e
2483 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2483 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000);
2484 o 617adc3a144c
2484 o 617adc3a144c
2485 |
2485 |
2486 | x 471597cad322
2486 | x 471597cad322
2487 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e by test (at 1970-01-01 00:00 +0000);
2487 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e by test (at 1970-01-01 00:00 +0000);
2488 o ea207398892e
2488 o ea207398892e
2489
2489
2490
2490
2491 Check other fatelog implementations
2491 Check other fatelog implementations
2492 -----------------------------------
2492 -----------------------------------
2493
2493
2494 $ hg fatelogkw --hidden -q
2494 $ hg fatelogkw --hidden -q
2495 @ 0d0ef4bdf70e
2495 @ 0d0ef4bdf70e
2496 | Obsfate: pruned
2496 | Obsfate: pruned
2497 o 617adc3a144c
2497 o 617adc3a144c
2498 |
2498 |
2499 | x 471597cad322
2499 | x 471597cad322
2500 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2500 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2501 o ea207398892e
2501 o ea207398892e
2502
2502
2503 $ hg fatelogkw --hidden
2503 $ hg fatelogkw --hidden
2504 @ 0d0ef4bdf70e
2504 @ 0d0ef4bdf70e
2505 | Obsfate: pruned
2505 | Obsfate: pruned
2506 o 617adc3a144c
2506 o 617adc3a144c
2507 |
2507 |
2508 | x 471597cad322
2508 | x 471597cad322
2509 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2509 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2510 o ea207398892e
2510 o ea207398892e
2511
2511
2512 $ hg fatelogkw --hidden -v
2512 $ hg fatelogkw --hidden -v
2513 @ 0d0ef4bdf70e
2513 @ 0d0ef4bdf70e
2514 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2514 | Obsfate: pruned by test (at 1970-01-01 00:00 +0000)
2515 o 617adc3a144c
2515 o 617adc3a144c
2516 |
2516 |
2517 | x 471597cad322
2517 | x 471597cad322
2518 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e by test (at 1970-01-01 00:00 +0000)
2518 |/ Obsfate: split as 2:617adc3a144c, 3:0d0ef4bdf70e by test (at 1970-01-01 00:00 +0000)
2519 o ea207398892e
2519 o ea207398892e
2520
2520
2521 $ hg log -G -T "default" --hidden
2521 $ hg log -G -T "default" --hidden
2522 @ changeset: 3:0d0ef4bdf70e
2522 @ changeset: 3:0d0ef4bdf70e
2523 | tag: tip
2523 | tag: tip
2524 | user: test
2524 | user: test
2525 | date: Thu Jan 01 00:00:00 1970 +0000
2525 | date: Thu Jan 01 00:00:00 1970 +0000
2526 | obsolete: pruned
2526 | obsolete: pruned
2527 | summary: A2
2527 | summary: A2
2528 |
2528 |
2529 o changeset: 2:617adc3a144c
2529 o changeset: 2:617adc3a144c
2530 | parent: 0:ea207398892e
2530 | parent: 0:ea207398892e
2531 | user: test
2531 | user: test
2532 | date: Thu Jan 01 00:00:00 1970 +0000
2532 | date: Thu Jan 01 00:00:00 1970 +0000
2533 | summary: A1
2533 | summary: A1
2534 |
2534 |
2535 | x changeset: 1:471597cad322
2535 | x changeset: 1:471597cad322
2536 |/ user: test
2536 |/ user: test
2537 | date: Thu Jan 01 00:00:00 1970 +0000
2537 | date: Thu Jan 01 00:00:00 1970 +0000
2538 | obsolete: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2538 | obsolete: split as 2:617adc3a144c, 3:0d0ef4bdf70e
2539 | summary: A0
2539 | summary: A0
2540 |
2540 |
2541 o changeset: 0:ea207398892e
2541 o changeset: 0:ea207398892e
2542 user: test
2542 user: test
2543 date: Thu Jan 01 00:00:00 1970 +0000
2543 date: Thu Jan 01 00:00:00 1970 +0000
2544 summary: ROOT
2544 summary: ROOT
2545
2545
General Comments 0
You need to be logged in to leave comments. Login now