##// END OF EJS Templates
pull: merge bookmark updates and imports...
Pierre-Yves David -
r22659:79818570 default
parent child Browse files
Show More
@@ -1,417 +1,425 b''
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
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 write(self):
51 51 '''Write bookmarks
52 52
53 53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
54 54 in a format equal to those of localtags.
55 55
56 56 We also store a backup of the previous state in undo.bookmarks that
57 57 can be copied back on rollback.
58 58 '''
59 59 repo = self._repo
60 60 if repo._bookmarkcurrent not in self:
61 61 unsetcurrent(repo)
62 62
63 63 wlock = repo.wlock()
64 64 try:
65 65
66 66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
67 67 for name, node in self.iteritems():
68 68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
69 69 file.close()
70 70
71 71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
72 72 try:
73 73 repo.svfs.utime('00changelog.i', None)
74 74 except OSError:
75 75 pass
76 76
77 77 finally:
78 78 wlock.release()
79 79
80 80 def readcurrent(repo):
81 81 '''Get the current bookmark
82 82
83 83 If we use gittish branches we have a current bookmark that
84 84 we are on. This function returns the name of the bookmark. It
85 85 is stored in .hg/bookmarks.current
86 86 '''
87 87 mark = None
88 88 try:
89 89 file = repo.opener('bookmarks.current')
90 90 except IOError, inst:
91 91 if inst.errno != errno.ENOENT:
92 92 raise
93 93 return None
94 94 try:
95 95 # No readline() in osutil.posixfile, reading everything is cheap
96 96 mark = encoding.tolocal((file.readlines() or [''])[0])
97 97 if mark == '' or mark not in repo._bookmarks:
98 98 mark = None
99 99 finally:
100 100 file.close()
101 101 return mark
102 102
103 103 def setcurrent(repo, mark):
104 104 '''Set the name of the bookmark that we are currently on
105 105
106 106 Set the name of the bookmark that we are on (hg update <bookmark>).
107 107 The name is recorded in .hg/bookmarks.current
108 108 '''
109 109 if mark not in repo._bookmarks:
110 110 raise AssertionError('bookmark %s does not exist!' % mark)
111 111
112 112 current = repo._bookmarkcurrent
113 113 if current == mark:
114 114 return
115 115
116 116 wlock = repo.wlock()
117 117 try:
118 118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
119 119 file.write(encoding.fromlocal(mark))
120 120 file.close()
121 121 finally:
122 122 wlock.release()
123 123 repo._bookmarkcurrent = mark
124 124
125 125 def unsetcurrent(repo):
126 126 wlock = repo.wlock()
127 127 try:
128 128 try:
129 129 repo.vfs.unlink('bookmarks.current')
130 130 repo._bookmarkcurrent = None
131 131 except OSError, inst:
132 132 if inst.errno != errno.ENOENT:
133 133 raise
134 134 finally:
135 135 wlock.release()
136 136
137 137 def iscurrent(repo, mark=None, parents=None):
138 138 '''Tell whether the current bookmark is also active
139 139
140 140 I.e., the bookmark listed in .hg/bookmarks.current also points to a
141 141 parent of the working directory.
142 142 '''
143 143 if not mark:
144 144 mark = repo._bookmarkcurrent
145 145 if not parents:
146 146 parents = [p.node() for p in repo[None].parents()]
147 147 marks = repo._bookmarks
148 148 return (mark in marks and marks[mark] in parents)
149 149
150 150 def updatecurrentbookmark(repo, oldnode, curbranch):
151 151 try:
152 152 return update(repo, oldnode, repo.branchtip(curbranch))
153 153 except error.RepoLookupError:
154 154 if curbranch == "default": # no default branch!
155 155 return update(repo, oldnode, repo.lookup("tip"))
156 156 else:
157 157 raise util.Abort(_("branch %s not found") % curbranch)
158 158
159 159 def deletedivergent(repo, deletefrom, bm):
160 160 '''Delete divergent versions of bm on nodes in deletefrom.
161 161
162 162 Return True if at least one bookmark was deleted, False otherwise.'''
163 163 deleted = False
164 164 marks = repo._bookmarks
165 165 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
166 166 for mark in divergent:
167 167 if mark == '@' or '@' not in mark:
168 168 # can't be divergent by definition
169 169 continue
170 170 if mark and marks[mark] in deletefrom:
171 171 if mark != bm:
172 172 del marks[mark]
173 173 deleted = True
174 174 return deleted
175 175
176 176 def calculateupdate(ui, repo, checkout):
177 177 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
178 178 check out and where to move the active bookmark from, if needed.'''
179 179 movemarkfrom = None
180 180 if checkout is None:
181 181 curmark = repo._bookmarkcurrent
182 182 if iscurrent(repo):
183 183 movemarkfrom = repo['.'].node()
184 184 elif curmark:
185 185 ui.status(_("updating to active bookmark %s\n") % curmark)
186 186 checkout = curmark
187 187 return (checkout, movemarkfrom)
188 188
189 189 def update(repo, parents, node):
190 190 deletefrom = parents
191 191 marks = repo._bookmarks
192 192 update = False
193 193 cur = repo._bookmarkcurrent
194 194 if not cur:
195 195 return False
196 196
197 197 if marks[cur] in parents:
198 198 new = repo[node]
199 199 divs = [repo[b] for b in marks
200 200 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
201 201 anc = repo.changelog.ancestors([new.rev()])
202 202 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
203 203 if validdest(repo, repo[marks[cur]], new):
204 204 marks[cur] = new.node()
205 205 update = True
206 206
207 207 if deletedivergent(repo, deletefrom, cur):
208 208 update = True
209 209
210 210 if update:
211 211 marks.write()
212 212 return update
213 213
214 214 def listbookmarks(repo):
215 215 # We may try to list bookmarks on a repo type that does not
216 216 # support it (e.g., statichttprepository).
217 217 marks = getattr(repo, '_bookmarks', {})
218 218
219 219 d = {}
220 220 hasnode = repo.changelog.hasnode
221 221 for k, v in marks.iteritems():
222 222 # don't expose local divergent bookmarks
223 223 if hasnode(v) and ('@' not in k or k.endswith('@')):
224 224 d[k] = hex(v)
225 225 return d
226 226
227 227 def pushbookmark(repo, key, old, new):
228 228 w = repo.wlock()
229 229 try:
230 230 marks = repo._bookmarks
231 231 existing = hex(marks.get(key, ''))
232 232 if existing != old and existing != new:
233 233 return False
234 234 if new == '':
235 235 del marks[key]
236 236 else:
237 237 if new not in repo:
238 238 return False
239 239 marks[key] = repo[new].node()
240 240 marks.write()
241 241 return True
242 242 finally:
243 243 w.release()
244 244
245 245 def compare(repo, srcmarks, dstmarks,
246 246 srchex=None, dsthex=None, targets=None):
247 247 '''Compare bookmarks between srcmarks and dstmarks
248 248
249 249 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
250 250 differ, invalid)", each are list of bookmarks below:
251 251
252 252 :addsrc: added on src side (removed on dst side, perhaps)
253 253 :adddst: added on dst side (removed on src side, perhaps)
254 254 :advsrc: advanced on src side
255 255 :advdst: advanced on dst side
256 256 :diverge: diverge
257 257 :differ: changed, but changeset referred on src is unknown on dst
258 258 :invalid: unknown on both side
259 259
260 260 Each elements of lists in result tuple is tuple "(bookmark name,
261 261 changeset ID on source side, changeset ID on destination
262 262 side)". Each changeset IDs are 40 hexadecimal digit string or
263 263 None.
264 264
265 265 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
266 266 "invalid" list may be unknown for repo.
267 267
268 268 This function expects that "srcmarks" and "dstmarks" return
269 269 changeset ID in 40 hexadecimal digit string for specified
270 270 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
271 271 binary value), "srchex" or "dsthex" should be specified to convert
272 272 into such form.
273 273
274 274 If "targets" is specified, only bookmarks listed in it are
275 275 examined.
276 276 '''
277 277 if not srchex:
278 278 srchex = lambda x: x
279 279 if not dsthex:
280 280 dsthex = lambda x: x
281 281
282 282 if targets:
283 283 bset = set(targets)
284 284 else:
285 285 srcmarkset = set(srcmarks)
286 286 dstmarkset = set(dstmarks)
287 287 bset = srcmarkset ^ dstmarkset
288 288 for b in srcmarkset & dstmarkset:
289 289 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
290 290 bset.add(b)
291 291
292 292 results = ([], [], [], [], [], [], [])
293 293 addsrc = results[0].append
294 294 adddst = results[1].append
295 295 advsrc = results[2].append
296 296 advdst = results[3].append
297 297 diverge = results[4].append
298 298 differ = results[5].append
299 299 invalid = results[6].append
300 300
301 301 for b in sorted(bset):
302 302 if b not in srcmarks:
303 303 if b in dstmarks:
304 304 adddst((b, None, dsthex(dstmarks[b])))
305 305 else:
306 306 invalid((b, None, None))
307 307 elif b not in dstmarks:
308 308 addsrc((b, srchex(srcmarks[b]), None))
309 309 else:
310 310 scid = srchex(srcmarks[b])
311 311 dcid = dsthex(dstmarks[b])
312 312 if scid in repo and dcid in repo:
313 313 sctx = repo[scid]
314 314 dctx = repo[dcid]
315 315 if sctx.rev() < dctx.rev():
316 316 if validdest(repo, sctx, dctx):
317 317 advdst((b, scid, dcid))
318 318 else:
319 319 diverge((b, scid, dcid))
320 320 else:
321 321 if validdest(repo, dctx, sctx):
322 322 advsrc((b, scid, dcid))
323 323 else:
324 324 diverge((b, scid, dcid))
325 325 else:
326 326 # it is too expensive to examine in detail, in this case
327 327 differ((b, scid, dcid))
328 328
329 329 return results
330 330
331 331 def _diverge(ui, b, path, localmarks):
332 332 if b == '@':
333 333 b = ''
334 334 # find a unique @ suffix
335 335 for x in range(1, 100):
336 336 n = '%s@%d' % (b, x)
337 337 if n not in localmarks:
338 338 break
339 339 # try to use an @pathalias suffix
340 340 # if an @pathalias already exists, we overwrite (update) it
341 341 if path.startswith("file:"):
342 342 path = util.url(path).path
343 343 for p, u in ui.configitems("paths"):
344 344 if u.startswith("file:"):
345 345 u = util.url(u).path
346 346 if path == u:
347 347 n = '%s@%s' % (b, p)
348 348 return n
349 349
350 350 def updatefromremote(ui, repo, remotemarks, path, explicit=()):
351 351 ui.debug("checking for updated bookmarks\n")
352 352 localmarks = repo._bookmarks
353 353 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
354 354 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
355 355
356 356 status = ui.status
357 357 warn = ui.warn
358 358 if ui.configbool('ui', 'quietbookmarkmove', False):
359 359 status = warn = ui.debug
360 360
361 explicit = set(explicit)
361 362 changed = []
362 363 for b, scid, dcid in addsrc:
363 364 if scid in repo: # add remote bookmarks for changes we already have
364 365 changed.append((b, bin(scid), status,
365 366 _("adding remote bookmark %s\n") % (b)))
366 367 for b, scid, dcid in advsrc:
367 368 changed.append((b, bin(scid), status,
368 369 _("updating bookmark %s\n") % (b)))
370 # remove normal movement from explicit set
371 explicit.difference_update(d[0] for d in changed)
372
369 373 for b, scid, dcid in diverge:
370 db = _diverge(ui, b, path, localmarks)
371 changed.append((db, bin(scid), warn,
372 _("divergent bookmark %s stored as %s\n") % (b, db)))
374 if b in explicit:
375 explicit.discard(b)
376 changed.append((b, bin(scid), status,
377 _("importing bookmark %s\n") % (b, b)))
378 else:
379 db = _diverge(ui, b, path, localmarks)
380 changed.append((db, bin(scid), warn,
381 _("divergent bookmark %s stored as %s\n")
382 % (b, db)))
383 for b, scid, dcid in adddst + advdst:
384 if b in explicit:
385 explicit.discard(b)
386 changed.append((b, bin(scid), status,
387 _("importing bookmark %s\n") % (b, b)))
388
373 389 if changed:
374 390 for b, node, writer, msg in sorted(changed):
375 391 localmarks[b] = node
376 392 writer(msg)
377 393 localmarks.write()
378 # update specified bookmarks
379 if explicit:
380 marks = repo._bookmarks
381 for b in explicit:
382 # explicit pull overrides local bookmark if any
383 repo.ui.status(_("importing bookmark %s\n") % b)
384 marks[b] = repo[remotemarks[b]].node()
385 marks.write()
386 394
387 395 def diff(ui, dst, src):
388 396 ui.status(_("searching for changed bookmarks\n"))
389 397
390 398 smarks = src.listkeys('bookmarks')
391 399 dmarks = dst.listkeys('bookmarks')
392 400
393 401 diff = sorted(set(smarks) - set(dmarks))
394 402 for k in diff:
395 403 mark = ui.debugflag and smarks[k] or smarks[k][:12]
396 404 ui.write(" %-25s %s\n" % (k, mark))
397 405
398 406 if len(diff) <= 0:
399 407 ui.status(_("no changed bookmarks found\n"))
400 408 return 1
401 409 return 0
402 410
403 411 def validdest(repo, old, new):
404 412 """Is the new bookmark destination a valid update from the old one"""
405 413 repo = repo.unfiltered()
406 414 if old == new:
407 415 # Old == new -> nothing to update.
408 416 return False
409 417 elif not old:
410 418 # old is nullrev, anything is valid.
411 419 # (new != nullrev has been excluded by the previous check)
412 420 return True
413 421 elif repo.obsstore:
414 422 return new.node() in obsolete.foreground(repo, [old.node()])
415 423 else:
416 424 # still an independent clause as it is lazyer (and therefore faster)
417 425 return old.descendant(new)
@@ -1,446 +1,444 b''
1 1 #require serve
2 2
3 3 $ cat << EOF >> $HGRCPATH
4 4 > [ui]
5 5 > logtemplate={rev}:{node|short} {desc|firstline}
6 6 > [phases]
7 7 > publish=False
8 8 > [extensions]
9 9 > EOF
10 10 $ cat > obs.py << EOF
11 11 > import mercurial.obsolete
12 12 > mercurial.obsolete._enabled = True
13 13 > EOF
14 14 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
15 15
16 16 initialize
17 17
18 18 $ hg init a
19 19 $ cd a
20 20 $ echo 'test' > test
21 21 $ hg commit -Am'test'
22 22 adding test
23 23
24 24 set bookmarks
25 25
26 26 $ hg bookmark X
27 27 $ hg bookmark Y
28 28 $ hg bookmark Z
29 29
30 30 import bookmark by name
31 31
32 32 $ hg init ../b
33 33 $ cd ../b
34 34 $ hg book Y
35 35 $ hg book
36 36 * Y -1:000000000000
37 37 $ hg pull ../a
38 38 pulling from ../a
39 39 requesting all changes
40 40 adding changesets
41 41 adding manifests
42 42 adding file changes
43 43 added 1 changesets with 1 changes to 1 files
44 44 adding remote bookmark X
45 45 updating bookmark Y
46 46 adding remote bookmark Z
47 47 (run 'hg update' to get a working copy)
48 48 $ hg bookmarks
49 49 X 0:4e3505fd9583
50 50 * Y 0:4e3505fd9583
51 51 Z 0:4e3505fd9583
52 52 $ hg debugpushkey ../a namespaces
53 53 bookmarks
54 54 namespaces
55 55 obsolete
56 56 phases
57 57 $ hg debugpushkey ../a bookmarks
58 58 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 59 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 60 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
61 61 $ hg pull -B X ../a
62 62 pulling from ../a
63 63 no changes found
64 importing bookmark X
65 64 $ hg bookmark
66 65 X 0:4e3505fd9583
67 66 * Y 0:4e3505fd9583
68 67 Z 0:4e3505fd9583
69 68
70 69 export bookmark by name
71 70
72 71 $ hg bookmark W
73 72 $ hg bookmark foo
74 73 $ hg bookmark foobar
75 74 $ hg push -B W ../a
76 75 pushing to ../a
77 76 searching for changes
78 77 no changes found
79 78 exporting bookmark W
80 79 [1]
81 80 $ hg -R ../a bookmarks
82 81 W -1:000000000000
83 82 X 0:4e3505fd9583
84 83 Y 0:4e3505fd9583
85 84 * Z 0:4e3505fd9583
86 85
87 86 delete a remote bookmark
88 87
89 88 $ hg book -d W
90 89 $ hg push -B W ../a
91 90 pushing to ../a
92 91 searching for changes
93 92 no changes found
94 93 deleting remote bookmark W
95 94 [1]
96 95
97 96 push/pull name that doesn't exist
98 97
99 98 $ hg push -B badname ../a
100 99 pushing to ../a
101 100 searching for changes
102 101 bookmark badname does not exist on the local or remote repository!
103 102 no changes found
104 103 [2]
105 104 $ hg pull -B anotherbadname ../a
106 105 pulling from ../a
107 106 abort: remote bookmark anotherbadname not found!
108 107 [255]
109 108
110 109 divergent bookmarks
111 110
112 111 $ cd ../a
113 112 $ echo c1 > f1
114 113 $ hg ci -Am1
115 114 adding f1
116 115 $ hg book -f @
117 116 $ hg book -f X
118 117 $ hg book
119 118 @ 1:0d2164f0ce0d
120 119 * X 1:0d2164f0ce0d
121 120 Y 0:4e3505fd9583
122 121 Z 1:0d2164f0ce0d
123 122
124 123 $ cd ../b
125 124 $ hg up
126 125 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 126 updating bookmark foobar
128 127 $ echo c2 > f2
129 128 $ hg ci -Am2
130 129 adding f2
131 130 $ hg book -if @
132 131 $ hg book -if X
133 132 $ hg book
134 133 @ 1:9b140be10808
135 134 X 1:9b140be10808
136 135 Y 0:4e3505fd9583
137 136 Z 0:4e3505fd9583
138 137 foo -1:000000000000
139 138 * foobar 1:9b140be10808
140 139
141 140 $ hg pull --config paths.foo=../a foo
142 141 pulling from $TESTTMP/a (glob)
143 142 searching for changes
144 143 adding changesets
145 144 adding manifests
146 145 adding file changes
147 146 added 1 changesets with 1 changes to 1 files (+1 heads)
148 147 divergent bookmark @ stored as @foo
149 148 divergent bookmark X stored as X@foo
150 149 updating bookmark Z
151 150 (run 'hg heads' to see heads, 'hg merge' to merge)
152 151 $ hg book
153 152 @ 1:9b140be10808
154 153 @foo 2:0d2164f0ce0d
155 154 X 1:9b140be10808
156 155 X@foo 2:0d2164f0ce0d
157 156 Y 0:4e3505fd9583
158 157 Z 2:0d2164f0ce0d
159 158 foo -1:000000000000
160 159 * foobar 1:9b140be10808
161 160 $ hg push -f ../a
162 161 pushing to ../a
163 162 searching for changes
164 163 adding changesets
165 164 adding manifests
166 165 adding file changes
167 166 added 1 changesets with 1 changes to 1 files (+1 heads)
168 167 $ hg -R ../a book
169 168 @ 1:0d2164f0ce0d
170 169 * X 1:0d2164f0ce0d
171 170 Y 0:4e3505fd9583
172 171 Z 1:0d2164f0ce0d
173 172
174 173 revsets should not ignore divergent bookmarks
175 174
176 175 $ hg bookmark -fr 1 Z
177 176 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
178 177 0:4e3505fd9583 Y
179 178 1:9b140be10808 @ X Z foobar
180 179 2:0d2164f0ce0d @foo X@foo
181 180 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
182 181 2:0d2164f0ce0d @foo X@foo
183 182 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
184 183 2:0d2164f0ce0d @foo X@foo
185 184
186 185 update a remote bookmark from a non-head to a head
187 186
188 187 $ hg up -q Y
189 188 $ echo c3 > f2
190 189 $ hg ci -Am3
191 190 adding f2
192 191 created new head
193 192 $ hg push ../a
194 193 pushing to ../a
195 194 searching for changes
196 195 adding changesets
197 196 adding manifests
198 197 adding file changes
199 198 added 1 changesets with 1 changes to 1 files (+1 heads)
200 199 updating bookmark Y
201 200 $ hg -R ../a book
202 201 @ 1:0d2164f0ce0d
203 202 * X 1:0d2164f0ce0d
204 203 Y 3:f6fc62dde3c0
205 204 Z 1:0d2164f0ce0d
206 205
207 206 update a bookmark in the middle of a client pulling changes
208 207
209 208 $ cd ..
210 209 $ hg clone -q a pull-race
211 210 $ hg clone -q pull-race pull-race2
212 211 $ cd pull-race
213 212 $ hg up -q Y
214 213 $ echo c4 > f2
215 214 $ hg ci -Am4
216 215 $ echo c5 > f3
217 216 $ cat <<EOF > .hg/hgrc
218 217 > [hooks]
219 218 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
220 219 > EOF
221 220 $ cd ../pull-race2
222 221 $ hg pull
223 222 pulling from $TESTTMP/pull-race (glob)
224 223 searching for changes
225 224 adding changesets
226 225 adding f3
227 226 committed in pull-race
228 227 adding manifests
229 228 adding file changes
230 229 added 1 changesets with 1 changes to 1 files
231 230 updating bookmark Y
232 231 (run 'hg update' to get a working copy)
233 232 $ hg book
234 233 * @ 1:0d2164f0ce0d
235 234 X 1:0d2164f0ce0d
236 235 Y 4:b0a5eff05604
237 236 Z 1:0d2164f0ce0d
238 237 $ cd ../b
239 238
240 239 diverging a remote bookmark fails
241 240
242 241 $ hg up -q 4e3505fd9583
243 242 $ echo c4 > f2
244 243 $ hg ci -Am4
245 244 adding f2
246 245 created new head
247 246 $ echo c5 > f2
248 247 $ hg ci -Am5
249 248 $ hg log -G
250 249 @ 5:c922c0139ca0 5
251 250 |
252 251 o 4:4efff6d98829 4
253 252 |
254 253 | o 3:f6fc62dde3c0 3
255 254 |/
256 255 | o 2:0d2164f0ce0d 1
257 256 |/
258 257 | o 1:9b140be10808 2
259 258 |/
260 259 o 0:4e3505fd9583 test
261 260
262 261
263 262 $ hg book -f Y
264 263
265 264 $ cat <<EOF > ../a/.hg/hgrc
266 265 > [web]
267 266 > push_ssl = false
268 267 > allow_push = *
269 268 > EOF
270 269
271 270 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
272 271 $ cat ../hg2.pid >> $DAEMON_PIDS
273 272
274 273 $ hg push http://localhost:$HGPORT2/
275 274 pushing to http://localhost:$HGPORT2/
276 275 searching for changes
277 276 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
278 277 (merge or see "hg help push" for details about pushing new heads)
279 278 [255]
280 279 $ hg -R ../a book
281 280 @ 1:0d2164f0ce0d
282 281 * X 1:0d2164f0ce0d
283 282 Y 3:f6fc62dde3c0
284 283 Z 1:0d2164f0ce0d
285 284
286 285
287 286 Unrelated marker does not alter the decision
288 287
289 288 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
290 289 $ hg push http://localhost:$HGPORT2/
291 290 pushing to http://localhost:$HGPORT2/
292 291 searching for changes
293 292 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
294 293 (merge or see "hg help push" for details about pushing new heads)
295 294 [255]
296 295 $ hg -R ../a book
297 296 @ 1:0d2164f0ce0d
298 297 * X 1:0d2164f0ce0d
299 298 Y 3:f6fc62dde3c0
300 299 Z 1:0d2164f0ce0d
301 300
302 301 Update to a successor works
303 302
304 303 $ hg id --debug -r 3
305 304 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
306 305 $ hg id --debug -r 4
307 306 4efff6d98829d9c824c621afd6e3f01865f5439f
308 307 $ hg id --debug -r 5
309 308 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
310 309 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
311 310 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
312 311 $ hg push http://localhost:$HGPORT2/
313 312 pushing to http://localhost:$HGPORT2/
314 313 searching for changes
315 314 remote: adding changesets
316 315 remote: adding manifests
317 316 remote: adding file changes
318 317 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
319 318 updating bookmark Y
320 319 $ hg -R ../a book
321 320 @ 1:0d2164f0ce0d
322 321 * X 1:0d2164f0ce0d
323 322 Y 5:c922c0139ca0
324 323 Z 1:0d2164f0ce0d
325 324
326 325 hgweb
327 326
328 327 $ cat <<EOF > .hg/hgrc
329 328 > [web]
330 329 > push_ssl = false
331 330 > allow_push = *
332 331 > EOF
333 332
334 333 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
335 334 $ cat ../hg.pid >> $DAEMON_PIDS
336 335 $ cd ../a
337 336
338 337 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
339 338 bookmarks
340 339 namespaces
341 340 obsolete
342 341 phases
343 342 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
344 343 @ 9b140be1080824d768c5a4691a564088eede71f9
345 344 X 9b140be1080824d768c5a4691a564088eede71f9
346 345 Y c922c0139ca03858f655e4a2af4dd02796a63969
347 346 Z 9b140be1080824d768c5a4691a564088eede71f9
348 347 foo 0000000000000000000000000000000000000000
349 348 foobar 9b140be1080824d768c5a4691a564088eede71f9
350 349 $ hg out -B http://localhost:$HGPORT/
351 350 comparing with http://localhost:$HGPORT/
352 351 searching for changed bookmarks
353 352 no changed bookmarks found
354 353 [1]
355 354 $ hg push -B Z http://localhost:$HGPORT/
356 355 pushing to http://localhost:$HGPORT/
357 356 searching for changes
358 357 no changes found
359 358 updating bookmark Z
360 359 [1]
361 360 $ hg book -d Z
362 361 $ hg in -B http://localhost:$HGPORT/
363 362 comparing with http://localhost:$HGPORT/
364 363 searching for changed bookmarks
365 364 Z 0d2164f0ce0d
366 365 foo 000000000000
367 366 foobar 9b140be10808
368 367 $ hg pull -B Z http://localhost:$HGPORT/
369 368 pulling from http://localhost:$HGPORT/
370 369 no changes found
371 370 divergent bookmark @ stored as @1
372 371 divergent bookmark X stored as X@1
373 372 adding remote bookmark Z
374 373 adding remote bookmark foo
375 374 adding remote bookmark foobar
376 importing bookmark Z
377 375 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
378 376 requesting all changes
379 377 adding changesets
380 378 adding manifests
381 379 adding file changes
382 380 added 5 changesets with 5 changes to 3 files (+2 heads)
383 381 updating to bookmark @
384 382 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
385 383 $ hg -R cloned-bookmarks bookmarks
386 384 * @ 1:9b140be10808
387 385 X 1:9b140be10808
388 386 Y 4:c922c0139ca0
389 387 Z 2:0d2164f0ce0d
390 388 foo -1:000000000000
391 389 foobar 1:9b140be10808
392 390
393 391 $ cd ..
394 392
395 393 Pushing a bookmark should only push the changes required by that
396 394 bookmark, not all outgoing changes:
397 395 $ hg clone http://localhost:$HGPORT/ addmarks
398 396 requesting all changes
399 397 adding changesets
400 398 adding manifests
401 399 adding file changes
402 400 added 5 changesets with 5 changes to 3 files (+2 heads)
403 401 updating to bookmark @
404 402 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 403 $ cd addmarks
406 404 $ echo foo > foo
407 405 $ hg add foo
408 406 $ hg commit -m 'add foo'
409 407 $ echo bar > bar
410 408 $ hg add bar
411 409 $ hg commit -m 'add bar'
412 410 $ hg co "tip^"
413 411 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
414 412 (leaving bookmark @)
415 413 $ hg book add-foo
416 414 $ hg book -r tip add-bar
417 415 Note: this push *must* push only a single changeset, as that's the point
418 416 of this test.
419 417 $ hg push -B add-foo --traceback
420 418 pushing to http://localhost:$HGPORT/
421 419 searching for changes
422 420 remote: adding changesets
423 421 remote: adding manifests
424 422 remote: adding file changes
425 423 remote: added 1 changesets with 1 changes to 1 files
426 424 exporting bookmark add-foo
427 425
428 426 pushing a new bookmark on a new head does not require -f if -B is specified
429 427
430 428 $ hg up -q X
431 429 $ hg book W
432 430 $ echo c5 > f2
433 431 $ hg ci -Am5
434 432 created new head
435 433 $ hg push -B W
436 434 pushing to http://localhost:$HGPORT/
437 435 searching for changes
438 436 remote: adding changesets
439 437 remote: adding manifests
440 438 remote: adding file changes
441 439 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
442 440 exporting bookmark W
443 441 $ hg -R ../b id -r W
444 442 cc978a373a53 tip W
445 443
446 444 $ cd ..
@@ -1,1195 +1,1193 b''
1 1
2 2 $ getmainid() {
3 3 > hg -R main log --template '{node}\n' --rev "$1"
4 4 > }
5 5
6 6 Create an extension to test bundle2 API
7 7
8 8 $ cat > bundle2.py << EOF
9 9 > """A small extension to test bundle2 implementation
10 10 >
11 11 > Current bundle2 implementation is far too limited to be used in any core
12 12 > code. We still need to be able to test it while it grow up.
13 13 > """
14 14 >
15 15 > import sys, os
16 16 > from mercurial import cmdutil
17 17 > from mercurial import util
18 18 > from mercurial import bundle2
19 19 > from mercurial import scmutil
20 20 > from mercurial import discovery
21 21 > from mercurial import changegroup
22 22 > from mercurial import error
23 23 > from mercurial import obsolete
24 24 >
25 25 > obsolete._enabled = True
26 26 >
27 27 > try:
28 28 > import msvcrt
29 29 > msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
30 30 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
31 31 > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
32 32 > except ImportError:
33 33 > pass
34 34 >
35 35 > cmdtable = {}
36 36 > command = cmdutil.command(cmdtable)
37 37 >
38 38 > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
39 39 > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
40 40 > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
41 41 > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
42 42 >
43 43 > @bundle2.parthandler('test:song')
44 44 > def songhandler(op, part):
45 45 > """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
46 46 > op.ui.write('The choir starts singing:\n')
47 47 > verses = 0
48 48 > for line in part.read().split('\n'):
49 49 > op.ui.write(' %s\n' % line)
50 50 > verses += 1
51 51 > op.records.add('song', {'verses': verses})
52 52 >
53 53 > @bundle2.parthandler('test:ping')
54 54 > def pinghandler(op, part):
55 55 > op.ui.write('received ping request (id %i)\n' % part.id)
56 56 > if op.reply is not None and 'ping-pong' in op.reply.capabilities:
57 57 > op.ui.write_err('replying to ping request (id %i)\n' % part.id)
58 58 > op.reply.newpart('test:pong', [('in-reply-to', str(part.id))])
59 59 >
60 60 > @bundle2.parthandler('test:debugreply')
61 61 > def debugreply(op, part):
62 62 > """print data about the capacity of the bundle reply"""
63 63 > if op.reply is None:
64 64 > op.ui.write('debugreply: no reply\n')
65 65 > else:
66 66 > op.ui.write('debugreply: capabilities:\n')
67 67 > for cap in sorted(op.reply.capabilities):
68 68 > op.ui.write('debugreply: %r\n' % cap)
69 69 > for val in op.reply.capabilities[cap]:
70 70 > op.ui.write('debugreply: %r\n' % val)
71 71 >
72 72 > @command('bundle2',
73 73 > [('', 'param', [], 'stream level parameter'),
74 74 > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
75 75 > ('', 'unknownparams', False, 'include an unknown part parameters in the bundle'),
76 76 > ('', 'parts', False, 'include some arbitrary parts to the bundle'),
77 77 > ('', 'reply', False, 'produce a reply bundle'),
78 78 > ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
79 79 > ('r', 'rev', [], 'includes those changeset in the bundle'),],
80 80 > '[OUTPUTFILE]')
81 81 > def cmdbundle2(ui, repo, path=None, **opts):
82 82 > """write a bundle2 container on standard ouput"""
83 83 > bundler = bundle2.bundle20(ui)
84 84 > for p in opts['param']:
85 85 > p = p.split('=', 1)
86 86 > try:
87 87 > bundler.addparam(*p)
88 88 > except ValueError, exc:
89 89 > raise util.Abort('%s' % exc)
90 90 >
91 91 > if opts['reply']:
92 92 > capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
93 93 > bundler.newpart('b2x:replycaps', data=capsstring)
94 94 >
95 95 > if opts['pushrace']:
96 96 > # also serve to test the assignement of data outside of init
97 97 > part = bundler.newpart('b2x:check:heads')
98 98 > part.data = '01234567890123456789'
99 99 >
100 100 > revs = opts['rev']
101 101 > if 'rev' in opts:
102 102 > revs = scmutil.revrange(repo, opts['rev'])
103 103 > if revs:
104 104 > # very crude version of a changegroup part creation
105 105 > bundled = repo.revs('%ld::%ld', revs, revs)
106 106 > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)]
107 107 > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)]
108 108 > outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing)
109 109 > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None)
110 110 > bundler.newpart('b2x:changegroup', data=cg.getchunks())
111 111 >
112 112 > if opts['parts']:
113 113 > bundler.newpart('test:empty')
114 114 > # add a second one to make sure we handle multiple parts
115 115 > bundler.newpart('test:empty')
116 116 > bundler.newpart('test:song', data=ELEPHANTSSONG)
117 117 > bundler.newpart('test:debugreply')
118 118 > mathpart = bundler.newpart('test:math')
119 119 > mathpart.addparam('pi', '3.14')
120 120 > mathpart.addparam('e', '2.72')
121 121 > mathpart.addparam('cooking', 'raw', mandatory=False)
122 122 > mathpart.data = '42'
123 123 > # advisory known part with unknown mandatory param
124 124 > bundler.newpart('test:song', [('randomparam','')])
125 125 > if opts['unknown']:
126 126 > bundler.newpart('test:UNKNOWN', data='some random content')
127 127 > if opts['unknownparams']:
128 128 > bundler.newpart('test:SONG', [('randomparams', '')])
129 129 > if opts['parts']:
130 130 > bundler.newpart('test:ping')
131 131 >
132 132 > if path is None:
133 133 > file = sys.stdout
134 134 > else:
135 135 > file = open(path, 'wb')
136 136 >
137 137 > for chunk in bundler.getchunks():
138 138 > file.write(chunk)
139 139 >
140 140 > @command('unbundle2', [], '')
141 141 > def cmdunbundle2(ui, repo, replypath=None):
142 142 > """process a bundle2 stream from stdin on the current repo"""
143 143 > try:
144 144 > tr = None
145 145 > lock = repo.lock()
146 146 > tr = repo.transaction('processbundle')
147 147 > try:
148 148 > unbundler = bundle2.unbundle20(ui, sys.stdin)
149 149 > op = bundle2.processbundle(repo, unbundler, lambda: tr)
150 150 > tr.close()
151 151 > except error.BundleValueError, exc:
152 152 > raise util.Abort('missing support for %s' % exc)
153 153 > except error.PushRaced, exc:
154 154 > raise util.Abort('push race: %s' % exc)
155 155 > finally:
156 156 > if tr is not None:
157 157 > tr.release()
158 158 > lock.release()
159 159 > remains = sys.stdin.read()
160 160 > ui.write('%i unread bytes\n' % len(remains))
161 161 > if op.records['song']:
162 162 > totalverses = sum(r['verses'] for r in op.records['song'])
163 163 > ui.write('%i total verses sung\n' % totalverses)
164 164 > for rec in op.records['changegroup']:
165 165 > ui.write('addchangegroup return: %i\n' % rec['return'])
166 166 > if op.reply is not None and replypath is not None:
167 167 > file = open(replypath, 'wb')
168 168 > for chunk in op.reply.getchunks():
169 169 > file.write(chunk)
170 170 >
171 171 > @command('statbundle2', [], '')
172 172 > def cmdstatbundle2(ui, repo):
173 173 > """print statistic on the bundle2 container read from stdin"""
174 174 > unbundler = bundle2.unbundle20(ui, sys.stdin)
175 175 > try:
176 176 > params = unbundler.params
177 177 > except error.BundleValueError, exc:
178 178 > raise util.Abort('unknown parameters: %s' % exc)
179 179 > ui.write('options count: %i\n' % len(params))
180 180 > for key in sorted(params):
181 181 > ui.write('- %s\n' % key)
182 182 > value = params[key]
183 183 > if value is not None:
184 184 > ui.write(' %s\n' % value)
185 185 > count = 0
186 186 > for p in unbundler.iterparts():
187 187 > count += 1
188 188 > ui.write(' :%s:\n' % p.type)
189 189 > ui.write(' mandatory: %i\n' % len(p.mandatoryparams))
190 190 > ui.write(' advisory: %i\n' % len(p.advisoryparams))
191 191 > ui.write(' payload: %i bytes\n' % len(p.read()))
192 192 > ui.write('parts count: %i\n' % count)
193 193 > EOF
194 194 $ cat >> $HGRCPATH << EOF
195 195 > [extensions]
196 196 > bundle2=$TESTTMP/bundle2.py
197 197 > [experimental]
198 198 > bundle2-exp=True
199 199 > [ui]
200 200 > ssh=python "$TESTDIR/dummyssh"
201 201 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
202 202 > [web]
203 203 > push_ssl = false
204 204 > allow_push = *
205 205 > [phases]
206 206 > publish=False
207 207 > EOF
208 208
209 209 The extension requires a repo (currently unused)
210 210
211 211 $ hg init main
212 212 $ cd main
213 213 $ touch a
214 214 $ hg add a
215 215 $ hg commit -m 'a'
216 216
217 217
218 218 Empty bundle
219 219 =================
220 220
221 221 - no option
222 222 - no parts
223 223
224 224 Test bundling
225 225
226 226 $ hg bundle2
227 227 HG2X\x00\x00\x00\x00 (no-eol) (esc)
228 228
229 229 Test unbundling
230 230
231 231 $ hg bundle2 | hg statbundle2
232 232 options count: 0
233 233 parts count: 0
234 234
235 235 Test old style bundle are detected and refused
236 236
237 237 $ hg bundle --all ../bundle.hg
238 238 1 changesets found
239 239 $ hg statbundle2 < ../bundle.hg
240 240 abort: unknown bundle version 10
241 241 [255]
242 242
243 243 Test parameters
244 244 =================
245 245
246 246 - some options
247 247 - no parts
248 248
249 249 advisory parameters, no value
250 250 -------------------------------
251 251
252 252 Simplest possible parameters form
253 253
254 254 Test generation simple option
255 255
256 256 $ hg bundle2 --param 'caution'
257 257 HG2X\x00\x07caution\x00\x00 (no-eol) (esc)
258 258
259 259 Test unbundling
260 260
261 261 $ hg bundle2 --param 'caution' | hg statbundle2
262 262 options count: 1
263 263 - caution
264 264 parts count: 0
265 265
266 266 Test generation multiple option
267 267
268 268 $ hg bundle2 --param 'caution' --param 'meal'
269 269 HG2X\x00\x0ccaution meal\x00\x00 (no-eol) (esc)
270 270
271 271 Test unbundling
272 272
273 273 $ hg bundle2 --param 'caution' --param 'meal' | hg statbundle2
274 274 options count: 2
275 275 - caution
276 276 - meal
277 277 parts count: 0
278 278
279 279 advisory parameters, with value
280 280 -------------------------------
281 281
282 282 Test generation
283 283
284 284 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants'
285 285 HG2X\x00\x1ccaution meal=vegan elephants\x00\x00 (no-eol) (esc)
286 286
287 287 Test unbundling
288 288
289 289 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | hg statbundle2
290 290 options count: 3
291 291 - caution
292 292 - elephants
293 293 - meal
294 294 vegan
295 295 parts count: 0
296 296
297 297 parameter with special char in value
298 298 ---------------------------------------------------
299 299
300 300 Test generation
301 301
302 302 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple
303 303 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
304 304
305 305 Test unbundling
306 306
307 307 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | hg statbundle2
308 308 options count: 2
309 309 - e|! 7/
310 310 babar%#==tutu
311 311 - simple
312 312 parts count: 0
313 313
314 314 Test unknown mandatory option
315 315 ---------------------------------------------------
316 316
317 317 $ hg bundle2 --param 'Gravity' | hg statbundle2
318 318 abort: unknown parameters: Stream Parameter - Gravity
319 319 [255]
320 320
321 321 Test debug output
322 322 ---------------------------------------------------
323 323
324 324 bundling debug
325 325
326 326 $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
327 327 start emission of HG2X stream
328 328 bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
329 329 start of parts
330 330 end of bundle
331 331
332 332 file content is ok
333 333
334 334 $ cat ../out.hg2
335 335 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
336 336
337 337 unbundling debug
338 338
339 339 $ hg statbundle2 --debug < ../out.hg2
340 340 start processing of HG2X stream
341 341 reading bundle2 stream parameters
342 342 ignoring unknown parameter 'e|! 7/'
343 343 ignoring unknown parameter 'simple'
344 344 options count: 2
345 345 - e|! 7/
346 346 babar%#==tutu
347 347 - simple
348 348 start extraction of bundle2 parts
349 349 part header size: 0
350 350 end of bundle2 stream
351 351 parts count: 0
352 352
353 353
354 354 Test buggy input
355 355 ---------------------------------------------------
356 356
357 357 empty parameter name
358 358
359 359 $ hg bundle2 --param '' --quiet
360 360 abort: empty parameter name
361 361 [255]
362 362
363 363 bad parameter name
364 364
365 365 $ hg bundle2 --param 42babar
366 366 abort: non letter first character: '42babar'
367 367 [255]
368 368
369 369
370 370 Test part
371 371 =================
372 372
373 373 $ hg bundle2 --parts ../parts.hg2 --debug
374 374 start emission of HG2X stream
375 375 bundle parameter:
376 376 start of parts
377 377 bundle part: "test:empty"
378 378 bundle part: "test:empty"
379 379 bundle part: "test:song"
380 380 bundle part: "test:debugreply"
381 381 bundle part: "test:math"
382 382 bundle part: "test:song"
383 383 bundle part: "test:ping"
384 384 end of bundle
385 385
386 386 $ cat ../parts.hg2
387 387 HG2X\x00\x00\x00\x11 (esc)
388 388 test:empty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
389 389 test:empty\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10 test:song\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc)
390 390 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
391 391 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00\x16\x0ftest:debugreply\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00+ test:math\x00\x00\x00\x04\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x1d test:song\x00\x00\x00\x05\x01\x00\x0b\x00randomparam\x00\x00\x00\x00\x00\x10 test:ping\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
392 392
393 393
394 394 $ hg statbundle2 < ../parts.hg2
395 395 options count: 0
396 396 :test:empty:
397 397 mandatory: 0
398 398 advisory: 0
399 399 payload: 0 bytes
400 400 :test:empty:
401 401 mandatory: 0
402 402 advisory: 0
403 403 payload: 0 bytes
404 404 :test:song:
405 405 mandatory: 0
406 406 advisory: 0
407 407 payload: 178 bytes
408 408 :test:debugreply:
409 409 mandatory: 0
410 410 advisory: 0
411 411 payload: 0 bytes
412 412 :test:math:
413 413 mandatory: 2
414 414 advisory: 1
415 415 payload: 2 bytes
416 416 :test:song:
417 417 mandatory: 1
418 418 advisory: 0
419 419 payload: 0 bytes
420 420 :test:ping:
421 421 mandatory: 0
422 422 advisory: 0
423 423 payload: 0 bytes
424 424 parts count: 7
425 425
426 426 $ hg statbundle2 --debug < ../parts.hg2
427 427 start processing of HG2X stream
428 428 reading bundle2 stream parameters
429 429 options count: 0
430 430 start extraction of bundle2 parts
431 431 part header size: 17
432 432 part type: "test:empty"
433 433 part id: "0"
434 434 part parameters: 0
435 435 :test:empty:
436 436 mandatory: 0
437 437 advisory: 0
438 438 payload chunk size: 0
439 439 payload: 0 bytes
440 440 part header size: 17
441 441 part type: "test:empty"
442 442 part id: "1"
443 443 part parameters: 0
444 444 :test:empty:
445 445 mandatory: 0
446 446 advisory: 0
447 447 payload chunk size: 0
448 448 payload: 0 bytes
449 449 part header size: 16
450 450 part type: "test:song"
451 451 part id: "2"
452 452 part parameters: 0
453 453 :test:song:
454 454 mandatory: 0
455 455 advisory: 0
456 456 payload chunk size: 178
457 457 payload chunk size: 0
458 458 payload: 178 bytes
459 459 part header size: 22
460 460 part type: "test:debugreply"
461 461 part id: "3"
462 462 part parameters: 0
463 463 :test:debugreply:
464 464 mandatory: 0
465 465 advisory: 0
466 466 payload chunk size: 0
467 467 payload: 0 bytes
468 468 part header size: 43
469 469 part type: "test:math"
470 470 part id: "4"
471 471 part parameters: 3
472 472 :test:math:
473 473 mandatory: 2
474 474 advisory: 1
475 475 payload chunk size: 2
476 476 payload chunk size: 0
477 477 payload: 2 bytes
478 478 part header size: 29
479 479 part type: "test:song"
480 480 part id: "5"
481 481 part parameters: 1
482 482 :test:song:
483 483 mandatory: 1
484 484 advisory: 0
485 485 payload chunk size: 0
486 486 payload: 0 bytes
487 487 part header size: 16
488 488 part type: "test:ping"
489 489 part id: "6"
490 490 part parameters: 0
491 491 :test:ping:
492 492 mandatory: 0
493 493 advisory: 0
494 494 payload chunk size: 0
495 495 payload: 0 bytes
496 496 part header size: 0
497 497 end of bundle2 stream
498 498 parts count: 7
499 499
500 500 Test actual unbundling of test part
501 501 =======================================
502 502
503 503 Process the bundle
504 504
505 505 $ hg unbundle2 --debug < ../parts.hg2
506 506 start processing of HG2X stream
507 507 reading bundle2 stream parameters
508 508 start extraction of bundle2 parts
509 509 part header size: 17
510 510 part type: "test:empty"
511 511 part id: "0"
512 512 part parameters: 0
513 513 ignoring unsupported advisory part test:empty
514 514 payload chunk size: 0
515 515 part header size: 17
516 516 part type: "test:empty"
517 517 part id: "1"
518 518 part parameters: 0
519 519 ignoring unsupported advisory part test:empty
520 520 payload chunk size: 0
521 521 part header size: 16
522 522 part type: "test:song"
523 523 part id: "2"
524 524 part parameters: 0
525 525 found a handler for part 'test:song'
526 526 The choir starts singing:
527 527 payload chunk size: 178
528 528 payload chunk size: 0
529 529 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
530 530 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
531 531 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
532 532 part header size: 22
533 533 part type: "test:debugreply"
534 534 part id: "3"
535 535 part parameters: 0
536 536 found a handler for part 'test:debugreply'
537 537 debugreply: no reply
538 538 payload chunk size: 0
539 539 part header size: 43
540 540 part type: "test:math"
541 541 part id: "4"
542 542 part parameters: 3
543 543 ignoring unsupported advisory part test:math
544 544 payload chunk size: 2
545 545 payload chunk size: 0
546 546 part header size: 29
547 547 part type: "test:song"
548 548 part id: "5"
549 549 part parameters: 1
550 550 found a handler for part 'test:song'
551 551 ignoring unsupported advisory part test:song - randomparam
552 552 payload chunk size: 0
553 553 part header size: 16
554 554 part type: "test:ping"
555 555 part id: "6"
556 556 part parameters: 0
557 557 found a handler for part 'test:ping'
558 558 received ping request (id 6)
559 559 payload chunk size: 0
560 560 part header size: 0
561 561 end of bundle2 stream
562 562 0 unread bytes
563 563 3 total verses sung
564 564
565 565 Unbundle with an unknown mandatory part
566 566 (should abort)
567 567
568 568 $ hg bundle2 --parts --unknown ../unknown.hg2
569 569
570 570 $ hg unbundle2 < ../unknown.hg2
571 571 The choir starts singing:
572 572 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
573 573 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
574 574 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
575 575 debugreply: no reply
576 576 0 unread bytes
577 577 abort: missing support for test:unknown
578 578 [255]
579 579
580 580 Unbundle with an unknown mandatory part parameters
581 581 (should abort)
582 582
583 583 $ hg bundle2 --unknownparams ../unknown.hg2
584 584
585 585 $ hg unbundle2 < ../unknown.hg2
586 586 0 unread bytes
587 587 abort: missing support for test:song - randomparams
588 588 [255]
589 589
590 590 unbundle with a reply
591 591
592 592 $ hg bundle2 --parts --reply ../parts-reply.hg2
593 593 $ hg unbundle2 ../reply.hg2 < ../parts-reply.hg2
594 594 0 unread bytes
595 595 3 total verses sung
596 596
597 597 The reply is a bundle
598 598
599 599 $ cat ../reply.hg2
600 600 HG2X\x00\x00\x00\x1f (esc)
601 601 b2x:output\x00\x00\x00\x00\x00\x01\x0b\x01in-reply-to3\x00\x00\x00\xd9The choir starts singing: (esc)
602 602 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
603 603 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
604 604 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
605 605 \x00\x00\x00\x00\x00\x1f (esc)
606 606 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to4\x00\x00\x00\xc9debugreply: capabilities: (esc)
607 607 debugreply: 'city=!'
608 608 debugreply: 'celeste,ville'
609 609 debugreply: 'elephants'
610 610 debugreply: 'babar'
611 611 debugreply: 'celeste'
612 612 debugreply: 'ping-pong'
613 613 \x00\x00\x00\x00\x00\x1e test:pong\x00\x00\x00\x02\x01\x00\x0b\x01in-reply-to7\x00\x00\x00\x00\x00\x1f (esc)
614 614 b2x:output\x00\x00\x00\x03\x00\x01\x0b\x01in-reply-to7\x00\x00\x00=received ping request (id 7) (esc)
615 615 replying to ping request (id 7)
616 616 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
617 617
618 618 The reply is valid
619 619
620 620 $ hg statbundle2 < ../reply.hg2
621 621 options count: 0
622 622 :b2x:output:
623 623 mandatory: 0
624 624 advisory: 1
625 625 payload: 217 bytes
626 626 :b2x:output:
627 627 mandatory: 0
628 628 advisory: 1
629 629 payload: 201 bytes
630 630 :test:pong:
631 631 mandatory: 1
632 632 advisory: 0
633 633 payload: 0 bytes
634 634 :b2x:output:
635 635 mandatory: 0
636 636 advisory: 1
637 637 payload: 61 bytes
638 638 parts count: 4
639 639
640 640 Unbundle the reply to get the output:
641 641
642 642 $ hg unbundle2 < ../reply.hg2
643 643 remote: The choir starts singing:
644 644 remote: Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
645 645 remote: Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
646 646 remote: Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
647 647 remote: debugreply: capabilities:
648 648 remote: debugreply: 'city=!'
649 649 remote: debugreply: 'celeste,ville'
650 650 remote: debugreply: 'elephants'
651 651 remote: debugreply: 'babar'
652 652 remote: debugreply: 'celeste'
653 653 remote: debugreply: 'ping-pong'
654 654 remote: received ping request (id 7)
655 655 remote: replying to ping request (id 7)
656 656 0 unread bytes
657 657
658 658 Test push race detection
659 659
660 660 $ hg bundle2 --pushrace ../part-race.hg2
661 661
662 662 $ hg unbundle2 < ../part-race.hg2
663 663 0 unread bytes
664 664 abort: push race: repository changed while pushing - please try again
665 665 [255]
666 666
667 667 Support for changegroup
668 668 ===================================
669 669
670 670 $ hg unbundle $TESTDIR/bundles/rebase.hg
671 671 adding changesets
672 672 adding manifests
673 673 adding file changes
674 674 added 8 changesets with 7 changes to 7 files (+3 heads)
675 675 (run 'hg heads' to see heads, 'hg merge' to merge)
676 676
677 677 $ hg log -G
678 678 o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H
679 679 |
680 680 | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G
681 681 |/|
682 682 o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
683 683 | |
684 684 | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
685 685 |/
686 686 | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D
687 687 | |
688 688 | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C
689 689 | |
690 690 | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B
691 691 |/
692 692 o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A
693 693
694 694 @ 0:3903775176ed draft test a
695 695
696 696
697 697 $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2
698 698 4 changesets found
699 699 list of changesets:
700 700 32af7686d403cf45b5d95f2d70cebea587ac806a
701 701 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
702 702 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
703 703 02de42196ebee42ef284b6780a87cdc96e8eaab6
704 704 start emission of HG2X stream
705 705 bundle parameter:
706 706 start of parts
707 707 bundle part: "b2x:changegroup"
708 708 bundling: 1/4 changesets (25.00%)
709 709 bundling: 2/4 changesets (50.00%)
710 710 bundling: 3/4 changesets (75.00%)
711 711 bundling: 4/4 changesets (100.00%)
712 712 bundling: 1/4 manifests (25.00%)
713 713 bundling: 2/4 manifests (50.00%)
714 714 bundling: 3/4 manifests (75.00%)
715 715 bundling: 4/4 manifests (100.00%)
716 716 bundling: D 1/3 files (33.33%)
717 717 bundling: E 2/3 files (66.67%)
718 718 bundling: H 3/3 files (100.00%)
719 719 end of bundle
720 720
721 721 $ cat ../rev.hg2
722 722 HG2X\x00\x00\x00\x16\x0fb2x:changegroup\x00\x00\x00\x00\x00\x00\x00\x00\x06\x13\x00\x00\x00\xa42\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j_\xdd\xd9\x89W\xc8\xa5JMCm\xfe\x1d\xa9\xd8\x7f!\xa1\xb9{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c (esc)
723 723 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02D (esc)
724 724 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01D\x00\x00\x00\xa4\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xcd\x01\x0b\x8c\xd9\x98\xf3\x98\x1aZ\x81\x15\xf9O\x8d\xa4\xabP`\x89\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)4dece9c826f69490507b98c6383a3009b295837d (esc)
725 725 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02E (esc)
726 726 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01E\x00\x00\x00\xa2\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)365b93d57fdf4814e2b5911d6bacff2b12014441 (esc)
727 727 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01G\x00\x00\x00\xa4\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
728 728 \x87\xcd\xc9n\x8e\xaa\xb6$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
729 729 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)8bee48edc7318541fc0013ee41b089276a8c24bf (esc)
730 730 \x00\x00\x00f\x00\x00\x00f\x00\x00\x00\x02H (esc)
731 731 \x00\x00\x00g\x00\x00\x00h\x00\x00\x00\x01H\x00\x00\x00\x00\x00\x00\x00\x8bn\x1fLG\xec\xb53\xff\xd0\xc8\xe5,\xdc\x88\xaf\xb6\xcd9\xe2\x0cf\xa5\xa0\x18\x17\xfd\xf5#\x9c'8\x02\xb5\xb7a\x8d\x05\x1c\x89\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+D\x00c3f1ca2924c16a19b0656a84900e504e5b0aec2d (esc)
732 732 \x00\x00\x00\x8bM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\x00}\x8c\x9d\x88\x84\x13%\xf5\xc6\xb0cq\xb3[N\x8a+\x1a\x83\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00+\x00\x00\x00\xac\x00\x00\x00+E\x009c6fd0350a6c0d0c49d4a9c5017cf07043f54e58 (esc)
733 733 \x00\x00\x00\x8b6[\x93\xd5\x7f\xdfH\x14\xe2\xb5\x91\x1dk\xac\xff+\x12\x01DA(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xceM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00V\x00\x00\x00V\x00\x00\x00+F\x0022bfcfd62a21a3287edbd4d656218d0f525ed76a (esc)
734 734 \x00\x00\x00\x97\x8b\xeeH\xed\xc71\x85A\xfc\x00\x13\xeeA\xb0\x89'j\x8c$\xbf(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
735 735 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00+\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+H\x008500189e74a9e0475e822093bc7db0d631aeb0b4 (esc)
736 736 \x00\x00\x00\x00\x00\x00\x00\x05D\x00\x00\x00b\xc3\xf1\xca)$\xc1j\x19\xb0ej\x84\x90\x0ePN[ (esc)
737 737 \xec-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02D (esc)
738 738 \x00\x00\x00\x00\x00\x00\x00\x05E\x00\x00\x00b\x9co\xd05 (esc)
739 739 l\r (no-eol) (esc)
740 740 \x0cI\xd4\xa9\xc5\x01|\xf0pC\xf5NX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02E (esc)
741 741 \x00\x00\x00\x00\x00\x00\x00\x05H\x00\x00\x00b\x85\x00\x18\x9et\xa9\xe0G^\x82 \x93\xbc}\xb0\xd61\xae\xb0\xb4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
742 742 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02H (esc)
743 743 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
744 744
745 745 $ hg unbundle2 < ../rev.hg2
746 746 adding changesets
747 747 adding manifests
748 748 adding file changes
749 749 added 0 changesets with 0 changes to 3 files
750 750 0 unread bytes
751 751 addchangegroup return: 1
752 752
753 753 with reply
754 754
755 755 $ hg bundle2 --rev '8+7+5+4' --reply ../rev-rr.hg2
756 756 $ hg unbundle2 ../rev-reply.hg2 < ../rev-rr.hg2
757 757 0 unread bytes
758 758 addchangegroup return: 1
759 759
760 760 $ cat ../rev-reply.hg2
761 761 HG2X\x00\x00\x003\x15b2x:reply:changegroup\x00\x00\x00\x00\x00\x02\x0b\x01\x06\x01in-reply-to1return1\x00\x00\x00\x00\x00\x1f (esc)
762 762 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to1\x00\x00\x00dadding changesets (esc)
763 763 adding manifests
764 764 adding file changes
765 765 added 0 changesets with 0 changes to 3 files
766 766 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
767 767
768 768 $ cd ..
769 769
770 770 Real world exchange
771 771 =====================
772 772
773 773 Add more obsolescence information
774 774
775 775 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
776 776 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
777 777
778 778 clone --pull
779 779
780 780 $ hg -R main phase --public cd010b8cd998
781 781 $ hg clone main other --pull --rev 9520eea781bc
782 782 adding changesets
783 783 adding manifests
784 784 adding file changes
785 785 added 2 changesets with 2 changes to 2 files
786 786 1 new obsolescence markers
787 787 updating to branch default
788 788 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
789 789 $ hg -R other log -G
790 790 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
791 791 |
792 792 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
793 793
794 794 $ hg -R other debugobsolete
795 795 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
796 796
797 797 pull
798 798
799 799 $ hg -R main phase --public 9520eea781bc
800 800 $ hg -R other pull -r 24b6387c8c8c
801 801 pulling from $TESTTMP/main (glob)
802 802 searching for changes
803 803 adding changesets
804 804 adding manifests
805 805 adding file changes
806 806 added 1 changesets with 1 changes to 1 files (+1 heads)
807 807 1 new obsolescence markers
808 808 (run 'hg heads' to see heads, 'hg merge' to merge)
809 809 $ hg -R other log -G
810 810 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
811 811 |
812 812 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
813 813 |/
814 814 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
815 815
816 816 $ hg -R other debugobsolete
817 817 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
818 818 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
819 819
820 820 pull empty (with phase movement)
821 821
822 822 $ hg -R main phase --public 24b6387c8c8c
823 823 $ hg -R other pull -r 24b6387c8c8c
824 824 pulling from $TESTTMP/main (glob)
825 825 no changes found
826 826 $ hg -R other log -G
827 827 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
828 828 |
829 829 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
830 830 |/
831 831 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
832 832
833 833 $ hg -R other debugobsolete
834 834 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
835 835 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
836 836
837 837 pull empty
838 838
839 839 $ hg -R other pull -r 24b6387c8c8c
840 840 pulling from $TESTTMP/main (glob)
841 841 no changes found
842 842 $ hg -R other log -G
843 843 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
844 844 |
845 845 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
846 846 |/
847 847 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
848 848
849 849 $ hg -R other debugobsolete
850 850 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
851 851 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
852 852
853 853 add extra data to test their exchange during push
854 854
855 855 $ hg -R main bookmark --rev eea13746799a book_eea1
856 856 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
857 857 $ hg -R main bookmark --rev 02de42196ebe book_02de
858 858 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
859 859 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
860 860 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
861 861 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
862 862 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
863 863 $ hg -R main bookmark --rev 32af7686d403 book_32af
864 864 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
865 865
866 866 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
867 867 $ hg -R other bookmark --rev cd010b8cd998 book_02de
868 868 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
869 869 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
870 870 $ hg -R other bookmark --rev cd010b8cd998 book_32af
871 871
872 872 $ hg -R main phase --public eea13746799a
873 873
874 874 push
875 875 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
876 876 pushing to other
877 877 searching for changes
878 878 remote: adding changesets
879 879 remote: adding manifests
880 880 remote: adding file changes
881 881 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
882 882 remote: 1 new obsolescence markers
883 883 updating bookmark book_eea1
884 884 $ hg -R other log -G
885 885 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
886 886 |\
887 887 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
888 888 | |
889 889 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
890 890 |/
891 891 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
892 892
893 893 $ hg -R other debugobsolete
894 894 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
895 895 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
896 896 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
897 897
898 898 pull over ssh
899 899
900 900 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
901 901 pulling from ssh://user@dummy/main
902 902 searching for changes
903 903 adding changesets
904 904 adding manifests
905 905 adding file changes
906 906 added 1 changesets with 1 changes to 1 files (+1 heads)
907 907 1 new obsolescence markers
908 908 updating bookmark book_02de
909 importing bookmark book_02de
910 909 (run 'hg heads' to see heads, 'hg merge' to merge)
911 910 $ hg -R other debugobsolete
912 911 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
913 912 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
914 913 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
915 914 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
916 915
917 916 pull over http
918 917
919 918 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
920 919 $ cat main.pid >> $DAEMON_PIDS
921 920
922 921 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
923 922 pulling from http://localhost:$HGPORT/
924 923 searching for changes
925 924 adding changesets
926 925 adding manifests
927 926 adding file changes
928 927 added 1 changesets with 1 changes to 1 files (+1 heads)
929 928 1 new obsolescence markers
930 929 updating bookmark book_42cc
931 importing bookmark book_42cc
932 930 (run 'hg heads .' to see heads, 'hg merge' to merge)
933 931 $ cat main-error.log
934 932 $ hg -R other debugobsolete
935 933 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
936 934 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
937 935 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
938 936 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
939 937 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
940 938
941 939 push over ssh
942 940
943 941 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
944 942 pushing to ssh://user@dummy/other
945 943 searching for changes
946 944 remote: adding changesets
947 945 remote: adding manifests
948 946 remote: adding file changes
949 947 remote: added 1 changesets with 1 changes to 1 files
950 948 remote: 1 new obsolescence markers
951 949 updating bookmark book_5fdd
952 950 $ hg -R other log -G
953 951 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
954 952 |
955 953 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
956 954 |
957 955 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
958 956 | |
959 957 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
960 958 | |/|
961 959 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
962 960 |/ /
963 961 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
964 962 |/
965 963 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
966 964
967 965 $ hg -R other debugobsolete
968 966 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
969 967 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
970 968 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
971 969 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
972 970 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
973 971 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
974 972
975 973 push over http
976 974
977 975 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
978 976 $ cat other.pid >> $DAEMON_PIDS
979 977
980 978 $ hg -R main phase --public 32af7686d403
981 979 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
982 980 pushing to http://localhost:$HGPORT2/
983 981 searching for changes
984 982 remote: adding changesets
985 983 remote: adding manifests
986 984 remote: adding file changes
987 985 remote: added 1 changesets with 1 changes to 1 files
988 986 remote: 1 new obsolescence markers
989 987 updating bookmark book_32af
990 988 $ cat other-error.log
991 989
992 990 Check final content.
993 991
994 992 $ hg -R other log -G
995 993 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
996 994 |
997 995 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
998 996 |
999 997 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
1000 998 |
1001 999 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
1002 1000 | |
1003 1001 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
1004 1002 | |/|
1005 1003 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
1006 1004 |/ /
1007 1005 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
1008 1006 |/
1009 1007 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
1010 1008
1011 1009 $ hg -R other debugobsolete
1012 1010 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1013 1011 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1014 1012 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1015 1013 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1016 1014 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1017 1015 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1018 1016 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1019 1017
1020 1018 Error Handling
1021 1019 ==============
1022 1020
1023 1021 Check that errors are properly returned to the client during push.
1024 1022
1025 1023 Setting up
1026 1024
1027 1025 $ cat > failpush.py << EOF
1028 1026 > """A small extension that makes push fails when using bundle2
1029 1027 >
1030 1028 > used to test error handling in bundle2
1031 1029 > """
1032 1030 >
1033 1031 > from mercurial import util
1034 1032 > from mercurial import bundle2
1035 1033 > from mercurial import exchange
1036 1034 > from mercurial import extensions
1037 1035 >
1038 1036 > def _pushbundle2failpart(pushop, bundler):
1039 1037 > reason = pushop.ui.config('failpush', 'reason', None)
1040 1038 > part = None
1041 1039 > if reason == 'abort':
1042 1040 > bundler.newpart('test:abort')
1043 1041 > if reason == 'unknown':
1044 1042 > bundler.newpart('TEST:UNKNOWN')
1045 1043 > if reason == 'race':
1046 1044 > # 20 Bytes of crap
1047 1045 > bundler.newpart('b2x:check:heads', data='01234567890123456789')
1048 1046 >
1049 1047 > @bundle2.parthandler("test:abort")
1050 1048 > def handleabort(op, part):
1051 1049 > raise util.Abort('Abandon ship!', hint="don't panic")
1052 1050 >
1053 1051 > def uisetup(ui):
1054 1052 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
1055 1053 > exchange.b2partsgenorder.insert(0, 'failpart')
1056 1054 >
1057 1055 > EOF
1058 1056
1059 1057 $ cd main
1060 1058 $ hg up tip
1061 1059 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
1062 1060 $ echo 'I' > I
1063 1061 $ hg add I
1064 1062 $ hg ci -m 'I'
1065 1063 $ hg id
1066 1064 e7ec4e813ba6 tip
1067 1065 $ cd ..
1068 1066
1069 1067 $ cat << EOF >> $HGRCPATH
1070 1068 > [extensions]
1071 1069 > failpush=$TESTTMP/failpush.py
1072 1070 > EOF
1073 1071
1074 1072 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1075 1073 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1076 1074 $ cat other.pid >> $DAEMON_PIDS
1077 1075
1078 1076 Doing the actual push: Abort error
1079 1077
1080 1078 $ cat << EOF >> $HGRCPATH
1081 1079 > [failpush]
1082 1080 > reason = abort
1083 1081 > EOF
1084 1082
1085 1083 $ hg -R main push other -r e7ec4e813ba6
1086 1084 pushing to other
1087 1085 searching for changes
1088 1086 abort: Abandon ship!
1089 1087 (don't panic)
1090 1088 [255]
1091 1089
1092 1090 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1093 1091 pushing to ssh://user@dummy/other
1094 1092 searching for changes
1095 1093 abort: Abandon ship!
1096 1094 (don't panic)
1097 1095 [255]
1098 1096
1099 1097 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1100 1098 pushing to http://localhost:$HGPORT2/
1101 1099 searching for changes
1102 1100 abort: Abandon ship!
1103 1101 (don't panic)
1104 1102 [255]
1105 1103
1106 1104
1107 1105 Doing the actual push: unknown mandatory parts
1108 1106
1109 1107 $ cat << EOF >> $HGRCPATH
1110 1108 > [failpush]
1111 1109 > reason = unknown
1112 1110 > EOF
1113 1111
1114 1112 $ hg -R main push other -r e7ec4e813ba6
1115 1113 pushing to other
1116 1114 searching for changes
1117 1115 abort: missing support for test:unknown
1118 1116 [255]
1119 1117
1120 1118 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1121 1119 pushing to ssh://user@dummy/other
1122 1120 searching for changes
1123 1121 abort: missing support for test:unknown
1124 1122 [255]
1125 1123
1126 1124 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1127 1125 pushing to http://localhost:$HGPORT2/
1128 1126 searching for changes
1129 1127 abort: missing support for test:unknown
1130 1128 [255]
1131 1129
1132 1130 Doing the actual push: race
1133 1131
1134 1132 $ cat << EOF >> $HGRCPATH
1135 1133 > [failpush]
1136 1134 > reason = race
1137 1135 > EOF
1138 1136
1139 1137 $ hg -R main push other -r e7ec4e813ba6
1140 1138 pushing to other
1141 1139 searching for changes
1142 1140 abort: push failed:
1143 1141 'repository changed while pushing - please try again'
1144 1142 [255]
1145 1143
1146 1144 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1147 1145 pushing to ssh://user@dummy/other
1148 1146 searching for changes
1149 1147 abort: push failed:
1150 1148 'repository changed while pushing - please try again'
1151 1149 [255]
1152 1150
1153 1151 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1154 1152 pushing to http://localhost:$HGPORT2/
1155 1153 searching for changes
1156 1154 abort: push failed:
1157 1155 'repository changed while pushing - please try again'
1158 1156 [255]
1159 1157
1160 1158 Doing the actual push: hook abort
1161 1159
1162 1160 $ cat << EOF >> $HGRCPATH
1163 1161 > [failpush]
1164 1162 > reason =
1165 1163 > [hooks]
1166 1164 > b2x-pretransactionclose.failpush = false
1167 1165 > EOF
1168 1166
1169 1167 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1170 1168 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1171 1169 $ cat other.pid >> $DAEMON_PIDS
1172 1170
1173 1171 $ hg -R main push other -r e7ec4e813ba6
1174 1172 pushing to other
1175 1173 searching for changes
1176 1174 transaction abort!
1177 1175 rollback completed
1178 1176 abort: b2x-pretransactionclose.failpush hook exited with status 1
1179 1177 [255]
1180 1178
1181 1179 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1182 1180 pushing to ssh://user@dummy/other
1183 1181 searching for changes
1184 1182 abort: b2x-pretransactionclose.failpush hook exited with status 1
1185 1183 remote: transaction abort!
1186 1184 remote: rollback completed
1187 1185 [255]
1188 1186
1189 1187 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1190 1188 pushing to http://localhost:$HGPORT2/
1191 1189 searching for changes
1192 1190 abort: b2x-pretransactionclose.failpush hook exited with status 1
1193 1191 [255]
1194 1192
1195 1193
@@ -1,644 +1,643 b''
1 1 commit hooks can see env vars
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ cat > .hg/hgrc <<EOF
6 6 > [hooks]
7 7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
8 8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
9 9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
10 10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
11 11 > pretxncommit.tip = hg -q tip
12 12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
13 13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
14 14 > post-cat = python "$TESTDIR/printenv.py" post-cat
15 15 > EOF
16 16 $ echo a > a
17 17 $ hg add a
18 18 $ hg commit -m a
19 19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
20 20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
21 21 0:cb9a9f314b8b
22 22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
24 24
25 25 $ hg clone . ../b
26 26 updating to branch default
27 27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 28 $ cd ../b
29 29
30 30 changegroup hooks can see env vars
31 31
32 32 $ cat > .hg/hgrc <<EOF
33 33 > [hooks]
34 34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
35 35 > changegroup = python "$TESTDIR/printenv.py" changegroup
36 36 > incoming = python "$TESTDIR/printenv.py" incoming
37 37 > EOF
38 38
39 39 pretxncommit and commit hooks can see both parents of merge
40 40
41 41 $ cd ../a
42 42 $ echo b >> a
43 43 $ hg commit -m a1 -d "1 0"
44 44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
46 46 1:ab228980c14d
47 47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
49 49 $ hg update -C 0
50 50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 51 $ echo b > b
52 52 $ hg add b
53 53 $ hg commit -m b -d '1 0'
54 54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
56 56 2:ee9deb46ab31
57 57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
59 59 created new head
60 60 $ hg merge 1
61 61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 62 (branch merge, don't forget to commit)
63 63 $ hg commit -m merge -d '2 0'
64 64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
66 66 3:07f3376c1e65
67 67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
69 69
70 70 test generic hooks
71 71
72 72 $ hg id
73 73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
74 74 abort: pre-identify hook exited with status 1
75 75 [255]
76 76 $ hg cat b
77 77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
78 78 b
79 79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
80 80
81 81 $ cd ../b
82 82 $ hg pull ../a
83 83 pulling from ../a
84 84 searching for changes
85 85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
86 86 adding changesets
87 87 adding manifests
88 88 adding file changes
89 89 added 3 changesets with 2 changes to 2 files
90 90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
94 94 (run 'hg update' to get a working copy)
95 95
96 96 tag hooks can see env vars
97 97
98 98 $ cd ../a
99 99 $ cat >> .hg/hgrc <<EOF
100 100 > pretag = python "$TESTDIR/printenv.py" pretag
101 101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
102 102 > EOF
103 103 $ hg tag -d '3 0' a
104 104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
106 106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
107 107 4:539e4b31b6dc
108 108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
109 109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
111 111 $ hg tag -l la
112 112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
114 114
115 115 pretag hook can forbid tagging
116 116
117 117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
118 118 $ hg tag -d '4 0' fa
119 119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
121 121 abort: pretag.forbid hook exited with status 1
122 122 [255]
123 123 $ hg tag -l fla
124 124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
126 126 abort: pretag.forbid hook exited with status 1
127 127 [255]
128 128
129 129 pretxncommit hook can see changeset, can roll back txn, changeset no
130 130 more there after
131 131
132 132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
133 133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
134 134 $ echo z > z
135 135 $ hg add z
136 136 $ hg -q tip
137 137 4:539e4b31b6dc
138 138 $ hg commit -m 'fail' -d '4 0'
139 139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
140 140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
141 141 5:6f611f8018c1
142 142 5:6f611f8018c1
143 143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
144 144 transaction abort!
145 145 rollback completed
146 146 abort: pretxncommit.forbid1 hook exited with status 1
147 147 [255]
148 148 $ hg -q tip
149 149 4:539e4b31b6dc
150 150
151 151 precommit hook can prevent commit
152 152
153 153 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
154 154 $ hg commit -m 'fail' -d '4 0'
155 155 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
156 156 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
157 157 abort: precommit.forbid hook exited with status 1
158 158 [255]
159 159 $ hg -q tip
160 160 4:539e4b31b6dc
161 161
162 162 preupdate hook can prevent update
163 163
164 164 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
165 165 $ hg update 1
166 166 preupdate hook: HG_PARENT1=ab228980c14d
167 167 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
168 168
169 169 update hook
170 170
171 171 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
172 172 $ hg update
173 173 preupdate hook: HG_PARENT1=539e4b31b6dc
174 174 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
175 175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 176
177 177 pushkey hook
178 178
179 179 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
180 180 $ cd ../b
181 181 $ hg bookmark -r null foo
182 182 $ hg push -B foo ../a
183 183 pushing to ../a
184 184 searching for changes
185 185 no changes found
186 186 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
187 187 exporting bookmark foo
188 188 [1]
189 189 $ cd ../a
190 190
191 191 listkeys hook
192 192
193 193 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
194 194 $ hg bookmark -r null bar
195 195 $ cd ../b
196 196 $ hg pull -B bar ../a
197 197 pulling from ../a
198 198 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
199 199 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
200 200 no changes found
201 201 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
202 202 adding remote bookmark bar
203 importing bookmark bar
204 203 $ cd ../a
205 204
206 205 test that prepushkey can prevent incoming keys
207 206
208 207 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
209 208 $ cd ../b
210 209 $ hg bookmark -r null baz
211 210 $ hg push -B baz ../a
212 211 pushing to ../a
213 212 searching for changes
214 213 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
215 214 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
216 215 no changes found
217 216 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
218 217 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
219 218 abort: prepushkey hook exited with status 1
220 219 [255]
221 220 $ cd ../a
222 221
223 222 test that prelistkeys can prevent listing keys
224 223
225 224 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
226 225 $ hg bookmark -r null quux
227 226 $ cd ../b
228 227 $ hg pull -B quux ../a
229 228 pulling from ../a
230 229 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
231 230 abort: prelistkeys hook exited with status 1
232 231 [255]
233 232 $ cd ../a
234 233 $ rm .hg/hgrc
235 234
236 235 prechangegroup hook can prevent incoming changes
237 236
238 237 $ cd ../b
239 238 $ hg -q tip
240 239 3:07f3376c1e65
241 240 $ cat > .hg/hgrc <<EOF
242 241 > [hooks]
243 242 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
244 243 > EOF
245 244 $ hg pull ../a
246 245 pulling from ../a
247 246 searching for changes
248 247 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
249 248 abort: prechangegroup.forbid hook exited with status 1
250 249 [255]
251 250
252 251 pretxnchangegroup hook can see incoming changes, can roll back txn,
253 252 incoming changes no longer there after
254 253
255 254 $ cat > .hg/hgrc <<EOF
256 255 > [hooks]
257 256 > pretxnchangegroup.forbid0 = hg tip -q
258 257 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
259 258 > EOF
260 259 $ hg pull ../a
261 260 pulling from ../a
262 261 searching for changes
263 262 adding changesets
264 263 adding manifests
265 264 adding file changes
266 265 added 1 changesets with 1 changes to 1 files
267 266 4:539e4b31b6dc
268 267 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
269 268 transaction abort!
270 269 rollback completed
271 270 abort: pretxnchangegroup.forbid1 hook exited with status 1
272 271 [255]
273 272 $ hg -q tip
274 273 3:07f3376c1e65
275 274
276 275 outgoing hooks can see env vars
277 276
278 277 $ rm .hg/hgrc
279 278 $ cat > ../a/.hg/hgrc <<EOF
280 279 > [hooks]
281 280 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
282 281 > outgoing = python "$TESTDIR/printenv.py" outgoing
283 282 > EOF
284 283 $ hg pull ../a
285 284 pulling from ../a
286 285 searching for changes
287 286 preoutgoing hook: HG_SOURCE=pull
288 287 adding changesets
289 288 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
290 289 adding manifests
291 290 adding file changes
292 291 added 1 changesets with 1 changes to 1 files
293 292 adding remote bookmark quux
294 293 (run 'hg update' to get a working copy)
295 294 $ hg rollback
296 295 repository tip rolled back to revision 3 (undo pull)
297 296
298 297 preoutgoing hook can prevent outgoing changes
299 298
300 299 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
301 300 $ hg pull ../a
302 301 pulling from ../a
303 302 searching for changes
304 303 preoutgoing hook: HG_SOURCE=pull
305 304 preoutgoing.forbid hook: HG_SOURCE=pull
306 305 abort: preoutgoing.forbid hook exited with status 1
307 306 [255]
308 307
309 308 outgoing hooks work for local clones
310 309
311 310 $ cd ..
312 311 $ cat > a/.hg/hgrc <<EOF
313 312 > [hooks]
314 313 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
315 314 > outgoing = python "$TESTDIR/printenv.py" outgoing
316 315 > EOF
317 316 $ hg clone a c
318 317 preoutgoing hook: HG_SOURCE=clone
319 318 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
320 319 updating to branch default
321 320 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 321 $ rm -rf c
323 322
324 323 preoutgoing hook can prevent outgoing changes for local clones
325 324
326 325 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
327 326 $ hg clone a zzz
328 327 preoutgoing hook: HG_SOURCE=clone
329 328 preoutgoing.forbid hook: HG_SOURCE=clone
330 329 abort: preoutgoing.forbid hook exited with status 1
331 330 [255]
332 331
333 332 $ cd "$TESTTMP/b"
334 333
335 334 $ cat > hooktests.py <<EOF
336 335 > from mercurial import util
337 336 >
338 337 > uncallable = 0
339 338 >
340 339 > def printargs(args):
341 340 > args.pop('ui', None)
342 341 > args.pop('repo', None)
343 342 > a = list(args.items())
344 343 > a.sort()
345 344 > print 'hook args:'
346 345 > for k, v in a:
347 346 > print ' ', k, v
348 347 >
349 348 > def passhook(**args):
350 349 > printargs(args)
351 350 >
352 351 > def failhook(**args):
353 352 > printargs(args)
354 353 > return True
355 354 >
356 355 > class LocalException(Exception):
357 356 > pass
358 357 >
359 358 > def raisehook(**args):
360 359 > raise LocalException('exception from hook')
361 360 >
362 361 > def aborthook(**args):
363 362 > raise util.Abort('raise abort from hook')
364 363 >
365 364 > def brokenhook(**args):
366 365 > return 1 + {}
367 366 >
368 367 > def verbosehook(ui, **args):
369 368 > ui.note('verbose output from hook\n')
370 369 >
371 370 > def printtags(ui, repo, **args):
372 371 > print sorted(repo.tags())
373 372 >
374 373 > class container:
375 374 > unreachable = 1
376 375 > EOF
377 376
378 377 test python hooks
379 378
380 379 #if windows
381 380 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
382 381 #else
383 382 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
384 383 #endif
385 384 $ export PYTHONPATH
386 385
387 386 $ echo '[hooks]' > ../a/.hg/hgrc
388 387 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
389 388 $ hg pull ../a 2>&1 | grep 'raised an exception'
390 389 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
391 390
392 391 $ echo '[hooks]' > ../a/.hg/hgrc
393 392 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
394 393 $ hg pull ../a 2>&1 | grep 'raised an exception'
395 394 error: preoutgoing.raise hook raised an exception: exception from hook
396 395
397 396 $ echo '[hooks]' > ../a/.hg/hgrc
398 397 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
399 398 $ hg pull ../a
400 399 pulling from ../a
401 400 searching for changes
402 401 error: preoutgoing.abort hook failed: raise abort from hook
403 402 abort: raise abort from hook
404 403 [255]
405 404
406 405 $ echo '[hooks]' > ../a/.hg/hgrc
407 406 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
408 407 $ hg pull ../a
409 408 pulling from ../a
410 409 searching for changes
411 410 hook args:
412 411 hooktype preoutgoing
413 412 source pull
414 413 abort: preoutgoing.fail hook failed
415 414 [255]
416 415
417 416 $ echo '[hooks]' > ../a/.hg/hgrc
418 417 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
419 418 $ hg pull ../a
420 419 pulling from ../a
421 420 searching for changes
422 421 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
423 422 [255]
424 423
425 424 $ echo '[hooks]' > ../a/.hg/hgrc
426 425 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
427 426 $ hg pull ../a
428 427 pulling from ../a
429 428 searching for changes
430 429 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
431 430 [255]
432 431
433 432 $ echo '[hooks]' > ../a/.hg/hgrc
434 433 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
435 434 $ hg pull ../a
436 435 pulling from ../a
437 436 searching for changes
438 437 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
439 438 [255]
440 439
441 440 $ echo '[hooks]' > ../a/.hg/hgrc
442 441 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
443 442 $ hg pull ../a
444 443 pulling from ../a
445 444 searching for changes
446 445 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
447 446 [255]
448 447
449 448 $ echo '[hooks]' > ../a/.hg/hgrc
450 449 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
451 450 $ hg pull ../a
452 451 pulling from ../a
453 452 searching for changes
454 453 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
455 454 [255]
456 455
457 456 $ echo '[hooks]' > ../a/.hg/hgrc
458 457 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
459 458 $ hg pull ../a
460 459 pulling from ../a
461 460 searching for changes
462 461 hook args:
463 462 hooktype preoutgoing
464 463 source pull
465 464 adding changesets
466 465 adding manifests
467 466 adding file changes
468 467 added 1 changesets with 1 changes to 1 files
469 468 adding remote bookmark quux
470 469 (run 'hg update' to get a working copy)
471 470
472 471 make sure --traceback works
473 472
474 473 $ echo '[hooks]' > .hg/hgrc
475 474 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
476 475
477 476 $ echo aa > a
478 477 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
479 478 Traceback (most recent call last):
480 479
481 480 $ cd ..
482 481 $ hg init c
483 482 $ cd c
484 483
485 484 $ cat > hookext.py <<EOF
486 485 > def autohook(**args):
487 486 > print "Automatically installed hook"
488 487 >
489 488 > def reposetup(ui, repo):
490 489 > repo.ui.setconfig("hooks", "commit.auto", autohook)
491 490 > EOF
492 491 $ echo '[extensions]' >> .hg/hgrc
493 492 $ echo 'hookext = hookext.py' >> .hg/hgrc
494 493
495 494 $ touch foo
496 495 $ hg add foo
497 496 $ hg ci -d '0 0' -m 'add foo'
498 497 Automatically installed hook
499 498 $ echo >> foo
500 499 $ hg ci --debug -d '0 0' -m 'change foo'
501 500 foo
502 501 calling hook commit.auto: hgext_hookext.autohook
503 502 Automatically installed hook
504 503 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
505 504
506 505 $ hg showconfig hooks
507 506 hooks.commit.auto=<function autohook at *> (glob)
508 507
509 508 test python hook configured with python:[file]:[hook] syntax
510 509
511 510 $ cd ..
512 511 $ mkdir d
513 512 $ cd d
514 513 $ hg init repo
515 514 $ mkdir hooks
516 515
517 516 $ cd hooks
518 517 $ cat > testhooks.py <<EOF
519 518 > def testhook(**args):
520 519 > print 'hook works'
521 520 > EOF
522 521 $ echo '[hooks]' > ../repo/.hg/hgrc
523 522 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
524 523
525 524 $ cd ../repo
526 525 $ hg commit -d '0 0'
527 526 hook works
528 527 nothing changed
529 528 [1]
530 529
531 530 $ echo '[hooks]' > .hg/hgrc
532 531 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
533 532 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
534 533
535 534 $ hg up null
536 535 loading update.ne hook failed:
537 536 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
538 537 [255]
539 538
540 539 $ hg id
541 540 loading pre-identify.npmd hook failed:
542 541 abort: No module named repo!
543 542 [255]
544 543
545 544 $ cd ../../b
546 545
547 546 make sure --traceback works on hook import failure
548 547
549 548 $ cat > importfail.py <<EOF
550 549 > import somebogusmodule
551 550 > # dereference something in the module to force demandimport to load it
552 551 > somebogusmodule.whatever
553 552 > EOF
554 553
555 554 $ echo '[hooks]' > .hg/hgrc
556 555 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
557 556
558 557 $ echo a >> a
559 558 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
560 559 exception from first failed import attempt:
561 560 Traceback (most recent call last):
562 561 ImportError: No module named somebogusmodule
563 562 exception from second failed import attempt:
564 563 Traceback (most recent call last):
565 564 ImportError: No module named hgext_importfail
566 565 Traceback (most recent call last):
567 566 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
568 567 abort: precommit.importfail hook is invalid (import of "importfail" failed)
569 568
570 569 Issue1827: Hooks Update & Commit not completely post operation
571 570
572 571 commit and update hooks should run after command completion
573 572
574 573 $ echo '[hooks]' > .hg/hgrc
575 574 $ echo 'commit = hg id' >> .hg/hgrc
576 575 $ echo 'update = hg id' >> .hg/hgrc
577 576 $ echo bb > a
578 577 $ hg ci -ma
579 578 223eafe2750c tip
580 579 $ hg up 0
581 580 cb9a9f314b8b
582 581 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 582
584 583 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
585 584 that is passed to pre/post hooks
586 585
587 586 $ echo '[hooks]' > .hg/hgrc
588 587 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
589 588 $ hg id
590 589 cb9a9f314b8b
591 590 $ hg id --verbose
592 591 calling hook pre-identify: hooktests.verbosehook
593 592 verbose output from hook
594 593 cb9a9f314b8b
595 594
596 595 Ensure hooks can be prioritized
597 596
598 597 $ echo '[hooks]' > .hg/hgrc
599 598 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
600 599 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
601 600 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
602 601 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
603 602 $ hg id --verbose
604 603 calling hook pre-identify.b: hooktests.verbosehook
605 604 verbose output from hook
606 605 calling hook pre-identify.a: hooktests.verbosehook
607 606 verbose output from hook
608 607 calling hook pre-identify.c: hooktests.verbosehook
609 608 verbose output from hook
610 609 cb9a9f314b8b
611 610
612 611 new tags must be visible in pretxncommit (issue3210)
613 612
614 613 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
615 614 $ hg tag -f foo
616 615 ['a', 'foo', 'tip']
617 616
618 617 new commits must be visible in pretxnchangegroup (issue3428)
619 618
620 619 $ cd ..
621 620 $ hg init to
622 621 $ echo '[hooks]' >> to/.hg/hgrc
623 622 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
624 623 $ echo a >> to/a
625 624 $ hg --cwd to ci -Ama
626 625 adding a
627 626 $ hg clone to from
628 627 updating to branch default
629 628 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
630 629 $ echo aa >> from/a
631 630 $ hg --cwd from ci -mb
632 631 $ hg --cwd from push
633 632 pushing to $TESTTMP/to (glob)
634 633 searching for changes
635 634 adding changesets
636 635 adding manifests
637 636 adding file changes
638 637 added 1 changesets with 1 changes to 1 files
639 638 changeset: 1:9836a07b9b9d
640 639 tag: tip
641 640 user: test
642 641 date: Thu Jan 01 00:00:00 1970 +0000
643 642 summary: b
644 643
@@ -1,432 +1,431 b''
1 1
2 2
3 3 This test tries to exercise the ssh functionality with a dummy script
4 4
5 5 creating 'remote' repo
6 6
7 7 $ hg init remote
8 8 $ cd remote
9 9 $ echo this > foo
10 10 $ echo this > fooO
11 11 $ hg ci -A -m "init" foo fooO
12 12 $ cat <<EOF > .hg/hgrc
13 13 > [server]
14 14 > uncompressed = True
15 15 >
16 16 > [hooks]
17 17 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
18 18 > EOF
19 19 $ cd ..
20 20
21 21 repo not found error
22 22
23 23 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
24 24 remote: abort: there is no Mercurial repository here (.hg not found)!
25 25 abort: no suitable response from remote hg!
26 26 [255]
27 27
28 28 non-existent absolute path
29 29
30 30 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
31 31 remote: abort: there is no Mercurial repository here (.hg not found)!
32 32 abort: no suitable response from remote hg!
33 33 [255]
34 34
35 35 clone remote via stream
36 36
37 37 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
38 38 streaming all changes
39 39 4 files to transfer, 392 bytes of data
40 40 transferred 392 bytes in * seconds (*/sec) (glob)
41 41 updating to branch default
42 42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 43 $ cd local-stream
44 44 $ hg verify
45 45 checking changesets
46 46 checking manifests
47 47 crosschecking files in changesets and manifests
48 48 checking files
49 49 2 files, 1 changesets, 2 total revisions
50 50 $ cd ..
51 51
52 52 clone remote via pull
53 53
54 54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
55 55 requesting all changes
56 56 adding changesets
57 57 adding manifests
58 58 adding file changes
59 59 added 1 changesets with 2 changes to 2 files
60 60 updating to branch default
61 61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 62
63 63 verify
64 64
65 65 $ cd local
66 66 $ hg verify
67 67 checking changesets
68 68 checking manifests
69 69 crosschecking files in changesets and manifests
70 70 checking files
71 71 2 files, 1 changesets, 2 total revisions
72 72 $ echo '[hooks]' >> .hg/hgrc
73 73 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
74 74
75 75 empty default pull
76 76
77 77 $ hg paths
78 78 default = ssh://user@dummy/remote
79 79 $ hg pull -e "python \"$TESTDIR/dummyssh\""
80 80 pulling from ssh://user@dummy/remote
81 81 searching for changes
82 82 no changes found
83 83
84 84 local change
85 85
86 86 $ echo bleah > foo
87 87 $ hg ci -m "add"
88 88
89 89 updating rc
90 90
91 91 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
92 92 $ echo "[ui]" >> .hg/hgrc
93 93 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
94 94
95 95 find outgoing
96 96
97 97 $ hg out ssh://user@dummy/remote
98 98 comparing with ssh://user@dummy/remote
99 99 searching for changes
100 100 changeset: 1:a28a9d1a809c
101 101 tag: tip
102 102 user: test
103 103 date: Thu Jan 01 00:00:00 1970 +0000
104 104 summary: add
105 105
106 106
107 107 find incoming on the remote side
108 108
109 109 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
110 110 comparing with ssh://user@dummy/local
111 111 searching for changes
112 112 changeset: 1:a28a9d1a809c
113 113 tag: tip
114 114 user: test
115 115 date: Thu Jan 01 00:00:00 1970 +0000
116 116 summary: add
117 117
118 118
119 119 find incoming on the remote side (using absolute path)
120 120
121 121 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
122 122 comparing with ssh://user@dummy/$TESTTMP/local
123 123 searching for changes
124 124 changeset: 1:a28a9d1a809c
125 125 tag: tip
126 126 user: test
127 127 date: Thu Jan 01 00:00:00 1970 +0000
128 128 summary: add
129 129
130 130
131 131 push
132 132
133 133 $ hg push
134 134 pushing to ssh://user@dummy/remote
135 135 searching for changes
136 136 remote: adding changesets
137 137 remote: adding manifests
138 138 remote: adding file changes
139 139 remote: added 1 changesets with 1 changes to 1 files
140 140 $ cd ../remote
141 141
142 142 check remote tip
143 143
144 144 $ hg tip
145 145 changeset: 1:a28a9d1a809c
146 146 tag: tip
147 147 user: test
148 148 date: Thu Jan 01 00:00:00 1970 +0000
149 149 summary: add
150 150
151 151 $ hg verify
152 152 checking changesets
153 153 checking manifests
154 154 crosschecking files in changesets and manifests
155 155 checking files
156 156 2 files, 2 changesets, 3 total revisions
157 157 $ hg cat -r tip foo
158 158 bleah
159 159 $ echo z > z
160 160 $ hg ci -A -m z z
161 161 created new head
162 162
163 163 test pushkeys and bookmarks
164 164
165 165 $ cd ../local
166 166 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
167 167 bookmarks
168 168 namespaces
169 169 phases
170 170 $ hg book foo -r 0
171 171 $ hg out -B
172 172 comparing with ssh://user@dummy/remote
173 173 searching for changed bookmarks
174 174 foo 1160648e36ce
175 175 $ hg push -B foo
176 176 pushing to ssh://user@dummy/remote
177 177 searching for changes
178 178 no changes found
179 179 exporting bookmark foo
180 180 [1]
181 181 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
182 182 foo 1160648e36cec0054048a7edc4110c6f84fde594
183 183 $ hg book -f foo
184 184 $ hg push --traceback
185 185 pushing to ssh://user@dummy/remote
186 186 searching for changes
187 187 no changes found
188 188 updating bookmark foo
189 189 [1]
190 190 $ hg book -d foo
191 191 $ hg in -B
192 192 comparing with ssh://user@dummy/remote
193 193 searching for changed bookmarks
194 194 foo a28a9d1a809c
195 195 $ hg book -f -r 0 foo
196 196 $ hg pull -B foo
197 197 pulling from ssh://user@dummy/remote
198 198 no changes found
199 199 updating bookmark foo
200 importing bookmark foo
201 200 $ hg book -d foo
202 201 $ hg push -B foo
203 202 pushing to ssh://user@dummy/remote
204 203 searching for changes
205 204 no changes found
206 205 deleting remote bookmark foo
207 206 [1]
208 207
209 208 a bad, evil hook that prints to stdout
210 209
211 210 $ cat <<EOF > $TESTTMP/badhook
212 211 > import sys
213 212 > sys.stdout.write("KABOOM\n")
214 213 > EOF
215 214
216 215 $ echo '[hooks]' >> ../remote/.hg/hgrc
217 216 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
218 217 $ echo r > r
219 218 $ hg ci -A -m z r
220 219
221 220 push should succeed even though it has an unexpected response
222 221
223 222 $ hg push
224 223 pushing to ssh://user@dummy/remote
225 224 searching for changes
226 225 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
227 226 remote: adding changesets
228 227 remote: adding manifests
229 228 remote: adding file changes
230 229 remote: added 1 changesets with 1 changes to 1 files
231 230 remote: KABOOM
232 231 $ hg -R ../remote heads
233 232 changeset: 3:1383141674ec
234 233 tag: tip
235 234 parent: 1:a28a9d1a809c
236 235 user: test
237 236 date: Thu Jan 01 00:00:00 1970 +0000
238 237 summary: z
239 238
240 239 changeset: 2:6c0482d977a3
241 240 parent: 0:1160648e36ce
242 241 user: test
243 242 date: Thu Jan 01 00:00:00 1970 +0000
244 243 summary: z
245 244
246 245
247 246 clone bookmarks
248 247
249 248 $ hg -R ../remote bookmark test
250 249 $ hg -R ../remote bookmarks
251 250 * test 2:6c0482d977a3
252 251 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
253 252 requesting all changes
254 253 adding changesets
255 254 adding manifests
256 255 adding file changes
257 256 added 4 changesets with 5 changes to 4 files (+1 heads)
258 257 updating to branch default
259 258 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 259 $ hg -R local-bookmarks bookmarks
261 260 test 2:6c0482d977a3
262 261
263 262 passwords in ssh urls are not supported
264 263 (we use a glob here because different Python versions give different
265 264 results here)
266 265
267 266 $ hg push ssh://user:erroneouspwd@dummy/remote
268 267 pushing to ssh://user:*@dummy/remote (glob)
269 268 abort: password in URL not supported!
270 269 [255]
271 270
272 271 $ cd ..
273 272
274 273 hide outer repo
275 274 $ hg init
276 275
277 276 Test remote paths with spaces (issue2983):
278 277
279 278 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
280 279 $ touch "$TESTTMP/a repo/test"
281 280 $ hg -R 'a repo' commit -A -m "test"
282 281 adding test
283 282 $ hg -R 'a repo' tag tag
284 283 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
285 284 73649e48688a
286 285
287 286 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
288 287 abort: unknown revision 'noNoNO'!
289 288 [255]
290 289
291 290 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
292 291
293 292 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
294 293 destination directory: a repo
295 294 abort: destination 'a repo' is not empty
296 295 [255]
297 296
298 297 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
299 298 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
300 299 parameters:
301 300
302 301 $ cat > ssh.sh << EOF
303 302 > userhost="\$1"
304 303 > SSH_ORIGINAL_COMMAND="\$2"
305 304 > export SSH_ORIGINAL_COMMAND
306 305 > PYTHONPATH="$PYTHONPATH"
307 306 > export PYTHONPATH
308 307 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
309 308 > EOF
310 309
311 310 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
312 311 73649e48688a
313 312
314 313 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
315 314 remote: Illegal repository "$TESTTMP/a'repo" (glob)
316 315 abort: no suitable response from remote hg!
317 316 [255]
318 317
319 318 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
320 319 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
321 320 abort: no suitable response from remote hg!
322 321 [255]
323 322
324 323 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
325 324 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
326 325 [255]
327 326
328 327 Test hg-ssh in read-only mode:
329 328
330 329 $ cat > ssh.sh << EOF
331 330 > userhost="\$1"
332 331 > SSH_ORIGINAL_COMMAND="\$2"
333 332 > export SSH_ORIGINAL_COMMAND
334 333 > PYTHONPATH="$PYTHONPATH"
335 334 > export PYTHONPATH
336 335 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
337 336 > EOF
338 337
339 338 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
340 339 requesting all changes
341 340 adding changesets
342 341 adding manifests
343 342 adding file changes
344 343 added 4 changesets with 5 changes to 4 files (+1 heads)
345 344 updating to branch default
346 345 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
347 346
348 347 $ cd read-only-local
349 348 $ echo "baz" > bar
350 349 $ hg ci -A -m "unpushable commit" bar
351 350 $ hg push --ssh "sh ../ssh.sh"
352 351 pushing to ssh://user@dummy/*/remote (glob)
353 352 searching for changes
354 353 remote: Permission denied
355 354 remote: abort: prechangegroup.hg-ssh hook failed
356 355 remote: Permission denied
357 356 remote: abort: prepushkey.hg-ssh hook failed
358 357 abort: unexpected response: empty string
359 358 [255]
360 359
361 360 $ cd ..
362 361
363 362 stderr from remote commands should be printed before stdout from local code (issue4336)
364 363
365 364 $ hg clone remote stderr-ordering
366 365 updating to branch default
367 366 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 367 $ cd stderr-ordering
369 368 $ cat >> localwrite.py << EOF
370 369 > from mercurial import exchange, extensions
371 370 >
372 371 > def wrappedpush(orig, repo, *args, **kwargs):
373 372 > res = orig(repo, *args, **kwargs)
374 373 > repo.ui.write('local stdout\n')
375 374 > return res
376 375 >
377 376 > def extsetup(ui):
378 377 > extensions.wrapfunction(exchange, 'push', wrappedpush)
379 378 > EOF
380 379
381 380 $ cat >> .hg/hgrc << EOF
382 381 > [paths]
383 382 > default-push = ssh://user@dummy/remote
384 383 > [ui]
385 384 > ssh = python "$TESTDIR/dummyssh"
386 385 > [extensions]
387 386 > localwrite = localwrite.py
388 387 > EOF
389 388
390 389 $ echo localwrite > foo
391 390 $ hg commit -m 'testing localwrite'
392 391 $ hg push
393 392 pushing to ssh://user@dummy/remote
394 393 searching for changes
395 394 remote: adding changesets
396 395 remote: adding manifests
397 396 remote: adding file changes
398 397 remote: added 1 changesets with 1 changes to 1 files
399 398 remote: KABOOM
400 399 local stdout
401 400
402 401 $ cd ..
403 402
404 403 $ cat dummylog
405 404 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
406 405 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
407 406 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
408 407 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
409 408 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
410 409 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
411 410 Got arguments 1:user@dummy 2:hg -R local serve --stdio
412 411 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
413 412 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
414 413 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
415 414 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
416 415 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
417 416 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
418 417 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
419 418 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
420 419 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
421 420 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
422 421 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
423 422 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
424 423 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
425 424 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
426 425 Got arguments 1:user@dummy 2:hg init 'a repo'
427 426 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
428 427 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
429 428 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
430 429 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
431 430 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
432 431 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
General Comments 0
You need to be logged in to leave comments. Login now