##// END OF EJS Templates
bookmarks: inform transaction-related hooks that some bookmarks were moved...
Pierre-Yves David -
r22941:da2758c0 default
parent child Browse files
Show More
@@ -1,440 +1,441
1 1 # Mercurial bookmark support code
2 2 #
3 3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from mercurial.i18n import _
9 9 from mercurial.node import hex, bin
10 10 from mercurial import encoding, error, util, obsolete, lock as lockmod
11 11 import errno
12 12
13 13 class bmstore(dict):
14 14 """Storage for bookmarks.
15 15
16 16 This object should do all bookmark reads and writes, so that it's
17 17 fairly simple to replace the storage underlying bookmarks without
18 18 having to clone the logic surrounding bookmarks.
19 19
20 20 This particular bmstore implementation stores bookmarks as
21 21 {hash}\s{name}\n (the same format as localtags) in
22 22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23 23
24 24 This class does NOT handle the "current" bookmark state at this
25 25 time.
26 26 """
27 27
28 28 def __init__(self, repo):
29 29 dict.__init__(self)
30 30 self._repo = repo
31 31 try:
32 32 for line in repo.vfs('bookmarks'):
33 33 line = line.strip()
34 34 if not line:
35 35 continue
36 36 if ' ' not in line:
37 37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
38 38 % line)
39 39 continue
40 40 sha, refspec = line.split(' ', 1)
41 41 refspec = encoding.tolocal(refspec)
42 42 try:
43 43 self[refspec] = repo.changelog.lookup(sha)
44 44 except LookupError:
45 45 pass
46 46 except IOError, inst:
47 47 if inst.errno != errno.ENOENT:
48 48 raise
49 49
50 50 def recordchange(self, tr):
51 51 """record that bookmarks have been changed in a transaction
52 52
53 53 The transaction is then responsible for updating the file content."""
54 54 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
55 55 vfs=self._repo.vfs)
56 tr.hookargs['bookmark_moved'] = '1'
56 57
57 58 def write(self):
58 59 '''Write bookmarks
59 60
60 61 Write the given bookmark => hash dictionary to the .hg/bookmarks file
61 62 in a format equal to those of localtags.
62 63
63 64 We also store a backup of the previous state in undo.bookmarks that
64 65 can be copied back on rollback.
65 66 '''
66 67 repo = self._repo
67 68 if repo._bookmarkcurrent not in self:
68 69 unsetcurrent(repo)
69 70
70 71 wlock = repo.wlock()
71 72 try:
72 73
73 74 file = repo.vfs('bookmarks', 'w', atomictemp=True)
74 75 self._write(file)
75 76 file.close()
76 77
77 78 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
78 79 try:
79 80 repo.svfs.utime('00changelog.i', None)
80 81 except OSError:
81 82 pass
82 83
83 84 finally:
84 85 wlock.release()
85 86
86 87 def _write(self, fp):
87 88 for name, node in self.iteritems():
88 89 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
89 90
90 91 def readcurrent(repo):
91 92 '''Get the current bookmark
92 93
93 94 If we use gittish branches we have a current bookmark that
94 95 we are on. This function returns the name of the bookmark. It
95 96 is stored in .hg/bookmarks.current
96 97 '''
97 98 mark = None
98 99 try:
99 100 file = repo.opener('bookmarks.current')
100 101 except IOError, inst:
101 102 if inst.errno != errno.ENOENT:
102 103 raise
103 104 return None
104 105 try:
105 106 # No readline() in osutil.posixfile, reading everything is cheap
106 107 mark = encoding.tolocal((file.readlines() or [''])[0])
107 108 if mark == '' or mark not in repo._bookmarks:
108 109 mark = None
109 110 finally:
110 111 file.close()
111 112 return mark
112 113
113 114 def setcurrent(repo, mark):
114 115 '''Set the name of the bookmark that we are currently on
115 116
116 117 Set the name of the bookmark that we are on (hg update <bookmark>).
117 118 The name is recorded in .hg/bookmarks.current
118 119 '''
119 120 if mark not in repo._bookmarks:
120 121 raise AssertionError('bookmark %s does not exist!' % mark)
121 122
122 123 current = repo._bookmarkcurrent
123 124 if current == mark:
124 125 return
125 126
126 127 wlock = repo.wlock()
127 128 try:
128 129 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
129 130 file.write(encoding.fromlocal(mark))
130 131 file.close()
131 132 finally:
132 133 wlock.release()
133 134 repo._bookmarkcurrent = mark
134 135
135 136 def unsetcurrent(repo):
136 137 wlock = repo.wlock()
137 138 try:
138 139 try:
139 140 repo.vfs.unlink('bookmarks.current')
140 141 repo._bookmarkcurrent = None
141 142 except OSError, inst:
142 143 if inst.errno != errno.ENOENT:
143 144 raise
144 145 finally:
145 146 wlock.release()
146 147
147 148 def iscurrent(repo, mark=None, parents=None):
148 149 '''Tell whether the current bookmark is also active
149 150
150 151 I.e., the bookmark listed in .hg/bookmarks.current also points to a
151 152 parent of the working directory.
152 153 '''
153 154 if not mark:
154 155 mark = repo._bookmarkcurrent
155 156 if not parents:
156 157 parents = [p.node() for p in repo[None].parents()]
157 158 marks = repo._bookmarks
158 159 return (mark in marks and marks[mark] in parents)
159 160
160 161 def updatecurrentbookmark(repo, oldnode, curbranch):
161 162 try:
162 163 return update(repo, oldnode, repo.branchtip(curbranch))
163 164 except error.RepoLookupError:
164 165 if curbranch == "default": # no default branch!
165 166 return update(repo, oldnode, repo.lookup("tip"))
166 167 else:
167 168 raise util.Abort(_("branch %s not found") % curbranch)
168 169
169 170 def deletedivergent(repo, deletefrom, bm):
170 171 '''Delete divergent versions of bm on nodes in deletefrom.
171 172
172 173 Return True if at least one bookmark was deleted, False otherwise.'''
173 174 deleted = False
174 175 marks = repo._bookmarks
175 176 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
176 177 for mark in divergent:
177 178 if mark == '@' or '@' not in mark:
178 179 # can't be divergent by definition
179 180 continue
180 181 if mark and marks[mark] in deletefrom:
181 182 if mark != bm:
182 183 del marks[mark]
183 184 deleted = True
184 185 return deleted
185 186
186 187 def calculateupdate(ui, repo, checkout):
187 188 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
188 189 check out and where to move the active bookmark from, if needed.'''
189 190 movemarkfrom = None
190 191 if checkout is None:
191 192 curmark = repo._bookmarkcurrent
192 193 if iscurrent(repo):
193 194 movemarkfrom = repo['.'].node()
194 195 elif curmark:
195 196 ui.status(_("updating to active bookmark %s\n") % curmark)
196 197 checkout = curmark
197 198 return (checkout, movemarkfrom)
198 199
199 200 def update(repo, parents, node):
200 201 deletefrom = parents
201 202 marks = repo._bookmarks
202 203 update = False
203 204 cur = repo._bookmarkcurrent
204 205 if not cur:
205 206 return False
206 207
207 208 if marks[cur] in parents:
208 209 new = repo[node]
209 210 divs = [repo[b] for b in marks
210 211 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
211 212 anc = repo.changelog.ancestors([new.rev()])
212 213 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
213 214 if validdest(repo, repo[marks[cur]], new):
214 215 marks[cur] = new.node()
215 216 update = True
216 217
217 218 if deletedivergent(repo, deletefrom, cur):
218 219 update = True
219 220
220 221 if update:
221 222 marks.write()
222 223 return update
223 224
224 225 def listbookmarks(repo):
225 226 # We may try to list bookmarks on a repo type that does not
226 227 # support it (e.g., statichttprepository).
227 228 marks = getattr(repo, '_bookmarks', {})
228 229
229 230 d = {}
230 231 hasnode = repo.changelog.hasnode
231 232 for k, v in marks.iteritems():
232 233 # don't expose local divergent bookmarks
233 234 if hasnode(v) and ('@' not in k or k.endswith('@')):
234 235 d[k] = hex(v)
235 236 return d
236 237
237 238 def pushbookmark(repo, key, old, new):
238 239 w = l = tr = None
239 240 try:
240 241 w = repo.wlock()
241 242 l = repo.lock()
242 243 tr = repo.transaction('bookmarks')
243 244 marks = repo._bookmarks
244 245 existing = hex(marks.get(key, ''))
245 246 if existing != old and existing != new:
246 247 return False
247 248 if new == '':
248 249 del marks[key]
249 250 else:
250 251 if new not in repo:
251 252 return False
252 253 marks[key] = repo[new].node()
253 254 marks.recordchange(tr)
254 255 tr.close()
255 256 return True
256 257 finally:
257 258 lockmod.release(tr, l, w)
258 259
259 260 def compare(repo, srcmarks, dstmarks,
260 261 srchex=None, dsthex=None, targets=None):
261 262 '''Compare bookmarks between srcmarks and dstmarks
262 263
263 264 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
264 265 differ, invalid)", each are list of bookmarks below:
265 266
266 267 :addsrc: added on src side (removed on dst side, perhaps)
267 268 :adddst: added on dst side (removed on src side, perhaps)
268 269 :advsrc: advanced on src side
269 270 :advdst: advanced on dst side
270 271 :diverge: diverge
271 272 :differ: changed, but changeset referred on src is unknown on dst
272 273 :invalid: unknown on both side
273 274
274 275 Each elements of lists in result tuple is tuple "(bookmark name,
275 276 changeset ID on source side, changeset ID on destination
276 277 side)". Each changeset IDs are 40 hexadecimal digit string or
277 278 None.
278 279
279 280 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
280 281 "invalid" list may be unknown for repo.
281 282
282 283 This function expects that "srcmarks" and "dstmarks" return
283 284 changeset ID in 40 hexadecimal digit string for specified
284 285 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
285 286 binary value), "srchex" or "dsthex" should be specified to convert
286 287 into such form.
287 288
288 289 If "targets" is specified, only bookmarks listed in it are
289 290 examined.
290 291 '''
291 292 if not srchex:
292 293 srchex = lambda x: x
293 294 if not dsthex:
294 295 dsthex = lambda x: x
295 296
296 297 if targets:
297 298 bset = set(targets)
298 299 else:
299 300 srcmarkset = set(srcmarks)
300 301 dstmarkset = set(dstmarks)
301 302 bset = srcmarkset ^ dstmarkset
302 303 for b in srcmarkset & dstmarkset:
303 304 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
304 305 bset.add(b)
305 306
306 307 results = ([], [], [], [], [], [], [])
307 308 addsrc = results[0].append
308 309 adddst = results[1].append
309 310 advsrc = results[2].append
310 311 advdst = results[3].append
311 312 diverge = results[4].append
312 313 differ = results[5].append
313 314 invalid = results[6].append
314 315
315 316 for b in sorted(bset):
316 317 if b not in srcmarks:
317 318 if b in dstmarks:
318 319 adddst((b, None, dsthex(dstmarks[b])))
319 320 else:
320 321 invalid((b, None, None))
321 322 elif b not in dstmarks:
322 323 addsrc((b, srchex(srcmarks[b]), None))
323 324 else:
324 325 scid = srchex(srcmarks[b])
325 326 dcid = dsthex(dstmarks[b])
326 327 if scid in repo and dcid in repo:
327 328 sctx = repo[scid]
328 329 dctx = repo[dcid]
329 330 if sctx.rev() < dctx.rev():
330 331 if validdest(repo, sctx, dctx):
331 332 advdst((b, scid, dcid))
332 333 else:
333 334 diverge((b, scid, dcid))
334 335 else:
335 336 if validdest(repo, dctx, sctx):
336 337 advsrc((b, scid, dcid))
337 338 else:
338 339 diverge((b, scid, dcid))
339 340 else:
340 341 # it is too expensive to examine in detail, in this case
341 342 differ((b, scid, dcid))
342 343
343 344 return results
344 345
345 346 def _diverge(ui, b, path, localmarks):
346 347 if b == '@':
347 348 b = ''
348 349 # find a unique @ suffix
349 350 for x in range(1, 100):
350 351 n = '%s@%d' % (b, x)
351 352 if n not in localmarks:
352 353 break
353 354 # try to use an @pathalias suffix
354 355 # if an @pathalias already exists, we overwrite (update) it
355 356 if path.startswith("file:"):
356 357 path = util.url(path).path
357 358 for p, u in ui.configitems("paths"):
358 359 if u.startswith("file:"):
359 360 u = util.url(u).path
360 361 if path == u:
361 362 n = '%s@%s' % (b, p)
362 363 return n
363 364
364 365 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
365 366 ui.debug("checking for updated bookmarks\n")
366 367 localmarks = repo._bookmarks
367 368 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
368 369 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
369 370
370 371 status = ui.status
371 372 warn = ui.warn
372 373 if ui.configbool('ui', 'quietbookmarkmove', False):
373 374 status = warn = ui.debug
374 375
375 376 explicit = set(explicit)
376 377 changed = []
377 378 for b, scid, dcid in addsrc:
378 379 if scid in repo: # add remote bookmarks for changes we already have
379 380 changed.append((b, bin(scid), status,
380 381 _("adding remote bookmark %s\n") % (b)))
381 382 for b, scid, dcid in advsrc:
382 383 changed.append((b, bin(scid), status,
383 384 _("updating bookmark %s\n") % (b)))
384 385 # remove normal movement from explicit set
385 386 explicit.difference_update(d[0] for d in changed)
386 387
387 388 for b, scid, dcid in diverge:
388 389 if b in explicit:
389 390 explicit.discard(b)
390 391 changed.append((b, bin(scid), status,
391 392 _("importing bookmark %s\n") % (b, b)))
392 393 else:
393 394 db = _diverge(ui, b, path, localmarks)
394 395 changed.append((db, bin(scid), warn,
395 396 _("divergent bookmark %s stored as %s\n")
396 397 % (b, db)))
397 398 for b, scid, dcid in adddst + advdst:
398 399 if b in explicit:
399 400 explicit.discard(b)
400 401 changed.append((b, bin(scid), status,
401 402 _("importing bookmark %s\n") % (b, b)))
402 403
403 404 if changed:
404 405 tr = trfunc()
405 406 for b, node, writer, msg in sorted(changed):
406 407 localmarks[b] = node
407 408 writer(msg)
408 409 localmarks.recordchange(tr)
409 410
410 411 def diff(ui, dst, src):
411 412 ui.status(_("searching for changed bookmarks\n"))
412 413
413 414 smarks = src.listkeys('bookmarks')
414 415 dmarks = dst.listkeys('bookmarks')
415 416
416 417 diff = sorted(set(smarks) - set(dmarks))
417 418 for k in diff:
418 419 mark = ui.debugflag and smarks[k] or smarks[k][:12]
419 420 ui.write(" %-25s %s\n" % (k, mark))
420 421
421 422 if len(diff) <= 0:
422 423 ui.status(_("no changed bookmarks found\n"))
423 424 return 1
424 425 return 0
425 426
426 427 def validdest(repo, old, new):
427 428 """Is the new bookmark destination a valid update from the old one"""
428 429 repo = repo.unfiltered()
429 430 if old == new:
430 431 # Old == new -> nothing to update.
431 432 return False
432 433 elif not old:
433 434 # old is nullrev, anything is valid.
434 435 # (new != nullrev has been excluded by the previous check)
435 436 return True
436 437 elif repo.obsstore:
437 438 return new.node() in obsolete.foreground(repo, [old.node()])
438 439 else:
439 440 # still an independent clause as it is lazyer (and therefore faster)
440 441 return old.descendant(new)
@@ -1,484 +1,484
1 1 Test exchange of common information using bundle2
2 2
3 3
4 4 $ getmainid() {
5 5 > hg -R main log --template '{node}\n' --rev "$1"
6 6 > }
7 7
8 8 enable obsolescence
9 9
10 10 $ cat > obs.py << EOF
11 11 > import mercurial.obsolete
12 12 > mercurial.obsolete._enabled = True
13 13 > EOF
14 14
15 15 $ cat >> $HGRCPATH << EOF
16 16 > [extensions]
17 17 > obsolete=$TESTTMP/obs.py
18 18 > [experimental]
19 19 > bundle2-exp=True
20 20 > [ui]
21 21 > ssh=python "$TESTDIR/dummyssh"
22 22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 23 > [web]
24 24 > push_ssl = false
25 25 > allow_push = *
26 26 > [phases]
27 27 > publish=False
28 28 > [hooks]
29 29 > changegroup = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" changegroup"
30 30 > b2x-transactionclose = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" b2x-transactionclose"
31 31 > EOF
32 32
33 33 The extension requires a repo (currently unused)
34 34
35 35 $ hg init main
36 36 $ cd main
37 37 $ touch a
38 38 $ hg add a
39 39 $ hg commit -m 'a'
40 40
41 41 $ hg unbundle $TESTDIR/bundles/rebase.hg
42 42 adding changesets
43 43 adding manifests
44 44 adding file changes
45 45 added 8 changesets with 7 changes to 7 files (+3 heads)
46 46 changegroup hook: HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
47 47 (run 'hg heads' to see heads, 'hg merge' to merge)
48 48
49 49 $ cd ..
50 50
51 51 Real world exchange
52 52 =====================
53 53
54 54 Add more obsolescence information
55 55
56 56 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
57 57 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
58 58
59 59 clone --pull
60 60
61 61 $ hg -R main phase --public cd010b8cd998
62 62 $ hg clone main other --pull --rev 9520eea781bc
63 63 adding changesets
64 64 adding manifests
65 65 adding file changes
66 66 added 2 changesets with 2 changes to 2 files
67 67 1 new obsolescence markers
68 68 changegroup hook: HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
69 69 updating to branch default
70 70 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 71 $ hg -R other log -G
72 72 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
73 73 |
74 74 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
75 75
76 76 $ hg -R other debugobsolete
77 77 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
78 78
79 79 pull
80 80
81 81 $ hg -R main phase --public 9520eea781bc
82 82 $ hg -R other pull -r 24b6387c8c8c
83 83 pulling from $TESTTMP/main (glob)
84 84 searching for changes
85 85 adding changesets
86 86 adding manifests
87 87 adding file changes
88 88 added 1 changesets with 1 changes to 1 files (+1 heads)
89 89 1 new obsolescence markers
90 90 changegroup hook: HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
91 91 (run 'hg heads' to see heads, 'hg merge' to merge)
92 92 $ hg -R other log -G
93 93 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
94 94 |
95 95 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
96 96 |/
97 97 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
98 98
99 99 $ hg -R other debugobsolete
100 100 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
101 101 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
102 102
103 103 pull empty (with phase movement)
104 104
105 105 $ hg -R main phase --public 24b6387c8c8c
106 106 $ hg -R other pull -r 24b6387c8c8c
107 107 pulling from $TESTTMP/main (glob)
108 108 no changes found
109 109 $ hg -R other log -G
110 110 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
111 111 |
112 112 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
113 113 |/
114 114 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
115 115
116 116 $ hg -R other debugobsolete
117 117 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
118 118 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
119 119
120 120 pull empty
121 121
122 122 $ hg -R other pull -r 24b6387c8c8c
123 123 pulling from $TESTTMP/main (glob)
124 124 no changes found
125 125 $ hg -R other log -G
126 126 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
127 127 |
128 128 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
129 129 |/
130 130 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
131 131
132 132 $ hg -R other debugobsolete
133 133 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
134 134 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
135 135
136 136 add extra data to test their exchange during push
137 137
138 138 $ hg -R main bookmark --rev eea13746799a book_eea1
139 139 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
140 140 $ hg -R main bookmark --rev 02de42196ebe book_02de
141 141 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
142 142 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
143 143 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
144 144 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
145 145 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
146 146 $ hg -R main bookmark --rev 32af7686d403 book_32af
147 147 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
148 148
149 149 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
150 150 $ hg -R other bookmark --rev cd010b8cd998 book_02de
151 151 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
152 152 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
153 153 $ hg -R other bookmark --rev cd010b8cd998 book_32af
154 154
155 155 $ hg -R main phase --public eea13746799a
156 156
157 157 push
158 158 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
159 159 pushing to other
160 160 searching for changes
161 b2x-transactionclose hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=push HG_URL=push
162 changegroup hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
161 b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=push HG_URL=push
162 changegroup hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
163 163 remote: adding changesets
164 164 remote: adding manifests
165 165 remote: adding file changes
166 166 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
167 167 remote: 1 new obsolescence markers
168 168 updating bookmark book_eea1
169 169 $ hg -R other log -G
170 170 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
171 171 |\
172 172 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
173 173 | |
174 174 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
175 175 |/
176 176 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
177 177
178 178 $ hg -R other debugobsolete
179 179 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
180 180 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
181 181 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
182 182
183 183 pull over ssh
184 184
185 185 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
186 186 pulling from ssh://user@dummy/main
187 187 searching for changes
188 188 adding changesets
189 189 adding manifests
190 190 adding file changes
191 191 added 1 changesets with 1 changes to 1 files (+1 heads)
192 192 1 new obsolescence markers
193 193 updating bookmark book_02de
194 changegroup hook: HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
194 changegroup hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
195 195 (run 'hg heads' to see heads, 'hg merge' to merge)
196 196 $ hg -R other debugobsolete
197 197 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
198 198 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
199 199 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
200 200 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
201 201
202 202 pull over http
203 203
204 204 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
205 205 $ cat main.pid >> $DAEMON_PIDS
206 206
207 207 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
208 208 pulling from http://localhost:$HGPORT/
209 209 searching for changes
210 210 adding changesets
211 211 adding manifests
212 212 adding file changes
213 213 added 1 changesets with 1 changes to 1 files (+1 heads)
214 214 1 new obsolescence markers
215 215 updating bookmark book_42cc
216 changegroup hook: HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
216 changegroup hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_PHASES_MOVED=1 HG_SOURCE=bundle2 HG_URL=bundle2
217 217 (run 'hg heads .' to see heads, 'hg merge' to merge)
218 218 $ cat main-error.log
219 219 $ hg -R other debugobsolete
220 220 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
221 221 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
222 222 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
223 223 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
224 224 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
225 225
226 226 push over ssh
227 227
228 228 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
229 229 pushing to ssh://user@dummy/other
230 230 searching for changes
231 231 remote: adding changesets
232 232 remote: adding manifests
233 233 remote: adding file changes
234 234 remote: added 1 changesets with 1 changes to 1 files
235 235 remote: 1 new obsolescence markers
236 236 updating bookmark book_5fdd
237 remote: b2x-transactionclose hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
238 remote: changegroup hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_SOURCE=bundle2 HG_URL=bundle2
237 remote: b2x-transactionclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
238 remote: changegroup hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=1 HG_SOURCE=bundle2 HG_URL=bundle2
239 239 $ hg -R other log -G
240 240 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
241 241 |
242 242 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
243 243 |
244 244 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
245 245 | |
246 246 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
247 247 | |/|
248 248 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
249 249 |/ /
250 250 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
251 251 |/
252 252 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
253 253
254 254 $ hg -R other debugobsolete
255 255 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
256 256 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
257 257 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
258 258 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
259 259 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
260 260 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
261 261
262 262 push over http
263 263
264 264 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
265 265 $ cat other.pid >> $DAEMON_PIDS
266 266
267 267 $ hg -R main phase --public 32af7686d403
268 268 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
269 269 pushing to http://localhost:$HGPORT2/
270 270 searching for changes
271 271 remote: adding changesets
272 272 remote: adding manifests
273 273 remote: adding file changes
274 274 remote: added 1 changesets with 1 changes to 1 files
275 275 remote: 1 new obsolescence markers
276 276 updating bookmark book_32af
277 277 $ cat other-error.log
278 278
279 279 Check final content.
280 280
281 281 $ hg -R other log -G
282 282 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
283 283 |
284 284 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
285 285 |
286 286 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
287 287 |
288 288 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
289 289 | |
290 290 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
291 291 | |/|
292 292 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
293 293 |/ /
294 294 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
295 295 |/
296 296 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
297 297
298 298 $ hg -R other debugobsolete
299 299 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
300 300 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
301 301 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
302 302 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
303 303 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
304 304 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
305 305 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
306 306
307 307 Error Handling
308 308 ==============
309 309
310 310 Check that errors are properly returned to the client during push.
311 311
312 312 Setting up
313 313
314 314 $ cat > failpush.py << EOF
315 315 > """A small extension that makes push fails when using bundle2
316 316 >
317 317 > used to test error handling in bundle2
318 318 > """
319 319 >
320 320 > from mercurial import util
321 321 > from mercurial import bundle2
322 322 > from mercurial import exchange
323 323 > from mercurial import extensions
324 324 >
325 325 > def _pushbundle2failpart(pushop, bundler):
326 326 > reason = pushop.ui.config('failpush', 'reason', None)
327 327 > part = None
328 328 > if reason == 'abort':
329 329 > bundler.newpart('test:abort')
330 330 > if reason == 'unknown':
331 331 > bundler.newpart('TEST:UNKNOWN')
332 332 > if reason == 'race':
333 333 > # 20 Bytes of crap
334 334 > bundler.newpart('b2x:check:heads', data='01234567890123456789')
335 335 >
336 336 > @bundle2.parthandler("test:abort")
337 337 > def handleabort(op, part):
338 338 > raise util.Abort('Abandon ship!', hint="don't panic")
339 339 >
340 340 > def uisetup(ui):
341 341 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
342 342 > exchange.b2partsgenorder.insert(0, 'failpart')
343 343 >
344 344 > EOF
345 345
346 346 $ cd main
347 347 $ hg up tip
348 348 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
349 349 $ echo 'I' > I
350 350 $ hg add I
351 351 $ hg ci -m 'I'
352 352 $ hg id
353 353 e7ec4e813ba6 tip
354 354 $ cd ..
355 355
356 356 $ cat << EOF >> $HGRCPATH
357 357 > [extensions]
358 358 > failpush=$TESTTMP/failpush.py
359 359 > EOF
360 360
361 361 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
362 362 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
363 363 $ cat other.pid >> $DAEMON_PIDS
364 364
365 365 Doing the actual push: Abort error
366 366
367 367 $ cat << EOF >> $HGRCPATH
368 368 > [failpush]
369 369 > reason = abort
370 370 > EOF
371 371
372 372 $ hg -R main push other -r e7ec4e813ba6
373 373 pushing to other
374 374 searching for changes
375 375 abort: Abandon ship!
376 376 (don't panic)
377 377 [255]
378 378
379 379 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
380 380 pushing to ssh://user@dummy/other
381 381 searching for changes
382 382 abort: Abandon ship!
383 383 (don't panic)
384 384 [255]
385 385
386 386 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
387 387 pushing to http://localhost:$HGPORT2/
388 388 searching for changes
389 389 abort: Abandon ship!
390 390 (don't panic)
391 391 [255]
392 392
393 393
394 394 Doing the actual push: unknown mandatory parts
395 395
396 396 $ cat << EOF >> $HGRCPATH
397 397 > [failpush]
398 398 > reason = unknown
399 399 > EOF
400 400
401 401 $ hg -R main push other -r e7ec4e813ba6
402 402 pushing to other
403 403 searching for changes
404 404 abort: missing support for test:unknown
405 405 [255]
406 406
407 407 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
408 408 pushing to ssh://user@dummy/other
409 409 searching for changes
410 410 abort: missing support for test:unknown
411 411 [255]
412 412
413 413 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
414 414 pushing to http://localhost:$HGPORT2/
415 415 searching for changes
416 416 abort: missing support for test:unknown
417 417 [255]
418 418
419 419 Doing the actual push: race
420 420
421 421 $ cat << EOF >> $HGRCPATH
422 422 > [failpush]
423 423 > reason = race
424 424 > EOF
425 425
426 426 $ hg -R main push other -r e7ec4e813ba6
427 427 pushing to other
428 428 searching for changes
429 429 abort: push failed:
430 430 'repository changed while pushing - please try again'
431 431 [255]
432 432
433 433 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
434 434 pushing to ssh://user@dummy/other
435 435 searching for changes
436 436 abort: push failed:
437 437 'repository changed while pushing - please try again'
438 438 [255]
439 439
440 440 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
441 441 pushing to http://localhost:$HGPORT2/
442 442 searching for changes
443 443 abort: push failed:
444 444 'repository changed while pushing - please try again'
445 445 [255]
446 446
447 447 Doing the actual push: hook abort
448 448
449 449 $ cat << EOF >> $HGRCPATH
450 450 > [failpush]
451 451 > reason =
452 452 > [hooks]
453 453 > b2x-pretransactionclose.failpush = false
454 454 > EOF
455 455
456 456 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
457 457 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
458 458 $ cat other.pid >> $DAEMON_PIDS
459 459
460 460 $ hg -R main push other -r e7ec4e813ba6
461 461 pushing to other
462 462 searching for changes
463 463 transaction abort!
464 464 rollback completed
465 465 changegroup hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=0 HG_SOURCE=bundle2 HG_URL=bundle2
466 466 abort: b2x-pretransactionclose.failpush hook exited with status 1
467 467 [255]
468 468
469 469 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
470 470 pushing to ssh://user@dummy/other
471 471 searching for changes
472 472 abort: b2x-pretransactionclose.failpush hook exited with status 1
473 473 remote: transaction abort!
474 474 remote: rollback completed
475 475 remote: changegroup hook: HG_BUNDLE2-EXP=1 HG_NEW_OBSMARKERS=0 HG_SOURCE=bundle2 HG_URL=bundle2
476 476 [255]
477 477
478 478 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
479 479 pushing to http://localhost:$HGPORT2/
480 480 searching for changes
481 481 abort: b2x-pretransactionclose.failpush hook exited with status 1
482 482 [255]
483 483
484 484
General Comments 0
You need to be logged in to leave comments. Login now