##// END OF EJS Templates
transaction: use a ".bck" extension for all backup file...
marmoute -
r51358:63dc24be default
parent child Browse files
Show More
@@ -1,960 +1,960 b''
1 1 # transaction.py - simple journaling scheme for mercurial
2 2 #
3 3 # This transaction scheme is intended to gracefully handle program
4 4 # errors and interruptions. More serious failures like system crashes
5 5 # can be recovered with an fsck-like tool. As the whole repository is
6 6 # effectively log-structured, this should amount to simply truncating
7 7 # anything that isn't referenced in the changelog.
8 8 #
9 9 # Copyright 2005, 2006 Olivia Mackall <olivia@selenic.com>
10 10 #
11 11 # This software may be used and distributed according to the terms of the
12 12 # GNU General Public License version 2 or any later version.
13 13
14 14 import errno
15 15 import os
16 16
17 17 from .i18n import _
18 18 from . import (
19 19 error,
20 20 pycompat,
21 21 util,
22 22 )
23 23 from .utils import stringutil
24 24
25 25 version = 2
26 26
27 27 GEN_GROUP_ALL = b'all'
28 28 GEN_GROUP_PRE_FINALIZE = b'prefinalize'
29 29 GEN_GROUP_POST_FINALIZE = b'postfinalize'
30 30
31 31
32 32 def active(func):
33 33 def _active(self, *args, **kwds):
34 34 if self._count == 0:
35 35 raise error.ProgrammingError(
36 36 b'cannot use transaction when it is already committed/aborted'
37 37 )
38 38 return func(self, *args, **kwds)
39 39
40 40 return _active
41 41
42 42
43 43 UNDO_BACKUP = b'%s.backupfiles'
44 44
45 45 UNDO_FILES_MAY_NEED_CLEANUP = [
46 46 # legacy entries that might exists on disk from previous version:
47 47 (b'store', b'%s.narrowspec'),
48 48 (b'plain', b'%s.narrowspec.dirstate'),
49 49 (b'plain', b'%s.branch'),
50 50 (b'plain', b'%s.bookmarks'),
51 51 (b'store', b'%s.phaseroots'),
52 52 (b'plain', b'%s.dirstate'),
53 53 # files actually in uses today:
54 54 (b'plain', b'%s.desc'),
55 55 # Always delete undo last to make sure we detect that a clean up is needed if
56 56 # the process is interrupted.
57 57 (b'store', b'%s'),
58 58 ]
59 59
60 60
61 61 def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'):
62 62 """remove "undo" files used by the rollback logic
63 63
64 64 This is useful to prevent rollback running in situation were it does not
65 65 make sense. For example after a strip.
66 66 """
67 67 backup_listing = UNDO_BACKUP % undo_prefix
68 68
69 69 backup_entries = []
70 70 undo_files = []
71 71 svfs = vfsmap[b'store']
72 72 try:
73 73 with svfs(backup_listing) as f:
74 74 backup_entries = read_backup_files(report, f)
75 75 except OSError as e:
76 76 if e.errno != errno.ENOENT:
77 77 msg = _(b'could not read %s: %s\n')
78 78 msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e))
79 79 report(msg)
80 80
81 81 for location, f, backup_path, c in backup_entries:
82 82 if location in vfsmap and backup_path:
83 83 undo_files.append((vfsmap[location], backup_path))
84 84
85 85 undo_files.append((svfs, backup_listing))
86 86 for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP:
87 87 undo_files.append((vfsmap[location], undo_path % undo_prefix))
88 88 for undovfs, undofile in undo_files:
89 89 try:
90 90 undovfs.unlink(undofile)
91 91 except OSError as e:
92 92 if e.errno != errno.ENOENT:
93 93 msg = _(b'error removing %s: %s\n')
94 94 msg %= (undovfs.join(undofile), stringutil.forcebytestr(e))
95 95 report(msg)
96 96
97 97
98 98 def _playback(
99 99 journal,
100 100 report,
101 101 opener,
102 102 vfsmap,
103 103 entries,
104 104 backupentries,
105 105 unlink=True,
106 106 checkambigfiles=None,
107 107 ):
108 108 """rollback a transaction :
109 109 - truncate files that have been appended to
110 110 - restore file backups
111 111 - delete temporary files
112 112 """
113 113 backupfiles = []
114 114
115 115 def restore_one_backup(vfs, f, b, checkambig):
116 116 filepath = vfs.join(f)
117 117 backuppath = vfs.join(b)
118 118 try:
119 119 util.copyfile(backuppath, filepath, checkambig=checkambig)
120 120 backupfiles.append((vfs, b))
121 121 except IOError as exc:
122 122 e_msg = stringutil.forcebytestr(exc)
123 123 report(_(b"failed to recover %s (%s)\n") % (f, e_msg))
124 124 raise
125 125
126 126 # gather all backup files that impact the store
127 127 # (we need this to detect files that are both backed up and truncated)
128 128 store_backup = {}
129 129 for entry in backupentries:
130 130 location, file_path, backup_path, cache = entry
131 131 vfs = vfsmap[location]
132 132 is_store = vfs.join(b'') == opener.join(b'')
133 133 if is_store and file_path and backup_path:
134 134 store_backup[file_path] = entry
135 135 copy_done = set()
136 136
137 137 # truncate all file `f` to offset `o`
138 138 for f, o in sorted(dict(entries).items()):
139 139 # if we have a backup for `f`, we should restore it first and truncate
140 140 # the restored file
141 141 bck_entry = store_backup.get(f)
142 142 if bck_entry is not None:
143 143 location, file_path, backup_path, cache = bck_entry
144 144 checkambig = False
145 145 if checkambigfiles:
146 146 checkambig = (file_path, location) in checkambigfiles
147 147 restore_one_backup(opener, file_path, backup_path, checkambig)
148 148 copy_done.add(bck_entry)
149 149 # truncate the file to its pre-transaction size
150 150 if o or not unlink:
151 151 checkambig = checkambigfiles and (f, b'') in checkambigfiles
152 152 try:
153 153 fp = opener(f, b'a', checkambig=checkambig)
154 154 if fp.tell() < o:
155 155 raise error.Abort(
156 156 _(
157 157 b"attempted to truncate %s to %d bytes, but it was "
158 158 b"already %d bytes\n"
159 159 )
160 160 % (f, o, fp.tell())
161 161 )
162 162 fp.truncate(o)
163 163 fp.close()
164 164 except IOError:
165 165 report(_(b"failed to truncate %s\n") % f)
166 166 raise
167 167 else:
168 168 # delete empty file
169 169 try:
170 170 opener.unlink(f)
171 171 except FileNotFoundError:
172 172 pass
173 173 # restore backed up files and clean up temporary files
174 174 for entry in backupentries:
175 175 if entry in copy_done:
176 176 continue
177 177 l, f, b, c = entry
178 178 if l not in vfsmap and c:
179 179 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l))
180 180 vfs = vfsmap[l]
181 181 try:
182 182 checkambig = checkambigfiles and (f, l) in checkambigfiles
183 183 if f and b:
184 184 restore_one_backup(vfs, f, b, checkambig)
185 185 else:
186 186 target = f or b
187 187 try:
188 188 vfs.unlink(target)
189 189 except FileNotFoundError:
190 190 # This is fine because
191 191 #
192 192 # either we are trying to delete the main file, and it is
193 193 # already deleted.
194 194 #
195 195 # or we are trying to delete a temporary file and it is
196 196 # already deleted.
197 197 #
198 198 # in both case, our target result (delete the file) is
199 199 # already achieved.
200 200 pass
201 201 except (IOError, OSError, error.Abort):
202 202 if not c:
203 203 raise
204 204
205 205 # cleanup transaction state file and the backups file
206 206 backuppath = b"%s.backupfiles" % journal
207 207 if opener.exists(backuppath):
208 208 opener.unlink(backuppath)
209 209 opener.unlink(journal)
210 210 try:
211 211 for vfs, f in backupfiles:
212 212 if vfs.exists(f):
213 213 vfs.unlink(f)
214 214 except (IOError, OSError, error.Abort):
215 215 # only pure backup file remains, it is sage to ignore any error
216 216 pass
217 217
218 218
219 219 class transaction(util.transactional):
220 220 def __init__(
221 221 self,
222 222 report,
223 223 opener,
224 224 vfsmap,
225 225 journalname,
226 226 undoname=None,
227 227 after=None,
228 228 createmode=None,
229 229 validator=None,
230 230 releasefn=None,
231 231 checkambigfiles=None,
232 232 name='<unnamed>',
233 233 ):
234 234 """Begin a new transaction
235 235
236 236 Begins a new transaction that allows rolling back writes in the event of
237 237 an exception.
238 238
239 239 * `after`: called after the transaction has been committed
240 240 * `createmode`: the mode of the journal file that will be created
241 241 * `releasefn`: called after releasing (with transaction and result)
242 242
243 243 `checkambigfiles` is a set of (path, vfs-location) tuples,
244 244 which determine whether file stat ambiguity should be avoided
245 245 for corresponded files.
246 246 """
247 247 self._count = 1
248 248 self._usages = 1
249 249 self._report = report
250 250 # a vfs to the store content
251 251 self._opener = opener
252 252 # a map to access file in various {location -> vfs}
253 253 vfsmap = vfsmap.copy()
254 254 vfsmap[b''] = opener # set default value
255 255 self._vfsmap = vfsmap
256 256 self._after = after
257 257 self._offsetmap = {}
258 258 self._newfiles = set()
259 259 self._journal = journalname
260 260 self._journal_files = []
261 261 self._undoname = undoname
262 262 self._queue = []
263 263 # A callback to do something just after releasing transaction.
264 264 if releasefn is None:
265 265 releasefn = lambda tr, success: None
266 266 self._releasefn = releasefn
267 267
268 268 self._checkambigfiles = set()
269 269 if checkambigfiles:
270 270 self._checkambigfiles.update(checkambigfiles)
271 271
272 272 self._names = [name]
273 273
274 274 # A dict dedicated to precisely tracking the changes introduced in the
275 275 # transaction.
276 276 self.changes = {}
277 277
278 278 # a dict of arguments to be passed to hooks
279 279 self.hookargs = {}
280 280 self._file = opener.open(self._journal, b"w+")
281 281
282 282 # a list of ('location', 'path', 'backuppath', cache) entries.
283 283 # - if 'backuppath' is empty, no file existed at backup time
284 284 # - if 'path' is empty, this is a temporary transaction file
285 285 # - if 'location' is not empty, the path is outside main opener reach.
286 286 # use 'location' value as a key in a vfsmap to find the right 'vfs'
287 287 # (cache is currently unused)
288 288 self._backupentries = []
289 289 self._backupmap = {}
290 290 self._backupjournal = b"%s.backupfiles" % self._journal
291 291 self._backupsfile = opener.open(self._backupjournal, b'w')
292 292 self._backupsfile.write(b'%d\n' % version)
293 293
294 294 if createmode is not None:
295 295 opener.chmod(self._journal, createmode & 0o666)
296 296 opener.chmod(self._backupjournal, createmode & 0o666)
297 297
298 298 # hold file generations to be performed on commit
299 299 self._filegenerators = {}
300 300 # hold callback to write pending data for hooks
301 301 self._pendingcallback = {}
302 302 # True is any pending data have been written ever
303 303 self._anypending = False
304 304 # holds callback to call when writing the transaction
305 305 self._finalizecallback = {}
306 306 # holds callback to call when validating the transaction
307 307 # should raise exception if anything is wrong
308 308 self._validatecallback = {}
309 309 if validator is not None:
310 310 self._validatecallback[b'001-userhooks'] = validator
311 311 # hold callback for post transaction close
312 312 self._postclosecallback = {}
313 313 # holds callbacks to call during abort
314 314 self._abortcallback = {}
315 315
316 316 def __repr__(self):
317 317 name = b'/'.join(self._names)
318 318 return '<transaction name=%s, count=%d, usages=%d>' % (
319 319 name,
320 320 self._count,
321 321 self._usages,
322 322 )
323 323
324 324 def __del__(self):
325 325 if self._journal:
326 326 self._abort()
327 327
328 328 @property
329 329 def finalized(self):
330 330 return self._finalizecallback is None
331 331
332 332 @active
333 333 def startgroup(self):
334 334 """delay registration of file entry
335 335
336 336 This is used by strip to delay vision of strip offset. The transaction
337 337 sees either none or all of the strip actions to be done."""
338 338 self._queue.append([])
339 339
340 340 @active
341 341 def endgroup(self):
342 342 """apply delayed registration of file entry.
343 343
344 344 This is used by strip to delay vision of strip offset. The transaction
345 345 sees either none or all of the strip actions to be done."""
346 346 q = self._queue.pop()
347 347 for f, o in q:
348 348 self._addentry(f, o)
349 349
350 350 @active
351 351 def add(self, file, offset):
352 352 """record the state of an append-only file before update"""
353 353 if (
354 354 file in self._newfiles
355 355 or file in self._offsetmap
356 356 or file in self._backupmap
357 357 ):
358 358 return
359 359 if self._queue:
360 360 self._queue[-1].append((file, offset))
361 361 return
362 362
363 363 self._addentry(file, offset)
364 364
365 365 def _addentry(self, file, offset):
366 366 """add a append-only entry to memory and on-disk state"""
367 367 if (
368 368 file in self._newfiles
369 369 or file in self._offsetmap
370 370 or file in self._backupmap
371 371 ):
372 372 return
373 373 if offset:
374 374 self._offsetmap[file] = offset
375 375 else:
376 376 self._newfiles.add(file)
377 377 # add enough data to the journal to do the truncate
378 378 self._file.write(b"%s\0%d\n" % (file, offset))
379 379 self._file.flush()
380 380
381 381 @active
382 382 def addbackup(self, file, hardlink=True, location=b'', for_offset=False):
383 383 """Adds a backup of the file to the transaction
384 384
385 385 Calling addbackup() creates a hardlink backup of the specified file
386 386 that is used to recover the file in the event of the transaction
387 387 aborting.
388 388
389 389 * `file`: the file path, relative to .hg/store
390 390 * `hardlink`: use a hardlink to quickly create the backup
391 391
392 392 If `for_offset` is set, we expect a offset for this file to have been previously recorded
393 393 """
394 394 if self._queue:
395 395 msg = b'cannot use transaction.addbackup inside "group"'
396 396 raise error.ProgrammingError(msg)
397 397
398 398 if file in self._newfiles or file in self._backupmap:
399 399 return
400 400 elif file in self._offsetmap and not for_offset:
401 401 return
402 402 elif for_offset and file not in self._offsetmap:
403 403 msg = (
404 404 'calling `addbackup` with `for_offmap=True`, '
405 405 'but no offset recorded: [%r] %r'
406 406 )
407 407 msg %= (location, file)
408 408 raise error.ProgrammingError(msg)
409 409
410 410 vfs = self._vfsmap[location]
411 411 dirname, filename = vfs.split(file)
412 backupfilename = b"%s.backup.%s" % (self._journal, filename)
412 backupfilename = b"%s.backup.%s.bck" % (self._journal, filename)
413 413 backupfile = vfs.reljoin(dirname, backupfilename)
414 414 if vfs.exists(file):
415 415 filepath = vfs.join(file)
416 416 backuppath = vfs.join(backupfile)
417 417 # store encoding may result in different directory here.
418 418 # so we have to ensure the destination directory exist
419 419 final_dir_name = os.path.dirname(backuppath)
420 420 util.makedirs(final_dir_name, mode=vfs.createmode, notindexed=True)
421 421 # then we can copy the backup
422 422 util.copyfile(filepath, backuppath, hardlink=hardlink)
423 423 else:
424 424 backupfile = b''
425 425
426 426 self._addbackupentry((location, file, backupfile, False))
427 427
428 428 def _addbackupentry(self, entry):
429 429 """register a new backup entry and write it to disk"""
430 430 self._backupentries.append(entry)
431 431 self._backupmap[entry[1]] = len(self._backupentries) - 1
432 432 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry)
433 433 self._backupsfile.flush()
434 434
435 435 @active
436 436 def registertmp(self, tmpfile, location=b''):
437 437 """register a temporary transaction file
438 438
439 439 Such files will be deleted when the transaction exits (on both
440 440 failure and success).
441 441 """
442 442 self._addbackupentry((location, b'', tmpfile, False))
443 443
444 444 @active
445 445 def addfilegenerator(
446 446 self,
447 447 genid,
448 448 filenames,
449 449 genfunc,
450 450 order=0,
451 451 location=b'',
452 452 post_finalize=False,
453 453 ):
454 454 """add a function to generates some files at transaction commit
455 455
456 456 The `genfunc` argument is a function capable of generating proper
457 457 content of each entry in the `filename` tuple.
458 458
459 459 At transaction close time, `genfunc` will be called with one file
460 460 object argument per entries in `filenames`.
461 461
462 462 The transaction itself is responsible for the backup, creation and
463 463 final write of such file.
464 464
465 465 The `genid` argument is used to ensure the same set of file is only
466 466 generated once. Call to `addfilegenerator` for a `genid` already
467 467 present will overwrite the old entry.
468 468
469 469 The `order` argument may be used to control the order in which multiple
470 470 generator will be executed.
471 471
472 472 The `location` arguments may be used to indicate the files are located
473 473 outside of the the standard directory for transaction. It should match
474 474 one of the key of the `transaction.vfsmap` dictionary.
475 475
476 476 The `post_finalize` argument can be set to `True` for file generation
477 477 that must be run after the transaction has been finalized.
478 478 """
479 479 # For now, we are unable to do proper backup and restore of custom vfs
480 480 # but for bookmarks that are handled outside this mechanism.
481 481 entry = (order, filenames, genfunc, location, post_finalize)
482 482 self._filegenerators[genid] = entry
483 483
484 484 @active
485 485 def removefilegenerator(self, genid):
486 486 """reverse of addfilegenerator, remove a file generator function"""
487 487 if genid in self._filegenerators:
488 488 del self._filegenerators[genid]
489 489
490 490 def _generatefiles(self, suffix=b'', group=GEN_GROUP_ALL):
491 491 # write files registered for generation
492 492 any = False
493 493
494 494 if group == GEN_GROUP_ALL:
495 495 skip_post = skip_pre = False
496 496 else:
497 497 skip_pre = group == GEN_GROUP_POST_FINALIZE
498 498 skip_post = group == GEN_GROUP_PRE_FINALIZE
499 499
500 500 for id, entry in sorted(self._filegenerators.items()):
501 501 any = True
502 502 order, filenames, genfunc, location, post_finalize = entry
503 503
504 504 # for generation at closing, check if it's before or after finalize
505 505 if skip_post and post_finalize:
506 506 continue
507 507 elif skip_pre and not post_finalize:
508 508 continue
509 509
510 510 vfs = self._vfsmap[location]
511 511 files = []
512 512 try:
513 513 for name in filenames:
514 514 name += suffix
515 515 if suffix:
516 516 self.registertmp(name, location=location)
517 517 checkambig = False
518 518 else:
519 519 self.addbackup(name, location=location)
520 520 checkambig = (name, location) in self._checkambigfiles
521 521 files.append(
522 522 vfs(name, b'w', atomictemp=True, checkambig=checkambig)
523 523 )
524 524 genfunc(*files)
525 525 for f in files:
526 526 f.close()
527 527 # skip discard() loop since we're sure no open file remains
528 528 del files[:]
529 529 finally:
530 530 for f in files:
531 531 f.discard()
532 532 return any
533 533
534 534 @active
535 535 def findoffset(self, file):
536 536 if file in self._newfiles:
537 537 return 0
538 538 return self._offsetmap.get(file)
539 539
540 540 @active
541 541 def readjournal(self):
542 542 self._file.seek(0)
543 543 entries = []
544 544 for l in self._file.readlines():
545 545 file, troffset = l.split(b'\0')
546 546 entries.append((file, int(troffset)))
547 547 return entries
548 548
549 549 @active
550 550 def replace(self, file, offset):
551 551 """
552 552 replace can only replace already committed entries
553 553 that are not pending in the queue
554 554 """
555 555 if file in self._newfiles:
556 556 if not offset:
557 557 return
558 558 self._newfiles.remove(file)
559 559 self._offsetmap[file] = offset
560 560 elif file in self._offsetmap:
561 561 if not offset:
562 562 del self._offsetmap[file]
563 563 self._newfiles.add(file)
564 564 else:
565 565 self._offsetmap[file] = offset
566 566 else:
567 567 raise KeyError(file)
568 568 self._file.write(b"%s\0%d\n" % (file, offset))
569 569 self._file.flush()
570 570
571 571 @active
572 572 def nest(self, name='<unnamed>'):
573 573 self._count += 1
574 574 self._usages += 1
575 575 self._names.append(name)
576 576 return self
577 577
578 578 def release(self):
579 579 if self._count > 0:
580 580 self._usages -= 1
581 581 if self._names:
582 582 self._names.pop()
583 583 # if the transaction scopes are left without being closed, fail
584 584 if self._count > 0 and self._usages == 0:
585 585 self._abort()
586 586
587 587 def running(self):
588 588 return self._count > 0
589 589
590 590 def addpending(self, category, callback):
591 591 """add a callback to be called when the transaction is pending
592 592
593 593 The transaction will be given as callback's first argument.
594 594
595 595 Category is a unique identifier to allow overwriting an old callback
596 596 with a newer callback.
597 597 """
598 598 self._pendingcallback[category] = callback
599 599
600 600 @active
601 601 def writepending(self):
602 602 """write pending file to temporary version
603 603
604 604 This is used to allow hooks to view a transaction before commit"""
605 605 categories = sorted(self._pendingcallback)
606 606 for cat in categories:
607 607 # remove callback since the data will have been flushed
608 608 any = self._pendingcallback.pop(cat)(self)
609 609 self._anypending = self._anypending or any
610 610 self._anypending |= self._generatefiles(suffix=b'.pending')
611 611 return self._anypending
612 612
613 613 @active
614 614 def hasfinalize(self, category):
615 615 """check is a callback already exist for a category"""
616 616 return category in self._finalizecallback
617 617
618 618 @active
619 619 def addfinalize(self, category, callback):
620 620 """add a callback to be called when the transaction is closed
621 621
622 622 The transaction will be given as callback's first argument.
623 623
624 624 Category is a unique identifier to allow overwriting old callbacks with
625 625 newer callbacks.
626 626 """
627 627 self._finalizecallback[category] = callback
628 628
629 629 @active
630 630 def addpostclose(self, category, callback):
631 631 """add or replace a callback to be called after the transaction closed
632 632
633 633 The transaction will be given as callback's first argument.
634 634
635 635 Category is a unique identifier to allow overwriting an old callback
636 636 with a newer callback.
637 637 """
638 638 self._postclosecallback[category] = callback
639 639
640 640 @active
641 641 def getpostclose(self, category):
642 642 """return a postclose callback added before, or None"""
643 643 return self._postclosecallback.get(category, None)
644 644
645 645 @active
646 646 def addabort(self, category, callback):
647 647 """add a callback to be called when the transaction is aborted.
648 648
649 649 The transaction will be given as the first argument to the callback.
650 650
651 651 Category is a unique identifier to allow overwriting an old callback
652 652 with a newer callback.
653 653 """
654 654 self._abortcallback[category] = callback
655 655
656 656 @active
657 657 def addvalidator(self, category, callback):
658 658 """adds a callback to be called when validating the transaction.
659 659
660 660 The transaction will be given as the first argument to the callback.
661 661
662 662 callback should raise exception if to abort transaction"""
663 663 self._validatecallback[category] = callback
664 664
665 665 @active
666 666 def close(self):
667 667 '''commit the transaction'''
668 668 if self._count == 1:
669 669 for category in sorted(self._validatecallback):
670 670 self._validatecallback[category](self)
671 671 self._validatecallback = None # Help prevent cycles.
672 672 self._generatefiles(group=GEN_GROUP_PRE_FINALIZE)
673 673 while self._finalizecallback:
674 674 callbacks = self._finalizecallback
675 675 self._finalizecallback = {}
676 676 categories = sorted(callbacks)
677 677 for cat in categories:
678 678 callbacks[cat](self)
679 679 # Prevent double usage and help clear cycles.
680 680 self._finalizecallback = None
681 681 self._generatefiles(group=GEN_GROUP_POST_FINALIZE)
682 682
683 683 self._count -= 1
684 684 if self._count != 0:
685 685 return
686 686 self._file.close()
687 687 self._backupsfile.close()
688 688 # cleanup temporary files
689 689 for l, f, b, c in self._backupentries:
690 690 if l not in self._vfsmap and c:
691 691 self._report(
692 692 b"couldn't remove %s: unknown cache location %s\n" % (b, l)
693 693 )
694 694 continue
695 695 vfs = self._vfsmap[l]
696 696 if not f and b and vfs.exists(b):
697 697 try:
698 698 vfs.unlink(b)
699 699 except (IOError, OSError, error.Abort) as inst:
700 700 if not c:
701 701 raise
702 702 # Abort may be raise by read only opener
703 703 self._report(
704 704 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
705 705 )
706 706 self._offsetmap = {}
707 707 self._newfiles = set()
708 708 self._writeundo()
709 709 if self._after:
710 710 self._after()
711 711 self._after = None # Help prevent cycles.
712 712 if self._opener.isfile(self._backupjournal):
713 713 self._opener.unlink(self._backupjournal)
714 714 if self._opener.isfile(self._journal):
715 715 self._opener.unlink(self._journal)
716 716 for l, _f, b, c in self._backupentries:
717 717 if l not in self._vfsmap and c:
718 718 self._report(
719 719 b"couldn't remove %s: unknown cache location"
720 720 b"%s\n" % (b, l)
721 721 )
722 722 continue
723 723 vfs = self._vfsmap[l]
724 724 if b and vfs.exists(b):
725 725 try:
726 726 vfs.unlink(b)
727 727 except (IOError, OSError, error.Abort) as inst:
728 728 if not c:
729 729 raise
730 730 # Abort may be raise by read only opener
731 731 self._report(
732 732 b"couldn't remove %s: %s\n" % (vfs.join(b), inst)
733 733 )
734 734 self._backupentries = []
735 735 self._journal = None
736 736
737 737 self._releasefn(self, True) # notify success of closing transaction
738 738 self._releasefn = None # Help prevent cycles.
739 739
740 740 # run post close action
741 741 categories = sorted(self._postclosecallback)
742 742 for cat in categories:
743 743 self._postclosecallback[cat](self)
744 744 # Prevent double usage and help clear cycles.
745 745 self._postclosecallback = None
746 746
747 747 @active
748 748 def abort(self):
749 749 """abort the transaction (generally called on error, or when the
750 750 transaction is not explicitly committed before going out of
751 751 scope)"""
752 752 self._abort()
753 753
754 754 @active
755 755 def add_journal(self, vfs_id, path):
756 756 self._journal_files.append((vfs_id, path))
757 757
758 758 def _writeundo(self):
759 759 """write transaction data for possible future undo call"""
760 760 if self._undoname is None:
761 761 return
762 762 cleanup_undo_files(
763 763 self._report,
764 764 self._vfsmap,
765 765 undo_prefix=self._undoname,
766 766 )
767 767
768 768 def undoname(fn: bytes) -> bytes:
769 769 base, name = os.path.split(fn)
770 770 assert name.startswith(self._journal)
771 771 new_name = name.replace(self._journal, self._undoname, 1)
772 772 return os.path.join(base, new_name)
773 773
774 774 undo_backup_path = b"%s.backupfiles" % self._undoname
775 775 undobackupfile = self._opener.open(undo_backup_path, b'w')
776 776 undobackupfile.write(b'%d\n' % version)
777 777 for l, f, b, c in self._backupentries:
778 778 if not f: # temporary file
779 779 continue
780 780 if not b:
781 781 u = b''
782 782 else:
783 783 if l not in self._vfsmap and c:
784 784 self._report(
785 785 b"couldn't remove %s: unknown cache location"
786 786 b"%s\n" % (b, l)
787 787 )
788 788 continue
789 789 vfs = self._vfsmap[l]
790 790 u = undoname(b)
791 791 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True)
792 792 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c))
793 793 undobackupfile.close()
794 794 for vfs, src in self._journal_files:
795 795 dest = undoname(src)
796 796 # if src and dest refer to a same file, vfs.rename is a no-op,
797 797 # leaving both src and dest on disk. delete dest to make sure
798 798 # the rename couldn't be such a no-op.
799 799 vfs.tryunlink(dest)
800 800 try:
801 801 vfs.rename(src, dest)
802 802 except FileNotFoundError: # journal file does not yet exist
803 803 pass
804 804
805 805 def _abort(self):
806 806 entries = self.readjournal()
807 807 self._count = 0
808 808 self._usages = 0
809 809 self._file.close()
810 810 self._backupsfile.close()
811 811
812 812 quick = self._can_quick_abort(entries)
813 813 try:
814 814 if not quick:
815 815 self._report(_(b"transaction abort!\n"))
816 816 for cat in sorted(self._abortcallback):
817 817 self._abortcallback[cat](self)
818 818 # Prevent double usage and help clear cycles.
819 819 self._abortcallback = None
820 820 if quick:
821 821 self._do_quick_abort(entries)
822 822 else:
823 823 self._do_full_abort(entries)
824 824 finally:
825 825 self._journal = None
826 826 self._releasefn(self, False) # notify failure of transaction
827 827 self._releasefn = None # Help prevent cycles.
828 828
829 829 def _can_quick_abort(self, entries):
830 830 """False if any semantic content have been written on disk
831 831
832 832 True if nothing, except temporary files has been writen on disk."""
833 833 if entries:
834 834 return False
835 835 for e in self._backupentries:
836 836 if e[1]:
837 837 return False
838 838 return True
839 839
840 840 def _do_quick_abort(self, entries):
841 841 """(Silently) do a quick cleanup (see _can_quick_abort)"""
842 842 assert self._can_quick_abort(entries)
843 843 tmp_files = [e for e in self._backupentries if not e[1]]
844 844 for vfs_id, old_path, tmp_path, xxx in tmp_files:
845 845 vfs = self._vfsmap[vfs_id]
846 846 try:
847 847 vfs.unlink(tmp_path)
848 848 except FileNotFoundError:
849 849 pass
850 850 if self._backupjournal:
851 851 self._opener.unlink(self._backupjournal)
852 852 if self._journal:
853 853 self._opener.unlink(self._journal)
854 854
855 855 def _do_full_abort(self, entries):
856 856 """(Noisily) rollback all the change introduced by the transaction"""
857 857 try:
858 858 _playback(
859 859 self._journal,
860 860 self._report,
861 861 self._opener,
862 862 self._vfsmap,
863 863 entries,
864 864 self._backupentries,
865 865 False,
866 866 checkambigfiles=self._checkambigfiles,
867 867 )
868 868 self._report(_(b"rollback completed\n"))
869 869 except BaseException as exc:
870 870 self._report(_(b"rollback failed - please run hg recover\n"))
871 871 self._report(
872 872 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc)
873 873 )
874 874
875 875
876 876 BAD_VERSION_MSG = _(
877 877 b"journal was created by a different version of Mercurial\n"
878 878 )
879 879
880 880
881 881 def read_backup_files(report, fp):
882 882 """parse an (already open) backup file an return contained backup entries
883 883
884 884 entries are in the form: (location, file, backupfile, xxx)
885 885
886 886 :location: the vfs identifier (vfsmap's key)
887 887 :file: original file path (in the vfs)
888 888 :backupfile: path of the backup (in the vfs)
889 889 :cache: a boolean currently always set to False
890 890 """
891 891 lines = fp.readlines()
892 892 backupentries = []
893 893 if lines:
894 894 ver = lines[0][:-1]
895 895 if ver != (b'%d' % version):
896 896 report(BAD_VERSION_MSG)
897 897 else:
898 898 for line in lines[1:]:
899 899 if line:
900 900 # Shave off the trailing newline
901 901 line = line[:-1]
902 902 l, f, b, c = line.split(b'\0')
903 903 backupentries.append((l, f, b, bool(c)))
904 904 return backupentries
905 905
906 906
907 907 def rollback(
908 908 opener,
909 909 vfsmap,
910 910 file,
911 911 report,
912 912 checkambigfiles=None,
913 913 skip_journal_pattern=None,
914 914 ):
915 915 """Rolls back the transaction contained in the given file
916 916
917 917 Reads the entries in the specified file, and the corresponding
918 918 '*.backupfiles' file, to recover from an incomplete transaction.
919 919
920 920 * `file`: a file containing a list of entries, specifying where
921 921 to truncate each file. The file should contain a list of
922 922 file\0offset pairs, delimited by newlines. The corresponding
923 923 '*.backupfiles' file should contain a list of file\0backupfile
924 924 pairs, delimited by \0.
925 925
926 926 `checkambigfiles` is a set of (path, vfs-location) tuples,
927 927 which determine whether file stat ambiguity should be avoided at
928 928 restoring corresponded files.
929 929 """
930 930 entries = []
931 931 backupentries = []
932 932
933 933 with opener.open(file) as fp:
934 934 lines = fp.readlines()
935 935 for l in lines:
936 936 try:
937 937 f, o = l.split(b'\0')
938 938 entries.append((f, int(o)))
939 939 except ValueError:
940 940 report(
941 941 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l)
942 942 )
943 943
944 944 backupjournal = b"%s.backupfiles" % file
945 945 if opener.exists(backupjournal):
946 946 with opener.open(backupjournal) as fp:
947 947 backupentries = read_backup_files(report, fp)
948 948 if skip_journal_pattern is not None:
949 949 keep = lambda x: not skip_journal_pattern.match(x[1])
950 950 backupentries = [x for x in backupentries if keep(x)]
951 951
952 952 _playback(
953 953 file,
954 954 report,
955 955 opener,
956 956 vfsmap,
957 957 entries,
958 958 backupentries,
959 959 checkambigfiles=checkambigfiles,
960 960 )
@@ -1,531 +1,531 b''
1 1 #require repofncache
2 2
3 3 An extension which will set fncache chunksize to 1 byte to make sure that logic
4 4 does not break
5 5
6 6 $ cat > chunksize.py <<EOF
7 7 > from mercurial import store
8 8 > store.fncache_chunksize = 1
9 9 > EOF
10 10
11 11 $ cat >> $HGRCPATH <<EOF
12 12 > [extensions]
13 13 > chunksize = $TESTTMP/chunksize.py
14 14 > EOF
15 15
16 16 Init repo1:
17 17
18 18 $ hg init repo1
19 19 $ cd repo1
20 20 $ echo "some text" > a
21 21 $ hg add
22 22 adding a
23 23 $ hg ci -m first
24 24 $ cat .hg/store/fncache | sort
25 25 data/a.i
26 26
27 27 Testing a.i/b:
28 28
29 29 $ mkdir a.i
30 30 $ echo "some other text" > a.i/b
31 31 $ hg add
32 32 adding a.i/b
33 33 $ hg ci -m second
34 34 $ cat .hg/store/fncache | sort
35 35 data/a.i
36 36 data/a.i.hg/b.i
37 37
38 38 Testing a.i.hg/c:
39 39
40 40 $ mkdir a.i.hg
41 41 $ echo "yet another text" > a.i.hg/c
42 42 $ hg add
43 43 adding a.i.hg/c
44 44 $ hg ci -m third
45 45 $ cat .hg/store/fncache | sort
46 46 data/a.i
47 47 data/a.i.hg.hg/c.i
48 48 data/a.i.hg/b.i
49 49
50 50 Testing verify:
51 51
52 52 $ hg verify -q
53 53
54 54 $ rm .hg/store/fncache
55 55
56 56 $ hg verify
57 57 checking changesets
58 58 checking manifests
59 59 crosschecking files in changesets and manifests
60 60 checking files
61 61 warning: revlog 'data/a.i' not in fncache!
62 62 warning: revlog 'data/a.i.hg/c.i' not in fncache!
63 63 warning: revlog 'data/a.i/b.i' not in fncache!
64 64 checking dirstate
65 65 checked 3 changesets with 3 changes to 3 files
66 66 3 warnings encountered!
67 67 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
68 68
69 69 Follow the hint to make sure it works
70 70
71 71 $ hg debugrebuildfncache
72 72 adding data/a.i
73 73 adding data/a.i.hg/c.i
74 74 adding data/a.i/b.i
75 75 3 items added, 0 removed from fncache
76 76
77 77 $ hg verify -q
78 78
79 79 $ cd ..
80 80
81 81 Non store repo:
82 82
83 83 $ hg --config format.usestore=False init foo
84 84 $ cd foo
85 85 $ mkdir tst.d
86 86 $ echo foo > tst.d/foo
87 87 $ hg ci -Amfoo
88 88 adding tst.d/foo
89 89 $ find .hg | sort
90 90 .hg
91 91 .hg/00changelog.i
92 92 .hg/00manifest.i
93 93 .hg/branch
94 94 .hg/cache
95 95 .hg/cache/branch2-served
96 96 .hg/cache/rbc-names-v1
97 97 .hg/cache/rbc-revs-v1
98 98 .hg/data
99 99 .hg/data/tst.d.hg
100 100 .hg/data/tst.d.hg/foo.i
101 101 .hg/dirstate
102 102 .hg/fsmonitor.state (fsmonitor !)
103 103 .hg/last-message.txt
104 104 .hg/phaseroots
105 105 .hg/requires
106 106 .hg/undo
107 .hg/undo.backup.branch
107 .hg/undo.backup.branch.bck
108 108 .hg/undo.backupfiles
109 109 .hg/undo.desc
110 110 .hg/wcache
111 111 .hg/wcache/checkisexec (execbit !)
112 112 .hg/wcache/checklink (symlink !)
113 113 .hg/wcache/checklink-target (symlink !)
114 114 .hg/wcache/manifestfulltextcache (reporevlogstore !)
115 115 $ cd ..
116 116
117 117 Non fncache repo:
118 118
119 119 $ hg --config format.usefncache=False init bar
120 120 $ cd bar
121 121 $ mkdir tst.d
122 122 $ echo foo > tst.d/Foo
123 123 $ hg ci -Amfoo
124 124 adding tst.d/Foo
125 125 $ find .hg | sort
126 126 .hg
127 127 .hg/00changelog.i
128 128 .hg/branch
129 129 .hg/cache
130 130 .hg/cache/branch2-served
131 131 .hg/cache/rbc-names-v1
132 132 .hg/cache/rbc-revs-v1
133 133 .hg/dirstate
134 134 .hg/fsmonitor.state (fsmonitor !)
135 135 .hg/last-message.txt
136 136 .hg/requires
137 137 .hg/store
138 138 .hg/store/00changelog.i
139 139 .hg/store/00manifest.i
140 140 .hg/store/data
141 141 .hg/store/data/tst.d.hg
142 142 .hg/store/data/tst.d.hg/_foo.i
143 143 .hg/store/phaseroots
144 144 .hg/store/requires
145 145 .hg/store/undo
146 146 .hg/store/undo.backupfiles
147 .hg/undo.backup.branch
147 .hg/undo.backup.branch.bck
148 148 .hg/undo.desc
149 149 .hg/wcache
150 150 .hg/wcache/checkisexec (execbit !)
151 151 .hg/wcache/checklink (symlink !)
152 152 .hg/wcache/checklink-target (symlink !)
153 153 .hg/wcache/manifestfulltextcache (reporevlogstore !)
154 154 $ cd ..
155 155
156 156 Encoding of reserved / long paths in the store
157 157
158 158 $ hg init r2
159 159 $ cd r2
160 160 $ cat <<EOF > .hg/hgrc
161 161 > [ui]
162 162 > portablefilenames = ignore
163 163 > EOF
164 164
165 165 $ hg import -q --bypass - <<EOF
166 166 > # HG changeset patch
167 167 > # User test
168 168 > # Date 0 0
169 169 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7
170 170 > # Parent 0000000000000000000000000000000000000000
171 171 > 1
172 172 >
173 173 > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
174 174 > new file mode 100644
175 175 > --- /dev/null
176 176 > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz
177 177 > @@ -0,0 +1,1 @@
178 178 > +foo
179 179 > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
180 180 > new file mode 100644
181 181 > --- /dev/null
182 182 > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT
183 183 > @@ -0,0 +1,1 @@
184 184 > +foo
185 185 > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
186 186 > new file mode 100644
187 187 > --- /dev/null
188 188 > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt
189 189 > @@ -0,0 +1,1 @@
190 190 > +foo
191 191 > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
192 192 > new file mode 100644
193 193 > --- /dev/null
194 194 > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c
195 195 > @@ -0,0 +1,1 @@
196 196 > +foo
197 197 > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
198 198 > new file mode 100644
199 199 > --- /dev/null
200 200 > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider
201 201 > @@ -0,0 +1,1 @@
202 202 > +foo
203 203 > EOF
204 204
205 205 $ find .hg/store -name *.i | sort
206 206 .hg/store/00changelog.i
207 207 .hg/store/00manifest.i
208 208 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
209 209 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
210 210 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
211 211 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
212 212 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
213 213
214 214 $ cd ..
215 215
216 216 Aborting lock does not prevent fncache writes
217 217
218 218 $ cat > exceptionext.py <<EOF
219 219 > import os
220 220 > from mercurial import commands, error, extensions
221 221 >
222 222 > def lockexception(orig, vfs, lockname, wait, releasefn, *args, **kwargs):
223 223 > def releasewrap():
224 224 > l.held = False # ensure __del__ is a noop
225 225 > raise error.Abort(b"forced lock failure")
226 226 > l = orig(vfs, lockname, wait, releasewrap, *args, **kwargs)
227 227 > return l
228 228 >
229 229 > def reposetup(ui, repo):
230 230 > extensions.wrapfunction(repo, '_lock', lockexception)
231 231 >
232 232 > cmdtable = {}
233 233 >
234 234 > # wrap "commit" command to prevent wlock from being '__del__()'-ed
235 235 > # at the end of dispatching (for intentional "forced lcok failure")
236 236 > def commitwrap(orig, ui, repo, *pats, **opts):
237 237 > repo = repo.unfiltered() # to use replaced repo._lock certainly
238 238 > wlock = repo.wlock()
239 239 > try:
240 240 > return orig(ui, repo, *pats, **opts)
241 241 > finally:
242 242 > # multiple 'relase()' is needed for complete releasing wlock,
243 243 > # because "forced" abort at last releasing store lock
244 244 > # prevents wlock from being released at same 'lockmod.release()'
245 245 > for i in range(wlock.held):
246 246 > wlock.release()
247 247 >
248 248 > def extsetup(ui):
249 249 > extensions.wrapcommand(commands.table, b"commit", commitwrap)
250 250 > EOF
251 251 $ extpath=`pwd`/exceptionext.py
252 252 $ hg init fncachetxn
253 253 $ cd fncachetxn
254 254 $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc
255 255 $ touch y
256 256 $ hg ci -qAm y
257 257 abort: forced lock failure
258 258 [255]
259 259 $ cat .hg/store/fncache
260 260 data/y.i
261 261
262 262 Aborting transaction prevents fncache change
263 263
264 264 $ cat > ../exceptionext.py <<EOF
265 265 > import os
266 266 > from mercurial import commands, error, extensions, localrepo
267 267 >
268 268 > def wrapper(orig, self, *args, **kwargs):
269 269 > tr = orig(self, *args, **kwargs)
270 270 > def fail(tr):
271 271 > raise error.Abort(b"forced transaction failure")
272 272 > # zzz prefix to ensure it sorted after store.write
273 273 > tr.addfinalize(b'zzz-forcefails', fail)
274 274 > return tr
275 275 >
276 276 > def uisetup(ui):
277 277 > extensions.wrapfunction(
278 278 > localrepo.localrepository, b'transaction', wrapper)
279 279 >
280 280 > cmdtable = {}
281 281 >
282 282 > EOF
283 283
284 284 Clean cached version
285 285 $ rm -f "${extpath}c"
286 286 $ rm -Rf "`dirname $extpath`/__pycache__"
287 287
288 288 $ touch z
289 289 $ hg ci -qAm z
290 290 transaction abort!
291 291 rollback completed
292 292 abort: forced transaction failure
293 293 [255]
294 294 $ cat .hg/store/fncache
295 295 data/y.i
296 296
297 297 Aborted transactions can be recovered later
298 298
299 299 $ cat > ../exceptionext.py <<EOF
300 300 > import os
301 301 > import signal
302 302 > from mercurial import (
303 303 > commands,
304 304 > error,
305 305 > extensions,
306 306 > localrepo,
307 307 > transaction,
308 308 > )
309 309 >
310 310 > def trwrapper(orig, self, *args, **kwargs):
311 311 > tr = orig(self, *args, **kwargs)
312 312 > def fail(tr):
313 313 > os.kill(os.getpid(), signal.SIGKILL)
314 314 > # zzz prefix to ensure it sorted after store.write
315 315 > tr.addfinalize(b'zzz-forcefails', fail)
316 316 > return tr
317 317 >
318 318 > def uisetup(ui):
319 319 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
320 320 > trwrapper)
321 321 >
322 322 > cmdtable = {}
323 323 >
324 324 > EOF
325 325
326 326 Clean cached versions
327 327 $ rm -f "${extpath}c"
328 328 $ rm -Rf "`dirname $extpath`/__pycache__"
329 329
330 330 $ hg up -q 1
331 331 $ touch z
332 332 # Cannot rely on the return code value as chg use a different one.
333 333 # So we use a `|| echo` trick
334 334 # XXX-CHG fixing chg behavior would be nice here.
335 335 $ hg ci -qAm z || echo "He's Dead, Jim." 2>/dev/null
336 336 *Killed* (glob) (?)
337 337 He's Dead, Jim.
338 338 $ cat .hg/store/fncache | sort
339 339 data/y.i
340 340 data/z.i
341 341 $ hg recover --verify
342 342 rolling back interrupted transaction
343 343 checking changesets
344 344 checking manifests
345 345 crosschecking files in changesets and manifests
346 346 checking files
347 347 checking dirstate
348 348 checked 1 changesets with 1 changes to 1 files
349 349 $ cat .hg/store/fncache
350 350 data/y.i
351 351
352 352 $ cd ..
353 353
354 354 debugrebuildfncache does nothing unless repo has fncache requirement
355 355
356 356 $ hg --config format.usefncache=false init nofncache
357 357 $ cd nofncache
358 358 $ hg debugrebuildfncache
359 359 (not rebuilding fncache because repository does not support fncache)
360 360
361 361 $ cd ..
362 362
363 363 debugrebuildfncache works on empty repository
364 364
365 365 $ hg init empty
366 366 $ cd empty
367 367 $ hg debugrebuildfncache
368 368 fncache already up to date
369 369 $ cd ..
370 370
371 371 debugrebuildfncache on an up to date repository no-ops
372 372
373 373 $ hg init repo
374 374 $ cd repo
375 375 $ echo initial > foo
376 376 $ echo initial > .bar
377 377 $ hg commit -A -m initial
378 378 adding .bar
379 379 adding foo
380 380
381 381 $ cat .hg/store/fncache | sort
382 382 data/.bar.i
383 383 data/foo.i
384 384
385 385 $ hg debugrebuildfncache
386 386 fncache already up to date
387 387
388 388 debugrebuildfncache restores deleted fncache file
389 389
390 390 $ rm -f .hg/store/fncache
391 391 $ hg debugrebuildfncache
392 392 adding data/.bar.i
393 393 adding data/foo.i
394 394 2 items added, 0 removed from fncache
395 395
396 396 $ cat .hg/store/fncache | sort
397 397 data/.bar.i
398 398 data/foo.i
399 399
400 400 Rebuild after rebuild should no-op
401 401
402 402 $ hg debugrebuildfncache
403 403 fncache already up to date
404 404
405 405 A single missing file should get restored, an extra file should be removed
406 406
407 407 $ cat > .hg/store/fncache << EOF
408 408 > data/foo.i
409 409 > data/bad-entry.i
410 410 > EOF
411 411
412 412 $ hg debugrebuildfncache
413 413 removing data/bad-entry.i
414 414 adding data/.bar.i
415 415 1 items added, 1 removed from fncache
416 416
417 417 $ cat .hg/store/fncache | sort
418 418 data/.bar.i
419 419 data/foo.i
420 420
421 421 debugrebuildfncache recovers from truncated line in fncache
422 422
423 423 $ printf a > .hg/store/fncache
424 424 $ hg debugrebuildfncache
425 425 fncache does not ends with a newline
426 426 adding data/.bar.i
427 427 adding data/foo.i
428 428 2 items added, 0 removed from fncache
429 429
430 430 $ cat .hg/store/fncache | sort
431 431 data/.bar.i
432 432 data/foo.i
433 433
434 434 $ cd ..
435 435
436 436 Try a simple variation without dotencode to ensure fncache is ignorant of encoding
437 437
438 438 $ hg --config format.dotencode=false init nodotencode
439 439 $ cd nodotencode
440 440 $ echo initial > foo
441 441 $ echo initial > .bar
442 442 $ hg commit -A -m initial
443 443 adding .bar
444 444 adding foo
445 445
446 446 $ cat .hg/store/fncache | sort
447 447 data/.bar.i
448 448 data/foo.i
449 449
450 450 $ rm .hg/store/fncache
451 451 $ hg debugrebuildfncache
452 452 adding data/.bar.i
453 453 adding data/foo.i
454 454 2 items added, 0 removed from fncache
455 455
456 456 $ cat .hg/store/fncache | sort
457 457 data/.bar.i
458 458 data/foo.i
459 459
460 460 $ cd ..
461 461
462 462 In repositories that have accumulated a large number of files over time, the
463 463 fncache file is going to be large. If we possibly can avoid loading it, so much the better.
464 464 The cache should not loaded when committing changes to existing files, or when unbundling
465 465 changesets that only contain changes to existing files:
466 466
467 467 $ cat > fncacheloadwarn.py << EOF
468 468 > from mercurial import extensions, localrepo
469 469 >
470 470 > def extsetup(ui):
471 471 > def wrapstore(orig, requirements, *args):
472 472 > store = orig(requirements, *args)
473 473 > if b'store' in requirements and b'fncache' in requirements:
474 474 > instrumentfncachestore(store, ui)
475 475 > return store
476 476 > extensions.wrapfunction(localrepo, 'makestore', wrapstore)
477 477 >
478 478 > def instrumentfncachestore(fncachestore, ui):
479 479 > class instrumentedfncache(type(fncachestore.fncache)):
480 480 > def _load(self):
481 481 > ui.warn(b'fncache load triggered!\n')
482 482 > super(instrumentedfncache, self)._load()
483 483 > fncachestore.fncache.__class__ = instrumentedfncache
484 484 > EOF
485 485
486 486 $ fncachextpath=`pwd`/fncacheloadwarn.py
487 487 $ hg init nofncacheload
488 488 $ cd nofncacheload
489 489 $ printf "[extensions]\nfncacheloadwarn=$fncachextpath\n" >> .hg/hgrc
490 490
491 491 A new file should trigger a load, as we'd want to update the fncache set in that case:
492 492
493 493 $ touch foo
494 494 $ hg ci -qAm foo
495 495 fncache load triggered!
496 496
497 497 But modifying that file should not:
498 498
499 499 $ echo bar >> foo
500 500 $ hg ci -qm foo
501 501
502 502 If a transaction has been aborted, the zero-size truncated index file will
503 503 not prevent the fncache from being loaded; rather than actually abort
504 504 a transaction, we simulate the situation by creating a zero-size index file:
505 505
506 506 $ touch .hg/store/data/bar.i
507 507 $ touch bar
508 508 $ hg ci -qAm bar
509 509 fncache load triggered!
510 510
511 511 Unbundling should follow the same rules; existing files should not cause a load:
512 512
513 513 (loading during the clone is expected)
514 514 $ hg clone -q . tobundle
515 515 fncache load triggered!
516 516 fncache load triggered!
517 517
518 518 $ echo 'new line' > tobundle/bar
519 519 $ hg -R tobundle ci -qm bar
520 520 $ hg -R tobundle bundle -q barupdated.hg
521 521 $ hg unbundle -q barupdated.hg
522 522
523 523 but adding new files should:
524 524
525 525 $ touch tobundle/newfile
526 526 $ hg -R tobundle ci -qAm newfile
527 527 $ hg -R tobundle bundle -q newfile.hg
528 528 $ hg unbundle -q newfile.hg
529 529 fncache load triggered!
530 530
531 531 $ cd ..
@@ -1,425 +1,425 b''
1 1 #require hardlink reporevlogstore
2 2
3 3 $ cat > nlinks.py <<EOF
4 4 > import sys
5 5 > from mercurial import pycompat, util
6 6 > for f in sorted(sys.stdin.readlines()):
7 7 > f = f[:-1]
8 8 > print(util.nlinks(pycompat.fsencode(f)), f)
9 9 > EOF
10 10
11 11 $ nlinksdir()
12 12 > {
13 13 > find "$@" -type f | "$PYTHON" $TESTTMP/nlinks.py
14 14 > }
15 15
16 16 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
17 17
18 18 $ cat > linkcp.py <<EOF
19 19 > import sys
20 20 > from mercurial import pycompat, util
21 21 > util.copyfiles(pycompat.fsencode(sys.argv[1]),
22 22 > pycompat.fsencode(sys.argv[2]), hardlink=True)
23 23 > EOF
24 24
25 25 $ linkcp()
26 26 > {
27 27 > "$PYTHON" $TESTTMP/linkcp.py $1 $2
28 28 > }
29 29
30 30 Prepare repo r1:
31 31
32 32 $ hg init r1
33 33 $ cd r1
34 34
35 35 $ echo c1 > f1
36 36 $ hg add f1
37 37 $ hg ci -m0
38 38
39 39 $ mkdir d1
40 40 $ cd d1
41 41 $ echo c2 > f2
42 42 $ hg add f2
43 43 $ hg ci -m1
44 44 $ cd ../..
45 45
46 46 $ nlinksdir r1/.hg/store
47 47 1 r1/.hg/store/00changelog.i
48 48 1 r1/.hg/store/00manifest.i
49 49 1 r1/.hg/store/data/d1/f2.i
50 50 1 r1/.hg/store/data/f1.i
51 51 1 r1/.hg/store/fncache (repofncache !)
52 52 1 r1/.hg/store/phaseroots
53 53 1 r1/.hg/store/requires
54 54 1 r1/.hg/store/undo
55 1 r1/.hg/store/undo.backup.fncache (repofncache !)
55 1 r1/.hg/store/undo.backup.fncache.bck (repofncache !)
56 56 1 r1/.hg/store/undo.backupfiles
57 57
58 58
59 59 Create hardlinked clone r2:
60 60
61 61 $ hg clone -U --debug r1 r2 --config progress.debug=true
62 62 linking: 1/7 files (14.29%)
63 63 linking: 2/7 files (28.57%)
64 64 linking: 3/7 files (42.86%)
65 65 linking: 4/7 files (57.14%)
66 66 linking: 5/7 files (71.43%)
67 67 linking: 6/7 files (85.71%)
68 68 linking: 7/7 files (100.00%)
69 69 linked 7 files
70 70 updating the branch cache
71 71
72 72 Create non-hardlinked clone r3:
73 73
74 74 $ hg clone --pull r1 r3
75 75 requesting all changes
76 76 adding changesets
77 77 adding manifests
78 78 adding file changes
79 79 added 2 changesets with 2 changes to 2 files
80 80 new changesets 40d85e9847f2:7069c422939c
81 81 updating to branch default
82 82 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 83
84 84
85 85 Repos r1 and r2 should now contain hardlinked files:
86 86
87 87 $ nlinksdir r1/.hg/store
88 88 2 r1/.hg/store/00changelog.i
89 89 2 r1/.hg/store/00manifest.i
90 90 2 r1/.hg/store/data/d1/f2.i
91 91 2 r1/.hg/store/data/f1.i
92 92 1 r1/.hg/store/fncache (repofncache !)
93 93 1 r1/.hg/store/phaseroots
94 94 1 r1/.hg/store/requires
95 95 1 r1/.hg/store/undo
96 1 r1/.hg/store/undo.backup.fncache (repofncache !)
96 1 r1/.hg/store/undo.backup.fncache.bck (repofncache !)
97 97 1 r1/.hg/store/undo.backupfiles
98 98
99 99 $ nlinksdir r2/.hg/store
100 100 2 r2/.hg/store/00changelog.i
101 101 2 r2/.hg/store/00manifest.i
102 102 2 r2/.hg/store/data/d1/f2.i
103 103 2 r2/.hg/store/data/f1.i
104 104 1 r2/.hg/store/fncache (repofncache !)
105 105 1 r2/.hg/store/requires
106 106
107 107 Repo r3 should not be hardlinked:
108 108
109 109 $ nlinksdir r3/.hg/store
110 110 1 r3/.hg/store/00changelog.i
111 111 1 r3/.hg/store/00manifest.i
112 112 1 r3/.hg/store/data/d1/f2.i
113 113 1 r3/.hg/store/data/f1.i
114 114 1 r3/.hg/store/fncache (repofncache !)
115 115 1 r3/.hg/store/phaseroots
116 116 1 r3/.hg/store/requires
117 117 1 r3/.hg/store/undo
118 118 1 r3/.hg/store/undo.backupfiles
119 119
120 120
121 121 Create a non-inlined filelog in r3:
122 122
123 123 $ cd r3/d1
124 124 >>> f = open('data1', 'wb')
125 125 >>> for x in range(10000):
126 126 ... f.write(b"%d\n" % x) and None
127 127 >>> f.close()
128 128 $ for j in 0 1 2 3 4 5 6 7 8 9; do
129 129 > cat data1 >> f2
130 130 > hg commit -m$j
131 131 > done
132 132 $ cd ../..
133 133
134 134 $ nlinksdir r3/.hg/store
135 135 1 r3/.hg/store/00changelog.i
136 136 1 r3/.hg/store/00manifest.i
137 137 1 r3/.hg/store/data/d1/f2.d
138 138 1 r3/.hg/store/data/d1/f2.i
139 139 1 r3/.hg/store/data/f1.i
140 140 1 r3/.hg/store/fncache (repofncache !)
141 141 1 r3/.hg/store/phaseroots
142 142 1 r3/.hg/store/requires
143 143 1 r3/.hg/store/undo
144 144 1 r3/.hg/store/undo.backupfiles
145 145
146 146 Push to repo r1 should break up most hardlinks in r2:
147 147
148 148 $ hg -R r2 verify -q
149 149
150 150 $ cd r3
151 151 $ hg push
152 152 pushing to $TESTTMP/r1
153 153 searching for changes
154 154 adding changesets
155 155 adding manifests
156 156 adding file changes
157 157 added 10 changesets with 10 changes to 1 files
158 158
159 159 $ cd ..
160 160
161 161 $ nlinksdir r2/.hg/store
162 162 1 r2/.hg/store/00changelog.i
163 163 1 r2/.hg/store/00manifest.i
164 164 1 r2/.hg/store/data/d1/f2.i
165 165 2 r2/.hg/store/data/f1.i
166 166 [12] r2/\.hg/store/fncache (re) (repofncache !)
167 167 1 r2/.hg/store/requires
168 168
169 169 #if hardlink-whitelisted repofncache
170 170 $ nlinksdir r2/.hg/store/fncache
171 171 1 r2/.hg/store/fncache
172 172 #endif
173 173
174 174 $ hg -R r2 verify -q
175 175
176 176 $ cd r1
177 177 $ hg up
178 178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 179
180 180 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
181 181
182 182 $ echo c1c1 >> f1
183 183 $ hg ci -m00
184 184 $ cd ..
185 185
186 186 $ nlinksdir r2/.hg/store
187 187 1 r2/.hg/store/00changelog.i
188 188 1 r2/.hg/store/00manifest.i
189 189 1 r2/.hg/store/data/d1/f2.i
190 190 1 r2/.hg/store/data/f1.i
191 191 1 r2/.hg/store/fncache (repofncache !)
192 192 1 r2/.hg/store/requires
193 193
194 194 #if hardlink-whitelisted repofncache
195 195 $ nlinksdir r2/.hg/store/fncache
196 196 1 r2/.hg/store/fncache
197 197 #endif
198 198
199 199 Create a file which exec permissions we will change
200 200 $ cd r3
201 201 $ echo "echo hello world" > f3
202 202 $ hg add f3
203 203 $ hg ci -mf3
204 204 $ cd ..
205 205
206 206 $ cd r3
207 207 $ hg tip --template '{rev}:{node|short}\n'
208 208 12:d3b77733a28a
209 209 $ echo bla > f1
210 210 $ chmod +x f3
211 211 $ hg ci -m1
212 212 $ cd ..
213 213
214 214 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
215 215
216 216 $ linkcp r3 r4
217 217
218 218 'checklink' is produced by hardlinking a symlink, which is undefined whether
219 219 the symlink should be followed or not. It does behave differently on Linux and
220 220 BSD. Just remove it so the test pass on both platforms.
221 221
222 222 $ rm -f r4/.hg/wcache/checklink
223 223
224 224 r4 has hardlinks in the working dir (not just inside .hg):
225 225
226 226 $ nlinksdir r4
227 227 2 r4/.hg/00changelog.i
228 228 [24] r4/.hg/branch (re)
229 229 2 r4/.hg/cache/branch2-base
230 230 2 r4/.hg/cache/branch2-immutable
231 231 2 r4/.hg/cache/branch2-served
232 232 2 r4/.hg/cache/branch2-served.hidden
233 233 2 r4/.hg/cache/branch2-visible
234 234 2 r4/.hg/cache/branch2-visible-hidden
235 235 2 r4/.hg/cache/rbc-names-v1
236 236 2 r4/.hg/cache/rbc-revs-v1
237 237 2 r4/.hg/cache/tags2
238 238 2 r4/.hg/cache/tags2-served
239 239 2 r4/.hg/dirstate
240 240 2 r4/.hg/fsmonitor.state (fsmonitor !)
241 241 2 r4/.hg/hgrc
242 242 2 r4/.hg/last-message.txt
243 243 2 r4/.hg/requires
244 244 2 r4/.hg/store/00changelog.i
245 245 2 r4/.hg/store/00manifest.i
246 246 2 r4/.hg/store/data/d1/f2.d
247 247 2 r4/.hg/store/data/d1/f2.i
248 248 2 r4/.hg/store/data/f1.i
249 249 2 r4/.hg/store/data/f3.i
250 250 2 r4/.hg/store/fncache (repofncache !)
251 251 2 r4/.hg/store/phaseroots
252 252 2 r4/.hg/store/requires
253 253 2 r4/.hg/store/undo
254 254 2 r4/.hg/store/undo.backupfiles
255 [24] r4/.hg/undo.backup.branch (re)
256 2 r4/\.hg/undo\.backup\.dirstate (re)
255 [24] r4/.hg/undo.backup.branch.bck (re)
256 2 r4/\.hg/undo\.backup\.dirstate.bck (re)
257 257 2 r4/.hg/undo.desc
258 258 2 r4/.hg/wcache/checkisexec (execbit !)
259 259 2 r4/.hg/wcache/checklink-target (symlink !)
260 260 2 r4/.hg/wcache/checknoexec (execbit !)
261 261 2 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
262 262 2 r4/d1/data1
263 263 2 r4/d1/f2
264 264 2 r4/f1
265 265 2 r4/f3
266 266
267 267 Update back to revision 12 in r4 should break hardlink of file f1 and f3:
268 268 #if hardlink-whitelisted
269 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
269 $ nlinksdir r4/.hg/undo.backup.dirstate.bck r4/.hg/dirstate
270 270 2 r4/.hg/dirstate
271 2 r4/.hg/undo.backup.dirstate
271 2 r4/.hg/undo.backup.dirstate.bck
272 272 #endif
273 273
274 274
275 275 $ hg -R r4 up 12
276 276 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (execbit !)
277 277 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-execbit !)
278 278
279 279 $ nlinksdir r4
280 280 2 r4/.hg/00changelog.i
281 281 1 r4/.hg/branch
282 282 2 r4/.hg/cache/branch2-base
283 283 2 r4/.hg/cache/branch2-immutable
284 284 2 r4/.hg/cache/branch2-served
285 285 2 r4/.hg/cache/branch2-served.hidden
286 286 2 r4/.hg/cache/branch2-visible
287 287 2 r4/.hg/cache/branch2-visible-hidden
288 288 2 r4/.hg/cache/rbc-names-v1
289 289 2 r4/.hg/cache/rbc-revs-v1
290 290 2 r4/.hg/cache/tags2
291 291 2 r4/.hg/cache/tags2-served
292 292 1 r4/.hg/dirstate
293 293 1 r4/.hg/fsmonitor.state (fsmonitor !)
294 294 2 r4/.hg/hgrc
295 295 2 r4/.hg/last-message.txt
296 296 2 r4/.hg/requires
297 297 2 r4/.hg/store/00changelog.i
298 298 2 r4/.hg/store/00manifest.i
299 299 2 r4/.hg/store/data/d1/f2.d
300 300 2 r4/.hg/store/data/d1/f2.i
301 301 2 r4/.hg/store/data/f1.i
302 302 2 r4/.hg/store/data/f3.i
303 303 2 r4/.hg/store/fncache
304 304 2 r4/.hg/store/phaseroots
305 305 2 r4/.hg/store/requires
306 306 2 r4/.hg/store/undo
307 307 2 r4/.hg/store/undo.backupfiles
308 [23] r4/.hg/undo.backup.branch (re)
309 2 r4/\.hg/undo\.backup\.dirstate (re)
308 [23] r4/.hg/undo.backup.branch.bck (re)
309 2 r4/\.hg/undo\.backup\.dirstate.bck (re)
310 310 2 r4/.hg/undo.desc
311 311 2 r4/.hg/wcache/checkisexec (execbit !)
312 312 2 r4/.hg/wcache/checklink-target (symlink !)
313 313 2 r4/.hg/wcache/checknoexec (execbit !)
314 314 1 r4/.hg/wcache/manifestfulltextcache (reporevlogstore !)
315 315 2 r4/d1/data1
316 316 2 r4/d1/f2
317 317 1 r4/f1
318 318 1 r4/f3 (execbit !)
319 319 2 r4/f3 (no-execbit !)
320 320
321 321 #if hardlink-whitelisted
322 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/dirstate
322 $ nlinksdir r4/.hg/undo.backup.dirstate.bck r4/.hg/dirstate
323 323 1 r4/.hg/dirstate
324 2 r4/.hg/undo.backup.dirstate
324 2 r4/.hg/undo.backup.dirstate.bck
325 325 #endif
326 326
327 327 Test hardlinking outside hg:
328 328
329 329 $ mkdir x
330 330 $ echo foo > x/a
331 331
332 332 $ linkcp x y
333 333 $ echo bar >> y/a
334 334
335 335 No diff if hardlink:
336 336
337 337 $ diff x/a y/a
338 338
339 339 Test mq hardlinking:
340 340
341 341 $ echo "[extensions]" >> $HGRCPATH
342 342 $ echo "mq=" >> $HGRCPATH
343 343
344 344 $ hg init a
345 345 $ cd a
346 346
347 347 $ hg qimport -n foo - << EOF
348 348 > # HG changeset patch
349 349 > # Date 1 0
350 350 > diff -r 2588a8b53d66 a
351 351 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
352 352 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
353 353 > @@ -0,0 +1,1 @@
354 354 > +a
355 355 > EOF
356 356 adding foo to series file
357 357
358 358 $ hg qpush
359 359 applying foo
360 360 now at: foo
361 361
362 362 $ cd ..
363 363 $ linkcp a b
364 364 $ cd b
365 365
366 366 $ hg qimport -n bar - << EOF
367 367 > # HG changeset patch
368 368 > # Date 2 0
369 369 > diff -r 2588a8b53d66 a
370 370 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
371 371 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
372 372 > @@ -0,0 +1,1 @@
373 373 > +b
374 374 > EOF
375 375 adding bar to series file
376 376
377 377 $ hg qpush
378 378 applying bar
379 379 now at: bar
380 380
381 381 $ cat .hg/patches/status
382 382 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
383 383 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
384 384
385 385 $ cat .hg/patches/series
386 386 foo
387 387 bar
388 388
389 389 $ cat ../a/.hg/patches/status
390 390 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
391 391
392 392 $ cat ../a/.hg/patches/series
393 393 foo
394 394
395 395 Test tags hardlinking:
396 396
397 397 $ hg qdel -r qbase:qtip
398 398 patch foo finalized without changeset message
399 399 patch bar finalized without changeset message
400 400
401 401 $ hg tag -l lfoo
402 402 $ hg tag foo
403 403
404 404 $ cd ..
405 405 $ linkcp b c
406 406 $ cd c
407 407
408 408 $ hg tag -l -r 0 lbar
409 409 $ hg tag -r 0 bar
410 410
411 411 $ cat .hgtags
412 412 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
413 413 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
414 414
415 415 $ cat .hg/localtags
416 416 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
417 417 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
418 418
419 419 $ cat ../b/.hgtags
420 420 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
421 421
422 422 $ cat ../b/.hg/localtags
423 423 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
424 424
425 425 $ cd ..
@@ -1,1463 +1,1463 b''
1 1 commit hooks can see env vars
2 2 (and post-transaction one are run unlocked)
3 3
4 4
5 5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
6 6 > from mercurial import pycompat
7 7 > def showargs(ui, repo, hooktype, **kwargs):
8 8 > kwargs = pycompat.byteskwargs(kwargs)
9 9 > ui.write(b'%s Python hook: %s\n' % (hooktype,
10 10 > b','.join(sorted(kwargs))))
11 11 > EOF
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ cat > .hg/hgrc <<EOF
16 16 > [hooks]
17 17 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit"
18 18 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit.b"
19 19 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py --line precommit"
20 20 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxncommit"
21 21 > pretxncommit.tip = hg -q tip
22 22 > pre-identify = sh -c "printenv.py --line pre-identify 1"
23 23 > pre-cat = sh -c "printenv.py --line pre-cat"
24 24 > post-cat = sh -c "printenv.py --line post-cat"
25 25 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnopen"
26 26 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnclose"
27 27 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnclose"
28 28 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
29 29 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnabort"
30 30 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
31 31 > EOF
32 32 $ echo a > a
33 33 $ hg add a
34 34 $ hg commit -m a
35 35 precommit hook: HG_HOOKNAME=precommit
36 36 HG_HOOKTYPE=precommit
37 37 HG_PARENT1=0000000000000000000000000000000000000000
38 38
39 39 pretxnopen hook: HG_HOOKNAME=pretxnopen
40 40 HG_HOOKTYPE=pretxnopen
41 41 HG_TXNID=TXN:$ID$
42 42 HG_TXNNAME=commit
43 43
44 44 pretxncommit hook: HG_HOOKNAME=pretxncommit
45 45 HG_HOOKTYPE=pretxncommit
46 46 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 47 HG_PARENT1=0000000000000000000000000000000000000000
48 48 HG_PENDING=$TESTTMP/a
49 49
50 50 0:cb9a9f314b8b
51 51 pretxnclose hook: HG_HOOKNAME=pretxnclose
52 52 HG_HOOKTYPE=pretxnclose
53 53 HG_PENDING=$TESTTMP/a
54 54 HG_PHASES_MOVED=1
55 55 HG_TXNID=TXN:$ID$
56 56 HG_TXNNAME=commit
57 57
58 58 txnclose hook: HG_HOOKNAME=txnclose
59 59 HG_HOOKTYPE=txnclose
60 60 HG_PHASES_MOVED=1
61 61 HG_TXNID=TXN:$ID$
62 62 HG_TXNNAME=commit
63 63
64 64 commit hook: HG_HOOKNAME=commit
65 65 HG_HOOKTYPE=commit
66 66 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 67 HG_PARENT1=0000000000000000000000000000000000000000
68 68
69 69 commit.b hook: HG_HOOKNAME=commit.b
70 70 HG_HOOKTYPE=commit
71 71 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 72 HG_PARENT1=0000000000000000000000000000000000000000
73 73
74 74
75 75 $ hg clone . ../b
76 76 updating to branch default
77 77 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ cd ../b
79 79
80 80 changegroup hooks can see env vars
81 81
82 82 $ cat > .hg/hgrc <<EOF
83 83 > [hooks]
84 84 > prechangegroup = sh -c "printenv.py --line prechangegroup"
85 85 > changegroup = sh -c "printenv.py --line changegroup"
86 86 > incoming = sh -c "printenv.py --line incoming"
87 87 > EOF
88 88
89 89 pretxncommit and commit hooks can see both parents of merge
90 90
91 91 $ cd ../a
92 92 $ echo b >> a
93 93 $ hg commit -m a1 -d "1 0"
94 94 precommit hook: HG_HOOKNAME=precommit
95 95 HG_HOOKTYPE=precommit
96 96 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
97 97
98 98 pretxnopen hook: HG_HOOKNAME=pretxnopen
99 99 HG_HOOKTYPE=pretxnopen
100 100 HG_TXNID=TXN:$ID$
101 101 HG_TXNNAME=commit
102 102
103 103 pretxncommit hook: HG_HOOKNAME=pretxncommit
104 104 HG_HOOKTYPE=pretxncommit
105 105 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
106 106 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
107 107 HG_PENDING=$TESTTMP/a
108 108
109 109 1:ab228980c14d
110 110 pretxnclose hook: HG_HOOKNAME=pretxnclose
111 111 HG_HOOKTYPE=pretxnclose
112 112 HG_PENDING=$TESTTMP/a
113 113 HG_TXNID=TXN:$ID$
114 114 HG_TXNNAME=commit
115 115
116 116 txnclose hook: HG_HOOKNAME=txnclose
117 117 HG_HOOKTYPE=txnclose
118 118 HG_TXNID=TXN:$ID$
119 119 HG_TXNNAME=commit
120 120
121 121 commit hook: HG_HOOKNAME=commit
122 122 HG_HOOKTYPE=commit
123 123 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
124 124 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
125 125
126 126 commit.b hook: HG_HOOKNAME=commit.b
127 127 HG_HOOKTYPE=commit
128 128 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
129 129 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
130 130
131 131 $ hg update -C 0
132 132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 133 $ echo b > b
134 134 $ hg add b
135 135 $ hg commit -m b -d '1 0'
136 136 precommit hook: HG_HOOKNAME=precommit
137 137 HG_HOOKTYPE=precommit
138 138 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
139 139
140 140 pretxnopen hook: HG_HOOKNAME=pretxnopen
141 141 HG_HOOKTYPE=pretxnopen
142 142 HG_TXNID=TXN:$ID$
143 143 HG_TXNNAME=commit
144 144
145 145 pretxncommit hook: HG_HOOKNAME=pretxncommit
146 146 HG_HOOKTYPE=pretxncommit
147 147 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
148 148 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
149 149 HG_PENDING=$TESTTMP/a
150 150
151 151 2:ee9deb46ab31
152 152 pretxnclose hook: HG_HOOKNAME=pretxnclose
153 153 HG_HOOKTYPE=pretxnclose
154 154 HG_PENDING=$TESTTMP/a
155 155 HG_TXNID=TXN:$ID$
156 156 HG_TXNNAME=commit
157 157
158 158 created new head
159 159 txnclose hook: HG_HOOKNAME=txnclose
160 160 HG_HOOKTYPE=txnclose
161 161 HG_TXNID=TXN:$ID$
162 162 HG_TXNNAME=commit
163 163
164 164 commit hook: HG_HOOKNAME=commit
165 165 HG_HOOKTYPE=commit
166 166 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
167 167 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
168 168
169 169 commit.b hook: HG_HOOKNAME=commit.b
170 170 HG_HOOKTYPE=commit
171 171 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
172 172 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
173 173
174 174 $ hg merge 1
175 175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 176 (branch merge, don't forget to commit)
177 177 $ hg commit -m merge -d '2 0'
178 178 precommit hook: HG_HOOKNAME=precommit
179 179 HG_HOOKTYPE=precommit
180 180 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
181 181 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
182 182
183 183 pretxnopen hook: HG_HOOKNAME=pretxnopen
184 184 HG_HOOKTYPE=pretxnopen
185 185 HG_TXNID=TXN:$ID$
186 186 HG_TXNNAME=commit
187 187
188 188 pretxncommit hook: HG_HOOKNAME=pretxncommit
189 189 HG_HOOKTYPE=pretxncommit
190 190 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
191 191 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
192 192 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
193 193 HG_PENDING=$TESTTMP/a
194 194
195 195 3:07f3376c1e65
196 196 pretxnclose hook: HG_HOOKNAME=pretxnclose
197 197 HG_HOOKTYPE=pretxnclose
198 198 HG_PENDING=$TESTTMP/a
199 199 HG_TXNID=TXN:$ID$
200 200 HG_TXNNAME=commit
201 201
202 202 txnclose hook: HG_HOOKNAME=txnclose
203 203 HG_HOOKTYPE=txnclose
204 204 HG_TXNID=TXN:$ID$
205 205 HG_TXNNAME=commit
206 206
207 207 commit hook: HG_HOOKNAME=commit
208 208 HG_HOOKTYPE=commit
209 209 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
210 210 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
211 211 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
212 212
213 213 commit.b hook: HG_HOOKNAME=commit.b
214 214 HG_HOOKTYPE=commit
215 215 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
216 216 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
217 217 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
218 218
219 219
220 220 test generic hooks
221 221
222 222 $ hg id
223 223 pre-identify hook: HG_ARGS=id
224 224 HG_HOOKNAME=pre-identify
225 225 HG_HOOKTYPE=pre-identify
226 226 HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None, 'template': ''}
227 227 HG_PATS=[]
228 228
229 229 abort: pre-identify hook exited with status 1
230 230 [40]
231 231 $ hg cat b
232 232 pre-cat hook: HG_ARGS=cat b
233 233 HG_HOOKNAME=pre-cat
234 234 HG_HOOKTYPE=pre-cat
235 235 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
236 236 HG_PATS=['b']
237 237
238 238 b
239 239 post-cat hook: HG_ARGS=cat b
240 240 HG_HOOKNAME=post-cat
241 241 HG_HOOKTYPE=post-cat
242 242 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
243 243 HG_PATS=['b']
244 244 HG_RESULT=0
245 245
246 246
247 247 $ cd ../b
248 248 $ hg pull ../a
249 249 pulling from ../a
250 250 searching for changes
251 251 prechangegroup hook: HG_HOOKNAME=prechangegroup
252 252 HG_HOOKTYPE=prechangegroup
253 253 HG_SOURCE=pull
254 254 HG_TXNID=TXN:$ID$
255 255 HG_TXNNAME=pull
256 256 file:/*/$TESTTMP/a (glob)
257 257 HG_URL=file:$TESTTMP/a
258 258
259 259 adding changesets
260 260 adding manifests
261 261 adding file changes
262 262 added 3 changesets with 2 changes to 2 files
263 263 new changesets ab228980c14d:07f3376c1e65
264 264 changegroup hook: HG_HOOKNAME=changegroup
265 265 HG_HOOKTYPE=changegroup
266 266 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
267 267 HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2
268 268 HG_SOURCE=pull
269 269 HG_TXNID=TXN:$ID$
270 270 HG_TXNNAME=pull
271 271 file:/*/$TESTTMP/a (glob)
272 272 HG_URL=file:$TESTTMP/a
273 273
274 274 incoming hook: HG_HOOKNAME=incoming
275 275 HG_HOOKTYPE=incoming
276 276 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
277 277 HG_SOURCE=pull
278 278 HG_TXNID=TXN:$ID$
279 279 HG_TXNNAME=pull
280 280 file:/*/$TESTTMP/a (glob)
281 281 HG_URL=file:$TESTTMP/a
282 282
283 283 incoming hook: HG_HOOKNAME=incoming
284 284 HG_HOOKTYPE=incoming
285 285 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
286 286 HG_SOURCE=pull
287 287 HG_TXNID=TXN:$ID$
288 288 HG_TXNNAME=pull
289 289 file:/*/$TESTTMP/a (glob)
290 290 HG_URL=file:$TESTTMP/a
291 291
292 292 incoming hook: HG_HOOKNAME=incoming
293 293 HG_HOOKTYPE=incoming
294 294 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
295 295 HG_SOURCE=pull
296 296 HG_TXNID=TXN:$ID$
297 297 HG_TXNNAME=pull
298 298 file:/*/$TESTTMP/a (glob)
299 299 HG_URL=file:$TESTTMP/a
300 300
301 301 (run 'hg update' to get a working copy)
302 302
303 303 tag hooks can see env vars
304 304
305 305 $ cd ../a
306 306 $ cat >> .hg/hgrc <<EOF
307 307 > pretag = sh -c "printenv.py --line pretag"
308 308 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py --line tag"
309 309 > EOF
310 310 $ hg tag -d '3 0' a
311 311 pretag hook: HG_HOOKNAME=pretag
312 312 HG_HOOKTYPE=pretag
313 313 HG_LOCAL=0
314 314 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
315 315 HG_TAG=a
316 316
317 317 precommit hook: HG_HOOKNAME=precommit
318 318 HG_HOOKTYPE=precommit
319 319 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
320 320
321 321 pretxnopen hook: HG_HOOKNAME=pretxnopen
322 322 HG_HOOKTYPE=pretxnopen
323 323 HG_TXNID=TXN:$ID$
324 324 HG_TXNNAME=commit
325 325
326 326 pretxncommit hook: HG_HOOKNAME=pretxncommit
327 327 HG_HOOKTYPE=pretxncommit
328 328 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
329 329 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
330 330 HG_PENDING=$TESTTMP/a
331 331
332 332 4:539e4b31b6dc
333 333 pretxnclose hook: HG_HOOKNAME=pretxnclose
334 334 HG_HOOKTYPE=pretxnclose
335 335 HG_PENDING=$TESTTMP/a
336 336 HG_TXNID=TXN:$ID$
337 337 HG_TXNNAME=commit
338 338
339 339 tag hook: HG_HOOKNAME=tag
340 340 HG_HOOKTYPE=tag
341 341 HG_LOCAL=0
342 342 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
343 343 HG_TAG=a
344 344
345 345 txnclose hook: HG_HOOKNAME=txnclose
346 346 HG_HOOKTYPE=txnclose
347 347 HG_TXNID=TXN:$ID$
348 348 HG_TXNNAME=commit
349 349
350 350 commit hook: HG_HOOKNAME=commit
351 351 HG_HOOKTYPE=commit
352 352 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
353 353 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
354 354
355 355 commit.b hook: HG_HOOKNAME=commit.b
356 356 HG_HOOKTYPE=commit
357 357 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
358 358 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
359 359
360 360 $ hg tag -l la
361 361 pretag hook: HG_HOOKNAME=pretag
362 362 HG_HOOKTYPE=pretag
363 363 HG_LOCAL=1
364 364 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
365 365 HG_TAG=la
366 366
367 367 tag hook: HG_HOOKNAME=tag
368 368 HG_HOOKTYPE=tag
369 369 HG_LOCAL=1
370 370 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
371 371 HG_TAG=la
372 372
373 373
374 374 pretag hook can forbid tagging
375 375
376 376 $ cat >> .hg/hgrc <<EOF
377 377 > pretag.forbid = sh -c "printenv.py --line pretag.forbid 1"
378 378 > EOF
379 379 $ hg tag -d '4 0' fa
380 380 pretag hook: HG_HOOKNAME=pretag
381 381 HG_HOOKTYPE=pretag
382 382 HG_LOCAL=0
383 383 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
384 384 HG_TAG=fa
385 385
386 386 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
387 387 HG_HOOKTYPE=pretag
388 388 HG_LOCAL=0
389 389 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
390 390 HG_TAG=fa
391 391
392 392 abort: pretag.forbid hook exited with status 1
393 393 [40]
394 394 $ hg tag -l fla
395 395 pretag hook: HG_HOOKNAME=pretag
396 396 HG_HOOKTYPE=pretag
397 397 HG_LOCAL=1
398 398 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
399 399 HG_TAG=fla
400 400
401 401 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
402 402 HG_HOOKTYPE=pretag
403 403 HG_LOCAL=1
404 404 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
405 405 HG_TAG=fla
406 406
407 407 abort: pretag.forbid hook exited with status 1
408 408 [40]
409 409
410 410 pretxncommit hook can see changeset, can roll back txn, changeset no
411 411 more there after
412 412
413 413 $ cat >> .hg/hgrc <<EOF
414 414 > pretxncommit.forbid0 = sh -c "hg tip -q"
415 415 > pretxncommit.forbid1 = sh -c "printenv.py --line pretxncommit.forbid 1"
416 416 > EOF
417 417 $ echo z > z
418 418 $ hg add z
419 419 $ hg -q tip
420 420 4:539e4b31b6dc
421 421 $ hg commit -m 'fail' -d '4 0'
422 422 precommit hook: HG_HOOKNAME=precommit
423 423 HG_HOOKTYPE=precommit
424 424 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
425 425
426 426 pretxnopen hook: HG_HOOKNAME=pretxnopen
427 427 HG_HOOKTYPE=pretxnopen
428 428 HG_TXNID=TXN:$ID$
429 429 HG_TXNNAME=commit
430 430
431 431 pretxncommit hook: HG_HOOKNAME=pretxncommit
432 432 HG_HOOKTYPE=pretxncommit
433 433 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
434 434 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
435 435 HG_PENDING=$TESTTMP/a
436 436
437 437 5:6f611f8018c1
438 438 5:6f611f8018c1
439 439 pretxncommit.forbid hook: HG_HOOKNAME=pretxncommit.forbid1
440 440 HG_HOOKTYPE=pretxncommit
441 441 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
442 442 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
443 443 HG_PENDING=$TESTTMP/a
444 444
445 445 transaction abort!
446 446 txnabort Python hook: changes,txnid,txnname
447 447 txnabort hook: HG_HOOKNAME=txnabort.1
448 448 HG_HOOKTYPE=txnabort
449 449 HG_TXNID=TXN:$ID$
450 450 HG_TXNNAME=commit
451 451
452 452 rollback completed
453 453 abort: pretxncommit.forbid1 hook exited with status 1
454 454 [40]
455 455 $ hg -q tip
456 456 4:539e4b31b6dc
457 457
458 458 (Check that no 'changelog.i.a' file were left behind)
459 459
460 460 $ ls -1 .hg/store/
461 461 00changelog.i
462 462 00manifest.i
463 463 data
464 464 fncache (repofncache !)
465 465 phaseroots
466 466 requires
467 467 undo
468 undo.backup.fncache (repofncache !)
468 undo.backup.fncache.bck (repofncache !)
469 469 undo.backupfiles
470 470
471 471
472 472 precommit hook can prevent commit
473 473
474 474 $ cat >> .hg/hgrc <<EOF
475 475 > precommit.forbid = sh -c "printenv.py --line precommit.forbid 1"
476 476 > EOF
477 477 $ hg commit -m 'fail' -d '4 0'
478 478 precommit hook: HG_HOOKNAME=precommit
479 479 HG_HOOKTYPE=precommit
480 480 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
481 481
482 482 precommit.forbid hook: HG_HOOKNAME=precommit.forbid
483 483 HG_HOOKTYPE=precommit
484 484 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
485 485
486 486 abort: precommit.forbid hook exited with status 1
487 487 [40]
488 488 $ hg -q tip
489 489 4:539e4b31b6dc
490 490
491 491 preupdate hook can prevent update
492 492
493 493 $ cat >> .hg/hgrc <<EOF
494 494 > preupdate = sh -c "printenv.py --line preupdate"
495 495 > EOF
496 496 $ hg update 1
497 497 preupdate hook: HG_HOOKNAME=preupdate
498 498 HG_HOOKTYPE=preupdate
499 499 HG_PARENT1=ab228980c14d
500 500
501 501 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
502 502
503 503 update hook
504 504
505 505 $ cat >> .hg/hgrc <<EOF
506 506 > update = sh -c "printenv.py --line update"
507 507 > EOF
508 508 $ hg update
509 509 preupdate hook: HG_HOOKNAME=preupdate
510 510 HG_HOOKTYPE=preupdate
511 511 HG_PARENT1=539e4b31b6dc
512 512
513 513 update hook: HG_ERROR=0
514 514 HG_HOOKNAME=update
515 515 HG_HOOKTYPE=update
516 516 HG_PARENT1=539e4b31b6dc
517 517
518 518 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 519
520 520 pushkey hook
521 521
522 522 $ cat >> .hg/hgrc <<EOF
523 523 > pushkey = sh -c "printenv.py --line pushkey"
524 524 > EOF
525 525 $ cd ../b
526 526 $ hg bookmark -r null foo
527 527 $ hg push -B foo ../a
528 528 pushing to ../a
529 529 searching for changes
530 530 no changes found
531 531 pretxnopen hook: HG_HOOKNAME=pretxnopen
532 532 HG_HOOKTYPE=pretxnopen
533 533 HG_TXNID=TXN:$ID$
534 534 HG_TXNNAME=push
535 535
536 536 pretxnclose hook: HG_BOOKMARK_MOVED=1
537 537 HG_BUNDLE2=1
538 538 HG_HOOKNAME=pretxnclose
539 539 HG_HOOKTYPE=pretxnclose
540 540 HG_PENDING=$TESTTMP/a
541 541 HG_SOURCE=push
542 542 HG_TXNID=TXN:$ID$
543 543 HG_TXNNAME=push
544 544 HG_URL=file:$TESTTMP/a
545 545
546 546 pushkey hook: HG_BUNDLE2=1
547 547 HG_HOOKNAME=pushkey
548 548 HG_HOOKTYPE=pushkey
549 549 HG_KEY=foo
550 550 HG_NAMESPACE=bookmarks
551 551 HG_NEW=0000000000000000000000000000000000000000
552 552 HG_PUSHKEYCOMPAT=1
553 553 HG_SOURCE=push
554 554 HG_TXNID=TXN:$ID$
555 555 HG_TXNNAME=push
556 556 HG_URL=file:$TESTTMP/a
557 557
558 558 txnclose hook: HG_BOOKMARK_MOVED=1
559 559 HG_BUNDLE2=1
560 560 HG_HOOKNAME=txnclose
561 561 HG_HOOKTYPE=txnclose
562 562 HG_SOURCE=push
563 563 HG_TXNID=TXN:$ID$
564 564 HG_TXNNAME=push
565 565 HG_URL=file:$TESTTMP/a
566 566
567 567 exporting bookmark foo
568 568 [1]
569 569 $ cd ../a
570 570
571 571 listkeys hook
572 572
573 573 $ cat >> .hg/hgrc <<EOF
574 574 > listkeys = sh -c "printenv.py --line listkeys"
575 575 > EOF
576 576 $ hg bookmark -r null bar
577 577 pretxnopen hook: HG_HOOKNAME=pretxnopen
578 578 HG_HOOKTYPE=pretxnopen
579 579 HG_TXNID=TXN:$ID$
580 580 HG_TXNNAME=bookmark
581 581
582 582 pretxnclose hook: HG_BOOKMARK_MOVED=1
583 583 HG_HOOKNAME=pretxnclose
584 584 HG_HOOKTYPE=pretxnclose
585 585 HG_PENDING=$TESTTMP/a
586 586 HG_TXNID=TXN:$ID$
587 587 HG_TXNNAME=bookmark
588 588
589 589 txnclose hook: HG_BOOKMARK_MOVED=1
590 590 HG_HOOKNAME=txnclose
591 591 HG_HOOKTYPE=txnclose
592 592 HG_TXNID=TXN:$ID$
593 593 HG_TXNNAME=bookmark
594 594
595 595 $ cd ../b
596 596 $ hg pull -B bar ../a
597 597 pulling from ../a
598 598 listkeys hook: HG_HOOKNAME=listkeys
599 599 HG_HOOKTYPE=listkeys
600 600 HG_NAMESPACE=bookmarks
601 601 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
602 602
603 603 no changes found
604 604 adding remote bookmark bar
605 605 $ cd ../a
606 606
607 607 test that prepushkey can prevent incoming keys
608 608
609 609 $ cat >> .hg/hgrc <<EOF
610 610 > prepushkey = sh -c "printenv.py --line prepushkey.forbid 1"
611 611 > EOF
612 612 $ cd ../b
613 613 $ hg bookmark -r null baz
614 614 $ hg push -B baz ../a
615 615 pushing to ../a
616 616 searching for changes
617 617 listkeys hook: HG_HOOKNAME=listkeys
618 618 HG_HOOKTYPE=listkeys
619 619 HG_NAMESPACE=phases
620 620 HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
621 621
622 622 listkeys hook: HG_HOOKNAME=listkeys
623 623 HG_HOOKTYPE=listkeys
624 624 HG_NAMESPACE=bookmarks
625 625 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
626 626
627 627 no changes found
628 628 pretxnopen hook: HG_HOOKNAME=pretxnopen
629 629 HG_HOOKTYPE=pretxnopen
630 630 HG_TXNID=TXN:$ID$
631 631 HG_TXNNAME=push
632 632
633 633 prepushkey.forbid hook: HG_BUNDLE2=1
634 634 HG_HOOKNAME=prepushkey
635 635 HG_HOOKTYPE=prepushkey
636 636 HG_KEY=baz
637 637 HG_NAMESPACE=bookmarks
638 638 HG_NEW=0000000000000000000000000000000000000000
639 639 HG_PUSHKEYCOMPAT=1
640 640 HG_SOURCE=push
641 641 HG_TXNID=TXN:$ID$
642 642 HG_TXNNAME=push
643 643 HG_URL=file:$TESTTMP/a
644 644
645 645 txnabort Python hook: bundle2,changes,source,txnid,txnname,url
646 646 txnabort hook: HG_BUNDLE2=1
647 647 HG_HOOKNAME=txnabort.1
648 648 HG_HOOKTYPE=txnabort
649 649 HG_SOURCE=push
650 650 HG_TXNID=TXN:$ID$
651 651 HG_TXNNAME=push
652 652 HG_URL=file:$TESTTMP/a
653 653
654 654 abort: prepushkey hook exited with status 1
655 655 [40]
656 656 $ cd ../a
657 657
658 658 test that prelistkeys can prevent listing keys
659 659
660 660 $ cat >> .hg/hgrc <<EOF
661 661 > prelistkeys = sh -c "printenv.py --line prelistkeys.forbid 1"
662 662 > EOF
663 663 $ hg bookmark -r null quux
664 664 pretxnopen hook: HG_HOOKNAME=pretxnopen
665 665 HG_HOOKTYPE=pretxnopen
666 666 HG_TXNID=TXN:$ID$
667 667 HG_TXNNAME=bookmark
668 668
669 669 pretxnclose hook: HG_BOOKMARK_MOVED=1
670 670 HG_HOOKNAME=pretxnclose
671 671 HG_HOOKTYPE=pretxnclose
672 672 HG_PENDING=$TESTTMP/a
673 673 HG_TXNID=TXN:$ID$
674 674 HG_TXNNAME=bookmark
675 675
676 676 txnclose hook: HG_BOOKMARK_MOVED=1
677 677 HG_HOOKNAME=txnclose
678 678 HG_HOOKTYPE=txnclose
679 679 HG_TXNID=TXN:$ID$
680 680 HG_TXNNAME=bookmark
681 681
682 682 $ cd ../b
683 683 $ hg pull -B quux ../a
684 684 pulling from ../a
685 685 prelistkeys.forbid hook: HG_HOOKNAME=prelistkeys
686 686 HG_HOOKTYPE=prelistkeys
687 687 HG_NAMESPACE=bookmarks
688 688
689 689 abort: prelistkeys hook exited with status 1
690 690 [40]
691 691 $ cd ../a
692 692 $ rm .hg/hgrc
693 693
694 694 prechangegroup hook can prevent incoming changes
695 695
696 696 $ cd ../b
697 697 $ hg -q tip
698 698 3:07f3376c1e65
699 699 $ cat > .hg/hgrc <<EOF
700 700 > [hooks]
701 701 > prechangegroup.forbid = sh -c "printenv.py --line prechangegroup.forbid 1"
702 702 > EOF
703 703 $ hg pull ../a
704 704 pulling from ../a
705 705 searching for changes
706 706 prechangegroup.forbid hook: HG_HOOKNAME=prechangegroup.forbid
707 707 HG_HOOKTYPE=prechangegroup
708 708 HG_SOURCE=pull
709 709 HG_TXNID=TXN:$ID$
710 710 HG_TXNNAME=pull
711 711 file:/*/$TESTTMP/a (glob)
712 712 HG_URL=file:$TESTTMP/a
713 713
714 714 abort: prechangegroup.forbid hook exited with status 1
715 715 [40]
716 716
717 717 pretxnchangegroup hook can see incoming changes, can roll back txn,
718 718 incoming changes no longer there after
719 719
720 720 $ cat > .hg/hgrc <<EOF
721 721 > [hooks]
722 722 > pretxnchangegroup.forbid0 = hg tip -q
723 723 > pretxnchangegroup.forbid1 = sh -c "printenv.py --line pretxnchangegroup.forbid 1"
724 724 > EOF
725 725 $ hg pull ../a
726 726 pulling from ../a
727 727 searching for changes
728 728 adding changesets
729 729 adding manifests
730 730 adding file changes
731 731 4:539e4b31b6dc
732 732 pretxnchangegroup.forbid hook: HG_HOOKNAME=pretxnchangegroup.forbid1
733 733 HG_HOOKTYPE=pretxnchangegroup
734 734 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
735 735 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
736 736 HG_PENDING=$TESTTMP/b
737 737 HG_SOURCE=pull
738 738 HG_TXNID=TXN:$ID$
739 739 HG_TXNNAME=pull
740 740 file:/*/$TESTTMP/a (glob)
741 741 HG_URL=file:$TESTTMP/a
742 742
743 743 transaction abort!
744 744 rollback completed
745 745 abort: pretxnchangegroup.forbid1 hook exited with status 1
746 746 [40]
747 747 $ hg -q tip
748 748 3:07f3376c1e65
749 749
750 750 outgoing hooks can see env vars
751 751
752 752 $ rm .hg/hgrc
753 753 $ cat > ../a/.hg/hgrc <<EOF
754 754 > [hooks]
755 755 > preoutgoing = sh -c "printenv.py --line preoutgoing"
756 756 > outgoing = sh -c "printenv.py --line outgoing"
757 757 > EOF
758 758 $ hg pull ../a
759 759 pulling from ../a
760 760 searching for changes
761 761 preoutgoing hook: HG_HOOKNAME=preoutgoing
762 762 HG_HOOKTYPE=preoutgoing
763 763 HG_SOURCE=pull
764 764
765 765 outgoing hook: HG_HOOKNAME=outgoing
766 766 HG_HOOKTYPE=outgoing
767 767 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
768 768 HG_SOURCE=pull
769 769
770 770 adding changesets
771 771 adding manifests
772 772 adding file changes
773 773 adding remote bookmark quux
774 774 added 1 changesets with 1 changes to 1 files
775 775 new changesets 539e4b31b6dc
776 776 (run 'hg update' to get a working copy)
777 777 $ hg rollback
778 778 repository tip rolled back to revision 3 (undo pull)
779 779
780 780 preoutgoing hook can prevent outgoing changes
781 781
782 782 $ cat >> ../a/.hg/hgrc <<EOF
783 783 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
784 784 > EOF
785 785 $ hg pull ../a
786 786 pulling from ../a
787 787 searching for changes
788 788 preoutgoing hook: HG_HOOKNAME=preoutgoing
789 789 HG_HOOKTYPE=preoutgoing
790 790 HG_SOURCE=pull
791 791
792 792 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
793 793 HG_HOOKTYPE=preoutgoing
794 794 HG_SOURCE=pull
795 795
796 796 abort: preoutgoing.forbid hook exited with status 1
797 797 [40]
798 798
799 799 outgoing hooks work for local clones
800 800
801 801 $ cd ..
802 802 $ cat > a/.hg/hgrc <<EOF
803 803 > [hooks]
804 804 > preoutgoing = sh -c "printenv.py --line preoutgoing"
805 805 > outgoing = sh -c "printenv.py --line outgoing"
806 806 > EOF
807 807 $ hg clone a c
808 808 preoutgoing hook: HG_HOOKNAME=preoutgoing
809 809 HG_HOOKTYPE=preoutgoing
810 810 HG_SOURCE=clone
811 811
812 812 outgoing hook: HG_HOOKNAME=outgoing
813 813 HG_HOOKTYPE=outgoing
814 814 HG_NODE=0000000000000000000000000000000000000000
815 815 HG_SOURCE=clone
816 816
817 817 updating to branch default
818 818 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
819 819 $ rm -rf c
820 820
821 821 preoutgoing hook can prevent outgoing changes for local clones
822 822
823 823 $ cat >> a/.hg/hgrc <<EOF
824 824 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
825 825 > EOF
826 826 $ hg clone a zzz
827 827 preoutgoing hook: HG_HOOKNAME=preoutgoing
828 828 HG_HOOKTYPE=preoutgoing
829 829 HG_SOURCE=clone
830 830
831 831 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
832 832 HG_HOOKTYPE=preoutgoing
833 833 HG_SOURCE=clone
834 834
835 835 abort: preoutgoing.forbid hook exited with status 1
836 836 [40]
837 837
838 838 $ cd "$TESTTMP/b"
839 839
840 840 $ cat > hooktests.py <<EOF
841 841 > from mercurial import (
842 842 > error,
843 843 > pycompat,
844 844 > )
845 845 >
846 846 > uncallable = 0
847 847 >
848 848 > def printargs(ui, args):
849 849 > a = list(pycompat.byteskwargs(args).items())
850 850 > a.sort()
851 851 > ui.write(b'hook args:\n')
852 852 > for k, v in a:
853 853 > ui.write(b' %s %s\n' % (k, v))
854 854 >
855 855 > def passhook(ui, repo, **args):
856 856 > printargs(ui, args)
857 857 >
858 858 > def failhook(ui, repo, **args):
859 859 > printargs(ui, args)
860 860 > return True
861 861 >
862 862 > class LocalException(Exception):
863 863 > pass
864 864 >
865 865 > def raisehook(**args):
866 866 > raise LocalException('exception from hook')
867 867 >
868 868 > def aborthook(**args):
869 869 > raise error.Abort(b'raise abort from hook')
870 870 >
871 871 > def brokenhook(**args):
872 872 > return 1 + {}
873 873 >
874 874 > def verbosehook(ui, **args):
875 875 > ui.note(b'verbose output from hook\n')
876 876 >
877 877 > def printtags(ui, repo, **args):
878 878 > ui.write(b'[%s]\n' % b', '.join(sorted(repo.tags())))
879 879 >
880 880 > class container(object):
881 881 > unreachable = 1
882 882 > EOF
883 883
884 884 $ cat > syntaxerror.py << NO_CHECK_EOF
885 885 > (foo
886 886 > NO_CHECK_EOF
887 887
888 888 test python hooks
889 889
890 890 #if windows
891 891 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
892 892 #else
893 893 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
894 894 #endif
895 895 $ export PYTHONPATH
896 896
897 897 $ echo '[hooks]' > ../a/.hg/hgrc
898 898 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
899 899 $ hg pull ../a 2>&1 | grep 'raised an exception'
900 900 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
901 901
902 902 $ echo '[hooks]' > ../a/.hg/hgrc
903 903 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
904 904 $ hg pull ../a 2>&1 | grep 'raised an exception'
905 905 error: preoutgoing.raise hook raised an exception: exception from hook
906 906
907 907 $ echo '[hooks]' > ../a/.hg/hgrc
908 908 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
909 909 $ hg pull ../a
910 910 pulling from ../a
911 911 searching for changes
912 912 error: preoutgoing.abort hook failed: raise abort from hook
913 913 abort: raise abort from hook
914 914 [255]
915 915
916 916 $ echo '[hooks]' > ../a/.hg/hgrc
917 917 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
918 918 $ hg pull ../a
919 919 pulling from ../a
920 920 searching for changes
921 921 hook args:
922 922 hooktype preoutgoing
923 923 source pull
924 924 abort: preoutgoing.fail hook failed
925 925 [40]
926 926
927 927 $ echo '[hooks]' > ../a/.hg/hgrc
928 928 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
929 929 $ hg pull ../a
930 930 pulling from ../a
931 931 searching for changes
932 932 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
933 933 [255]
934 934
935 935 $ echo '[hooks]' > ../a/.hg/hgrc
936 936 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
937 937 $ hg pull ../a
938 938 pulling from ../a
939 939 searching for changes
940 940 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
941 941 [255]
942 942
943 943 $ echo '[hooks]' > ../a/.hg/hgrc
944 944 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
945 945 $ hg pull ../a
946 946 pulling from ../a
947 947 searching for changes
948 948 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
949 949 [255]
950 950
951 951 $ echo '[hooks]' > ../a/.hg/hgrc
952 952 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
953 953 $ hg pull ../a
954 954 pulling from ../a
955 955 searching for changes
956 956 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
957 957 (run with --traceback for stack trace)
958 958 [255]
959 959
960 960 $ echo '[hooks]' > ../a/.hg/hgrc
961 961 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
962 962 $ hg pull ../a
963 963 pulling from ../a
964 964 searching for changes
965 965 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
966 966 (run with --traceback for stack trace)
967 967 [255]
968 968
969 969 $ echo '[hooks]' > ../a/.hg/hgrc
970 970 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
971 971 $ hg pull ../a
972 972 pulling from ../a
973 973 searching for changes
974 974 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
975 975 (run with --traceback for stack trace)
976 976 [255]
977 977
978 978 $ hg pull ../a --traceback 2>&1 | egrep 'pulling|searching|^exception|Traceback|SyntaxError|ImportError|ModuleNotFoundError|HookLoadError|abort'
979 979 pulling from ../a
980 980 searching for changes
981 981 exception from first failed import attempt:
982 982 Traceback (most recent call last):
983 983 SyntaxError: * (glob)
984 984 exception from second failed import attempt:
985 985 Traceback (most recent call last):
986 986 SyntaxError: * (glob)
987 987 Traceback (most recent call last):
988 988 ModuleNotFoundError: No module named 'hgext_syntaxerror'
989 989 Traceback (most recent call last):
990 990 SyntaxError: * (glob)
991 991 Traceback (most recent call last):
992 992 ModuleNotFoundError: No module named 'hgext_syntaxerror'
993 993 Traceback (most recent call last):
994 994 raise error.HookLoadError( (py38 !)
995 995 mercurial.error.HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
996 996 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
997 997
998 998 $ echo '[hooks]' > ../a/.hg/hgrc
999 999 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
1000 1000 $ hg pull ../a
1001 1001 pulling from ../a
1002 1002 searching for changes
1003 1003 hook args:
1004 1004 hooktype preoutgoing
1005 1005 source pull
1006 1006 adding changesets
1007 1007 adding manifests
1008 1008 adding file changes
1009 1009 adding remote bookmark quux
1010 1010 added 1 changesets with 1 changes to 1 files
1011 1011 new changesets 539e4b31b6dc
1012 1012 (run 'hg update' to get a working copy)
1013 1013
1014 1014 post- python hooks that fail to *run* don't cause an abort
1015 1015 $ rm ../a/.hg/hgrc
1016 1016 $ echo '[hooks]' > .hg/hgrc
1017 1017 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
1018 1018 $ hg pull ../a
1019 1019 pulling from ../a
1020 1020 searching for changes
1021 1021 no changes found
1022 1022 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
1023 1023 (run with --traceback for stack trace)
1024 1024
1025 1025 but post- python hooks that fail to *load* do
1026 1026 $ echo '[hooks]' > .hg/hgrc
1027 1027 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
1028 1028 $ hg pull ../a
1029 1029 pulling from ../a
1030 1030 searching for changes
1031 1031 no changes found
1032 1032 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
1033 1033 [255]
1034 1034
1035 1035 $ echo '[hooks]' > .hg/hgrc
1036 1036 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
1037 1037 $ hg pull ../a
1038 1038 pulling from ../a
1039 1039 searching for changes
1040 1040 no changes found
1041 1041 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
1042 1042 (run with --traceback for stack trace)
1043 1043 [255]
1044 1044
1045 1045 $ echo '[hooks]' > .hg/hgrc
1046 1046 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
1047 1047 $ hg pull ../a
1048 1048 pulling from ../a
1049 1049 searching for changes
1050 1050 no changes found
1051 1051 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
1052 1052 [255]
1053 1053
1054 1054 make sure --traceback works
1055 1055
1056 1056 $ echo '[hooks]' > .hg/hgrc
1057 1057 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
1058 1058
1059 1059 $ echo aa > a
1060 1060 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
1061 1061 Traceback (most recent call last):
1062 1062
1063 1063 $ cd ..
1064 1064 $ hg init c
1065 1065 $ cd c
1066 1066
1067 1067 $ cat > hookext.py <<EOF
1068 1068 > def autohook(ui, **args):
1069 1069 > ui.write(b'Automatically installed hook\n')
1070 1070 >
1071 1071 > def reposetup(ui, repo):
1072 1072 > repo.ui.setconfig(b"hooks", b"commit.auto", autohook)
1073 1073 > EOF
1074 1074 $ echo '[extensions]' >> .hg/hgrc
1075 1075 $ echo 'hookext = hookext.py' >> .hg/hgrc
1076 1076
1077 1077 $ touch foo
1078 1078 $ hg add foo
1079 1079 $ hg ci -d '0 0' -m 'add foo'
1080 1080 Automatically installed hook
1081 1081 $ echo >> foo
1082 1082 $ hg ci --debug -d '0 0' -m 'change foo'
1083 1083 committing files:
1084 1084 foo
1085 1085 committing manifest
1086 1086 committing changelog
1087 1087 updating the branch cache
1088 1088 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
1089 1089 calling hook commit.auto: hgext_hookext.autohook
1090 1090 Automatically installed hook
1091 1091
1092 1092 $ hg showconfig hooks
1093 1093 hooks.commit.auto=<function autohook at *> (glob)
1094 1094
1095 1095 test python hook configured with python:[file]:[hook] syntax
1096 1096
1097 1097 $ cd ..
1098 1098 $ mkdir d
1099 1099 $ cd d
1100 1100 $ hg init repo
1101 1101 $ mkdir hooks
1102 1102
1103 1103 $ cd hooks
1104 1104 $ cat > testhooks.py <<EOF
1105 1105 > def testhook(ui, **args):
1106 1106 > ui.write(b'hook works\n')
1107 1107 > EOF
1108 1108 $ echo '[hooks]' > ../repo/.hg/hgrc
1109 1109 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
1110 1110
1111 1111 $ cd ../repo
1112 1112 $ hg commit -d '0 0'
1113 1113 hook works
1114 1114 nothing changed
1115 1115 [1]
1116 1116
1117 1117 $ echo '[hooks]' > .hg/hgrc
1118 1118 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
1119 1119 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
1120 1120
1121 1121 $ hg up null
1122 1122 loading update.ne hook failed:
1123 1123 abort: $ENOENT$: '$TESTTMP/d/repo/nonexistent.py'
1124 1124 [255]
1125 1125
1126 1126 $ hg id
1127 1127 loading pre-identify.npmd hook failed:
1128 1128 abort: No module named 'repo'
1129 1129 [255]
1130 1130
1131 1131 $ cd ../../b
1132 1132
1133 1133 make sure --traceback works on hook import failure
1134 1134
1135 1135 $ cat > importfail.py <<EOF
1136 1136 > import somebogusmodule
1137 1137 > # dereference something in the module to force demandimport to load it
1138 1138 > somebogusmodule.whatever
1139 1139 > EOF
1140 1140
1141 1141 $ echo '[hooks]' > .hg/hgrc
1142 1142 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
1143 1143
1144 1144 $ echo a >> a
1145 1145 $ hg --traceback commit -ma 2>&1 | egrep '^exception|ImportError|ModuleNotFoundError|Traceback|HookLoadError|abort'
1146 1146 exception from first failed import attempt:
1147 1147 Traceback (most recent call last):
1148 1148 ModuleNotFoundError: No module named 'somebogusmodule'
1149 1149 exception from second failed import attempt:
1150 1150 Traceback (most recent call last):
1151 1151 ModuleNotFoundError: No module named 'somebogusmodule'
1152 1152 Traceback (most recent call last):
1153 1153 ModuleNotFoundError: No module named 'hgext_importfail'
1154 1154 Traceback (most recent call last):
1155 1155 ModuleNotFoundError: No module named 'somebogusmodule'
1156 1156 Traceback (most recent call last):
1157 1157 ModuleNotFoundError: No module named 'hgext_importfail'
1158 1158 Traceback (most recent call last):
1159 1159 raise error.HookLoadError( (py38 !)
1160 1160 mercurial.error.HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
1161 1161 abort: precommit.importfail hook is invalid: import of "importfail" failed
1162 1162
1163 1163 Issue1827: Hooks Update & Commit not completely post operation
1164 1164
1165 1165 commit and update hooks should run after command completion. The largefiles
1166 1166 use demonstrates a recursive wlock, showing the hook doesn't run until the
1167 1167 final release (and dirstate flush).
1168 1168
1169 1169 $ echo '[hooks]' > .hg/hgrc
1170 1170 $ echo 'commit = hg id' >> .hg/hgrc
1171 1171 $ echo 'update = hg id' >> .hg/hgrc
1172 1172 $ echo bb > a
1173 1173 $ hg ci -ma
1174 1174 223eafe2750c tip
1175 1175 $ hg up 0 --config extensions.largefiles=
1176 1176 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
1177 1177 cb9a9f314b8b
1178 1178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1179 1179
1180 1180 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
1181 1181 that is passed to pre/post hooks
1182 1182
1183 1183 $ echo '[hooks]' > .hg/hgrc
1184 1184 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
1185 1185 $ hg id
1186 1186 cb9a9f314b8b
1187 1187 $ hg id --verbose
1188 1188 calling hook pre-identify: hooktests.verbosehook
1189 1189 verbose output from hook
1190 1190 cb9a9f314b8b
1191 1191
1192 1192 Ensure hooks can be prioritized
1193 1193
1194 1194 $ echo '[hooks]' > .hg/hgrc
1195 1195 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
1196 1196 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
1197 1197 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
1198 1198 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
1199 1199 $ hg id --verbose
1200 1200 calling hook pre-identify.b: hooktests.verbosehook
1201 1201 verbose output from hook
1202 1202 calling hook pre-identify.a: hooktests.verbosehook
1203 1203 verbose output from hook
1204 1204 calling hook pre-identify.c: hooktests.verbosehook
1205 1205 verbose output from hook
1206 1206 cb9a9f314b8b
1207 1207
1208 1208 new tags must be visible in pretxncommit (issue3210)
1209 1209
1210 1210 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
1211 1211 $ hg tag -f foo
1212 1212 [a, foo, tip]
1213 1213
1214 1214 post-init hooks must not crash (issue4983)
1215 1215 This also creates the `to` repo for the next test block.
1216 1216
1217 1217 $ cd ..
1218 1218 $ cat << EOF >> hgrc-with-post-init-hook
1219 1219 > [hooks]
1220 1220 > post-init = sh -c "printenv.py --line post-init"
1221 1221 > EOF
1222 1222 $ HGRCPATH=hgrc-with-post-init-hook hg init to
1223 1223 post-init hook: HG_ARGS=init to
1224 1224 HG_HOOKNAME=post-init
1225 1225 HG_HOOKTYPE=post-init
1226 1226 HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''}
1227 1227 HG_PATS=['to']
1228 1228 HG_RESULT=0
1229 1229
1230 1230
1231 1231 new commits must be visible in pretxnchangegroup (issue3428)
1232 1232
1233 1233 $ echo '[hooks]' >> to/.hg/hgrc
1234 1234 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
1235 1235 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
1236 1236 $ echo a >> to/a
1237 1237 $ hg --cwd to ci -Ama
1238 1238 adding a
1239 1239 $ hg clone to from
1240 1240 updating to branch default
1241 1241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1242 1242 $ echo aa >> from/a
1243 1243 $ hg --cwd from ci -mb
1244 1244 $ hg --cwd from push
1245 1245 pushing to $TESTTMP/to
1246 1246 searching for changes
1247 1247 changeset: 0:cb9a9f314b8b
1248 1248 tag: tip
1249 1249 user: test
1250 1250 date: Thu Jan 01 00:00:00 1970 +0000
1251 1251 summary: a
1252 1252
1253 1253 adding changesets
1254 1254 adding manifests
1255 1255 adding file changes
1256 1256 changeset: 1:9836a07b9b9d
1257 1257 tag: tip
1258 1258 user: test
1259 1259 date: Thu Jan 01 00:00:00 1970 +0000
1260 1260 summary: b
1261 1261
1262 1262 added 1 changesets with 1 changes to 1 files
1263 1263
1264 1264 pretxnclose hook failure should abort the transaction
1265 1265
1266 1266 $ hg init txnfailure
1267 1267 $ cd txnfailure
1268 1268 $ touch a && hg commit -Aqm a
1269 1269 $ cat >> .hg/hgrc <<EOF
1270 1270 > [hooks]
1271 1271 > pretxnclose.error = exit 1
1272 1272 > EOF
1273 1273 $ hg strip -r 0 --config extensions.strip=
1274 1274 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1275 1275 saved backup bundle to * (glob)
1276 1276 transaction abort!
1277 1277 rollback completed
1278 1278 strip failed, backup bundle stored in * (glob)
1279 1279 abort: pretxnclose.error hook exited with status 1
1280 1280 [40]
1281 1281 $ hg recover
1282 1282 no interrupted transaction available
1283 1283 [1]
1284 1284 $ cd ..
1285 1285
1286 1286 check whether HG_PENDING makes pending changes only in related
1287 1287 repositories visible to an external hook.
1288 1288
1289 1289 (emulate a transaction running concurrently by copied
1290 1290 .hg/store/00changelog.i.a in subsequent test)
1291 1291
1292 1292 $ cat > $TESTTMP/savepending.sh <<EOF
1293 1293 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
1294 1294 > exit 1 # to avoid adding new revision for subsequent tests
1295 1295 > EOF
1296 1296 $ cd a
1297 1297 $ hg tip -q
1298 1298 4:539e4b31b6dc
1299 1299 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
1300 1300 transaction abort!
1301 1301 rollback completed
1302 1302 abort: pretxnclose hook exited with status 1
1303 1303 [40]
1304 1304 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
1305 1305
1306 1306 (check (in)visibility of new changeset while transaction running in
1307 1307 repo)
1308 1308
1309 1309 $ cat > $TESTTMP/checkpending.sh <<EOF
1310 1310 > echo '@a'
1311 1311 > hg -R "$TESTTMP/a" tip -q
1312 1312 > echo '@a/nested'
1313 1313 > hg -R "$TESTTMP/a/nested" tip -q
1314 1314 > exit 1 # to avoid adding new revision for subsequent tests
1315 1315 > EOF
1316 1316 $ hg init nested
1317 1317 $ cd nested
1318 1318 $ echo a > a
1319 1319 $ hg add a
1320 1320 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
1321 1321 @a
1322 1322 4:539e4b31b6dc
1323 1323 @a/nested
1324 1324 0:bf5e395ced2c
1325 1325 transaction abort!
1326 1326 rollback completed
1327 1327 abort: pretxnclose hook exited with status 1
1328 1328 [40]
1329 1329
1330 1330 Hook from untrusted hgrc are reported as failure
1331 1331 ================================================
1332 1332
1333 1333 $ cat << EOF > $TESTTMP/untrusted.py
1334 1334 > from mercurial import scmutil, util
1335 1335 > def uisetup(ui):
1336 1336 > class untrustedui(ui.__class__):
1337 1337 > def _trusted(self, fp, f):
1338 1338 > if util.normpath(fp.name).endswith(b'untrusted/.hg/hgrc'):
1339 1339 > return False
1340 1340 > return super(untrustedui, self)._trusted(fp, f)
1341 1341 > ui.__class__ = untrustedui
1342 1342 > EOF
1343 1343 $ cat << EOF >> $HGRCPATH
1344 1344 > [extensions]
1345 1345 > untrusted=$TESTTMP/untrusted.py
1346 1346 > EOF
1347 1347 $ hg init untrusted
1348 1348 $ cd untrusted
1349 1349
1350 1350 Non-blocking hook
1351 1351 -----------------
1352 1352
1353 1353 $ cat << EOF >> .hg/hgrc
1354 1354 > [hooks]
1355 1355 > txnclose.testing=echo txnclose hook called
1356 1356 > EOF
1357 1357 $ touch a && hg commit -Aqm a
1358 1358 warning: untrusted hook txnclose.testing not executed
1359 1359 $ hg log
1360 1360 changeset: 0:3903775176ed
1361 1361 tag: tip
1362 1362 user: test
1363 1363 date: Thu Jan 01 00:00:00 1970 +0000
1364 1364 summary: a
1365 1365
1366 1366
1367 1367 Non-blocking hook
1368 1368 -----------------
1369 1369
1370 1370 $ cat << EOF >> .hg/hgrc
1371 1371 > [hooks]
1372 1372 > pretxnclose.testing=echo pre-txnclose hook called
1373 1373 > EOF
1374 1374 $ touch b && hg commit -Aqm a
1375 1375 transaction abort!
1376 1376 rollback completed
1377 1377 abort: untrusted hook pretxnclose.testing not executed
1378 1378 (see 'hg help config.trusted')
1379 1379 [40]
1380 1380 $ hg log
1381 1381 changeset: 0:3903775176ed
1382 1382 tag: tip
1383 1383 user: test
1384 1384 date: Thu Jan 01 00:00:00 1970 +0000
1385 1385 summary: a
1386 1386
1387 1387
1388 1388 unsetup the test
1389 1389 ----------------
1390 1390
1391 1391 # touch the file to unconfuse chg with a diffrent mtime
1392 1392 $ sleep 1
1393 1393 $ touch $TESTTMP/untrusted.py
1394 1394 $ cat << EOF >> $HGRCPATH
1395 1395 > [extensions]
1396 1396 > untrusted=!
1397 1397 > EOF
1398 1398
1399 1399 HGPLAIN setting in hooks
1400 1400 ========================
1401 1401
1402 1402 $ cat << EOF >> .hg/hgrc
1403 1403 > [hooks]
1404 1404 > pre-version.testing-default=sh -c "echo '### default ###' plain: \${HGPLAIN:-'<unset>'}"
1405 1405 > pre-version.testing-yes=sh -c "echo '### yes #######' plain: \${HGPLAIN:-'<unset>'}"
1406 1406 > pre-version.testing-yes:run-with-plain=yes
1407 1407 > pre-version.testing-no=sh -c "echo '### no ########' plain: \${HGPLAIN:-'<unset>'}"
1408 1408 > pre-version.testing-no:run-with-plain=no
1409 1409 > pre-version.testing-auto=sh -c "echo '### auto ######' plain: \${HGPLAIN:-'<unset>'}"
1410 1410 > pre-version.testing-auto:run-with-plain=auto
1411 1411 > EOF
1412 1412
1413 1413 $ (unset HGPLAIN; hg version --quiet)
1414 1414 ### default ### plain: 1
1415 1415 ### yes ####### plain: 1
1416 1416 ### no ######## plain: <unset>
1417 1417 ### auto ###### plain: <unset>
1418 1418 Mercurial Distributed SCM (*) (glob)
1419 1419
1420 1420 $ HGPLAIN=1 hg version --quiet
1421 1421 ### default ### plain: 1
1422 1422 ### yes ####### plain: 1
1423 1423 ### no ######## plain: <unset>
1424 1424 ### auto ###### plain: 1
1425 1425 Mercurial Distributed SCM (*) (glob)
1426 1426
1427 1427 Test hook that change the underlying repo
1428 1428 =========================================
1429 1429
1430 1430 blackbox access the dirstate afterward and can see a changelog / dirstate
1431 1431 desync.
1432 1432
1433 1433
1434 1434 $ cd $TESTTMP
1435 1435 $ cat <<EOF >> $HGRCPATH
1436 1436 > [extensions]
1437 1437 > blackbox=
1438 1438 > [hooks]
1439 1439 > post-merge = hg commit -m "auto merge"
1440 1440 > EOF
1441 1441
1442 1442 $ hg init t
1443 1443 $ cd t
1444 1444 $ touch ".hgignore"
1445 1445 $ hg commit -Am "initial" -d'0 0'
1446 1446 adding .hgignore
1447 1447
1448 1448 $ echo This is file a1 > a
1449 1449 $ hg commit -Am "commit #1" -d'0 0'
1450 1450 adding a
1451 1451
1452 1452 $ hg update 0
1453 1453 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1454 1454 $ echo This is file b1 > b
1455 1455 $ hg commit -Am "commit #2" -d'0 0'
1456 1456 adding b
1457 1457 created new head
1458 1458
1459 1459 $ hg merge 1
1460 1460 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1461 1461 (branch merge, don't forget to commit)
1462 1462
1463 1463 $ cd ..
@@ -1,180 +1,180 b''
1 1 #require unix-permissions
2 2
3 3 test that new files created in .hg inherit the permissions from .hg/store
4 4
5 5 $ mkdir dir
6 6
7 7 just in case somebody has a strange $TMPDIR
8 8
9 9 $ chmod g-s dir
10 10 $ cd dir
11 11
12 12 $ cat >printmodes.py <<EOF
13 13 > import os
14 14 > import sys
15 15 >
16 16 > allnames = []
17 17 > isdir = {}
18 18 > for root, dirs, files in os.walk(sys.argv[1]):
19 19 > for d in dirs:
20 20 > name = os.path.join(root, d)
21 21 > isdir[name] = 1
22 22 > allnames.append(name)
23 23 > for f in files:
24 24 > name = os.path.join(root, f)
25 25 > allnames.append(name)
26 26 > allnames.sort()
27 27 > for name in allnames:
28 28 > suffix = name in isdir and '/' or ''
29 29 > print('%05o %s%s' % (os.lstat(name).st_mode & 0o7777, name, suffix))
30 30 > EOF
31 31
32 32 $ cat >mode.py <<EOF
33 33 > import os
34 34 > import sys
35 35 > print('%05o' % os.lstat(sys.argv[1]).st_mode)
36 36 > EOF
37 37
38 38 $ umask 077
39 39
40 40 $ hg init repo
41 41 $ cd repo
42 42
43 43 $ chmod 0770 .hg/store .hg/cache .hg/wcache
44 44
45 45 before commit
46 46 store can be written by the group, other files cannot
47 47 store is setgid
48 48
49 49 $ "$PYTHON" ../printmodes.py .
50 50 00700 ./.hg/
51 51 00600 ./.hg/00changelog.i
52 52 00770 ./.hg/cache/
53 53 00600 ./.hg/requires
54 54 00770 ./.hg/store/
55 55 00600 ./.hg/store/requires
56 56 00770 ./.hg/wcache/
57 57
58 58 $ mkdir dir
59 59 $ touch foo dir/bar
60 60 $ hg ci -qAm 'add files'
61 61
62 62 after commit
63 63 working dir files can only be written by the owner
64 64 files created in .hg can be written by the group
65 65 (in particular, store/**, dirstate, branch cache file, undo files)
66 66 new directories are setgid
67 67
68 68 $ "$PYTHON" ../printmodes.py .
69 69 00700 ./.hg/
70 70 00600 ./.hg/00changelog.i
71 71 00660 ./.hg/branch
72 72 00770 ./.hg/cache/
73 73 00660 ./.hg/cache/branch2-served
74 74 00660 ./.hg/cache/rbc-names-v1
75 75 00660 ./.hg/cache/rbc-revs-v1
76 76 00660 ./.hg/dirstate
77 77 00660 ./.hg/fsmonitor.state (fsmonitor !)
78 78 00660 ./.hg/last-message.txt
79 79 00600 ./.hg/requires
80 80 00770 ./.hg/store/
81 81 00660 ./.hg/store/00changelog.i
82 82 00660 ./.hg/store/00manifest.i
83 83 00770 ./.hg/store/data/
84 84 00770 ./.hg/store/data/dir/
85 85 00660 ./.hg/store/data/dir/bar.i (reporevlogstore !)
86 86 00660 ./.hg/store/data/foo.i (reporevlogstore !)
87 87 00770 ./.hg/store/data/dir/bar/ (reposimplestore !)
88 88 00660 ./.hg/store/data/dir/bar/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
89 89 00660 ./.hg/store/data/dir/bar/index (reposimplestore !)
90 90 00770 ./.hg/store/data/foo/ (reposimplestore !)
91 91 00660 ./.hg/store/data/foo/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
92 92 00660 ./.hg/store/data/foo/index (reposimplestore !)
93 93 00660 ./.hg/store/fncache (repofncache !)
94 94 00660 ./.hg/store/phaseroots
95 95 00600 ./.hg/store/requires
96 96 00660 ./.hg/store/undo
97 97 00660 ./.hg/store/undo.backupfiles
98 00660 ./.hg/undo.backup.branch
98 00660 ./.hg/undo.backup.branch.bck
99 99 00660 ./.hg/undo.desc
100 100 00770 ./.hg/wcache/
101 101 00711 ./.hg/wcache/checkisexec
102 102 007.. ./.hg/wcache/checklink (re)
103 103 00600 ./.hg/wcache/checklink-target
104 104 00660 ./.hg/wcache/manifestfulltextcache (reporevlogstore !)
105 105 00700 ./dir/
106 106 00600 ./dir/bar
107 107 00600 ./foo
108 108
109 109 $ umask 007
110 110 $ hg init ../push
111 111
112 112 before push
113 113 group can write everything
114 114
115 115 $ "$PYTHON" ../printmodes.py ../push
116 116 00770 ../push/.hg/
117 117 00660 ../push/.hg/00changelog.i
118 118 00770 ../push/.hg/cache/
119 119 00660 ../push/.hg/requires
120 120 00770 ../push/.hg/store/
121 121 00660 ../push/.hg/store/requires
122 122 00770 ../push/.hg/wcache/
123 123
124 124 $ umask 077
125 125 $ hg -q push ../push
126 126
127 127 after push
128 128 group can still write everything
129 129
130 130 $ "$PYTHON" ../printmodes.py ../push
131 131 00770 ../push/.hg/
132 132 00660 ../push/.hg/00changelog.i
133 133 00660 ../push/.hg/branch
134 134 00770 ../push/.hg/cache/
135 135 00660 ../push/.hg/cache/branch2-base
136 136 00660 ../push/.hg/cache/rbc-names-v1
137 137 00660 ../push/.hg/cache/rbc-revs-v1
138 138 00660 ../push/.hg/requires
139 139 00770 ../push/.hg/store/
140 140 00660 ../push/.hg/store/00changelog.i
141 141 00660 ../push/.hg/store/00manifest.i
142 142 00770 ../push/.hg/store/data/
143 143 00770 ../push/.hg/store/data/dir/
144 144 00660 ../push/.hg/store/data/dir/bar.i (reporevlogstore !)
145 145 00660 ../push/.hg/store/data/foo.i (reporevlogstore !)
146 146 00770 ../push/.hg/store/data/dir/bar/ (reposimplestore !)
147 147 00660 ../push/.hg/store/data/dir/bar/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
148 148 00660 ../push/.hg/store/data/dir/bar/index (reposimplestore !)
149 149 00770 ../push/.hg/store/data/foo/ (reposimplestore !)
150 150 00660 ../push/.hg/store/data/foo/b80de5d138758541c5f05265ad144ab9fa86d1db (reposimplestore !)
151 151 00660 ../push/.hg/store/data/foo/index (reposimplestore !)
152 152 00660 ../push/.hg/store/fncache (repofncache !)
153 153 00660 ../push/.hg/store/requires
154 154 00660 ../push/.hg/store/undo
155 155 00660 ../push/.hg/store/undo.backupfiles
156 00660 ../push/.hg/undo.backup.branch
156 00660 ../push/.hg/undo.backup.branch.bck
157 157 00660 ../push/.hg/undo.desc
158 158 00770 ../push/.hg/wcache/
159 159
160 160
161 161 Test that we don't lose the setgid bit when we call chmod.
162 162 Not all systems support setgid directories (e.g. HFS+), so
163 163 just check that directories have the same mode.
164 164
165 165 $ cd ..
166 166 $ hg init setgid
167 167 $ cd setgid
168 168 $ chmod g+rwx .hg/store
169 169 $ chmod g+s .hg/store 2> /dev/null || true
170 170 $ mkdir dir
171 171 $ touch dir/file
172 172 $ hg ci -qAm 'add dir/file'
173 173 $ storemode=`"$PYTHON" ../mode.py .hg/store`
174 174 $ dirmode=`"$PYTHON" ../mode.py .hg/store/data/dir`
175 175 $ if [ "$storemode" != "$dirmode" ]; then
176 176 > echo "$storemode != $dirmode"
177 177 > fi
178 178 $ cd ..
179 179
180 180 $ cd .. # g-s dir
@@ -1,263 +1,263 b''
1 1 Create user cache directory
2 2
3 3 $ USERCACHE=`pwd`/cache; export USERCACHE
4 4 $ cat <<EOF >> ${HGRCPATH}
5 5 > [extensions]
6 6 > hgext.largefiles=
7 7 > [largefiles]
8 8 > usercache=${USERCACHE}
9 9 > EOF
10 10 $ mkdir -p ${USERCACHE}
11 11
12 12 Create source repo, and commit adding largefile.
13 13
14 14 $ hg init src
15 15 $ cd src
16 16 $ echo large > large
17 17 $ hg add --large large
18 18 $ hg commit -m 'add largefile'
19 19 $ hg rm large
20 20 $ hg commit -m 'branchhead without largefile' large
21 21 $ hg up -qr 0
22 22 $ rm large
23 23 $ echo "0000000000000000000000000000000000000000" > .hglf/large
24 24 $ hg commit -m 'commit missing file with corrupt standin' large
25 25 abort: large: file not found!
26 26 [255]
27 27 $ hg up -Cqr 0
28 28 $ cd ..
29 29
30 30 Discard all cached largefiles in USERCACHE
31 31
32 32 $ rm -rf ${USERCACHE}
33 33
34 34 Create mirror repo, and pull from source without largefile:
35 35 "pull" is used instead of "clone" for suppression of (1) updating to
36 36 tip (= caching largefile from source repo), and (2) recording source
37 37 repo as "default" path in .hg/hgrc.
38 38
39 39 $ hg init mirror
40 40 $ cd mirror
41 41 $ hg pull ../src
42 42 pulling from ../src
43 43 requesting all changes
44 44 adding changesets
45 45 adding manifests
46 46 adding file changes
47 47 added 2 changesets with 1 changes to 1 files
48 48 new changesets eb85d9124f3f:26c18ce05e4e
49 49 (run 'hg update' to get a working copy)
50 50
51 51 Update working directory to "tip", which requires largefile("large"),
52 52 but there is no cache file for it. So, hg must treat it as
53 53 "missing"(!) file.
54 54
55 55 $ hg update -r0
56 56 getting changed largefiles
57 57 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
58 58 0 largefiles updated, 0 removed
59 59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 60 $ hg status
61 61 ! large
62 62
63 63 Update working directory to null: this cleanup .hg/largefiles/dirstate
64 64
65 65 $ hg update null
66 66 getting changed largefiles
67 67 0 largefiles updated, 0 removed
68 68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
69 69
70 70 Update working directory to tip, again.
71 71
72 72 $ hg update -r0
73 73 getting changed largefiles
74 74 large: largefile 7f7097b041ccf68cc5561e9600da4655d21c6d18 not available from file:/*/$TESTTMP/mirror (glob)
75 75 0 largefiles updated, 0 removed
76 76 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 77 $ hg status
78 78 ! large
79 79 $ cd ..
80 80
81 81 Verify that largefiles from pulled branchheads are fetched, also to an empty repo
82 82
83 83 $ hg init mirror2
84 84 $ hg -R mirror2 pull src -r0
85 85 pulling from src
86 86 adding changesets
87 87 adding manifests
88 88 adding file changes
89 89 added 1 changesets with 1 changes to 1 files
90 90 new changesets eb85d9124f3f
91 91 (run 'hg update' to get a working copy)
92 92
93 93 #if unix-permissions
94 94
95 95 Portable way to print file permissions:
96 96
97 97 $ cat > ls-l.py <<EOF
98 98 > #!$PYTHON
99 99 > import os
100 100 > import sys
101 101 > path = sys.argv[1]
102 102 > print('%03o' % (os.lstat(path).st_mode & 0o777))
103 103 > EOF
104 104 $ chmod +x ls-l.py
105 105
106 106 Test that files in .hg/largefiles inherit mode from .hg/store, not
107 107 from file in working copy:
108 108
109 109 $ cd src
110 110 $ chmod 750 .hg/store
111 111 $ chmod 660 large
112 112 $ echo change >> large
113 113 $ hg commit -m change
114 114 created new head
115 115 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
116 116 640
117 117
118 118 Test permission of with files in .hg/largefiles created by update:
119 119
120 120 $ cd ../mirror
121 121 $ rm -r "$USERCACHE" .hg/largefiles # avoid links
122 122 $ chmod 750 .hg/store
123 123 $ hg pull ../src --update -q
124 124 $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
125 125 640
126 126
127 127 Test permission of files created by push:
128 128
129 129 $ hg serve -R ../src -d -p $HGPORT --pid-file hg.pid \
130 130 > --config "web.allow_push=*" --config web.push_ssl=no
131 131 $ cat hg.pid >> $DAEMON_PIDS
132 132
133 133 $ echo change >> large
134 134 $ hg commit -m change
135 135
136 136 $ rm -r "$USERCACHE"
137 137
138 138 $ hg push -q http://localhost:$HGPORT/
139 139
140 140 $ ../ls-l.py ../src/.hg/largefiles/b734e14a0971e370408ab9bce8d56d8485e368a9
141 141 640
142 142
143 143 $ cd ..
144 144
145 145 #endif
146 146
147 147 Test issue 4053 (remove --after on a deleted, uncommitted file shouldn't say
148 148 it is missing, but a remove on a nonexistent unknown file still should. Same
149 149 for a forget.)
150 150
151 151 $ cd src
152 152 $ touch x
153 153 $ hg add x
154 154 $ mv x y
155 155 $ hg remove -A x y ENOENT
156 156 ENOENT: * (glob)
157 157 not removing y: file is untracked
158 158 [1]
159 159 $ hg add y
160 160 $ mv y z
161 161 $ hg forget y z ENOENT
162 162 ENOENT: * (glob)
163 163 not removing z: file is already untracked
164 164 [1]
165 165
166 166 Largefiles are accessible from the share's store
167 167 $ cd ..
168 168 $ hg share -q src share_dst --config extensions.share=
169 169 $ hg -R share_dst update -r0
170 170 getting changed largefiles
171 171 1 largefiles updated, 0 removed
172 172 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
173 173
174 174 $ echo modified > share_dst/large
175 175 $ hg -R share_dst ci -m modified
176 176 created new head
177 177
178 178 Only dirstate is in the local store for the share, and the largefile is in the
179 179 share source's local store. Avoid the extra largefiles added in the unix
180 180 conditional above.
181 181 $ hash=`hg -R share_dst cat share_dst/.hglf/large`
182 182 $ echo $hash
183 183 e2fb5f2139d086ded2cb600d5a91a196e76bf020
184 184
185 185 $ find share_dst/.hg/largefiles/* | sort
186 186 share_dst/.hg/largefiles/dirstate
187 share_dst/.hg/largefiles/undo.backup.dirstate
187 share_dst/.hg/largefiles/undo.backup.dirstate.bck
188 188
189 189 $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort
190 190 src/.hg/largefiles/dirstate
191 191 src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
192 192
193 193 Verify that backwards compatibility is maintained for old storage layout
194 194 $ mv src/.hg/largefiles/$hash share_dst/.hg/largefiles
195 195 $ hg verify --quiet --lfa -R share_dst --config largefiles.usercache=
196 196
197 197 Inject corruption into the largefiles store and see how update handles that:
198 198
199 199 $ cd src
200 200 $ hg up -qC tip
201 201 $ cat large
202 202 modified
203 203 $ rm large
204 204 $ cat .hglf/large
205 205 e2fb5f2139d086ded2cb600d5a91a196e76bf020
206 206 $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
207 207 $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
208 208 $ hg up -C
209 209 getting changed largefiles
210 210 large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
211 211 0 largefiles updated, 0 removed
212 212 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 213 updated to "cd24c147f45c: modified"
214 214 [12] other heads for branch "default" (re)
215 215 $ hg st
216 216 ! large
217 217 ? z
218 218 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
219 219
220 220 #if serve
221 221
222 222 Test coverage of error handling from putlfile:
223 223
224 224 $ mkdir $TESTTMP/mirrorcache
225 225 $ hg serve -R ../mirror -d -p $HGPORT1 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache
226 226 $ cat hg.pid >> $DAEMON_PIDS
227 227
228 228 $ hg push http://localhost:$HGPORT1 -f --config files.usercache=nocache
229 229 pushing to http://localhost:$HGPORT1/
230 230 searching for changes
231 231 abort: remotestore: could not open file $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020: HTTP Error 403: ssl required
232 232 [255]
233 233
234 234 $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
235 235
236 236 Test coverage of 'missing from store':
237 237
238 238 $ hg serve -R ../mirror -d -p $HGPORT2 --pid-file hg.pid --config largefiles.usercache=$TESTTMP/mirrorcache --config "web.allow_push=*" --config web.push_ssl=no
239 239 $ cat hg.pid >> $DAEMON_PIDS
240 240
241 241 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache
242 242 pushing to http://localhost:$HGPORT2/
243 243 searching for changes
244 244 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
245 245 [255]
246 246
247 247 Verify that --lfrev controls which revisions are checked for largefiles to push
248 248
249 249 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev tip
250 250 pushing to http://localhost:$HGPORT2/
251 251 searching for changes
252 252 abort: largefile e2fb5f2139d086ded2cb600d5a91a196e76bf020 missing from store (needs to be uploaded)
253 253 [255]
254 254
255 255 $ hg push http://localhost:$HGPORT2 -f --config largefiles.usercache=nocache --lfrev null
256 256 pushing to http://localhost:$HGPORT2/
257 257 searching for changes
258 258 remote: adding changesets
259 259 remote: adding manifests
260 260 remote: adding file changes
261 261 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
262 262
263 263 #endif
@@ -1,1260 +1,1258 b''
1 1 ===================================
2 2 Test the persistent on-disk nodemap
3 3 ===================================
4 4
5 5
6 6 $ cat << EOF >> $HGRCPATH
7 7 > [format]
8 8 > use-share-safe=yes
9 9 > [extensions]
10 10 > share=
11 11 > EOF
12 12
13 13 #if no-rust
14 14
15 15 $ cat << EOF >> $HGRCPATH
16 16 > [format]
17 17 > use-persistent-nodemap=yes
18 18 > [devel]
19 19 > persistent-nodemap=yes
20 20 > EOF
21 21
22 22 #endif
23 23
24 24 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
25 25 $ cd test-repo
26 26
27 27 Check handling of the default slow-path value
28 28
29 29 #if no-pure no-rust
30 30
31 31 $ hg id
32 32 abort: accessing `persistent-nodemap` repository without associated fast implementation.
33 33 (check `hg help config.format.use-persistent-nodemap` for details)
34 34 [255]
35 35
36 36 Unlock further check (we are here to test the feature)
37 37
38 38 $ cat << EOF >> $HGRCPATH
39 39 > [storage]
40 40 > # to avoid spamming the test
41 41 > revlog.persistent-nodemap.slow-path=allow
42 42 > EOF
43 43
44 44 #endif
45 45
46 46 #if rust
47 47
48 48 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
49 49 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
50 50 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
51 51 incorrectly used `libc::c_int` (32 bits).
52 52 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
53 53
54 54 $ hg log -r 00000000
55 55 changeset: -1:000000000000
56 56 tag: tip
57 57 user:
58 58 date: Thu Jan 01 00:00:00 1970 +0000
59 59
60 60
61 61 #endif
62 62
63 63
64 64 $ hg debugformat
65 65 format-variant repo
66 66 fncache: yes
67 67 dirstate-v2: no
68 68 tracked-hint: no
69 69 dotencode: yes
70 70 generaldelta: yes
71 71 share-safe: yes
72 72 sparserevlog: yes
73 73 persistent-nodemap: yes
74 74 copies-sdc: no
75 75 revlog-v2: no
76 76 changelog-v2: no
77 77 plain-cl-delta: yes
78 78 compression: zlib (no-zstd !)
79 79 compression: zstd (zstd !)
80 80 compression-level: default
81 81 $ hg debugbuilddag .+5000 --new-file
82 82
83 83 $ hg debugnodemap --metadata
84 84 uid: ???????? (glob)
85 85 tip-rev: 5000
86 86 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
87 87 data-length: 121088
88 88 data-unused: 0
89 89 data-unused: 0.000%
90 90 $ f --size .hg/store/00changelog.n
91 91 .hg/store/00changelog.n: size=62
92 92
93 93 Simple lookup works
94 94
95 95 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
96 96 $ hg log -r "$ANYNODE" --template '{rev}\n'
97 97 5000
98 98
99 99
100 100 #if rust
101 101
102 102 $ f --sha256 .hg/store/00changelog-*.nd
103 103 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
104 104
105 105 $ f --sha256 .hg/store/00manifest-*.nd
106 106 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
107 107 $ hg debugnodemap --dump-new | f --sha256 --size
108 108 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
109 109 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
110 110 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
111 111 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
112 112 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
113 113 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
114 114 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
115 115 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
116 116 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
117 117 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
118 118 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
119 119 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
120 120 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
121 121 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
122 122 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
123 123 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
124 124 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
125 125 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
126 126 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
127 127
128 128
129 129 #else
130 130
131 131 $ f --sha256 .hg/store/00changelog-*.nd
132 132 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
133 133 $ hg debugnodemap --dump-new | f --sha256 --size
134 134 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
135 135 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
136 136 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
137 137 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 138 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
139 139 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
140 140 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 141 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 142 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
143 143 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
144 144 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
145 145 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
146 146 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
147 147 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
148 148 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
149 149 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
150 150 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
151 151 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
152 152 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
153 153
154 154 #endif
155 155
156 156 $ hg debugnodemap --check
157 157 revision in index: 5001
158 158 revision in nodemap: 5001
159 159
160 160 add a new commit
161 161
162 162 $ hg up
163 163 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 164 $ echo foo > foo
165 165 $ hg add foo
166 166
167 167
168 168 Check slow-path config value handling
169 169 -------------------------------------
170 170
171 171 #if no-pure no-rust
172 172
173 173 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
174 174 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
175 175 falling back to default value: abort
176 176 abort: accessing `persistent-nodemap` repository without associated fast implementation.
177 177 (check `hg help config.format.use-persistent-nodemap` for details)
178 178 [255]
179 179
180 180 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
181 181 warning: accessing `persistent-nodemap` repository without associated fast implementation.
182 182 (check `hg help config.format.use-persistent-nodemap` for details)
183 183 changeset: 5000:6b02b8c7b966
184 184 tag: tip
185 185 user: debugbuilddag
186 186 date: Thu Jan 01 01:23:20 1970 +0000
187 187 summary: r5000
188 188
189 189 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
190 190 abort: accessing `persistent-nodemap` repository without associated fast implementation.
191 191 (check `hg help config.format.use-persistent-nodemap` for details)
192 192 [255]
193 193
194 194 #else
195 195
196 196 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
197 197 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
198 198 falling back to default value: abort
199 199 6b02b8c7b966+ tip
200 200
201 201 #endif
202 202
203 203 $ hg ci -m 'foo'
204 204
205 205 #if no-pure no-rust
206 206 $ hg debugnodemap --metadata
207 207 uid: ???????? (glob)
208 208 tip-rev: 5001
209 209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
210 210 data-length: 121088
211 211 data-unused: 0
212 212 data-unused: 0.000%
213 213 #else
214 214 $ hg debugnodemap --metadata
215 215 uid: ???????? (glob)
216 216 tip-rev: 5001
217 217 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
218 218 data-length: 121344
219 219 data-unused: 256
220 220 data-unused: 0.211%
221 221 #endif
222 222
223 223 $ f --size .hg/store/00changelog.n
224 224 .hg/store/00changelog.n: size=62
225 225
226 226 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
227 227
228 228 #if pure
229 229 $ f --sha256 .hg/store/00changelog-*.nd --size
230 230 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
231 231 #endif
232 232
233 233 #if rust
234 234 $ f --sha256 .hg/store/00changelog-*.nd --size
235 235 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
236 236 #endif
237 237
238 238 #if no-pure no-rust
239 239 $ f --sha256 .hg/store/00changelog-*.nd --size
240 240 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
241 241 #endif
242 242
243 243 $ hg debugnodemap --check
244 244 revision in index: 5002
245 245 revision in nodemap: 5002
246 246
247 247 Test code path without mmap
248 248 ---------------------------
249 249
250 250 $ echo bar > bar
251 251 $ hg add bar
252 252 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
253 253
254 254 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
255 255 revision in index: 5003
256 256 revision in nodemap: 5003
257 257 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
258 258 revision in index: 5003
259 259 revision in nodemap: 5003
260 260
261 261
262 262 #if pure
263 263 $ hg debugnodemap --metadata
264 264 uid: ???????? (glob)
265 265 tip-rev: 5002
266 266 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
267 267 data-length: 121600
268 268 data-unused: 512
269 269 data-unused: 0.421%
270 270 $ f --sha256 .hg/store/00changelog-*.nd --size
271 271 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
272 272 #endif
273 273 #if rust
274 274 $ hg debugnodemap --metadata
275 275 uid: ???????? (glob)
276 276 tip-rev: 5002
277 277 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
278 278 data-length: 121600
279 279 data-unused: 512
280 280 data-unused: 0.421%
281 281 $ f --sha256 .hg/store/00changelog-*.nd --size
282 282 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
283 283 #endif
284 284 #if no-pure no-rust
285 285 $ hg debugnodemap --metadata
286 286 uid: ???????? (glob)
287 287 tip-rev: 5002
288 288 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
289 289 data-length: 121088
290 290 data-unused: 0
291 291 data-unused: 0.000%
292 292 $ f --sha256 .hg/store/00changelog-*.nd --size
293 293 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
294 294 #endif
295 295
296 296 Test force warming the cache
297 297
298 298 $ rm .hg/store/00changelog.n
299 299 $ hg debugnodemap --metadata
300 300 $ hg debugupdatecache
301 301 #if pure
302 302 $ hg debugnodemap --metadata
303 303 uid: ???????? (glob)
304 304 tip-rev: 5002
305 305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
306 306 data-length: 121088
307 307 data-unused: 0
308 308 data-unused: 0.000%
309 309 #else
310 310 $ hg debugnodemap --metadata
311 311 uid: ???????? (glob)
312 312 tip-rev: 5002
313 313 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
314 314 data-length: 121088
315 315 data-unused: 0
316 316 data-unused: 0.000%
317 317 #endif
318 318
319 319 Check out of sync nodemap
320 320 =========================
321 321
322 322 First copy old data on the side.
323 323
324 324 $ mkdir ../tmp-copies
325 325 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
326 326
327 327 Nodemap lagging behind
328 328 ----------------------
329 329
330 330 make a new commit
331 331
332 332 $ echo bar2 > bar
333 333 $ hg ci -m 'bar2'
334 334 $ NODE=`hg log -r tip -T '{node}\n'`
335 335 $ hg log -r "$NODE" -T '{rev}\n'
336 336 5003
337 337
338 338 If the nodemap is lagging behind, it can catch up fine
339 339
340 340 $ hg debugnodemap --metadata
341 341 uid: ???????? (glob)
342 342 tip-rev: 5003
343 343 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
344 344 data-length: 121344 (pure !)
345 345 data-length: 121344 (rust !)
346 346 data-length: 121152 (no-rust no-pure !)
347 347 data-unused: 192 (pure !)
348 348 data-unused: 192 (rust !)
349 349 data-unused: 0 (no-rust no-pure !)
350 350 data-unused: 0.158% (pure !)
351 351 data-unused: 0.158% (rust !)
352 352 data-unused: 0.000% (no-rust no-pure !)
353 353 $ cp -f ../tmp-copies/* .hg/store/
354 354 $ hg debugnodemap --metadata
355 355 uid: ???????? (glob)
356 356 tip-rev: 5002
357 357 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
358 358 data-length: 121088
359 359 data-unused: 0
360 360 data-unused: 0.000%
361 361 $ hg log -r "$NODE" -T '{rev}\n'
362 362 5003
363 363
364 364 changelog altered
365 365 -----------------
366 366
367 367 If the nodemap is not gated behind a requirements, an unaware client can alter
368 368 the repository so the revlog used to generate the nodemap is not longer
369 369 compatible with the persistent nodemap. We need to detect that.
370 370
371 371 $ hg up "$NODE~5"
372 372 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
373 373 $ echo bar > babar
374 374 $ hg add babar
375 375 $ hg ci -m 'babar'
376 376 created new head
377 377 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
378 378 $ hg log -r "$OTHERNODE" -T '{rev}\n'
379 379 5004
380 380
381 381 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
382 382
383 383 the nodemap should detect the changelog have been tampered with and recover.
384 384
385 385 $ hg debugnodemap --metadata
386 386 uid: ???????? (glob)
387 387 tip-rev: 5002
388 388 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
389 389 data-length: 121536 (pure !)
390 390 data-length: 121088 (rust !)
391 391 data-length: 121088 (no-pure no-rust !)
392 392 data-unused: 448 (pure !)
393 393 data-unused: 0 (rust !)
394 394 data-unused: 0 (no-pure no-rust !)
395 395 data-unused: 0.000% (rust !)
396 396 data-unused: 0.369% (pure !)
397 397 data-unused: 0.000% (no-pure no-rust !)
398 398
399 399 $ cp -f ../tmp-copies/* .hg/store/
400 400 $ hg debugnodemap --metadata
401 401 uid: ???????? (glob)
402 402 tip-rev: 5002
403 403 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
404 404 data-length: 121088
405 405 data-unused: 0
406 406 data-unused: 0.000%
407 407 $ hg log -r "$OTHERNODE" -T '{rev}\n'
408 408 5002
409 409
410 410 missing data file
411 411 -----------------
412 412
413 413 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
414 414 > sed 's/uid: //'`
415 415 $ FILE=.hg/store/00changelog-"${UUID}".nd
416 416 $ mv $FILE ../tmp-data-file
417 417 $ cp .hg/store/00changelog.n ../tmp-docket
418 418
419 419 mercurial don't crash
420 420
421 421 $ hg log -r .
422 422 changeset: 5002:b355ef8adce0
423 423 tag: tip
424 424 parent: 4998:d918ad6d18d3
425 425 user: test
426 426 date: Thu Jan 01 00:00:00 1970 +0000
427 427 summary: babar
428 428
429 429 $ hg debugnodemap --metadata
430 430
431 431 $ hg debugupdatecache
432 432 $ hg debugnodemap --metadata
433 433 uid: * (glob)
434 434 tip-rev: 5002
435 435 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
436 436 data-length: 121088
437 437 data-unused: 0
438 438 data-unused: 0.000%
439 439 $ mv ../tmp-data-file $FILE
440 440 $ mv ../tmp-docket .hg/store/00changelog.n
441 441
442 442 Check transaction related property
443 443 ==================================
444 444
445 445 An up to date nodemap should be available to shell hooks,
446 446
447 447 $ echo dsljfl > a
448 448 $ hg add a
449 449 $ hg ci -m a
450 450 $ hg debugnodemap --metadata
451 451 uid: ???????? (glob)
452 452 tip-rev: 5003
453 453 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
454 454 data-length: 121088
455 455 data-unused: 0
456 456 data-unused: 0.000%
457 457 $ echo babar2 > babar
458 458 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
459 459 uid: ???????? (glob)
460 460 tip-rev: 5004
461 461 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
462 462 data-length: 121280 (pure !)
463 463 data-length: 121280 (rust !)
464 464 data-length: 121088 (no-pure no-rust !)
465 465 data-unused: 192 (pure !)
466 466 data-unused: 192 (rust !)
467 467 data-unused: 0 (no-pure no-rust !)
468 468 data-unused: 0.158% (pure !)
469 469 data-unused: 0.158% (rust !)
470 470 data-unused: 0.000% (no-pure no-rust !)
471 471 $ hg debugnodemap --metadata
472 472 uid: ???????? (glob)
473 473 tip-rev: 5004
474 474 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
475 475 data-length: 121280 (pure !)
476 476 data-length: 121280 (rust !)
477 477 data-length: 121088 (no-pure no-rust !)
478 478 data-unused: 192 (pure !)
479 479 data-unused: 192 (rust !)
480 480 data-unused: 0 (no-pure no-rust !)
481 481 data-unused: 0.158% (pure !)
482 482 data-unused: 0.158% (rust !)
483 483 data-unused: 0.000% (no-pure no-rust !)
484 484
485 485 Another process does not see the pending nodemap content during run.
486 486
487 487 $ echo qpoasp > a
488 488 $ hg ci -m a2 \
489 489 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
490 490 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
491 491
492 492 (read the repository while the commit transaction is pending)
493 493
494 494 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
495 495 > hg debugnodemap --metadata && \
496 496 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
497 497 uid: ???????? (glob)
498 498 tip-rev: 5004
499 499 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
500 500 data-length: 121280 (pure !)
501 501 data-length: 121280 (rust !)
502 502 data-length: 121088 (no-pure no-rust !)
503 503 data-unused: 192 (pure !)
504 504 data-unused: 192 (rust !)
505 505 data-unused: 0 (no-pure no-rust !)
506 506 data-unused: 0.158% (pure !)
507 507 data-unused: 0.158% (rust !)
508 508 data-unused: 0.000% (no-pure no-rust !)
509 509 $ hg debugnodemap --metadata
510 510 uid: ???????? (glob)
511 511 tip-rev: 5005
512 512 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
513 513 data-length: 121536 (pure !)
514 514 data-length: 121536 (rust !)
515 515 data-length: 121088 (no-pure no-rust !)
516 516 data-unused: 448 (pure !)
517 517 data-unused: 448 (rust !)
518 518 data-unused: 0 (no-pure no-rust !)
519 519 data-unused: 0.369% (pure !)
520 520 data-unused: 0.369% (rust !)
521 521 data-unused: 0.000% (no-pure no-rust !)
522 522
523 523 $ cat output.txt
524 524
525 525 Check that a failing transaction will properly revert the data
526 526
527 527 $ echo plakfe > a
528 528 $ f --size --sha256 .hg/store/00changelog-*.nd
529 529 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
530 530 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
531 531 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
532 532 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
533 533 transaction abort!
534 534 rollback completed
535 535 abort: This is a late abort
536 536 [255]
537 537 $ hg debugnodemap --metadata
538 538 uid: ???????? (glob)
539 539 tip-rev: 5005
540 540 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
541 541 data-length: 121536 (pure !)
542 542 data-length: 121536 (rust !)
543 543 data-length: 121088 (no-pure no-rust !)
544 544 data-unused: 448 (pure !)
545 545 data-unused: 448 (rust !)
546 546 data-unused: 0 (no-pure no-rust !)
547 547 data-unused: 0.369% (pure !)
548 548 data-unused: 0.369% (rust !)
549 549 data-unused: 0.000% (no-pure no-rust !)
550 550 $ f --size --sha256 .hg/store/00changelog-*.nd
551 551 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
552 552 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
553 553 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
554 554
555 555 Check that removing content does not confuse the nodemap
556 556 --------------------------------------------------------
557 557
558 558 removing data with rollback
559 559
560 560 $ echo aso > a
561 561 $ hg ci -m a4
562 562 $ hg rollback
563 563 repository tip rolled back to revision 5005 (undo commit)
564 564 working directory now based on revision 5005
565 565 $ hg id -r .
566 566 90d5d3ba2fc4 tip
567 567
568 568 removing data with strip
569 569
570 570 $ echo aso > a
571 571 $ hg ci -m a4
572 572 $ hg --config extensions.strip= strip -r . --no-backup
573 573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 574 $ hg id -r . --traceback
575 575 90d5d3ba2fc4 tip
576 576
577 577 (be a good citizen and regenerate the nodemap)
578 578 $ hg debugupdatecaches
579 579 $ hg debugnodemap --metadata
580 580 uid: * (glob)
581 581 tip-rev: 5005
582 582 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
583 583 data-length: 121088
584 584 data-unused: 0
585 585 data-unused: 0.000%
586 586
587 587 Check race condition when multiple process write new data to the repository
588 588 ---------------------------------------------------------------------------
589 589
590 590 In this test, we check that two writers touching the repositories will not
591 591 overwrite each other data. This test is prompted by the existent of issue6554.
592 592 Where a writer ended up using and outdated docket to update the repository. See
593 593 the dedicated extension for details on the race windows and read/write schedule
594 594 necessary to end up in this situation: testlib/persistent-nodemap-race-ext.py
595 595
596 596 The issue was initially observed on a server with a high push trafic, but it
597 597 can be reproduced using a share and two commiting process which seems simpler.
598 598
599 599 The test is Rust only as the other implementation does not use the same
600 600 read/write patterns.
601 601
602 602 $ cd ..
603 603
604 604 #if rust
605 605
606 606 $ cp -R test-repo race-repo
607 607 $ hg share race-repo ./other-wc --config format.use-share-safe=yes
608 608 updating working directory
609 609 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 610 $ hg debugformat -R ./race-repo | egrep 'share-safe|persistent-nodemap'
611 611 share-safe: yes
612 612 persistent-nodemap: yes
613 613 $ hg debugformat -R ./other-wc/ | egrep 'share-safe|persistent-nodemap'
614 614 share-safe: yes
615 615 persistent-nodemap: yes
616 616 $ hg -R ./other-wc update 'min(head())'
617 617 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
618 618 $ hg -R ./race-repo debugnodemap --metadata
619 619 uid: 43c37dde
620 620 tip-rev: 5005
621 621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
622 622 data-length: 121088
623 623 data-unused: 0
624 624 data-unused: 0.000%
625 625 $ hg -R ./race-repo log -G -r 'head()'
626 626 @ changeset: 5005:90d5d3ba2fc4
627 627 | tag: tip
628 628 ~ user: test
629 629 date: Thu Jan 01 00:00:00 1970 +0000
630 630 summary: a2
631 631
632 632 o changeset: 5001:16395c3cf7e2
633 633 | user: test
634 634 ~ date: Thu Jan 01 00:00:00 1970 +0000
635 635 summary: foo
636 636
637 637 $ hg -R ./other-wc log -G -r 'head()'
638 638 o changeset: 5005:90d5d3ba2fc4
639 639 | tag: tip
640 640 ~ user: test
641 641 date: Thu Jan 01 00:00:00 1970 +0000
642 642 summary: a2
643 643
644 644 @ changeset: 5001:16395c3cf7e2
645 645 | user: test
646 646 ~ date: Thu Jan 01 00:00:00 1970 +0000
647 647 summary: foo
648 648
649 649 $ echo left-side-race > race-repo/left-side-race
650 650 $ hg -R ./race-repo/ add race-repo/left-side-race
651 651
652 652 $ echo right-side-race > ./other-wc/right-side-race
653 653 $ hg -R ./other-wc/ add ./other-wc/right-side-race
654 654
655 655 $ mkdir sync-files
656 656 $ mkdir outputs
657 657 $ (
658 658 > hg -R ./race-repo/ commit -m left-side-commit \
659 659 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
660 660 > --config 'devel.nodemap-race.role=left';
661 661 > touch sync-files/left-done
662 662 > ) > outputs/left.txt 2>&1 &
663 663 $ (
664 664 > hg -R ./other-wc/ commit -m right-side-commit \
665 665 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
666 666 > --config 'devel.nodemap-race.role=right';
667 667 > touch sync-files/right-done
668 668 > ) > outputs/right.txt 2>&1 &
669 669 $ (
670 670 > hg -R ./race-repo/ check-nodemap-race \
671 671 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
672 672 > --config 'devel.nodemap-race.role=reader';
673 673 > touch sync-files/reader-done
674 674 > ) > outputs/reader.txt 2>&1 &
675 675 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/left-done
676 676 $ cat outputs/left.txt
677 677 docket-details:
678 678 uid: 43c37dde
679 679 actual-tip: 5005
680 680 tip-rev: 5005
681 681 data-length: 121088
682 682 nodemap-race: left side locked and ready to commit
683 683 docket-details:
684 684 uid: 43c37dde
685 685 actual-tip: 5005
686 686 tip-rev: 5005
687 687 data-length: 121088
688 688 finalized changelog write
689 689 persisting changelog nodemap
690 690 new data start at 121088
691 691 persisted changelog nodemap
692 692 docket-details:
693 693 uid: 43c37dde
694 694 actual-tip: 5006
695 695 tip-rev: 5006
696 696 data-length: 121280
697 697 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/right-done
698 698 $ cat outputs/right.txt
699 699 nodemap-race: right side start of the locking sequence
700 700 nodemap-race: right side reading changelog
701 701 nodemap-race: right side reading of changelog is done
702 702 docket-details:
703 703 uid: 43c37dde
704 704 actual-tip: 5006
705 705 tip-rev: 5005
706 706 data-length: 121088
707 707 nodemap-race: right side ready to wait for the lock
708 708 nodemap-race: right side locked and ready to commit
709 709 docket-details:
710 710 uid: 43c37dde
711 711 actual-tip: 5006
712 712 tip-rev: 5006
713 713 data-length: 121280
714 714 right ready to write, waiting for reader
715 715 right proceeding with writing its changelog index and nodemap
716 716 finalized changelog write
717 717 persisting changelog nodemap
718 718 new data start at 121280
719 719 persisted changelog nodemap
720 720 docket-details:
721 721 uid: 43c37dde
722 722 actual-tip: 5007
723 723 tip-rev: 5007
724 724 data-length: 121536
725 725 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/reader-done
726 726 $ cat outputs/reader.txt
727 727 reader: reading changelog
728 728 reader ready to read the changelog, waiting for right
729 729 reader: nodemap docket read
730 730 record-data-length: 121280
731 731 actual-data-length: 121280
732 732 file-actual-length: 121536
733 733 reader: changelog read
734 734 docket-details:
735 735 uid: 43c37dde
736 736 actual-tip: 5006
737 737 tip-rev: 5006
738 738 data-length: 121280
739 739 tip-rev: 5006
740 740 tip-node: 492901161367
741 741 node-rev: 5006
742 742
743 743 $ hg -R ./race-repo log -G -r 'head()'
744 744 o changeset: 5007:ac4a2abde241
745 745 | tag: tip
746 746 ~ parent: 5001:16395c3cf7e2
747 747 user: test
748 748 date: Thu Jan 01 00:00:00 1970 +0000
749 749 summary: right-side-commit
750 750
751 751 @ changeset: 5006:492901161367
752 752 | user: test
753 753 ~ date: Thu Jan 01 00:00:00 1970 +0000
754 754 summary: left-side-commit
755 755
756 756 $ hg -R ./other-wc log -G -r 'head()'
757 757 @ changeset: 5007:ac4a2abde241
758 758 | tag: tip
759 759 ~ parent: 5001:16395c3cf7e2
760 760 user: test
761 761 date: Thu Jan 01 00:00:00 1970 +0000
762 762 summary: right-side-commit
763 763
764 764 o changeset: 5006:492901161367
765 765 | user: test
766 766 ~ date: Thu Jan 01 00:00:00 1970 +0000
767 767 summary: left-side-commit
768 768
769 769 #endif
770 770
771 771 Test upgrade / downgrade
772 772 ========================
773 773
774 774 $ cd ./test-repo/
775 775
776 776 downgrading
777 777
778 778 $ cat << EOF >> .hg/hgrc
779 779 > [format]
780 780 > use-persistent-nodemap=no
781 781 > EOF
782 782 $ hg debugformat -v
783 783 format-variant repo config default
784 784 fncache: yes yes yes
785 785 dirstate-v2: no no no
786 786 tracked-hint: no no no
787 787 dotencode: yes yes yes
788 788 generaldelta: yes yes yes
789 789 share-safe: yes yes yes
790 790 sparserevlog: yes yes yes
791 791 persistent-nodemap: yes no no
792 792 copies-sdc: no no no
793 793 revlog-v2: no no no
794 794 changelog-v2: no no no
795 795 plain-cl-delta: yes yes yes
796 796 compression: zlib zlib zlib (no-zstd !)
797 797 compression: zstd zstd zstd (zstd !)
798 798 compression-level: default default default
799 799 $ hg debugupgraderepo --run --no-backup --quiet
800 800 upgrade will perform the following actions:
801 801
802 802 requirements
803 803 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
804 804 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
805 805 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
806 806 removed: persistent-nodemap
807 807
808 808 processed revlogs:
809 809 - all-filelogs
810 810 - changelog
811 811 - manifest
812 812
813 813 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
814 814 [1]
815 815 $ hg debugnodemap --metadata
816 816
817 817
818 818 upgrading
819 819
820 820 $ cat << EOF >> .hg/hgrc
821 821 > [format]
822 822 > use-persistent-nodemap=yes
823 823 > EOF
824 824 $ hg debugformat -v
825 825 format-variant repo config default
826 826 fncache: yes yes yes
827 827 dirstate-v2: no no no
828 828 tracked-hint: no no no
829 829 dotencode: yes yes yes
830 830 generaldelta: yes yes yes
831 831 share-safe: yes yes yes
832 832 sparserevlog: yes yes yes
833 833 persistent-nodemap: no yes no
834 834 copies-sdc: no no no
835 835 revlog-v2: no no no
836 836 changelog-v2: no no no
837 837 plain-cl-delta: yes yes yes
838 838 compression: zlib zlib zlib (no-zstd !)
839 839 compression: zstd zstd zstd (zstd !)
840 840 compression-level: default default default
841 841 $ hg debugupgraderepo --run --no-backup --quiet
842 842 upgrade will perform the following actions:
843 843
844 844 requirements
845 845 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
846 846 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
847 847 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
848 848 added: persistent-nodemap
849 849
850 850 processed revlogs:
851 851 - all-filelogs
852 852 - changelog
853 853 - manifest
854 854
855 855 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
856 856 00changelog-*.nd (glob)
857 857 00changelog.n
858 858 00manifest-*.nd (glob)
859 859 00manifest.n
860 860
861 861 $ hg debugnodemap --metadata
862 862 uid: * (glob)
863 863 tip-rev: 5005
864 864 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
865 865 data-length: 121088
866 866 data-unused: 0
867 867 data-unused: 0.000%
868 868
869 869 Running unrelated upgrade
870 870
871 871 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
872 872 upgrade will perform the following actions:
873 873
874 874 requirements
875 875 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
876 876 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
877 877 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
878 878
879 879 optimisations: re-delta-all
880 880
881 881 processed revlogs:
882 882 - all-filelogs
883 883 - changelog
884 884 - manifest
885 885
886 886 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
887 887 00changelog-*.nd (glob)
888 888 00changelog.n
889 889 00manifest-*.nd (glob)
890 890 00manifest.n
891 891
892 892 $ hg debugnodemap --metadata
893 893 uid: * (glob)
894 894 tip-rev: 5005
895 895 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
896 896 data-length: 121088
897 897 data-unused: 0
898 898 data-unused: 0.000%
899 899
900 900 Persistent nodemap and local/streaming clone
901 901 ============================================
902 902
903 903 $ cd ..
904 904
905 905 standard clone
906 906 --------------
907 907
908 908 The persistent nodemap should exist after a streaming clone
909 909
910 910 $ hg clone --pull --quiet -U test-repo standard-clone
911 911 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
912 912 00changelog-*.nd (glob)
913 913 00changelog.n
914 914 00manifest-*.nd (glob)
915 915 00manifest.n
916 916 $ hg -R standard-clone debugnodemap --metadata
917 917 uid: * (glob)
918 918 tip-rev: 5005
919 919 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
920 920 data-length: 121088
921 921 data-unused: 0
922 922 data-unused: 0.000%
923 923
924 924
925 925 local clone
926 926 ------------
927 927
928 928 The persistent nodemap should exist after a streaming clone
929 929
930 930 $ hg clone -U test-repo local-clone
931 931 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
932 932 00changelog-*.nd (glob)
933 933 00changelog.n
934 934 00manifest-*.nd (glob)
935 935 00manifest.n
936 936 $ hg -R local-clone debugnodemap --metadata
937 937 uid: * (glob)
938 938 tip-rev: 5005
939 939 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
940 940 data-length: 121088
941 941 data-unused: 0
942 942 data-unused: 0.000%
943 943
944 944 Test various corruption case
945 945 ============================
946 946
947 947 Missing datafile
948 948 ----------------
949 949
950 950 Test behavior with a missing datafile
951 951
952 952 $ hg clone --quiet --pull test-repo corruption-test-repo
953 953 $ ls -1 corruption-test-repo/.hg/store/00changelog*
954 954 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
955 955 corruption-test-repo/.hg/store/00changelog.d
956 956 corruption-test-repo/.hg/store/00changelog.i
957 957 corruption-test-repo/.hg/store/00changelog.n
958 958 $ rm corruption-test-repo/.hg/store/00changelog*.nd
959 959 $ hg log -R corruption-test-repo -r .
960 960 changeset: 5005:90d5d3ba2fc4
961 961 tag: tip
962 962 user: test
963 963 date: Thu Jan 01 00:00:00 1970 +0000
964 964 summary: a2
965 965
966 966 $ ls -1 corruption-test-repo/.hg/store/00changelog*
967 967 corruption-test-repo/.hg/store/00changelog.d
968 968 corruption-test-repo/.hg/store/00changelog.i
969 969 corruption-test-repo/.hg/store/00changelog.n
970 970
971 971 Truncated data file
972 972 -------------------
973 973
974 974 Test behavior with a too short datafile
975 975
976 976 rebuild the missing data
977 977 $ hg -R corruption-test-repo debugupdatecache
978 978 $ ls -1 corruption-test-repo/.hg/store/00changelog*
979 979 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
980 980 corruption-test-repo/.hg/store/00changelog.d
981 981 corruption-test-repo/.hg/store/00changelog.i
982 982 corruption-test-repo/.hg/store/00changelog.n
983 983
984 984 truncate the file
985 985
986 986 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
987 987 $ f -s $datafilepath
988 988 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
989 989 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp
990 990 10+0 records in
991 991 10+0 records out
992 992 * bytes * (glob)
993 993 $ mv $datafilepath-tmp $datafilepath
994 994 $ f -s $datafilepath
995 995 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
996 996
997 997 Check that Mercurial reaction to this event
998 998
999 999 $ hg -R corruption-test-repo log -r . --traceback
1000 1000 changeset: 5005:90d5d3ba2fc4
1001 1001 tag: tip
1002 1002 user: test
1003 1003 date: Thu Jan 01 00:00:00 1970 +0000
1004 1004 summary: a2
1005 1005
1006 1006
1007 1007
1008 1008 stream clone
1009 1009 ============
1010 1010
1011 1011 The persistent nodemap should exist after a streaming clone
1012 1012
1013 1013 Simple case
1014 1014 -----------
1015 1015
1016 1016 No race condition
1017 1017
1018 1018 $ hg clone -U --stream ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
1019 1019 adding [s] 00manifest.n (62 bytes)
1020 1020 adding [s] 00manifest-*.nd (118 KB) (glob)
1021 1021 adding [s] 00changelog.n (62 bytes)
1022 1022 adding [s] 00changelog-*.nd (118 KB) (glob)
1023 1023 adding [s] 00manifest.d (452 KB) (no-zstd !)
1024 1024 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1025 1025 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1026 1026 adding [s] 00changelog.d (360 KB) (no-zstd !)
1027 1027 adding [s] 00changelog.d (368 KB) (zstd !)
1028 1028 adding [s] 00manifest.i (313 KB)
1029 1029 adding [s] 00changelog.i (313 KB)
1030 1030 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
1031 1031 00changelog-*.nd (glob)
1032 1032 00changelog.n
1033 1033 00manifest-*.nd (glob)
1034 1034 00manifest.n
1035 1035 $ hg -R stream-clone debugnodemap --metadata
1036 1036 uid: * (glob)
1037 1037 tip-rev: 5005
1038 1038 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1039 1039 data-length: 121088
1040 1040 data-unused: 0
1041 1041 data-unused: 0.000%
1042 1042
1043 1043 new data appened
1044 1044 -----------------
1045 1045
1046 1046 Other commit happening on the server during the stream clone
1047 1047
1048 1048 setup the step-by-step stream cloning
1049 1049
1050 1050 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
1051 1051 $ export HG_TEST_STREAM_WALKED_FILE_1
1052 1052 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
1053 1053 $ export HG_TEST_STREAM_WALKED_FILE_2
1054 1054 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
1055 1055 $ export HG_TEST_STREAM_WALKED_FILE_3
1056 1056 $ cat << EOF >> test-repo/.hg/hgrc
1057 1057 > [extensions]
1058 1058 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
1059 1059 > EOF
1060 1060
1061 1061 Check and record file state beforehand
1062 1062
1063 1063 $ f --size test-repo/.hg/store/00changelog*
1064 1064 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
1065 1065 test-repo/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1066 1066 test-repo/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1067 1067 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
1068 1068 test-repo/.hg/store/00changelog.i: size=320384
1069 1069 test-repo/.hg/store/00changelog.n: size=62
1070 1070 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
1071 1071 uid: * (glob)
1072 1072 tip-rev: 5005
1073 1073 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1074 1074 data-length: 121088
1075 1075 data-unused: 0
1076 1076 data-unused: 0.000%
1077 1077
1078 1078 Prepare a commit
1079 1079
1080 1080 $ echo foo >> test-repo/foo
1081 1081 $ hg -R test-repo/ add test-repo/foo
1082 1082
1083 1083 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
1084 1084
1085 1085 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1086 1086 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1087 1087 $ hg -R test-repo/ commit -m foo
1088 1088 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1089 1089 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1090 1090 $ cat clone-output
1091 1091 adding [s] 00manifest.n (62 bytes)
1092 1092 adding [s] 00manifest-*.nd (118 KB) (glob)
1093 1093 adding [s] 00changelog.n (62 bytes)
1094 1094 adding [s] 00changelog-*.nd (118 KB) (glob)
1095 1095 adding [s] 00manifest.d (452 KB) (no-zstd !)
1096 1096 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1097 1097 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1098 1098 adding [s] 00changelog.d (360 KB) (no-zstd !)
1099 1099 adding [s] 00changelog.d (368 KB) (zstd !)
1100 1100 adding [s] 00manifest.i (313 KB)
1101 1101 adding [s] 00changelog.i (313 KB)
1102 1102
1103 1103 Check the result state
1104 1104
1105 1105 $ f --size stream-clone-race-1/.hg/store/00changelog*
1106 1106 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
1107 1107 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
1108 1108 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1109 1109 stream-clone-race-1/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1110 1110 stream-clone-race-1/.hg/store/00changelog.i: size=320384
1111 1111 stream-clone-race-1/.hg/store/00changelog.n: size=62
1112 1112
1113 1113 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
1114 1114 uid: * (glob)
1115 1115 tip-rev: 5005
1116 1116 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1117 1117 data-length: 121088
1118 1118 data-unused: 0
1119 1119 data-unused: 0.000%
1120 1120
1121 1121 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1122 1122 (ie: the following diff should be empty)
1123 1123
1124 1124 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1125 1125
1126 1126 #if no-rust no-pure
1127 1127 $ diff -u server-metadata.txt client-metadata.txt
1128 1128 --- server-metadata.txt * (glob)
1129 1129 +++ client-metadata.txt * (glob)
1130 1130 @@ -1,4 +1,4 @@
1131 1131 -uid: * (glob)
1132 1132 +uid: * (glob)
1133 1133 tip-rev: 5005
1134 1134 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1135 1135 data-length: 121088
1136 1136 [1]
1137 1137 #else
1138 1138 $ diff -u server-metadata.txt client-metadata.txt
1139 1139 #endif
1140 1140
1141 1141
1142 1142 Clean up after the test.
1143 1143
1144 1144 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
1145 1145 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
1146 1146 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
1147 1147
1148 1148 full regeneration
1149 1149 -----------------
1150 1150
1151 1151 A full nodemap is generated
1152 1152
1153 1153 (ideally this test would append enough data to make sure the nodemap data file
1154 1154 get changed, however to make thing simpler we will force the regeneration for
1155 1155 this test.
1156 1156
1157 1157 Check the initial state
1158 1158
1159 1159 $ f --size test-repo/.hg/store/00changelog*
1160 1160 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1161 1161 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1162 1162 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1163 1163 test-repo/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1164 1164 test-repo/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1165 1165 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1166 1166 test-repo/.hg/store/00changelog.i: size=320448
1167 1167 test-repo/.hg/store/00changelog.n: size=62
1168 1168 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1169 1169 uid: * (glob)
1170 1170 tip-rev: 5006
1171 1171 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1172 1172 data-length: 121344 (rust !)
1173 1173 data-length: 121344 (pure !)
1174 1174 data-length: 121152 (no-rust no-pure !)
1175 1175 data-unused: 192 (rust !)
1176 1176 data-unused: 192 (pure !)
1177 1177 data-unused: 0 (no-rust no-pure !)
1178 1178 data-unused: 0.158% (rust !)
1179 1179 data-unused: 0.158% (pure !)
1180 1180 data-unused: 0.000% (no-rust no-pure !)
1181 1181
1182 1182 Performe the mix of clone and full refresh of the nodemap, so that the files
1183 1183 (and filenames) are different between listing time and actual transfer time.
1184 1184
1185 1185 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1186 1186 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1187 1187 $ rm test-repo/.hg/store/00changelog.n
1188 1188 $ rm test-repo/.hg/store/00changelog-*.nd
1189 1189 $ hg -R test-repo/ debugupdatecache
1190 1190 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1191 1191 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1192 1192
1193 1193 (note: the stream clone code wronly pick the `undo.` files)
1194 1194
1195 1195 $ cat clone-output-2
1196 adding [s] undo.backup.00manifest.n (62 bytes) (known-bad-output !)
1197 adding [s] undo.backup.00changelog.n (62 bytes) (known-bad-output !)
1198 1196 adding [s] 00manifest.n (62 bytes)
1199 1197 adding [s] 00manifest-*.nd (118 KB) (glob)
1200 1198 adding [s] 00changelog.n (62 bytes)
1201 1199 adding [s] 00changelog-*.nd (118 KB) (glob)
1202 1200 adding [s] 00manifest.d (492 KB) (zstd !)
1203 1201 adding [s] 00manifest.d (452 KB) (no-zstd !)
1204 1202 adding [s] 00changelog.d (360 KB) (no-zstd !)
1205 1203 adding [s] 00changelog.d (368 KB) (zstd !)
1206 1204 adding [s] 00manifest.i (313 KB)
1207 1205 adding [s] 00changelog.i (313 KB)
1208 1206
1209 1207 Check the result.
1210 1208
1211 1209 $ f --size stream-clone-race-2/.hg/store/00changelog*
1212 1210 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1213 1211 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1214 1212 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1215 1213 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1216 1214 stream-clone-race-2/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1217 1215 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1218 1216 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1219 1217 stream-clone-race-2/.hg/store/00changelog.n: size=62
1220 1218
1221 1219 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1222 1220 uid: * (glob)
1223 1221 tip-rev: 5006
1224 1222 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1225 1223 data-length: 121344 (rust !)
1226 1224 data-unused: 192 (rust !)
1227 1225 data-unused: 0.158% (rust !)
1228 1226 data-length: 121152 (no-rust no-pure !)
1229 1227 data-unused: 0 (no-rust no-pure !)
1230 1228 data-unused: 0.000% (no-rust no-pure !)
1231 1229 data-length: 121344 (pure !)
1232 1230 data-unused: 192 (pure !)
1233 1231 data-unused: 0.158% (pure !)
1234 1232
1235 1233 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1236 1234 (ie: the following diff should be empty)
1237 1235
1238 1236 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1239 1237
1240 1238 #if no-rust no-pure
1241 1239 $ diff -u server-metadata-2.txt client-metadata-2.txt
1242 1240 --- server-metadata-2.txt * (glob)
1243 1241 +++ client-metadata-2.txt * (glob)
1244 1242 @@ -1,4 +1,4 @@
1245 1243 -uid: * (glob)
1246 1244 +uid: * (glob)
1247 1245 tip-rev: 5006
1248 1246 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1249 1247 data-length: 121152
1250 1248 [1]
1251 1249 #else
1252 1250 $ diff -u server-metadata-2.txt client-metadata-2.txt
1253 1251 #endif
1254 1252
1255 1253 Clean up after the test
1256 1254
1257 1255 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1258 1256 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1259 1257 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1260 1258
@@ -1,511 +1,510 b''
1 1 #testcases abortcommand abortflag
2 2 #testcases continuecommand continueflag
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > rebase=
7 7 >
8 8 > [phases]
9 9 > publish=False
10 10 >
11 11 > [alias]
12 12 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
13 13 > EOF
14 14
15 15 #if abortflag
16 16 $ cat >> $HGRCPATH <<EOF
17 17 > [alias]
18 18 > abort = rebase --abort
19 19 > EOF
20 20 #endif
21 21
22 22 #if continueflag
23 23 $ cat >> $HGRCPATH <<EOF
24 24 > [alias]
25 25 > continue = rebase --continue
26 26 > EOF
27 27 #endif
28 28
29 29 $ hg init a
30 30 $ cd a
31 31
32 32 $ touch .hg/rebasestate
33 33 $ hg sum
34 34 parent: -1:000000000000 tip (empty repository)
35 35 branch: default
36 36 commit: (clean)
37 37 update: (current)
38 38 abort: .hg/rebasestate is incomplete
39 39 [255]
40 40 $ rm .hg/rebasestate
41 41
42 42 $ echo c1 > common
43 43 $ hg add common
44 44 $ hg ci -m C1
45 45
46 46 $ echo c2 >> common
47 47 $ hg ci -m C2
48 48
49 49 $ echo c3 >> common
50 50 $ hg ci -m C3
51 51
52 52 $ hg up -q -C 1
53 53
54 54 $ echo l1 >> extra
55 55 $ hg add extra
56 56 $ hg ci -m L1
57 57 created new head
58 58
59 59 $ sed -e 's/c2/l2/' common > common.new
60 60 $ mv common.new common
61 61 $ hg ci -m L2
62 62
63 63 $ hg phase --force --secret 2
64 64
65 65 $ hg tglog
66 66 @ 4:draft 'L2'
67 67 |
68 68 o 3:draft 'L1'
69 69 |
70 70 | o 2:secret 'C3'
71 71 |/
72 72 o 1:draft 'C2'
73 73 |
74 74 o 0:draft 'C1'
75 75
76 76
77 77 Conflicting rebase:
78 78
79 79 $ hg rebase -s 3 -d 2
80 80 rebasing 3:3163e20567cc "L1"
81 81 rebasing 4:46f0b057b5c0 tip "L2"
82 82 merging common
83 83 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
84 84 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
85 85 [240]
86 86
87 87 Insert unsupported advisory merge record:
88 88
89 89 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
90 90 $ hg debugmergestate
91 91 local (dest): 3e046f2ecedb793b97ed32108086edd1a162f8bc
92 92 other (source): 46f0b057b5c061d276b91491c22151f78698abd2
93 93 file: common (state "u")
94 94 local path: common (hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1, flags "")
95 95 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
96 96 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
97 97 extra: ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c
98 98 extra: merged = yes
99 99 $ hg resolve -l
100 100 U common
101 101
102 102 Insert unsupported mandatory merge record:
103 103
104 104 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
105 105 $ hg debugmergestate
106 106 abort: unsupported merge state records: X
107 107 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
108 108 [255]
109 109 $ hg resolve -l
110 110 abort: unsupported merge state records: X
111 111 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
112 112 [255]
113 113 $ hg resolve -ma
114 114 abort: unsupported merge state records: X
115 115 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
116 116 [255]
117 117
118 118 Abort (should clear out unsupported merge state):
119 119
120 120 #if abortcommand
121 121 when in dry-run mode
122 122 $ hg abort --dry-run
123 123 rebase in progress, will be aborted
124 124 #endif
125 125
126 126 $ hg abort
127 127 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg
128 128 rebase aborted
129 129 $ hg debugmergestate
130 130 no merge state found
131 131
132 132 $ hg tglog
133 133 @ 4:draft 'L2'
134 134 |
135 135 o 3:draft 'L1'
136 136 |
137 137 | o 2:secret 'C3'
138 138 |/
139 139 o 1:draft 'C2'
140 140 |
141 141 o 0:draft 'C1'
142 142
143 143 Test safety for inconsistent rebase state, which may be created (and
144 144 forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
145 145 earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
146 146
147 147 $ hg rebase -s 3 -d 2
148 148 rebasing 3:3163e20567cc "L1"
149 149 rebasing 4:46f0b057b5c0 tip "L2"
150 150 merging common
151 151 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
152 152 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
153 153 [240]
154 154
155 155 $ mv .hg/rebasestate .hg/rebasestate.back
156 156 $ hg update --quiet --clean 2
157 157 $ hg --config extensions.mq= strip --quiet "destination()"
158 158 $ mv .hg/rebasestate.back .hg/rebasestate
159 159
160 160 $ hg continue
161 161 abort: cannot continue inconsistent rebase
162 162 (use "hg rebase --abort" to clear broken state)
163 163 [255]
164 164 $ hg summary | grep '^rebase: '
165 165 rebase: (use "hg rebase --abort" to clear broken state)
166 166 $ hg abort
167 167 rebase aborted (no revision is removed, only broken state is cleared)
168 168
169 169 $ cd ..
170 170
171 171
172 172 Construct new repo:
173 173
174 174 $ hg init b
175 175 $ cd b
176 176
177 177 $ echo a > a
178 178 $ hg ci -Am A
179 179 adding a
180 180
181 181 $ echo b > b
182 182 $ hg ci -Am B
183 183 adding b
184 184
185 185 $ echo c > c
186 186 $ hg ci -Am C
187 187 adding c
188 188
189 189 $ hg up -q 0
190 190
191 191 $ echo b > b
192 192 $ hg ci -Am 'B bis'
193 193 adding b
194 194 created new head
195 195
196 196 $ echo c1 > c
197 197 $ hg ci -Am C1
198 198 adding c
199 199
200 200 $ hg phase --force --secret 1
201 201 $ hg phase --public 1
202 202
203 203 Rebase and abort without generating new changesets:
204 204
205 205 $ hg tglog
206 206 @ 4:draft 'C1'
207 207 |
208 208 o 3:draft 'B bis'
209 209 |
210 210 | o 2:secret 'C'
211 211 | |
212 212 | o 1:public 'B'
213 213 |/
214 214 o 0:public 'A'
215 215
216 216 $ hg rebase -b 4 -d 2
217 217 rebasing 3:a6484957d6b9 "B bis"
218 218 note: not rebasing 3:a6484957d6b9 "B bis", its destination already has all its changes
219 219 rebasing 4:145842775fec tip "C1"
220 220 merging c
221 221 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
222 222 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
223 223 [240]
224 224
225 225 $ hg tglog
226 226 % 4:draft 'C1'
227 227 |
228 228 o 3:draft 'B bis'
229 229 |
230 230 | @ 2:secret 'C'
231 231 | |
232 232 | o 1:public 'B'
233 233 |/
234 234 o 0:public 'A'
235 235
236 236 $ hg rebase -a
237 237 rebase aborted
238 238
239 239 $ hg tglog
240 240 @ 4:draft 'C1'
241 241 |
242 242 o 3:draft 'B bis'
243 243 |
244 244 | o 2:secret 'C'
245 245 | |
246 246 | o 1:public 'B'
247 247 |/
248 248 o 0:public 'A'
249 249
250 250
251 251 $ cd ..
252 252
253 253 rebase abort should not leave working copy in a merge state if tip-1 is public
254 254 (issue4082)
255 255
256 256 $ hg init abortpublic
257 257 $ cd abortpublic
258 258 $ echo a > a && hg ci -Aqm a
259 259 $ hg book master
260 260 $ hg book foo
261 261 $ echo b > b && hg ci -Aqm b
262 262 $ hg up -q master
263 263 $ echo c > c && hg ci -Aqm c
264 264 $ hg phase -p -r .
265 265 $ hg up -q foo
266 266 $ echo C > c && hg ci -Aqm C
267 267 $ hg log -G --template "{rev} {desc} {bookmarks}"
268 268 @ 3 C foo
269 269 |
270 270 | o 2 c master
271 271 | |
272 272 o | 1 b
273 273 |/
274 274 o 0 a
275 275
276 276
277 277 $ hg rebase -d master -r foo
278 278 rebasing 3:6c0f977a22d8 foo tip "C"
279 279 merging c
280 280 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
281 281 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
282 282 [240]
283 283 $ hg abort
284 284 rebase aborted
285 285 $ hg log -G --template "{rev} {desc} {bookmarks}"
286 286 @ 3 C foo
287 287 |
288 288 | o 2 c master
289 289 | |
290 290 o | 1 b
291 291 |/
292 292 o 0 a
293 293
294 294 $ cd ..
295 295
296 296 Make sure we don't clobber changes in the working directory when the
297 297 user has somehow managed to update to a different revision (issue4009)
298 298
299 299 $ hg init noupdate
300 300 $ cd noupdate
301 301 $ hg book @
302 302 $ echo original > a
303 303 $ hg add a
304 304 $ hg commit -m a
305 305 $ echo x > b
306 306 $ hg add b
307 307 $ hg commit -m b1
308 308 $ hg up 0
309 309 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
310 310 (leaving bookmark @)
311 311 $ hg book foo
312 312 $ echo y > b
313 313 $ hg add b
314 314 $ hg commit -m b2
315 315 created new head
316 316
317 317 $ hg rebase -d @ -b foo --tool=internal:fail
318 318 rebasing 2:070cf4580bb5 foo tip "b2"
319 319 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
320 320 [240]
321 321
322 322 $ mv .hg/rebasestate ./ # so we're allowed to hg up like in mercurial <2.6.3
323 323 $ hg up -C 0 # user does other stuff in the repo
324 324 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
325 325
326 326 $ mv rebasestate .hg/ # user upgrades to 2.7
327 327
328 328 $ echo new > a
329 329 $ hg up 1 # user gets an error saying to run hg rebase --abort
330 330 abort: rebase in progress
331 331 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
332 332 [20]
333 333
334 334 $ cat a
335 335 new
336 336 $ hg abort
337 337 rebase aborted
338 338 $ cat a
339 339 new
340 340
341 341 $ cd ..
342 342
343 343 test aborting an interrupted series (issue5084)
344 344 $ hg init interrupted
345 345 $ cd interrupted
346 346 $ touch base
347 347 $ hg add base
348 348 $ hg commit -m base
349 349 $ touch a
350 350 $ hg add a
351 351 $ hg commit -m a
352 352 $ echo 1 > a
353 353 $ hg commit -m 1
354 354 $ touch b
355 355 $ hg add b
356 356 $ hg commit -m b
357 357 $ echo 2 >> a
358 358 $ hg commit -m c
359 359 $ touch d
360 360 $ hg add d
361 361 $ hg commit -m d
362 362 $ hg co -q 1
363 363 $ hg rm a
364 364 $ hg commit -m no-a
365 365 created new head
366 366 $ hg co 0
367 367 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 368 $ hg log -G --template "{rev} {desc} {bookmarks}"
369 369 o 6 no-a
370 370 |
371 371 | o 5 d
372 372 | |
373 373 | o 4 c
374 374 | |
375 375 | o 3 b
376 376 | |
377 377 | o 2 1
378 378 |/
379 379 o 1 a
380 380 |
381 381 @ 0 base
382 382
383 383 $ hg --config extensions.n=$TESTDIR/failfilemerge.py rebase -s 3 -d tip
384 384 rebasing 3:3a71550954f1 "b"
385 385 rebasing 4:e80b69427d80 "c"
386 386 abort: ^C
387 387 [255]
388 388
389 389 New operations are blocked with the correct state message
390 390
391 391 $ find .hg -name '*state' -prune | sort
392 392 .hg/dirstate
393 393 .hg/merge/state
394 394 .hg/rebasestate
395 .hg/undo.backup.dirstate
396 395 .hg/updatestate
397 396
398 397 $ hg rebase -s 3 -d tip
399 398 abort: rebase in progress
400 399 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
401 400 [20]
402 401 $ hg up .
403 402 abort: rebase in progress
404 403 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
405 404 [20]
406 405 $ hg up -C .
407 406 abort: rebase in progress
408 407 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
409 408 [20]
410 409
411 410 $ hg graft 3
412 411 abort: rebase in progress
413 412 (use 'hg rebase --continue', 'hg rebase --abort', or 'hg rebase --stop')
414 413 [20]
415 414
416 415 $ hg abort
417 416 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/3d8812cf300d-93041a90-backup.hg
418 417 rebase aborted
419 418 $ hg log -G --template "{rev} {desc} {bookmarks}"
420 419 o 6 no-a
421 420 |
422 421 | o 5 d
423 422 | |
424 423 | o 4 c
425 424 | |
426 425 | o 3 b
427 426 | |
428 427 | o 2 1
429 428 |/
430 429 o 1 a
431 430 |
432 431 @ 0 base
433 432
434 433 $ hg summary
435 434 parent: 0:df4f53cec30a
436 435 base
437 436 branch: default
438 437 commit: (clean)
439 438 update: 6 new changesets (update)
440 439 phases: 7 draft
441 440
442 441 $ cd ..
443 442 On the other hand, make sure we *do* clobber changes whenever we
444 443 haven't somehow managed to update the repo to a different revision
445 444 during a rebase (issue4661)
446 445
447 446 $ hg ini yesupdate
448 447 $ cd yesupdate
449 448 $ echo "initial data" > foo.txt
450 449 $ hg add
451 450 adding foo.txt
452 451 $ hg ci -m "initial checkin"
453 452 $ echo "change 1" > foo.txt
454 453 $ hg ci -m "change 1"
455 454 $ hg up 0
456 455 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 456 $ echo "conflicting change 1" > foo.txt
458 457 $ hg ci -m "conflicting 1"
459 458 created new head
460 459 $ echo "conflicting change 2" > foo.txt
461 460 $ hg ci -m "conflicting 2"
462 461
463 462 $ hg rebase -d 1 --tool 'internal:fail'
464 463 rebasing 2:e4ea5cdc9789 "conflicting 1"
465 464 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
466 465 [240]
467 466 $ hg abort
468 467 rebase aborted
469 468 $ hg summary
470 469 parent: 3:b16646383533 tip
471 470 conflicting 2
472 471 branch: default
473 472 commit: (clean)
474 473 update: 1 new changesets, 2 branch heads (merge)
475 474 phases: 4 draft
476 475 $ cd ..
477 476
478 477 test aborting a rebase succeeds after rebasing with skipped commits onto a
479 478 public changeset (issue4896)
480 479
481 480 $ hg init succeedonpublic
482 481 $ cd succeedonpublic
483 482 $ echo 'content' > root
484 483 $ hg commit -A -m 'root' -q
485 484
486 485 set up public branch
487 486 $ echo 'content' > disappear
488 487 $ hg commit -A -m 'disappear public' -q
489 488 commit will cause merge conflict on rebase
490 489 $ echo '' > root
491 490 $ hg commit -m 'remove content public' -q
492 491 $ hg phase --public
493 492
494 493 setup the draft branch that will be rebased onto public commit
495 494 $ hg up -r 0 -q
496 495 $ echo 'content' > disappear
497 496 commit will disappear
498 497 $ hg commit -A -m 'disappear draft' -q
499 498 $ echo 'addedcontADDEDentadded' > root
500 499 commit will cause merge conflict on rebase
501 500 $ hg commit -m 'add content draft' -q
502 501
503 502 $ hg rebase -d 'public()' --tool :merge -q
504 503 note: not rebasing 3:0682fd3dabf5 "disappear draft", its destination already has all its changes
505 504 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
506 505 unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
507 506 [240]
508 507 $ hg abort
509 508 rebase aborted
510 509 $ cd ..
511 510
@@ -1,457 +1,457 b''
1 1 setup repo
2 2 $ hg init t
3 3 $ cd t
4 4 $ echo a > a
5 5 $ hg add a
6 6 $ hg commit -m 'add a'
7 7 $ hg verify -q
8 8 $ hg parents
9 9 changeset: 0:1f0dee641bb7
10 10 tag: tip
11 11 user: test
12 12 date: Thu Jan 01 00:00:00 1970 +0000
13 13 summary: add a
14 14
15 15
16 16 rollback to null revision
17 17 $ hg status
18 18 $ hg rollback
19 19 repository tip rolled back to revision -1 (undo commit)
20 20 working directory now based on revision -1
21 21 $ hg verify -q
22 22 $ hg parents
23 23 $ hg status
24 24 A a
25 25
26 26 Two changesets this time so we rollback to a real changeset
27 27 $ hg commit -m'add a again'
28 28 $ echo a >> a
29 29 $ hg commit -m'modify a'
30 30
31 31 Test issue 902 (current branch is preserved)
32 32 $ hg branch test
33 33 marked working directory as branch test
34 34 (branches are permanent and global, did you want a bookmark?)
35 35 $ hg rollback
36 36 repository tip rolled back to revision 0 (undo commit)
37 37 working directory now based on revision 0
38 38 $ hg branch
39 39 default
40 40
41 41 Test issue 1635 (commit message saved)
42 42 $ cat .hg/last-message.txt ; echo
43 43 modify a
44 44
45 45
46 46 working dir unaffected by rollback: do not restore dirstate et. al.
47 47 $ hg branch test --quiet
48 48 $ hg branch
49 49 test
50 50 $ hg log --template '{rev} {branch} {desc|firstline}\n'
51 51 0 default add a again
52 52 $ hg status
53 53 M a
54 54 $ hg bookmark foo
55 55 $ hg commit -m'modify a again'
56 56 $ echo b > b
57 57 $ hg bookmark bar -r default #making bar active, before the transaction
58 58 $ hg log -G --template '{rev} [{branch}] ({bookmarks}) {desc|firstline}\n'
59 59 @ 1 [test] (foo) modify a again
60 60 |
61 61 o 0 [default] (bar) add a again
62 62
63 63 $ hg add b
64 64 $ hg commit -m'add b'
65 65 $ hg log -G --template '{rev} [{branch}] ({bookmarks}) {desc|firstline}\n'
66 66 @ 2 [test] (foo) add b
67 67 |
68 68 o 1 [test] () modify a again
69 69 |
70 70 o 0 [default] (bar) add a again
71 71
72 72 $ hg update bar
73 73 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
74 74 (activating bookmark bar)
75 $ cat .hg/undo.backup.branch
75 $ cat .hg/undo.backup.branch.bck
76 76 test
77 77 $ hg log -G --template '{rev} [{branch}] ({bookmarks}) {desc|firstline}\n'
78 78 o 2 [test] (foo) add b
79 79 |
80 80 o 1 [test] () modify a again
81 81 |
82 82 @ 0 [default] (bar) add a again
83 83
84 84 $ hg rollback
85 85 abort: rollback of last commit while not checked out may lose data
86 86 (use -f to force)
87 87 [255]
88 88 $ hg rollback -f
89 89 repository tip rolled back to revision 1 (undo commit)
90 90 $ hg id -n
91 91 0
92 92 $ hg log -G --template '{rev} [{branch}] ({bookmarks}) {desc|firstline}\n'
93 93 o 1 [test] (foo) modify a again
94 94 |
95 95 @ 0 [default] (bar) add a again
96 96
97 97 $ hg branch
98 98 default
99 99 $ cat .hg/bookmarks.current ; echo
100 100 bar
101 101 $ hg bookmark --delete foo bar
102 102
103 103 rollback by pretxncommit saves commit message (issue1635)
104 104
105 105 $ echo a >> a
106 106 $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
107 107 transaction abort!
108 108 rollback completed
109 109 abort: pretxncommit hook exited with status * (glob)
110 110 [40]
111 111 $ cat .hg/last-message.txt ; echo
112 112 precious commit message
113 113
114 114 same thing, but run $EDITOR
115 115
116 116 $ cat > editor.sh << '__EOF__'
117 117 > echo "another precious commit message" > "$1"
118 118 > __EOF__
119 119 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg --config hooks.pretxncommit=false commit 2>&1
120 120 transaction abort!
121 121 rollback completed
122 122 note: commit message saved in .hg/last-message.txt
123 123 note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it
124 124 abort: pretxncommit hook exited with status * (glob)
125 125 [40]
126 126 $ cat .hg/last-message.txt
127 127 another precious commit message
128 128
129 129 test rollback on served repository
130 130
131 131 #if serve
132 132 $ hg commit -m "precious commit message"
133 133 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
134 134 $ cat hg.pid >> $DAEMON_PIDS
135 135 $ cd ..
136 136 $ hg clone http://localhost:$HGPORT u
137 137 requesting all changes
138 138 adding changesets
139 139 adding manifests
140 140 adding file changes
141 141 added 3 changesets with 2 changes to 1 files (+1 heads)
142 142 new changesets 23b0221f3370:068774709090
143 143 updating to branch default
144 144 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 145 $ cd u
146 146 $ hg id default
147 147 068774709090
148 148
149 149 now rollback and observe that 'hg serve' reloads the repository and
150 150 presents the correct tip changeset:
151 151
152 152 $ hg -R ../t rollback
153 153 repository tip rolled back to revision 1 (undo commit)
154 154 working directory now based on revision 0
155 155 $ hg id default
156 156 791dd2169706
157 157
158 158 $ killdaemons.py
159 159 #endif
160 160
161 161 update to older changeset and then refuse rollback, because
162 162 that would lose data (issue2998)
163 163 $ cd ../t
164 164 $ hg -q update
165 165 $ rm `hg status -un`
166 166 $ template='{rev}:{node|short} [{branch}] {desc|firstline}\n'
167 167 $ echo 'valuable new file' > b
168 168 $ echo 'valuable modification' >> a
169 169 $ hg commit -A -m'a valuable change'
170 170 adding b
171 171 $ hg update 0
172 172 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
173 173 $ hg rollback
174 174 abort: rollback of last commit while not checked out may lose data
175 175 (use -f to force)
176 176 [255]
177 177 $ hg tip -q
178 178 2:4d9cd3795eea
179 179 $ hg rollback -f
180 180 repository tip rolled back to revision 1 (undo commit)
181 181 $ hg status
182 182 $ hg log --removed b # yep, it's gone
183 183
184 184 same again, but emulate an old client that doesn't write undo.desc
185 185 $ hg -q update
186 186 $ echo 'valuable modification redux' >> a
187 187 $ hg commit -m'a valuable change redux'
188 188 $ rm .hg/undo.desc
189 189 $ hg update 0
190 190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191 $ hg rollback
192 192 rolling back unknown transaction
193 193 working directory now based on revision 0
194 194 $ cat a
195 195 a
196 196
197 197 corrupt journal test
198 198 $ echo "foo" > .hg/store/journal
199 199 $ hg recover --verify -q
200 200 couldn't read journal entry 'foo\n'!
201 201
202 202 rollback disabled by config
203 203 $ cat >> $HGRCPATH <<EOF
204 204 > [ui]
205 205 > rollback = false
206 206 > EOF
207 207 $ echo narf >> pinky-sayings.txt
208 208 $ hg add pinky-sayings.txt
209 209 $ hg ci -m 'First one.'
210 210 $ hg rollback
211 211 abort: rollback is disabled because it is unsafe
212 212 (see `hg help -v rollback` for information)
213 213 [255]
214 214
215 215 $ cd ..
216 216
217 217 I/O errors on stdio are handled properly (issue5658)
218 218
219 219 $ cat > badui.py << EOF
220 220 > import errno
221 221 > from mercurial.i18n import _
222 222 > from mercurial import (
223 223 > error,
224 224 > registrar,
225 225 > ui as uimod,
226 226 > )
227 227 >
228 228 > configtable = {}
229 229 > configitem = registrar.configitem(configtable)
230 230 >
231 231 > configitem(b'ui', b'ioerrors',
232 232 > default=list,
233 233 > )
234 234 >
235 235 > def pretxncommit(ui, repo, **kwargs):
236 236 > ui.warn(b'warn during pretxncommit\n')
237 237 >
238 238 > def pretxnclose(ui, repo, **kwargs):
239 239 > ui.warn(b'warn during pretxnclose\n')
240 240 >
241 241 > def txnclose(ui, repo, **kwargs):
242 242 > ui.warn(b'warn during txnclose\n')
243 243 >
244 244 > def txnabort(ui, repo, **kwargs):
245 245 > ui.warn(b'warn during abort\n')
246 246 >
247 247 > class fdproxy(object):
248 248 > def __init__(self, ui, o):
249 249 > self._ui = ui
250 250 > self._o = o
251 251 >
252 252 > def __getattr__(self, attr):
253 253 > return getattr(self._o, attr)
254 254 >
255 255 > def write(self, msg):
256 256 > errors = set(self._ui.configlist(b'ui', b'ioerrors'))
257 257 > pretxncommit = msg == b'warn during pretxncommit\n'
258 258 > pretxnclose = msg == b'warn during pretxnclose\n'
259 259 > txnclose = msg == b'warn during txnclose\n'
260 260 > txnabort = msg == b'warn during abort\n'
261 261 > msgabort = msg == _(b'transaction abort!\n')
262 262 > msgrollback = msg == _(b'rollback completed\n')
263 263 >
264 264 > if pretxncommit and b'pretxncommit' in errors:
265 265 > raise IOError(errno.EPIPE, 'simulated epipe')
266 266 > if pretxnclose and b'pretxnclose' in errors:
267 267 > raise IOError(errno.EIO, 'simulated eio')
268 268 > if txnclose and b'txnclose' in errors:
269 269 > raise IOError(errno.EBADF, 'simulated badf')
270 270 > if txnabort and b'txnabort' in errors:
271 271 > raise IOError(errno.EPIPE, 'simulated epipe')
272 272 > if msgabort and b'msgabort' in errors:
273 273 > raise IOError(errno.EBADF, 'simulated ebadf')
274 274 > if msgrollback and b'msgrollback' in errors:
275 275 > raise IOError(errno.EIO, 'simulated eio')
276 276 >
277 277 > return self._o.write(msg)
278 278 >
279 279 > def uisetup(ui):
280 280 > class badui(ui.__class__):
281 281 > def _write(self, dest, *args, **kwargs):
282 282 > olderr = self.ferr
283 283 > try:
284 284 > if dest is self.ferr:
285 285 > self.ferr = dest = fdproxy(self, olderr)
286 286 > return super(badui, self)._write(dest, *args, **kwargs)
287 287 > finally:
288 288 > self.ferr = olderr
289 289 >
290 290 > ui.__class__ = badui
291 291 >
292 292 > def reposetup(ui, repo):
293 293 > ui.setconfig(b'hooks', b'pretxnclose.badui', pretxnclose, b'badui')
294 294 > ui.setconfig(b'hooks', b'txnclose.badui', txnclose, b'badui')
295 295 > ui.setconfig(b'hooks', b'pretxncommit.badui', pretxncommit, b'badui')
296 296 > ui.setconfig(b'hooks', b'txnabort.badui', txnabort, b'badui')
297 297 > EOF
298 298
299 299 $ cat >> $HGRCPATH << EOF
300 300 > [extensions]
301 301 > badui = $TESTTMP/badui.py
302 302 > EOF
303 303
304 304 An I/O error during pretxncommit is handled
305 305
306 306 $ hg init ioerror-pretxncommit
307 307 $ cd ioerror-pretxncommit
308 308 $ echo 0 > foo
309 309 $ hg -q commit -A -m initial
310 310 warn during pretxncommit
311 311 warn during pretxnclose
312 312 warn during txnclose
313 313 $ echo 1 > foo
314 314 $ hg --config ui.ioerrors=pretxncommit commit -m 'error during pretxncommit'
315 315 warn during pretxnclose
316 316 warn during txnclose
317 317
318 318 $ hg commit -m 'commit 1'
319 319 nothing changed
320 320 [1]
321 321
322 322 $ cd ..
323 323
324 324 An I/O error during pretxnclose is handled
325 325
326 326 $ hg init ioerror-pretxnclose
327 327 $ cd ioerror-pretxnclose
328 328 $ echo 0 > foo
329 329 $ hg -q commit -A -m initial
330 330 warn during pretxncommit
331 331 warn during pretxnclose
332 332 warn during txnclose
333 333
334 334 $ echo 1 > foo
335 335 $ hg --config ui.ioerrors=pretxnclose commit -m 'error during pretxnclose'
336 336 warn during pretxncommit
337 337 warn during txnclose
338 338
339 339 $ hg commit -m 'commit 1'
340 340 nothing changed
341 341 [1]
342 342
343 343 $ cd ..
344 344
345 345 An I/O error during txnclose is handled
346 346
347 347 $ hg init ioerror-txnclose
348 348 $ cd ioerror-txnclose
349 349 $ echo 0 > foo
350 350 $ hg -q commit -A -m initial
351 351 warn during pretxncommit
352 352 warn during pretxnclose
353 353 warn during txnclose
354 354
355 355 $ echo 1 > foo
356 356 $ hg --config ui.ioerrors=txnclose commit -m 'error during txnclose'
357 357 warn during pretxncommit
358 358 warn during pretxnclose
359 359
360 360 $ hg commit -m 'commit 1'
361 361 nothing changed
362 362 [1]
363 363
364 364 $ cd ..
365 365
366 366 An I/O error writing "transaction abort" is handled
367 367
368 368 $ hg init ioerror-msgabort
369 369 $ cd ioerror-msgabort
370 370
371 371 $ echo 0 > foo
372 372 $ hg -q commit -A -m initial
373 373 warn during pretxncommit
374 374 warn during pretxnclose
375 375 warn during txnclose
376 376
377 377 $ echo 1 > foo
378 378 $ hg --config ui.ioerrors=msgabort --config hooks.pretxncommit=false commit -m 'error during abort message'
379 379 warn during abort
380 380 rollback completed
381 381 abort: pretxncommit hook exited with status 1
382 382 [40]
383 383
384 384 $ hg commit -m 'commit 1'
385 385 warn during pretxncommit
386 386 warn during pretxnclose
387 387 warn during txnclose
388 388
389 389 $ cd ..
390 390
391 391 An I/O error during txnabort should still result in rollback
392 392
393 393 $ hg init ioerror-txnabort
394 394 $ cd ioerror-txnabort
395 395
396 396 $ echo 0 > foo
397 397 $ hg -q commit -A -m initial
398 398 warn during pretxncommit
399 399 warn during pretxnclose
400 400 warn during txnclose
401 401
402 402 $ echo 1 > foo
403 403 $ hg --config ui.ioerrors=txnabort --config hooks.pretxncommit=false commit -m 'error during abort'
404 404 transaction abort!
405 405 rollback completed
406 406 abort: pretxncommit hook exited with status 1
407 407 [40]
408 408
409 409 $ hg commit -m 'commit 1'
410 410 warn during pretxncommit
411 411 warn during pretxnclose
412 412 warn during txnclose
413 413
414 414 $ cd ..
415 415
416 416 An I/O error writing "rollback completed" is handled
417 417
418 418 $ hg init ioerror-msgrollback
419 419 $ cd ioerror-msgrollback
420 420
421 421 $ echo 0 > foo
422 422 $ hg -q commit -A -m initial
423 423 warn during pretxncommit
424 424 warn during pretxnclose
425 425 warn during txnclose
426 426
427 427 $ echo 1 > foo
428 428
429 429 $ hg --config ui.ioerrors=msgrollback --config hooks.pretxncommit=false commit -m 'error during rollback message'
430 430 transaction abort!
431 431 warn during abort
432 432 abort: pretxncommit hook exited with status 1
433 433 [40]
434 434
435 435 $ hg verify -q
436 436
437 437 $ cd ..
438 438
439 439 Multiple I/O errors after transaction open are handled.
440 440 This is effectively what happens if a peer disconnects in the middle
441 441 of a transaction.
442 442
443 443 $ hg init ioerror-multiple
444 444 $ cd ioerror-multiple
445 445 $ echo 0 > foo
446 446 $ hg -q commit -A -m initial
447 447 warn during pretxncommit
448 448 warn during pretxnclose
449 449 warn during txnclose
450 450
451 451 $ echo 1 > foo
452 452
453 453 $ hg --config ui.ioerrors=pretxncommit,pretxnclose,txnclose,txnabort,msgabort,msgrollback commit -m 'multiple errors'
454 454
455 455 $ hg verify -q
456 456
457 457 $ cd ..
@@ -1,448 +1,448 b''
1 1 Test correctness of revlog inline -> non-inline transition
2 2 ----------------------------------------------------------
3 3
4 4 We test various file length and naming pattern as this created issue in the
5 5 past.
6 6
7 7 Helper extension to intercept renames and kill process
8 8
9 9 $ cat > $TESTTMP/intercept_before_rename.py << EOF
10 10 > import os
11 11 > import signal
12 12 > from mercurial import extensions, util
13 13 >
14 14 > def extsetup(ui):
15 15 > def rename(orig, src, dest, *args, **kwargs):
16 16 > path = util.normpath(dest)
17 17 > if path.endswith(b'data/file.i'):
18 18 > os.kill(os.getpid(), signal.SIGKILL)
19 19 > return orig(src, dest, *args, **kwargs)
20 20 > extensions.wrapfunction(util, 'rename', rename)
21 21 > EOF
22 22
23 23 $ cat > $TESTTMP/intercept_after_rename.py << EOF
24 24 > import os
25 25 > import signal
26 26 > from mercurial import extensions, util
27 27 >
28 28 > def extsetup(ui):
29 29 > def close(orig, *args, **kwargs):
30 30 > path = util.normpath(args[0]._atomictempfile__name)
31 31 > r = orig(*args, **kwargs)
32 32 > if path.endswith(b'/.hg/store/data/file.i'):
33 33 > os.kill(os.getpid(), signal.SIGKILL)
34 34 > return r
35 35 > extensions.wrapfunction(util.atomictempfile, 'close', close)
36 36 > def extsetup(ui):
37 37 > def rename(orig, src, dest, *args, **kwargs):
38 38 > path = util.normpath(dest)
39 39 > r = orig(src, dest, *args, **kwargs)
40 40 > if path.endswith(b'data/file.i'):
41 41 > os.kill(os.getpid(), signal.SIGKILL)
42 42 > return r
43 43 > extensions.wrapfunction(util, 'rename', rename)
44 44 > EOF
45 45
46 46 $ cat > $TESTTMP/killme.py << EOF
47 47 > import os
48 48 > import signal
49 49 >
50 50 > def killme(ui, repo, hooktype, **kwargs):
51 51 > os.kill(os.getpid(), signal.SIGKILL)
52 52 > EOF
53 53
54 54 $ cat > $TESTTMP/reader_wait_split.py << EOF
55 55 > import os
56 56 > import signal
57 57 > from mercurial import extensions, revlog, testing
58 58 > def _wait_post_load(orig, self, *args, **kwargs):
59 59 > wait = b'data/file' in self.radix
60 60 > if wait:
61 61 > testing.wait_file(b"$TESTTMP/writer-revlog-split")
62 62 > r = orig(self, *args, **kwargs)
63 63 > if wait:
64 64 > testing.write_file(b"$TESTTMP/reader-index-read")
65 65 > testing.wait_file(b"$TESTTMP/writer-revlog-unsplit")
66 66 > return r
67 67 >
68 68 > def extsetup(ui):
69 69 > extensions.wrapfunction(revlog.revlog, '_loadindex', _wait_post_load)
70 70 > EOF
71 71
72 72 setup a repository for tests
73 73 ----------------------------
74 74
75 75 $ cat >> $HGRCPATH << EOF
76 76 > [format]
77 77 > revlog-compression=none
78 78 > EOF
79 79
80 80 $ hg init troffset-computation
81 81 $ cd troffset-computation
82 82 $ files="
83 83 > file
84 84 > Directory_With,Special%Char/Complex_File.babar
85 85 > foo/bar/babar_celeste/foo
86 86 > 1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/f
87 87 > "
88 88 $ for f in $files; do
89 89 > mkdir -p `dirname $f`
90 90 > done
91 91 $ for f in $files; do
92 92 > printf '%20d' '1' > $f
93 93 > done
94 94 $ hg commit -Aqma
95 95 $ for f in $files; do
96 96 > printf '%1024d' '1' > $f
97 97 > done
98 98 $ hg commit -Aqmb
99 99 $ for f in $files; do
100 100 > printf '%20d' '1' > $f
101 101 > done
102 102 $ hg commit -Aqmc
103 103 $ for f in $files; do
104 104 > dd if=/dev/zero of=$f bs=1k count=128 > /dev/null 2>&1
105 105 > done
106 106 $ hg commit -AqmD --traceback
107 107
108 108 Reference size:
109 109 $ f -s file
110 110 file: size=131072
111 111 $ f -s .hg/store/data/file*
112 112 .hg/store/data/file.d: size=132139
113 113 .hg/store/data/file.i: size=256
114 114
115 115 $ cd ..
116 116
117 117
118 118 Test a hard crash after the file was split but before the transaction was committed
119 119 ===================================================================================
120 120
121 121 Test offset computation to correctly factor in the index entries themselves.
122 122 Also test that the new data size has the correct size if the transaction is aborted
123 123 after the index has been replaced.
124 124
125 125 Test repo has commits a, b, c, D, where D is large (grows the revlog enough that it
126 126 transitions to non-inline storage). The clone initially has changes a, b
127 127 and will transition to non-inline storage when adding c, D.
128 128
129 129 If the transaction adding c, D is rolled back, then we don't undo the revlog split,
130 130 but truncate the index and the data to remove both c and D.
131 131
132 132
133 133 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy
134 134 $ cd troffset-computation-copy
135 135
136 136 Reference size:
137 137 $ f -s file
138 138 file: size=1024
139 139 $ f -s .hg/store/data/file*
140 140 .hg/store/data/file.i: size=1174
141 141
142 142 $ cat > .hg/hgrc <<EOF
143 143 > [hooks]
144 144 > pretxnchangegroup = python:$TESTTMP/killme.py:killme
145 145 > EOF
146 146 #if chg
147 147 $ hg pull ../troffset-computation
148 148 pulling from ../troffset-computation
149 149 [255]
150 150 #else
151 151 $ hg pull ../troffset-computation
152 152 pulling from ../troffset-computation
153 153 *Killed* (glob)
154 154 [137]
155 155 #endif
156 156
157 157
158 158 The inline revlog still exist, but a split version exist next to it
159 159
160 160 $ f -s .hg/store/data/file*
161 161 .hg/store/data/file.d: size=132139
162 162 .hg/store/data/file.i: size=132395
163 163 .hg/store/data/file.i.s: size=256
164 164
165 165
166 166 The first file.i entry should match the "Reference size" above.
167 167 The first file.d entry is the temporary record during the split,
168 168
169 169 A "temporary file" entry exist for the split index.
170 170
171 171 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
172 172 data/file.i 1174
173 173 data/file.d 0
174 174 $ cat .hg/store/journal.backupfiles | tr -s '\000' ' ' | tr -s '\00' ' '| grep data/file
175 data/file.i data/journal.backup.file.i 0
175 data/file.i data/journal.backup.file.i.bck 0
176 176 data/file.i.s 0
177 177
178 178 recover is rolling the split back, the fncache is still valid
179 179
180 180 $ hg recover
181 181 rolling back interrupted transaction
182 182 (verify step skipped, run `hg verify` to check your repository content)
183 183 $ f -s .hg/store/data/file*
184 184 .hg/store/data/file.i: size=1174
185 185 $ hg tip
186 186 changeset: 1:cc8dfb126534
187 187 tag: tip
188 188 user: test
189 189 date: Thu Jan 01 00:00:00 1970 +0000
190 190 summary: b
191 191
192 192 $ hg verify -q
193 193 $ hg debugrebuildfncache --only-data
194 194 fncache already up to date
195 195 $ hg verify -q
196 196 $ cd ..
197 197
198 198 Test a hard crash right before the index is move into place
199 199 ===========================================================
200 200
201 201 Now retry the procedure but intercept the rename of the index and check that
202 202 the journal does not contain the new index size. This demonstrates the edge case
203 203 where the data file is left as garbage.
204 204
205 205 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy2
206 206 $ cd troffset-computation-copy2
207 207
208 208 Reference size:
209 209 $ f -s file
210 210 file: size=1024
211 211 $ f -s .hg/store/data/file*
212 212 .hg/store/data/file.i: size=1174
213 213
214 214 $ cat > .hg/hgrc <<EOF
215 215 > [extensions]
216 216 > intercept_rename = $TESTTMP/intercept_before_rename.py
217 217 > EOF
218 218 #if chg
219 219 $ hg pull ../troffset-computation
220 220 pulling from ../troffset-computation
221 221 searching for changes
222 222 adding changesets
223 223 adding manifests
224 224 adding file changes
225 225 [255]
226 226 #else
227 227 $ hg pull ../troffset-computation
228 228 pulling from ../troffset-computation
229 229 searching for changes
230 230 adding changesets
231 231 adding manifests
232 232 adding file changes
233 233 *Killed* (glob)
234 234 [137]
235 235 #endif
236 236
237 237 The inline revlog still exist, but a split version exist next to it
238 238
239 239 $ f -s .hg/store/data/file*
240 240 .hg/store/data/file.d: size=132139
241 241 .hg/store/data/file.i: size=132395
242 242 .hg/store/data/file.i.s: size=256
243 243
244 244 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
245 245 data/file.i 1174
246 246 data/file.d 0
247 247
248 248 recover is rolling the split back, the fncache is still valid
249 249
250 250 $ hg recover
251 251 rolling back interrupted transaction
252 252 (verify step skipped, run `hg verify` to check your repository content)
253 253 $ f -s .hg/store/data/file*
254 254 .hg/store/data/file.i: size=1174
255 255 $ hg tip
256 256 changeset: 1:cc8dfb126534
257 257 tag: tip
258 258 user: test
259 259 date: Thu Jan 01 00:00:00 1970 +0000
260 260 summary: b
261 261
262 262 $ hg verify -q
263 263 $ cd ..
264 264
265 265 Test a hard crash right after the index is move into place
266 266 ===========================================================
267 267
268 268 Now retry the procedure but intercept the rename of the index.
269 269
270 270 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-crash-after-rename
271 271 $ cd troffset-computation-crash-after-rename
272 272
273 273 Reference size:
274 274 $ f -s file
275 275 file: size=1024
276 276 $ f -s .hg/store/data/file*
277 277 .hg/store/data/file.i: size=1174
278 278
279 279 $ cat > .hg/hgrc <<EOF
280 280 > [extensions]
281 281 > intercept_rename = $TESTTMP/intercept_after_rename.py
282 282 > EOF
283 283 #if chg
284 284 $ hg pull ../troffset-computation
285 285 pulling from ../troffset-computation
286 286 searching for changes
287 287 adding changesets
288 288 adding manifests
289 289 adding file changes
290 290 [255]
291 291 #else
292 292 $ hg pull ../troffset-computation
293 293 pulling from ../troffset-computation
294 294 searching for changes
295 295 adding changesets
296 296 adding manifests
297 297 adding file changes
298 298 *Killed* (glob)
299 299 [137]
300 300 #endif
301 301
302 302 The inline revlog was over written on disk
303 303
304 304 $ f -s .hg/store/data/file*
305 305 .hg/store/data/file.d: size=132139
306 306 .hg/store/data/file.i: size=256
307 307
308 308 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
309 309 data/file.i 1174
310 310 data/file.d 0
311 311
312 312 recover is rolling the split back, the fncache is still valid
313 313
314 314 $ hg recover
315 315 rolling back interrupted transaction
316 316 (verify step skipped, run `hg verify` to check your repository content)
317 317 $ f -s .hg/store/data/file*
318 318 .hg/store/data/file.i: size=1174
319 319 $ hg tip
320 320 changeset: 1:cc8dfb126534
321 321 tag: tip
322 322 user: test
323 323 date: Thu Jan 01 00:00:00 1970 +0000
324 324 summary: b
325 325
326 326 $ hg verify -q
327 327 $ cd ..
328 328
329 329 Have the transaction rollback itself without any hard crash
330 330 ===========================================================
331 331
332 332
333 333 Repeat the original test but let hg rollback the transaction.
334 334
335 335 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy-rb
336 336 $ cd troffset-computation-copy-rb
337 337 $ cat > .hg/hgrc <<EOF
338 338 > [hooks]
339 339 > pretxnchangegroup = false
340 340 > EOF
341 341 $ hg pull ../troffset-computation
342 342 pulling from ../troffset-computation
343 343 searching for changes
344 344 adding changesets
345 345 adding manifests
346 346 adding file changes
347 347 transaction abort!
348 348 rollback completed
349 349 abort: pretxnchangegroup hook exited with status 1
350 350 [40]
351 351
352 352 The split was rollback
353 353
354 354 $ f -s .hg/store/data/file*
355 355 .hg/store/data/file.d: size=0
356 356 .hg/store/data/file.i: size=1174
357 357
358 358
359 359 $ hg tip
360 360 changeset: 1:cc8dfb126534
361 361 tag: tip
362 362 user: test
363 363 date: Thu Jan 01 00:00:00 1970 +0000
364 364 summary: b
365 365
366 366 $ hg verify -q
367 367 $ cd ..
368 368
369 369 Read race
370 370 =========
371 371
372 372 We check that a client that started reading a revlog (its index) after the
373 373 split and end reading (the data) after the rollback should be fine
374 374
375 375 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-race
376 376 $ cd troffset-computation-race
377 377 $ cat > .hg/hgrc <<EOF
378 378 > [hooks]
379 379 > pretxnchangegroup=$RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/reader-index-read $TESTTMP/writer-revlog-split
380 380 > pretxnclose = false
381 381 > EOF
382 382
383 383 start a reader
384 384
385 385 $ hg cat --rev 0 file \
386 386 > --config "extensions.wait_read=$TESTTMP/reader_wait_split.py" \
387 387 > 2> $TESTTMP/reader.stderr \
388 388 > > $TESTTMP/reader.stdout &
389 389
390 390 Do a failed pull in //
391 391
392 392 $ hg pull ../troffset-computation
393 393 pulling from ../troffset-computation
394 394 searching for changes
395 395 adding changesets
396 396 adding manifests
397 397 adding file changes
398 398 transaction abort!
399 399 rollback completed
400 400 abort: pretxnclose hook exited with status 1
401 401 [40]
402 402 $ touch $TESTTMP/writer-revlog-unsplit
403 403 $ wait
404 404
405 405 The reader should be fine
406 406 $ cat $TESTTMP/reader.stderr
407 407 $ cat $TESTTMP/reader.stdout
408 408 1 (no-eol)
409 409 $ cd ..
410 410
411 411 pending hooks
412 412 =============
413 413
414 414 We checks that hooks properly see the inside of the transaction, while other process don't.
415 415
416 416 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-hooks
417 417 $ cd troffset-computation-hooks
418 418 $ cat > .hg/hgrc <<EOF
419 419 > [hooks]
420 420 > pretxnclose.01-echo = hg cat -r 'max(all())' file | f --size
421 421 > pretxnclose.02-echo = $RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/hook-done $TESTTMP/hook-tr-ready
422 422 > pretxnclose.03-abort = false
423 423 > EOF
424 424
425 425 $ (
426 426 > $RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/hook-tr-ready;\
427 427 > hg cat -r 'max(all())' file | f --size;\
428 428 > touch $TESTTMP/hook-done
429 429 > ) >stdout 2>stderr &
430 430
431 431 $ hg pull ../troffset-computation
432 432 pulling from ../troffset-computation
433 433 searching for changes
434 434 adding changesets
435 435 adding manifests
436 436 adding file changes
437 437 size=131072
438 438 transaction abort!
439 439 rollback completed
440 440 abort: pretxnclose.03-abort hook exited with status 1
441 441 [40]
442 442
443 443 $ cat stdout
444 444 size=1024
445 445 $ cat stderr
446 446
447 447
448 448 $ cd ..
@@ -1,2101 +1,2101 b''
1 1 #require no-reposimplestore
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > share =
6 6 > [format]
7 7 > # stabilize test accross variant
8 8 > revlog-compression=zlib
9 9 > [storage]
10 10 > dirstate-v2.slow-path=allow
11 11 > EOF
12 12
13 13 store and revlogv1 are required in source
14 14
15 15 $ hg --config format.usestore=false init no-store
16 16 $ hg -R no-store debugupgraderepo
17 17 abort: cannot upgrade repository; requirement missing: store
18 18 [255]
19 19
20 20 $ hg init no-revlogv1
21 21 $ cat > no-revlogv1/.hg/requires << EOF
22 22 > dotencode
23 23 > fncache
24 24 > generaldelta
25 25 > store
26 26 > EOF
27 27
28 28 $ hg -R no-revlogv1 debugupgraderepo
29 29 abort: cannot upgrade repository; missing a revlog version
30 30 [255]
31 31
32 32 Cannot upgrade shared repositories
33 33
34 34 $ hg init share-parent
35 35 $ hg -R share-parent debugbuilddag -n .+9
36 36 $ hg -R share-parent up tip
37 37 10 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 38 $ hg -q share share-parent share-child
39 39
40 40 $ hg -R share-child debugupgraderepo --config format.sparse-revlog=no
41 41 abort: cannot use these actions on a share repository: sparserevlog
42 42 (upgrade the main repository directly)
43 43 [255]
44 44
45 45 Unless the action is compatible with share
46 46
47 47 $ hg -R share-child debugupgraderepo --config format.use-dirstate-v2=yes --quiet
48 48 requirements
49 49 preserved: * (glob)
50 50 added: dirstate-v2
51 51
52 52 no revlogs to process
53 53
54 54
55 55 $ hg -R share-child debugupgraderepo --config format.use-dirstate-v2=yes --quiet --run
56 56 upgrade will perform the following actions:
57 57
58 58 requirements
59 59 preserved: * (glob)
60 60 added: dirstate-v2
61 61
62 62 no revlogs to process
63 63
64 64 $ hg debugformat -R share-child | grep dirstate-v2
65 65 dirstate-v2: yes
66 66 $ hg debugformat -R share-parent | grep dirstate-v2
67 67 dirstate-v2: no
68 68 $ hg status --all -R share-child
69 69 C nf0
70 70 C nf1
71 71 C nf2
72 72 C nf3
73 73 C nf4
74 74 C nf5
75 75 C nf6
76 76 C nf7
77 77 C nf8
78 78 C nf9
79 79 $ hg log -l 3 -R share-child
80 80 changeset: 9:0059eb38e4a4
81 81 tag: tip
82 82 user: debugbuilddag
83 83 date: Thu Jan 01 00:00:09 1970 +0000
84 84 summary: r9
85 85
86 86 changeset: 8:4d5be70c8130
87 87 user: debugbuilddag
88 88 date: Thu Jan 01 00:00:08 1970 +0000
89 89 summary: r8
90 90
91 91 changeset: 7:e60bfe72517e
92 92 user: debugbuilddag
93 93 date: Thu Jan 01 00:00:07 1970 +0000
94 94 summary: r7
95 95
96 96 $ hg status --all -R share-parent
97 97 C nf0
98 98 C nf1
99 99 C nf2
100 100 C nf3
101 101 C nf4
102 102 C nf5
103 103 C nf6
104 104 C nf7
105 105 C nf8
106 106 C nf9
107 107 $ hg log -l 3 -R share-parent
108 108 changeset: 9:0059eb38e4a4
109 109 tag: tip
110 110 user: debugbuilddag
111 111 date: Thu Jan 01 00:00:09 1970 +0000
112 112 summary: r9
113 113
114 114 changeset: 8:4d5be70c8130
115 115 user: debugbuilddag
116 116 date: Thu Jan 01 00:00:08 1970 +0000
117 117 summary: r8
118 118
119 119 changeset: 7:e60bfe72517e
120 120 user: debugbuilddag
121 121 date: Thu Jan 01 00:00:07 1970 +0000
122 122 summary: r7
123 123
124 124
125 125 $ hg -R share-child debugupgraderepo --config format.use-dirstate-v2=no --quiet --run
126 126 upgrade will perform the following actions:
127 127
128 128 requirements
129 129 preserved: * (glob)
130 130 removed: dirstate-v2
131 131
132 132 no revlogs to process
133 133
134 134 $ hg debugformat -R share-child | grep dirstate-v2
135 135 dirstate-v2: no
136 136 $ hg debugformat -R share-parent | grep dirstate-v2
137 137 dirstate-v2: no
138 138 $ hg status --all -R share-child
139 139 C nf0
140 140 C nf1
141 141 C nf2
142 142 C nf3
143 143 C nf4
144 144 C nf5
145 145 C nf6
146 146 C nf7
147 147 C nf8
148 148 C nf9
149 149 $ hg log -l 3 -R share-child
150 150 changeset: 9:0059eb38e4a4
151 151 tag: tip
152 152 user: debugbuilddag
153 153 date: Thu Jan 01 00:00:09 1970 +0000
154 154 summary: r9
155 155
156 156 changeset: 8:4d5be70c8130
157 157 user: debugbuilddag
158 158 date: Thu Jan 01 00:00:08 1970 +0000
159 159 summary: r8
160 160
161 161 changeset: 7:e60bfe72517e
162 162 user: debugbuilddag
163 163 date: Thu Jan 01 00:00:07 1970 +0000
164 164 summary: r7
165 165
166 166 $ hg status --all -R share-parent
167 167 C nf0
168 168 C nf1
169 169 C nf2
170 170 C nf3
171 171 C nf4
172 172 C nf5
173 173 C nf6
174 174 C nf7
175 175 C nf8
176 176 C nf9
177 177 $ hg log -l 3 -R share-parent
178 178 changeset: 9:0059eb38e4a4
179 179 tag: tip
180 180 user: debugbuilddag
181 181 date: Thu Jan 01 00:00:09 1970 +0000
182 182 summary: r9
183 183
184 184 changeset: 8:4d5be70c8130
185 185 user: debugbuilddag
186 186 date: Thu Jan 01 00:00:08 1970 +0000
187 187 summary: r8
188 188
189 189 changeset: 7:e60bfe72517e
190 190 user: debugbuilddag
191 191 date: Thu Jan 01 00:00:07 1970 +0000
192 192 summary: r7
193 193
194 194
195 195 Do not yet support upgrading treemanifest repos
196 196
197 197 $ hg --config experimental.treemanifest=true init treemanifest
198 198 $ hg -R treemanifest debugupgraderepo
199 199 abort: cannot upgrade repository; unsupported source requirement: treemanifest
200 200 [255]
201 201
202 202 Cannot add treemanifest requirement during upgrade
203 203
204 204 $ hg init disallowaddedreq
205 205 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
206 206 abort: cannot upgrade repository; do not support adding requirement: treemanifest
207 207 [255]
208 208
209 209 An upgrade of a repository created with recommended settings only suggests optimizations
210 210
211 211 $ hg init empty
212 212 $ cd empty
213 213 $ hg debugformat
214 214 format-variant repo
215 215 fncache: yes
216 216 dirstate-v2: no
217 217 tracked-hint: no
218 218 dotencode: yes
219 219 generaldelta: yes
220 220 share-safe: yes
221 221 sparserevlog: yes
222 222 persistent-nodemap: no (no-rust !)
223 223 persistent-nodemap: yes (rust !)
224 224 copies-sdc: no
225 225 revlog-v2: no
226 226 changelog-v2: no
227 227 plain-cl-delta: yes
228 228 compression: zlib
229 229 compression-level: default
230 230 $ hg debugformat --verbose
231 231 format-variant repo config default
232 232 fncache: yes yes yes
233 233 dirstate-v2: no no no
234 234 tracked-hint: no no no
235 235 dotencode: yes yes yes
236 236 generaldelta: yes yes yes
237 237 share-safe: yes yes yes
238 238 sparserevlog: yes yes yes
239 239 persistent-nodemap: no no no (no-rust !)
240 240 persistent-nodemap: yes yes no (rust !)
241 241 copies-sdc: no no no
242 242 revlog-v2: no no no
243 243 changelog-v2: no no no
244 244 plain-cl-delta: yes yes yes
245 245 compression: zlib zlib zlib (no-zstd !)
246 246 compression: zlib zlib zstd (zstd !)
247 247 compression-level: default default default
248 248 $ hg debugformat --verbose --config format.usefncache=no
249 249 format-variant repo config default
250 250 fncache: yes no yes
251 251 dirstate-v2: no no no
252 252 tracked-hint: no no no
253 253 dotencode: yes no yes
254 254 generaldelta: yes yes yes
255 255 share-safe: yes yes yes
256 256 sparserevlog: yes yes yes
257 257 persistent-nodemap: no no no (no-rust !)
258 258 persistent-nodemap: yes yes no (rust !)
259 259 copies-sdc: no no no
260 260 revlog-v2: no no no
261 261 changelog-v2: no no no
262 262 plain-cl-delta: yes yes yes
263 263 compression: zlib zlib zlib (no-zstd !)
264 264 compression: zlib zlib zstd (zstd !)
265 265 compression-level: default default default
266 266 $ hg debugformat --verbose --config format.usefncache=no --color=debug
267 267 format-variant repo config default
268 268 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
269 269 [formatvariant.name.uptodate|dirstate-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
270 270 [formatvariant.name.uptodate|tracked-hint: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
271 271 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
272 272 [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
273 273 [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
274 274 [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
275 275 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
276 276 [formatvariant.name.mismatchdefault|persistent-nodemap:][formatvariant.repo.mismatchdefault| yes][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
277 277 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
278 278 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
279 279 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
280 280 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
281 281 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
282 282 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
283 283 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
284 284 $ hg debugformat -Tjson
285 285 [
286 286 {
287 287 "config": true,
288 288 "default": true,
289 289 "name": "fncache",
290 290 "repo": true
291 291 },
292 292 {
293 293 "config": false,
294 294 "default": false,
295 295 "name": "dirstate-v2",
296 296 "repo": false
297 297 },
298 298 {
299 299 "config": false,
300 300 "default": false,
301 301 "name": "tracked-hint",
302 302 "repo": false
303 303 },
304 304 {
305 305 "config": true,
306 306 "default": true,
307 307 "name": "dotencode",
308 308 "repo": true
309 309 },
310 310 {
311 311 "config": true,
312 312 "default": true,
313 313 "name": "generaldelta",
314 314 "repo": true
315 315 },
316 316 {
317 317 "config": true,
318 318 "default": true,
319 319 "name": "share-safe",
320 320 "repo": true
321 321 },
322 322 {
323 323 "config": true,
324 324 "default": true,
325 325 "name": "sparserevlog",
326 326 "repo": true
327 327 },
328 328 {
329 329 "config": false, (no-rust !)
330 330 "config": true, (rust !)
331 331 "default": false,
332 332 "name": "persistent-nodemap",
333 333 "repo": false (no-rust !)
334 334 "repo": true (rust !)
335 335 },
336 336 {
337 337 "config": false,
338 338 "default": false,
339 339 "name": "copies-sdc",
340 340 "repo": false
341 341 },
342 342 {
343 343 "config": false,
344 344 "default": false,
345 345 "name": "revlog-v2",
346 346 "repo": false
347 347 },
348 348 {
349 349 "config": false,
350 350 "default": false,
351 351 "name": "changelog-v2",
352 352 "repo": false
353 353 },
354 354 {
355 355 "config": true,
356 356 "default": true,
357 357 "name": "plain-cl-delta",
358 358 "repo": true
359 359 },
360 360 {
361 361 "config": "zlib",
362 362 "default": "zlib", (no-zstd !)
363 363 "default": "zstd", (zstd !)
364 364 "name": "compression",
365 365 "repo": "zlib"
366 366 },
367 367 {
368 368 "config": "default",
369 369 "default": "default",
370 370 "name": "compression-level",
371 371 "repo": "default"
372 372 }
373 373 ]
374 374 $ hg debugupgraderepo
375 375 (no format upgrades found in existing repository)
376 376 performing an upgrade with "--run" will make the following changes:
377 377
378 378 requirements
379 379 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
380 380 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
381 381
382 382 no revlogs to process
383 383
384 384 additional optimizations are available by specifying "--optimize <name>":
385 385
386 386 re-delta-parent
387 387 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
388 388
389 389 re-delta-multibase
390 390 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
391 391
392 392 re-delta-all
393 393 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
394 394
395 395 re-delta-fulladd
396 396 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
397 397
398 398
399 399 $ hg debugupgraderepo --quiet
400 400 requirements
401 401 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
402 402 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
403 403
404 404 no revlogs to process
405 405
406 406
407 407 --optimize can be used to add optimizations
408 408
409 409 $ hg debugupgrade --optimize 're-delta-parent'
410 410 (no format upgrades found in existing repository)
411 411 performing an upgrade with "--run" will make the following changes:
412 412
413 413 requirements
414 414 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
415 415 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
416 416
417 417 optimisations: re-delta-parent
418 418
419 419 re-delta-parent
420 420 deltas within internal storage will choose a new base revision if needed
421 421
422 422 processed revlogs:
423 423 - all-filelogs
424 424 - changelog
425 425 - manifest
426 426
427 427 additional optimizations are available by specifying "--optimize <name>":
428 428
429 429 re-delta-multibase
430 430 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
431 431
432 432 re-delta-all
433 433 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
434 434
435 435 re-delta-fulladd
436 436 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
437 437
438 438
439 439 modern form of the option
440 440
441 441 $ hg debugupgrade --optimize re-delta-parent
442 442 (no format upgrades found in existing repository)
443 443 performing an upgrade with "--run" will make the following changes:
444 444
445 445 requirements
446 446 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
447 447 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
448 448
449 449 optimisations: re-delta-parent
450 450
451 451 re-delta-parent
452 452 deltas within internal storage will choose a new base revision if needed
453 453
454 454 processed revlogs:
455 455 - all-filelogs
456 456 - changelog
457 457 - manifest
458 458
459 459 additional optimizations are available by specifying "--optimize <name>":
460 460
461 461 re-delta-multibase
462 462 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
463 463
464 464 re-delta-all
465 465 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
466 466
467 467 re-delta-fulladd
468 468 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
469 469
470 470
471 471 $ hg debugupgrade --optimize re-delta-parent --quiet
472 472 requirements
473 473 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
474 474 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
475 475
476 476 optimisations: re-delta-parent
477 477
478 478 processed revlogs:
479 479 - all-filelogs
480 480 - changelog
481 481 - manifest
482 482
483 483
484 484 passing multiple optimization:
485 485
486 486 $ hg debugupgrade --optimize re-delta-parent --optimize re-delta-multibase --quiet
487 487 requirements
488 488 preserved: * (glob)
489 489
490 490 optimisations: re-delta-multibase, re-delta-parent
491 491
492 492 processed revlogs:
493 493 - all-filelogs
494 494 - changelog
495 495 - manifest
496 496
497 497
498 498 unknown optimization:
499 499
500 500 $ hg debugupgrade --optimize foobar
501 501 abort: unknown optimization action requested: foobar
502 502 (run without arguments to see valid optimizations)
503 503 [255]
504 504
505 505 Various sub-optimal detections work
506 506
507 507 $ cat > .hg/requires << EOF
508 508 > revlogv1
509 509 > store
510 510 > EOF
511 511
512 512 $ hg debugformat
513 513 format-variant repo
514 514 fncache: no
515 515 dirstate-v2: no
516 516 tracked-hint: no
517 517 dotencode: no
518 518 generaldelta: no
519 519 share-safe: no
520 520 sparserevlog: no
521 521 persistent-nodemap: no
522 522 copies-sdc: no
523 523 revlog-v2: no
524 524 changelog-v2: no
525 525 plain-cl-delta: yes
526 526 compression: zlib
527 527 compression-level: default
528 528 $ hg debugformat --verbose
529 529 format-variant repo config default
530 530 fncache: no yes yes
531 531 dirstate-v2: no no no
532 532 tracked-hint: no no no
533 533 dotencode: no yes yes
534 534 generaldelta: no yes yes
535 535 share-safe: no yes yes
536 536 sparserevlog: no yes yes
537 537 persistent-nodemap: no no no (no-rust !)
538 538 persistent-nodemap: no yes no (rust !)
539 539 copies-sdc: no no no
540 540 revlog-v2: no no no
541 541 changelog-v2: no no no
542 542 plain-cl-delta: yes yes yes
543 543 compression: zlib zlib zlib (no-zstd !)
544 544 compression: zlib zlib zstd (zstd !)
545 545 compression-level: default default default
546 546 $ hg debugformat --verbose --config format.usegeneraldelta=no
547 547 format-variant repo config default
548 548 fncache: no yes yes
549 549 dirstate-v2: no no no
550 550 tracked-hint: no no no
551 551 dotencode: no yes yes
552 552 generaldelta: no no yes
553 553 share-safe: no yes yes
554 554 sparserevlog: no no yes
555 555 persistent-nodemap: no no no (no-rust !)
556 556 persistent-nodemap: no yes no (rust !)
557 557 copies-sdc: no no no
558 558 revlog-v2: no no no
559 559 changelog-v2: no no no
560 560 plain-cl-delta: yes yes yes
561 561 compression: zlib zlib zlib (no-zstd !)
562 562 compression: zlib zlib zstd (zstd !)
563 563 compression-level: default default default
564 564 $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug
565 565 format-variant repo config default
566 566 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
567 567 [formatvariant.name.uptodate|dirstate-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
568 568 [formatvariant.name.uptodate|tracked-hint: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
569 569 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
570 570 [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
571 571 [formatvariant.name.mismatchconfig|share-safe: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
572 572 [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
573 573 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
574 574 [formatvariant.name.mismatchconfig|persistent-nodemap:][formatvariant.repo.mismatchconfig| no][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
575 575 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
576 576 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
577 577 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
578 578 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
579 579 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
580 580 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
581 581 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
582 582 $ hg debugupgraderepo
583 583 note: selecting all-filelogs for processing to change: dotencode
584 584 note: selecting all-manifestlogs for processing to change: dotencode
585 585 note: selecting changelog for processing to change: dotencode
586 586
587 587 repository lacks features recommended by current config options:
588 588
589 589 fncache
590 590 long and reserved filenames may not work correctly; repository performance is sub-optimal
591 591
592 592 dotencode
593 593 storage of filenames beginning with a period or space may not work correctly
594 594
595 595 generaldelta
596 596 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
597 597
598 598 share-safe
599 599 old shared repositories do not share source repository requirements and config. This leads to various problems when the source repository format is upgraded or some new extensions are enabled.
600 600
601 601 sparserevlog
602 602 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
603 603
604 604 persistent-nodemap (rust !)
605 605 persist the node -> rev mapping on disk to speedup lookup (rust !)
606 606 (rust !)
607 607
608 608 performing an upgrade with "--run" will make the following changes:
609 609
610 610 requirements
611 611 preserved: revlogv1, store
612 612 added: dotencode, fncache, generaldelta, share-safe, sparserevlog (no-rust !)
613 613 added: dotencode, fncache, generaldelta, persistent-nodemap, share-safe, sparserevlog (rust !)
614 614
615 615 fncache
616 616 repository will be more resilient to storing certain paths and performance of certain operations should be improved
617 617
618 618 dotencode
619 619 repository will be better able to store files beginning with a space or period
620 620
621 621 generaldelta
622 622 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
623 623
624 624 share-safe
625 625 Upgrades a repository to share-safe format so that future shares of this repository share its requirements and configs.
626 626
627 627 sparserevlog
628 628 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
629 629
630 630 persistent-nodemap (rust !)
631 631 Speedup revision lookup by node id. (rust !)
632 632 (rust !)
633 633 processed revlogs:
634 634 - all-filelogs
635 635 - changelog
636 636 - manifest
637 637
638 638 additional optimizations are available by specifying "--optimize <name>":
639 639
640 640 re-delta-parent
641 641 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
642 642
643 643 re-delta-multibase
644 644 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
645 645
646 646 re-delta-all
647 647 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
648 648
649 649 re-delta-fulladd
650 650 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
651 651
652 652 $ hg debugupgraderepo --quiet
653 653 requirements
654 654 preserved: revlogv1, store
655 655 added: dotencode, fncache, generaldelta, share-safe, sparserevlog (no-rust !)
656 656 added: dotencode, fncache, generaldelta, persistent-nodemap, share-safe, sparserevlog (rust !)
657 657
658 658 processed revlogs:
659 659 - all-filelogs
660 660 - changelog
661 661 - manifest
662 662
663 663
664 664 $ hg --config format.dotencode=false debugupgraderepo
665 665 note: selecting all-filelogs for processing to change: fncache
666 666 note: selecting all-manifestlogs for processing to change: fncache
667 667 note: selecting changelog for processing to change: fncache
668 668
669 669 repository lacks features recommended by current config options:
670 670
671 671 fncache
672 672 long and reserved filenames may not work correctly; repository performance is sub-optimal
673 673
674 674 generaldelta
675 675 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
676 676
677 677 share-safe
678 678 old shared repositories do not share source repository requirements and config. This leads to various problems when the source repository format is upgraded or some new extensions are enabled.
679 679
680 680 sparserevlog
681 681 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
682 682
683 683 persistent-nodemap (rust !)
684 684 persist the node -> rev mapping on disk to speedup lookup (rust !)
685 685 (rust !)
686 686 repository lacks features used by the default config options:
687 687
688 688 dotencode
689 689 storage of filenames beginning with a period or space may not work correctly
690 690
691 691
692 692 performing an upgrade with "--run" will make the following changes:
693 693
694 694 requirements
695 695 preserved: revlogv1, store
696 696 added: fncache, generaldelta, share-safe, sparserevlog (no-rust !)
697 697 added: fncache, generaldelta, persistent-nodemap, share-safe, sparserevlog (rust !)
698 698
699 699 fncache
700 700 repository will be more resilient to storing certain paths and performance of certain operations should be improved
701 701
702 702 generaldelta
703 703 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
704 704
705 705 share-safe
706 706 Upgrades a repository to share-safe format so that future shares of this repository share its requirements and configs.
707 707
708 708 sparserevlog
709 709 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
710 710
711 711 persistent-nodemap (rust !)
712 712 Speedup revision lookup by node id. (rust !)
713 713 (rust !)
714 714 processed revlogs:
715 715 - all-filelogs
716 716 - changelog
717 717 - manifest
718 718
719 719 additional optimizations are available by specifying "--optimize <name>":
720 720
721 721 re-delta-parent
722 722 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
723 723
724 724 re-delta-multibase
725 725 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
726 726
727 727 re-delta-all
728 728 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
729 729
730 730 re-delta-fulladd
731 731 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
732 732
733 733
734 734 $ cd ..
735 735
736 736 Upgrading a repository that is already modern essentially no-ops
737 737
738 738 $ hg init modern
739 739 $ hg -R modern debugupgraderepo --run
740 740 nothing to do
741 741
742 742 Upgrading a repository to generaldelta works
743 743
744 744 $ hg --config format.usegeneraldelta=false init upgradegd
745 745 $ cd upgradegd
746 746 $ touch f0
747 747 $ hg -q commit -A -m initial
748 748 $ mkdir FooBarDirectory.d
749 749 $ touch FooBarDirectory.d/f1
750 750 $ hg -q commit -A -m 'add f1'
751 751 $ hg -q up -r 0
752 752 >>> import random
753 753 >>> random.seed(0) # have a reproducible content
754 754 >>> with open("f2", "wb") as f:
755 755 ... for i in range(100000):
756 756 ... f.write(b"%d\n" % random.randint(1000000000, 9999999999)) and None
757 757 $ hg -q commit -A -m 'add f2'
758 758
759 759 make sure we have a .d file
760 760
761 761 $ ls -d .hg/store/data/*
762 762 .hg/store/data/_foo_bar_directory.d.hg
763 763 .hg/store/data/f0.i
764 764 .hg/store/data/f2.d
765 765 .hg/store/data/f2.i
766 766
767 767 $ hg debugupgraderepo --run --config format.sparse-revlog=false
768 768 note: selecting all-filelogs for processing to change: generaldelta
769 769 note: selecting all-manifestlogs for processing to change: generaldelta
770 770 note: selecting changelog for processing to change: generaldelta
771 771
772 772 upgrade will perform the following actions:
773 773
774 774 requirements
775 775 preserved: dotencode, fncache, revlogv1, share-safe, store (no-rust !)
776 776 preserved: dotencode, fncache, persistent-nodemap, revlogv1, share-safe, store (rust !)
777 777 added: generaldelta
778 778
779 779 generaldelta
780 780 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
781 781
782 782 processed revlogs:
783 783 - all-filelogs
784 784 - changelog
785 785 - manifest
786 786
787 787 beginning upgrade...
788 788 repository locked and read-only
789 789 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
790 790 (it is safe to interrupt this process any time before data migration completes)
791 791 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
792 792 migrating 519 KB in store; 1.05 MB tracked data
793 793 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
794 794 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
795 795 migrating 1 manifests containing 3 revisions (384 bytes in store; 238 bytes tracked data)
796 796 finished migrating 3 manifest revisions across 1 manifests; change in size: -17 bytes
797 797 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
798 798 finished migrating 3 changelog revisions; change in size: 0 bytes
799 799 finished migrating 9 total revisions; total change in store size: -17 bytes
800 800 copying phaseroots
801 801 copying requires
802 802 data fully upgraded in a temporary repository
803 803 marking source repository as being upgraded; clients will be unable to read from repository
804 804 starting in-place swap of repository data
805 805 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
806 806 replacing store...
807 807 store replacement complete; repository was inconsistent for *s (glob)
808 808 finalizing requirements file and making repository readable again
809 809 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
810 810 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
811 811 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
812 812
813 813 Original requirements backed up
814 814
815 815 $ cat .hg/upgradebackup.*/requires
816 816 share-safe
817 817 $ cat .hg/upgradebackup.*/store/requires
818 818 dotencode
819 819 fncache
820 820 persistent-nodemap (rust !)
821 821 revlogv1
822 822 store
823 823 upgradeinprogress
824 824
825 825 generaldelta added to original requirements files
826 826
827 827 $ hg debugrequires
828 828 dotencode
829 829 fncache
830 830 generaldelta
831 831 persistent-nodemap (rust !)
832 832 revlogv1
833 833 share-safe
834 834 store
835 835
836 836 store directory has files we expect
837 837
838 838 $ ls .hg/store
839 839 00changelog.i
840 840 00manifest.i
841 841 data
842 842 fncache
843 843 phaseroots
844 844 requires
845 845 undo
846 846 undo.backupfiles
847 847
848 848 manifest should be generaldelta
849 849
850 850 $ hg debugrevlog -m | grep flags
851 851 flags : inline, generaldelta
852 852
853 853 verify should be happy
854 854
855 855 $ hg verify -q
856 856
857 857 old store should be backed up
858 858
859 859 $ ls -d .hg/upgradebackup.*/
860 860 .hg/upgradebackup.*/ (glob)
861 861 $ ls .hg/upgradebackup.*/store
862 862 00changelog.i
863 863 00manifest.i
864 864 data
865 865 fncache
866 866 phaseroots
867 867 requires
868 868 undo
869 undo.backup.fncache
869 undo.backup.fncache.bck
870 870 undo.backupfiles
871 871
872 872 unless --no-backup is passed
873 873
874 874 $ rm -rf .hg/upgradebackup.*/
875 875 $ hg debugupgraderepo --run --no-backup
876 876 note: selecting all-filelogs for processing to change: sparserevlog
877 877 note: selecting all-manifestlogs for processing to change: sparserevlog
878 878 note: selecting changelog for processing to change: sparserevlog
879 879
880 880 upgrade will perform the following actions:
881 881
882 882 requirements
883 883 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
884 884 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
885 885 added: sparserevlog
886 886
887 887 sparserevlog
888 888 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
889 889
890 890 processed revlogs:
891 891 - all-filelogs
892 892 - changelog
893 893 - manifest
894 894
895 895 beginning upgrade...
896 896 repository locked and read-only
897 897 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
898 898 (it is safe to interrupt this process any time before data migration completes)
899 899 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
900 900 migrating 519 KB in store; 1.05 MB tracked data
901 901 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
902 902 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
903 903 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
904 904 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
905 905 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
906 906 finished migrating 3 changelog revisions; change in size: 0 bytes
907 907 finished migrating 9 total revisions; total change in store size: 0 bytes
908 908 copying phaseroots
909 909 copying requires
910 910 data fully upgraded in a temporary repository
911 911 marking source repository as being upgraded; clients will be unable to read from repository
912 912 starting in-place swap of repository data
913 913 replacing store...
914 914 store replacement complete; repository was inconsistent for * (glob)
915 915 finalizing requirements file and making repository readable again
916 916 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
917 917 $ ls -1 .hg/ | grep upgradebackup
918 918 [1]
919 919
920 920 We can restrict optimization to some revlog:
921 921
922 922 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
923 923 upgrade will perform the following actions:
924 924
925 925 requirements
926 926 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
927 927 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
928 928
929 929 optimisations: re-delta-parent
930 930
931 931 re-delta-parent
932 932 deltas within internal storage will choose a new base revision if needed
933 933
934 934 processed revlogs:
935 935 - manifest
936 936
937 937 beginning upgrade...
938 938 repository locked and read-only
939 939 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
940 940 (it is safe to interrupt this process any time before data migration completes)
941 941 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
942 942 migrating 519 KB in store; 1.05 MB tracked data
943 943 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
944 944 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
945 945 blindly copying data/f0.i containing 1 revisions
946 946 blindly copying data/f2.i containing 1 revisions
947 947 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
948 948 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
949 949 cloning 3 revisions from 00manifest.i
950 950 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
951 951 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
952 952 blindly copying 00changelog.i containing 3 revisions
953 953 finished migrating 3 changelog revisions; change in size: 0 bytes
954 954 finished migrating 9 total revisions; total change in store size: 0 bytes
955 955 copying phaseroots
956 956 copying requires
957 957 data fully upgraded in a temporary repository
958 958 marking source repository as being upgraded; clients will be unable to read from repository
959 959 starting in-place swap of repository data
960 960 replacing store...
961 961 store replacement complete; repository was inconsistent for *s (glob)
962 962 finalizing requirements file and making repository readable again
963 963 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
964 964
965 965 Check that the repo still works fine
966 966
967 967 $ hg log -G --stat
968 968 @ changeset: 2:fca376863211
969 969 | tag: tip
970 970 | parent: 0:ba592bf28da2
971 971 | user: test
972 972 | date: Thu Jan 01 00:00:00 1970 +0000
973 973 | summary: add f2
974 974 |
975 975 | f2 | 100000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
976 976 | 1 files changed, 100000 insertions(+), 0 deletions(-)
977 977 |
978 978 | o changeset: 1:2029ce2354e2
979 979 |/ user: test
980 980 | date: Thu Jan 01 00:00:00 1970 +0000
981 981 | summary: add f1
982 982 |
983 983 |
984 984 o changeset: 0:ba592bf28da2
985 985 user: test
986 986 date: Thu Jan 01 00:00:00 1970 +0000
987 987 summary: initial
988 988
989 989
990 990
991 991 $ hg verify -q
992 992
993 993 Check we can select negatively
994 994
995 995 $ hg debugupgrade --optimize re-delta-parent --run --no-manifest --no-backup --debug --traceback
996 996 upgrade will perform the following actions:
997 997
998 998 requirements
999 999 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1000 1000 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1001 1001
1002 1002 optimisations: re-delta-parent
1003 1003
1004 1004 re-delta-parent
1005 1005 deltas within internal storage will choose a new base revision if needed
1006 1006
1007 1007 processed revlogs:
1008 1008 - all-filelogs
1009 1009 - changelog
1010 1010
1011 1011 beginning upgrade...
1012 1012 repository locked and read-only
1013 1013 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1014 1014 (it is safe to interrupt this process any time before data migration completes)
1015 1015 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1016 1016 migrating 519 KB in store; 1.05 MB tracked data
1017 1017 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1018 1018 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1019 1019 cloning 1 revisions from data/f0.i
1020 1020 cloning 1 revisions from data/f2.i
1021 1021 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1022 1022 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1023 1023 blindly copying 00manifest.i containing 3 revisions
1024 1024 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1025 1025 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1026 1026 cloning 3 revisions from 00changelog.i
1027 1027 finished migrating 3 changelog revisions; change in size: 0 bytes
1028 1028 finished migrating 9 total revisions; total change in store size: 0 bytes
1029 1029 copying phaseroots
1030 1030 copying requires
1031 1031 data fully upgraded in a temporary repository
1032 1032 marking source repository as being upgraded; clients will be unable to read from repository
1033 1033 starting in-place swap of repository data
1034 1034 replacing store...
1035 1035 store replacement complete; repository was inconsistent for *s (glob)
1036 1036 finalizing requirements file and making repository readable again
1037 1037 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1038 1038 $ hg verify -q
1039 1039
1040 1040 Check that we can select changelog only
1041 1041
1042 1042 $ hg debugupgrade --optimize re-delta-parent --run --changelog --no-backup --debug --traceback
1043 1043 upgrade will perform the following actions:
1044 1044
1045 1045 requirements
1046 1046 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1047 1047 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1048 1048
1049 1049 optimisations: re-delta-parent
1050 1050
1051 1051 re-delta-parent
1052 1052 deltas within internal storage will choose a new base revision if needed
1053 1053
1054 1054 processed revlogs:
1055 1055 - changelog
1056 1056
1057 1057 beginning upgrade...
1058 1058 repository locked and read-only
1059 1059 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1060 1060 (it is safe to interrupt this process any time before data migration completes)
1061 1061 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1062 1062 migrating 519 KB in store; 1.05 MB tracked data
1063 1063 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1064 1064 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
1065 1065 blindly copying data/f0.i containing 1 revisions
1066 1066 blindly copying data/f2.i containing 1 revisions
1067 1067 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1068 1068 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1069 1069 blindly copying 00manifest.i containing 3 revisions
1070 1070 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1071 1071 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1072 1072 cloning 3 revisions from 00changelog.i
1073 1073 finished migrating 3 changelog revisions; change in size: 0 bytes
1074 1074 finished migrating 9 total revisions; total change in store size: 0 bytes
1075 1075 copying phaseroots
1076 1076 copying requires
1077 1077 data fully upgraded in a temporary repository
1078 1078 marking source repository as being upgraded; clients will be unable to read from repository
1079 1079 starting in-place swap of repository data
1080 1080 replacing store...
1081 1081 store replacement complete; repository was inconsistent for *s (glob)
1082 1082 finalizing requirements file and making repository readable again
1083 1083 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1084 1084 $ hg verify -q
1085 1085
1086 1086 Check that we can select filelog only
1087 1087
1088 1088 $ hg debugupgrade --optimize re-delta-parent --run --no-changelog --no-manifest --no-backup --debug --traceback
1089 1089 upgrade will perform the following actions:
1090 1090
1091 1091 requirements
1092 1092 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1093 1093 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1094 1094
1095 1095 optimisations: re-delta-parent
1096 1096
1097 1097 re-delta-parent
1098 1098 deltas within internal storage will choose a new base revision if needed
1099 1099
1100 1100 processed revlogs:
1101 1101 - all-filelogs
1102 1102
1103 1103 beginning upgrade...
1104 1104 repository locked and read-only
1105 1105 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1106 1106 (it is safe to interrupt this process any time before data migration completes)
1107 1107 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1108 1108 migrating 519 KB in store; 1.05 MB tracked data
1109 1109 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1110 1110 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1111 1111 cloning 1 revisions from data/f0.i
1112 1112 cloning 1 revisions from data/f2.i
1113 1113 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1114 1114 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1115 1115 blindly copying 00manifest.i containing 3 revisions
1116 1116 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1117 1117 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1118 1118 blindly copying 00changelog.i containing 3 revisions
1119 1119 finished migrating 3 changelog revisions; change in size: 0 bytes
1120 1120 finished migrating 9 total revisions; total change in store size: 0 bytes
1121 1121 copying phaseroots
1122 1122 copying requires
1123 1123 data fully upgraded in a temporary repository
1124 1124 marking source repository as being upgraded; clients will be unable to read from repository
1125 1125 starting in-place swap of repository data
1126 1126 replacing store...
1127 1127 store replacement complete; repository was inconsistent for *s (glob)
1128 1128 finalizing requirements file and making repository readable again
1129 1129 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1130 1130 $ hg verify -q
1131 1131
1132 1132
1133 1133 Check you can't skip revlog clone during important format downgrade
1134 1134
1135 1135 $ echo "[format]" > .hg/hgrc
1136 1136 $ echo "sparse-revlog=no" >> .hg/hgrc
1137 1137 $ hg debugupgrade --optimize re-delta-parent --no-manifest --no-backup --quiet
1138 1138 warning: ignoring --no-manifest, as upgrade is changing: sparserevlog
1139 1139
1140 1140 requirements
1141 1141 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1142 1142 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1143 1143 removed: sparserevlog
1144 1144
1145 1145 optimisations: re-delta-parent
1146 1146
1147 1147 processed revlogs:
1148 1148 - all-filelogs
1149 1149 - changelog
1150 1150 - manifest
1151 1151
1152 1152 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
1153 1153 note: selecting all-filelogs for processing to change: sparserevlog
1154 1154 note: selecting changelog for processing to change: sparserevlog
1155 1155
1156 1156 upgrade will perform the following actions:
1157 1157
1158 1158 requirements
1159 1159 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1160 1160 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1161 1161 removed: sparserevlog
1162 1162
1163 1163 optimisations: re-delta-parent
1164 1164
1165 1165 re-delta-parent
1166 1166 deltas within internal storage will choose a new base revision if needed
1167 1167
1168 1168 processed revlogs:
1169 1169 - all-filelogs
1170 1170 - changelog
1171 1171 - manifest
1172 1172
1173 1173 beginning upgrade...
1174 1174 repository locked and read-only
1175 1175 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1176 1176 (it is safe to interrupt this process any time before data migration completes)
1177 1177 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1178 1178 migrating 519 KB in store; 1.05 MB tracked data
1179 1179 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1180 1180 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1181 1181 cloning 1 revisions from data/f0.i
1182 1182 cloning 1 revisions from data/f2.i
1183 1183 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1184 1184 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1185 1185 cloning 3 revisions from 00manifest.i
1186 1186 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1187 1187 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1188 1188 cloning 3 revisions from 00changelog.i
1189 1189 finished migrating 3 changelog revisions; change in size: 0 bytes
1190 1190 finished migrating 9 total revisions; total change in store size: 0 bytes
1191 1191 copying phaseroots
1192 1192 copying requires
1193 1193 data fully upgraded in a temporary repository
1194 1194 marking source repository as being upgraded; clients will be unable to read from repository
1195 1195 starting in-place swap of repository data
1196 1196 replacing store...
1197 1197 store replacement complete; repository was inconsistent for *s (glob)
1198 1198 finalizing requirements file and making repository readable again
1199 1199 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1200 1200 $ hg verify -q
1201 1201
1202 1202 Check you can't skip revlog clone during important format upgrade
1203 1203
1204 1204 $ echo "sparse-revlog=yes" >> .hg/hgrc
1205 1205 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
1206 1206 note: selecting all-filelogs for processing to change: sparserevlog
1207 1207 note: selecting changelog for processing to change: sparserevlog
1208 1208
1209 1209 upgrade will perform the following actions:
1210 1210
1211 1211 requirements
1212 1212 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1213 1213 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1214 1214 added: sparserevlog
1215 1215
1216 1216 optimisations: re-delta-parent
1217 1217
1218 1218 sparserevlog
1219 1219 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
1220 1220
1221 1221 re-delta-parent
1222 1222 deltas within internal storage will choose a new base revision if needed
1223 1223
1224 1224 processed revlogs:
1225 1225 - all-filelogs
1226 1226 - changelog
1227 1227 - manifest
1228 1228
1229 1229 beginning upgrade...
1230 1230 repository locked and read-only
1231 1231 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1232 1232 (it is safe to interrupt this process any time before data migration completes)
1233 1233 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1234 1234 migrating 519 KB in store; 1.05 MB tracked data
1235 1235 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1236 1236 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1237 1237 cloning 1 revisions from data/f0.i
1238 1238 cloning 1 revisions from data/f2.i
1239 1239 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1240 1240 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1241 1241 cloning 3 revisions from 00manifest.i
1242 1242 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1243 1243 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1244 1244 cloning 3 revisions from 00changelog.i
1245 1245 finished migrating 3 changelog revisions; change in size: 0 bytes
1246 1246 finished migrating 9 total revisions; total change in store size: 0 bytes
1247 1247 copying phaseroots
1248 1248 copying requires
1249 1249 data fully upgraded in a temporary repository
1250 1250 marking source repository as being upgraded; clients will be unable to read from repository
1251 1251 starting in-place swap of repository data
1252 1252 replacing store...
1253 1253 store replacement complete; repository was inconsistent for *s (glob)
1254 1254 finalizing requirements file and making repository readable again
1255 1255 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1256 1256 $ hg verify -q
1257 1257
1258 1258 $ cd ..
1259 1259
1260 1260 store files with special filenames aren't encoded during copy
1261 1261
1262 1262 $ hg init store-filenames
1263 1263 $ cd store-filenames
1264 1264 $ touch foo
1265 1265 $ hg -q commit -A -m initial
1266 1266 $ touch .hg/store/.XX_special_filename
1267 1267
1268 1268 $ hg debugupgraderepo --run
1269 1269 nothing to do
1270 1270 $ hg debugupgraderepo --run --optimize 're-delta-fulladd'
1271 1271 upgrade will perform the following actions:
1272 1272
1273 1273 requirements
1274 1274 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1275 1275 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1276 1276
1277 1277 optimisations: re-delta-fulladd
1278 1278
1279 1279 re-delta-fulladd
1280 1280 each revision will be added as new content to the internal storage; this will likely drastically slow down execution time, but some extensions might need it
1281 1281
1282 1282 processed revlogs:
1283 1283 - all-filelogs
1284 1284 - changelog
1285 1285 - manifest
1286 1286
1287 1287 beginning upgrade...
1288 1288 repository locked and read-only
1289 1289 creating temporary repository to stage upgraded data: $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1290 1290 (it is safe to interrupt this process any time before data migration completes)
1291 1291 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
1292 1292 migrating 301 bytes in store; 107 bytes tracked data
1293 1293 migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data)
1294 1294 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
1295 1295 migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data)
1296 1296 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
1297 1297 migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data)
1298 1298 finished migrating 1 changelog revisions; change in size: 0 bytes
1299 1299 finished migrating 3 total revisions; total change in store size: 0 bytes
1300 1300 copying .XX_special_filename
1301 1301 copying phaseroots
1302 1302 copying requires
1303 1303 data fully upgraded in a temporary repository
1304 1304 marking source repository as being upgraded; clients will be unable to read from repository
1305 1305 starting in-place swap of repository data
1306 1306 replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1307 1307 replacing store...
1308 1308 store replacement complete; repository was inconsistent for *s (glob)
1309 1309 finalizing requirements file and making repository readable again
1310 1310 removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1311 1311 copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1312 1312 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1313 1313
1314 1314 fncache is valid after upgrade
1315 1315
1316 1316 $ hg debugrebuildfncache
1317 1317 fncache already up to date
1318 1318
1319 1319 $ cd ..
1320 1320
1321 1321 Check upgrading a large file repository
1322 1322 ---------------------------------------
1323 1323
1324 1324 $ hg init largefilesrepo
1325 1325 $ cat << EOF >> largefilesrepo/.hg/hgrc
1326 1326 > [extensions]
1327 1327 > largefiles =
1328 1328 > EOF
1329 1329
1330 1330 $ cd largefilesrepo
1331 1331 $ touch foo
1332 1332 $ hg add --large foo
1333 1333 $ hg -q commit -m initial
1334 1334 $ hg debugrequires
1335 1335 dotencode
1336 1336 fncache
1337 1337 generaldelta
1338 1338 largefiles
1339 1339 persistent-nodemap (rust !)
1340 1340 revlogv1
1341 1341 share-safe
1342 1342 sparserevlog
1343 1343 store
1344 1344
1345 1345 $ hg debugupgraderepo --run
1346 1346 nothing to do
1347 1347 $ hg debugrequires
1348 1348 dotencode
1349 1349 fncache
1350 1350 generaldelta
1351 1351 largefiles
1352 1352 persistent-nodemap (rust !)
1353 1353 revlogv1
1354 1354 share-safe
1355 1355 sparserevlog
1356 1356 store
1357 1357
1358 1358 $ cat << EOF >> .hg/hgrc
1359 1359 > [extensions]
1360 1360 > lfs =
1361 1361 > [lfs]
1362 1362 > threshold = 10
1363 1363 > EOF
1364 1364 $ echo '123456789012345' > lfs.bin
1365 1365 $ hg ci -Am 'lfs.bin'
1366 1366 adding lfs.bin
1367 1367 $ hg debugrequires | grep lfs
1368 1368 lfs
1369 1369 $ find .hg/store/lfs -type f
1370 1370 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1371 1371
1372 1372 $ hg debugupgraderepo --run
1373 1373 nothing to do
1374 1374
1375 1375 $ hg debugrequires | grep lfs
1376 1376 lfs
1377 1377 $ find .hg/store/lfs -type f
1378 1378 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1379 1379 $ hg verify -q
1380 1380 $ hg debugdata lfs.bin 0
1381 1381 version https://git-lfs.github.com/spec/v1
1382 1382 oid sha256:d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1383 1383 size 16
1384 1384 x-is-binary 0
1385 1385
1386 1386 $ cd ..
1387 1387
1388 1388 repository config is taken in account
1389 1389 -------------------------------------
1390 1390
1391 1391 $ cat << EOF >> $HGRCPATH
1392 1392 > [format]
1393 1393 > maxchainlen = 1
1394 1394 > EOF
1395 1395
1396 1396 $ hg init localconfig
1397 1397 $ cd localconfig
1398 1398 $ cat << EOF > file
1399 1399 > some content
1400 1400 > with some length
1401 1401 > to make sure we get a delta
1402 1402 > after changes
1403 1403 > very long
1404 1404 > very long
1405 1405 > very long
1406 1406 > very long
1407 1407 > very long
1408 1408 > very long
1409 1409 > very long
1410 1410 > very long
1411 1411 > very long
1412 1412 > very long
1413 1413 > very long
1414 1414 > EOF
1415 1415 $ hg -q commit -A -m A
1416 1416 $ echo "new line" >> file
1417 1417 $ hg -q commit -m B
1418 1418 $ echo "new line" >> file
1419 1419 $ hg -q commit -m C
1420 1420
1421 1421 $ cat << EOF >> .hg/hgrc
1422 1422 > [format]
1423 1423 > maxchainlen = 9001
1424 1424 > EOF
1425 1425 $ hg config format
1426 1426 format.revlog-compression=$BUNDLE2_COMPRESSIONS$
1427 1427 format.maxchainlen=9001
1428 1428 $ hg debugdeltachain file
1429 1429 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1430 1430 0 -1 -1 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1431 1431 1 0 -1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1432 1432 2 1 -1 1 2 0 snap 30 200 107 0.53500 128 21 0.19626 128 128 0.83594 1
1433 1433
1434 1434 $ hg debugupgraderepo --run --optimize 're-delta-all'
1435 1435 upgrade will perform the following actions:
1436 1436
1437 1437 requirements
1438 1438 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1439 1439 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1440 1440
1441 1441 optimisations: re-delta-all
1442 1442
1443 1443 re-delta-all
1444 1444 deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time
1445 1445
1446 1446 processed revlogs:
1447 1447 - all-filelogs
1448 1448 - changelog
1449 1449 - manifest
1450 1450
1451 1451 beginning upgrade...
1452 1452 repository locked and read-only
1453 1453 creating temporary repository to stage upgraded data: $TESTTMP/localconfig/.hg/upgrade.* (glob)
1454 1454 (it is safe to interrupt this process any time before data migration completes)
1455 1455 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1456 1456 migrating 1019 bytes in store; 882 bytes tracked data
1457 1457 migrating 1 filelogs containing 3 revisions (320 bytes in store; 573 bytes tracked data)
1458 1458 finished migrating 3 filelog revisions across 1 filelogs; change in size: -9 bytes
1459 1459 migrating 1 manifests containing 3 revisions (333 bytes in store; 138 bytes tracked data)
1460 1460 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1461 1461 migrating changelog containing 3 revisions (366 bytes in store; 171 bytes tracked data)
1462 1462 finished migrating 3 changelog revisions; change in size: 0 bytes
1463 1463 finished migrating 9 total revisions; total change in store size: -9 bytes
1464 1464 copying phaseroots
1465 1465 copying requires
1466 1466 data fully upgraded in a temporary repository
1467 1467 marking source repository as being upgraded; clients will be unable to read from repository
1468 1468 starting in-place swap of repository data
1469 1469 replaced files will be backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1470 1470 replacing store...
1471 1471 store replacement complete; repository was inconsistent for *s (glob)
1472 1472 finalizing requirements file and making repository readable again
1473 1473 removing temporary repository $TESTTMP/localconfig/.hg/upgrade.* (glob)
1474 1474 copy of old repository backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1475 1475 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1476 1476 $ hg debugdeltachain file
1477 1477 rev p1 p2 chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1478 1478 0 -1 -1 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1479 1479 1 0 -1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1480 1480 2 1 -1 1 3 1 p1 21 200 119 0.59500 119 0 0.00000 119 119 1.00000 1
1481 1481 $ cd ..
1482 1482
1483 1483 $ cat << EOF >> $HGRCPATH
1484 1484 > [format]
1485 1485 > maxchainlen = 9001
1486 1486 > EOF
1487 1487
1488 1488 Check upgrading a sparse-revlog repository
1489 1489 ---------------------------------------
1490 1490
1491 1491 $ hg init sparserevlogrepo --config format.sparse-revlog=no
1492 1492 $ cd sparserevlogrepo
1493 1493 $ touch foo
1494 1494 $ hg add foo
1495 1495 $ hg -q commit -m "foo"
1496 1496 $ hg debugrequires
1497 1497 dotencode
1498 1498 fncache
1499 1499 generaldelta
1500 1500 persistent-nodemap (rust !)
1501 1501 revlogv1
1502 1502 share-safe
1503 1503 store
1504 1504
1505 1505 Check that we can add the sparse-revlog format requirement
1506 1506 $ hg --config format.sparse-revlog=yes debugupgraderepo --run --quiet
1507 1507 upgrade will perform the following actions:
1508 1508
1509 1509 requirements
1510 1510 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1511 1511 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1512 1512 added: sparserevlog
1513 1513
1514 1514 processed revlogs:
1515 1515 - all-filelogs
1516 1516 - changelog
1517 1517 - manifest
1518 1518
1519 1519 $ hg debugrequires
1520 1520 dotencode
1521 1521 fncache
1522 1522 generaldelta
1523 1523 persistent-nodemap (rust !)
1524 1524 revlogv1
1525 1525 share-safe
1526 1526 sparserevlog
1527 1527 store
1528 1528
1529 1529 Check that we can remove the sparse-revlog format requirement
1530 1530 $ hg --config format.sparse-revlog=no debugupgraderepo --run --quiet
1531 1531 upgrade will perform the following actions:
1532 1532
1533 1533 requirements
1534 1534 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1535 1535 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1536 1536 removed: sparserevlog
1537 1537
1538 1538 processed revlogs:
1539 1539 - all-filelogs
1540 1540 - changelog
1541 1541 - manifest
1542 1542
1543 1543 $ hg debugrequires
1544 1544 dotencode
1545 1545 fncache
1546 1546 generaldelta
1547 1547 persistent-nodemap (rust !)
1548 1548 revlogv1
1549 1549 share-safe
1550 1550 store
1551 1551
1552 1552 #if zstd
1553 1553
1554 1554 Check upgrading to a zstd revlog
1555 1555 --------------------------------
1556 1556
1557 1557 upgrade
1558 1558
1559 1559 $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup --quiet
1560 1560 upgrade will perform the following actions:
1561 1561
1562 1562 requirements
1563 1563 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, store (no-rust !)
1564 1564 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, store (rust !)
1565 1565 added: revlog-compression-zstd, sparserevlog
1566 1566
1567 1567 processed revlogs:
1568 1568 - all-filelogs
1569 1569 - changelog
1570 1570 - manifest
1571 1571
1572 1572 $ hg debugformat -v
1573 1573 format-variant repo config default
1574 1574 fncache: yes yes yes
1575 1575 dirstate-v2: no no no
1576 1576 tracked-hint: no no no
1577 1577 dotencode: yes yes yes
1578 1578 generaldelta: yes yes yes
1579 1579 share-safe: yes yes yes
1580 1580 sparserevlog: yes yes yes
1581 1581 persistent-nodemap: no no no (no-rust !)
1582 1582 persistent-nodemap: yes yes no (rust !)
1583 1583 copies-sdc: no no no
1584 1584 revlog-v2: no no no
1585 1585 changelog-v2: no no no
1586 1586 plain-cl-delta: yes yes yes
1587 1587 compression: zlib zlib zlib (no-zstd !)
1588 1588 compression: zstd zlib zstd (zstd !)
1589 1589 compression-level: default default default
1590 1590 $ hg debugrequires
1591 1591 dotencode
1592 1592 fncache
1593 1593 generaldelta
1594 1594 persistent-nodemap (rust !)
1595 1595 revlog-compression-zstd
1596 1596 revlogv1
1597 1597 share-safe
1598 1598 sparserevlog
1599 1599 store
1600 1600
1601 1601 downgrade
1602 1602
1603 1603 $ hg debugupgraderepo --run --no-backup --quiet
1604 1604 upgrade will perform the following actions:
1605 1605
1606 1606 requirements
1607 1607 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1608 1608 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1609 1609 removed: revlog-compression-zstd
1610 1610
1611 1611 processed revlogs:
1612 1612 - all-filelogs
1613 1613 - changelog
1614 1614 - manifest
1615 1615
1616 1616 $ hg debugformat -v
1617 1617 format-variant repo config default
1618 1618 fncache: yes yes yes
1619 1619 dirstate-v2: no no no
1620 1620 tracked-hint: no no no
1621 1621 dotencode: yes yes yes
1622 1622 generaldelta: yes yes yes
1623 1623 share-safe: yes yes yes
1624 1624 sparserevlog: yes yes yes
1625 1625 persistent-nodemap: no no no (no-rust !)
1626 1626 persistent-nodemap: yes yes no (rust !)
1627 1627 copies-sdc: no no no
1628 1628 revlog-v2: no no no
1629 1629 changelog-v2: no no no
1630 1630 plain-cl-delta: yes yes yes
1631 1631 compression: zlib zlib zlib (no-zstd !)
1632 1632 compression: zlib zlib zstd (zstd !)
1633 1633 compression-level: default default default
1634 1634 $ hg debugrequires
1635 1635 dotencode
1636 1636 fncache
1637 1637 generaldelta
1638 1638 persistent-nodemap (rust !)
1639 1639 revlogv1
1640 1640 share-safe
1641 1641 sparserevlog
1642 1642 store
1643 1643
1644 1644 upgrade from hgrc
1645 1645
1646 1646 $ cat >> .hg/hgrc << EOF
1647 1647 > [format]
1648 1648 > revlog-compression=zstd
1649 1649 > EOF
1650 1650 $ hg debugupgraderepo --run --no-backup --quiet
1651 1651 upgrade will perform the following actions:
1652 1652
1653 1653 requirements
1654 1654 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
1655 1655 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (rust !)
1656 1656 added: revlog-compression-zstd
1657 1657
1658 1658 processed revlogs:
1659 1659 - all-filelogs
1660 1660 - changelog
1661 1661 - manifest
1662 1662
1663 1663 $ hg debugformat -v
1664 1664 format-variant repo config default
1665 1665 fncache: yes yes yes
1666 1666 dirstate-v2: no no no
1667 1667 tracked-hint: no no no
1668 1668 dotencode: yes yes yes
1669 1669 generaldelta: yes yes yes
1670 1670 share-safe: yes yes yes
1671 1671 sparserevlog: yes yes yes
1672 1672 persistent-nodemap: no no no (no-rust !)
1673 1673 persistent-nodemap: yes yes no (rust !)
1674 1674 copies-sdc: no no no
1675 1675 revlog-v2: no no no
1676 1676 changelog-v2: no no no
1677 1677 plain-cl-delta: yes yes yes
1678 1678 compression: zlib zlib zlib (no-zstd !)
1679 1679 compression: zstd zstd zstd (zstd !)
1680 1680 compression-level: default default default
1681 1681 $ hg debugrequires
1682 1682 dotencode
1683 1683 fncache
1684 1684 generaldelta
1685 1685 persistent-nodemap (rust !)
1686 1686 revlog-compression-zstd
1687 1687 revlogv1
1688 1688 share-safe
1689 1689 sparserevlog
1690 1690 store
1691 1691
1692 1692 #endif
1693 1693
1694 1694 Check upgrading to a revlog format supporting sidedata
1695 1695 ------------------------------------------------------
1696 1696
1697 1697 upgrade
1698 1698
1699 1699 $ hg debugsidedata -c 0
1700 1700 $ hg --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data debugupgraderepo --run --no-backup --config "extensions.sidedata=$TESTDIR/testlib/ext-sidedata.py" --quiet
1701 1701 upgrade will perform the following actions:
1702 1702
1703 1703 requirements
1704 1704 preserved: dotencode, fncache, generaldelta, share-safe, store (no-zstd !)
1705 1705 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, share-safe, sparserevlog, store (zstd no-rust !)
1706 1706 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, share-safe, sparserevlog, store (rust !)
1707 1707 removed: revlogv1
1708 1708 added: exp-revlogv2.2 (zstd !)
1709 1709 added: exp-revlogv2.2, sparserevlog (no-zstd !)
1710 1710
1711 1711 processed revlogs:
1712 1712 - all-filelogs
1713 1713 - changelog
1714 1714 - manifest
1715 1715
1716 1716 $ hg debugformat -v
1717 1717 format-variant repo config default
1718 1718 fncache: yes yes yes
1719 1719 dirstate-v2: no no no
1720 1720 tracked-hint: no no no
1721 1721 dotencode: yes yes yes
1722 1722 generaldelta: yes yes yes
1723 1723 share-safe: yes yes yes
1724 1724 sparserevlog: yes yes yes
1725 1725 persistent-nodemap: no no no (no-rust !)
1726 1726 persistent-nodemap: yes yes no (rust !)
1727 1727 copies-sdc: no no no
1728 1728 revlog-v2: yes no no
1729 1729 changelog-v2: no no no
1730 1730 plain-cl-delta: yes yes yes
1731 1731 compression: zlib zlib zlib (no-zstd !)
1732 1732 compression: zstd zstd zstd (zstd !)
1733 1733 compression-level: default default default
1734 1734 $ hg debugrequires
1735 1735 dotencode
1736 1736 exp-revlogv2.2
1737 1737 fncache
1738 1738 generaldelta
1739 1739 persistent-nodemap (rust !)
1740 1740 revlog-compression-zstd (zstd !)
1741 1741 share-safe
1742 1742 sparserevlog
1743 1743 store
1744 1744 $ hg debugsidedata -c 0
1745 1745 2 sidedata entries
1746 1746 entry-0001 size 4
1747 1747 entry-0002 size 32
1748 1748
1749 1749 downgrade
1750 1750
1751 1751 $ hg debugupgraderepo --config experimental.revlogv2=no --run --no-backup --quiet
1752 1752 upgrade will perform the following actions:
1753 1753
1754 1754 requirements
1755 1755 preserved: dotencode, fncache, generaldelta, share-safe, sparserevlog, store (no-zstd !)
1756 1756 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, share-safe, sparserevlog, store (zstd no-rust !)
1757 1757 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, share-safe, sparserevlog, store (rust !)
1758 1758 removed: exp-revlogv2.2
1759 1759 added: revlogv1
1760 1760
1761 1761 processed revlogs:
1762 1762 - all-filelogs
1763 1763 - changelog
1764 1764 - manifest
1765 1765
1766 1766 $ hg debugformat -v
1767 1767 format-variant repo config default
1768 1768 fncache: yes yes yes
1769 1769 dirstate-v2: no no no
1770 1770 tracked-hint: no no no
1771 1771 dotencode: yes yes yes
1772 1772 generaldelta: yes yes yes
1773 1773 share-safe: yes yes yes
1774 1774 sparserevlog: yes yes yes
1775 1775 persistent-nodemap: no no no (no-rust !)
1776 1776 persistent-nodemap: yes yes no (rust !)
1777 1777 copies-sdc: no no no
1778 1778 revlog-v2: no no no
1779 1779 changelog-v2: no no no
1780 1780 plain-cl-delta: yes yes yes
1781 1781 compression: zlib zlib zlib (no-zstd !)
1782 1782 compression: zstd zstd zstd (zstd !)
1783 1783 compression-level: default default default
1784 1784 $ hg debugrequires
1785 1785 dotencode
1786 1786 fncache
1787 1787 generaldelta
1788 1788 persistent-nodemap (rust !)
1789 1789 revlog-compression-zstd (zstd !)
1790 1790 revlogv1
1791 1791 share-safe
1792 1792 sparserevlog
1793 1793 store
1794 1794 $ hg debugsidedata -c 0
1795 1795
1796 1796 upgrade from hgrc
1797 1797
1798 1798 $ cat >> .hg/hgrc << EOF
1799 1799 > [experimental]
1800 1800 > revlogv2=enable-unstable-format-and-corrupt-my-data
1801 1801 > EOF
1802 1802 $ hg debugupgraderepo --run --no-backup --quiet
1803 1803 upgrade will perform the following actions:
1804 1804
1805 1805 requirements
1806 1806 preserved: dotencode, fncache, generaldelta, share-safe, sparserevlog, store (no-zstd !)
1807 1807 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, share-safe, sparserevlog, store (zstd no-rust !)
1808 1808 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, share-safe, sparserevlog, store (rust !)
1809 1809 removed: revlogv1
1810 1810 added: exp-revlogv2.2
1811 1811
1812 1812 processed revlogs:
1813 1813 - all-filelogs
1814 1814 - changelog
1815 1815 - manifest
1816 1816
1817 1817 $ hg debugformat -v
1818 1818 format-variant repo config default
1819 1819 fncache: yes yes yes
1820 1820 dirstate-v2: no no no
1821 1821 tracked-hint: no no no
1822 1822 dotencode: yes yes yes
1823 1823 generaldelta: yes yes yes
1824 1824 share-safe: yes yes yes
1825 1825 sparserevlog: yes yes yes
1826 1826 persistent-nodemap: no no no (no-rust !)
1827 1827 persistent-nodemap: yes yes no (rust !)
1828 1828 copies-sdc: no no no
1829 1829 revlog-v2: yes yes no
1830 1830 changelog-v2: no no no
1831 1831 plain-cl-delta: yes yes yes
1832 1832 compression: zlib zlib zlib (no-zstd !)
1833 1833 compression: zstd zstd zstd (zstd !)
1834 1834 compression-level: default default default
1835 1835 $ hg debugrequires
1836 1836 dotencode
1837 1837 exp-revlogv2.2
1838 1838 fncache
1839 1839 generaldelta
1840 1840 persistent-nodemap (rust !)
1841 1841 revlog-compression-zstd (zstd !)
1842 1842 share-safe
1843 1843 sparserevlog
1844 1844 store
1845 1845 $ hg debugsidedata -c 0
1846 1846
1847 1847 Demonstrate that nothing to perform upgrade will still run all the way through
1848 1848
1849 1849 $ hg debugupgraderepo --run
1850 1850 nothing to do
1851 1851
1852 1852 #if no-rust
1853 1853
1854 1854 $ cat << EOF >> $HGRCPATH
1855 1855 > [storage]
1856 1856 > dirstate-v2.slow-path = allow
1857 1857 > EOF
1858 1858
1859 1859 #endif
1860 1860
1861 1861 Upgrade to dirstate-v2
1862 1862
1863 1863 $ hg debugformat -v --config format.use-dirstate-v2=1 | grep dirstate-v2
1864 1864 dirstate-v2: no yes no
1865 1865 $ hg debugupgraderepo --config format.use-dirstate-v2=1 --run
1866 1866 upgrade will perform the following actions:
1867 1867
1868 1868 requirements
1869 1869 preserved: * (glob)
1870 1870 added: dirstate-v2
1871 1871
1872 1872 dirstate-v2
1873 1873 "hg status" will be faster
1874 1874
1875 1875 no revlogs to process
1876 1876
1877 1877 beginning upgrade...
1878 1878 repository locked and read-only
1879 1879 creating temporary repository to stage upgraded data: $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1880 1880 (it is safe to interrupt this process any time before data migration completes)
1881 1881 upgrading to dirstate-v2 from v1
1882 1882 replaced files will be backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
1883 1883 removing temporary repository $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1884 1884 $ ls .hg/upgradebackup.*/dirstate
1885 1885 .hg/upgradebackup.*/dirstate (glob)
1886 1886 $ hg debugformat -v | grep dirstate-v2
1887 1887 dirstate-v2: yes no no
1888 1888 $ hg status
1889 1889 $ dd bs=12 count=1 if=.hg/dirstate 2> /dev/null
1890 1890 dirstate-v2
1891 1891
1892 1892 Downgrade from dirstate-v2
1893 1893
1894 1894 $ hg debugupgraderepo --run
1895 1895 upgrade will perform the following actions:
1896 1896
1897 1897 requirements
1898 1898 preserved: * (glob)
1899 1899 removed: dirstate-v2
1900 1900
1901 1901 no revlogs to process
1902 1902
1903 1903 beginning upgrade...
1904 1904 repository locked and read-only
1905 1905 creating temporary repository to stage upgraded data: $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1906 1906 (it is safe to interrupt this process any time before data migration completes)
1907 1907 downgrading from dirstate-v2 to v1
1908 1908 replaced files will be backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
1909 1909 removing temporary repository $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1910 1910 $ hg debugformat -v | grep dirstate-v2
1911 1911 dirstate-v2: no no no
1912 1912 $ hg status
1913 1913
1914 1914 $ cd ..
1915 1915
1916 1916 dirstate-v2: upgrade and downgrade from and empty repository:
1917 1917 -------------------------------------------------------------
1918 1918
1919 1919 $ hg init --config format.use-dirstate-v2=no dirstate-v2-empty
1920 1920 $ cd dirstate-v2-empty
1921 1921 $ hg debugformat | grep dirstate-v2
1922 1922 dirstate-v2: no
1923 1923
1924 1924 upgrade
1925 1925
1926 1926 $ hg debugupgraderepo --run --config format.use-dirstate-v2=yes
1927 1927 upgrade will perform the following actions:
1928 1928
1929 1929 requirements
1930 1930 preserved: * (glob)
1931 1931 added: dirstate-v2
1932 1932
1933 1933 dirstate-v2
1934 1934 "hg status" will be faster
1935 1935
1936 1936 no revlogs to process
1937 1937
1938 1938 beginning upgrade...
1939 1939 repository locked and read-only
1940 1940 creating temporary repository to stage upgraded data: $TESTTMP/dirstate-v2-empty/.hg/upgrade.* (glob)
1941 1941 (it is safe to interrupt this process any time before data migration completes)
1942 1942 upgrading to dirstate-v2 from v1
1943 1943 replaced files will be backed up at $TESTTMP/dirstate-v2-empty/.hg/upgradebackup.* (glob)
1944 1944 removing temporary repository $TESTTMP/dirstate-v2-empty/.hg/upgrade.* (glob)
1945 1945 $ hg debugformat | grep dirstate-v2
1946 1946 dirstate-v2: yes
1947 1947
1948 1948 downgrade
1949 1949
1950 1950 $ hg debugupgraderepo --run --config format.use-dirstate-v2=no
1951 1951 upgrade will perform the following actions:
1952 1952
1953 1953 requirements
1954 1954 preserved: * (glob)
1955 1955 removed: dirstate-v2
1956 1956
1957 1957 no revlogs to process
1958 1958
1959 1959 beginning upgrade...
1960 1960 repository locked and read-only
1961 1961 creating temporary repository to stage upgraded data: $TESTTMP/dirstate-v2-empty/.hg/upgrade.* (glob)
1962 1962 (it is safe to interrupt this process any time before data migration completes)
1963 1963 downgrading from dirstate-v2 to v1
1964 1964 replaced files will be backed up at $TESTTMP/dirstate-v2-empty/.hg/upgradebackup.* (glob)
1965 1965 removing temporary repository $TESTTMP/dirstate-v2-empty/.hg/upgrade.* (glob)
1966 1966 $ hg debugformat | grep dirstate-v2
1967 1967 dirstate-v2: no
1968 1968
1969 1969 $ cd ..
1970 1970
1971 1971 Test automatic upgrade/downgrade
1972 1972 ================================
1973 1973
1974 1974
1975 1975 For dirstate v2
1976 1976 ---------------
1977 1977
1978 1978 create an initial repository
1979 1979
1980 1980 $ hg init auto-upgrade \
1981 1981 > --config format.use-dirstate-v2=no \
1982 1982 > --config format.use-dirstate-tracked-hint=yes \
1983 1983 > --config format.use-share-safe=no
1984 1984 $ hg debugbuilddag -R auto-upgrade --new-file .+5
1985 1985 $ hg -R auto-upgrade update
1986 1986 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1987 1987 $ hg debugformat -R auto-upgrade | grep dirstate-v2
1988 1988 dirstate-v2: no
1989 1989
1990 1990 upgrade it to dirstate-v2 automatically
1991 1991
1992 1992 $ hg status -R auto-upgrade \
1993 1993 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
1994 1994 > --config format.use-dirstate-v2=yes
1995 1995 automatically upgrading repository to the `dirstate-v2` feature
1996 1996 (see `hg help config.format.use-dirstate-v2` for details)
1997 1997 $ hg debugformat -R auto-upgrade | grep dirstate-v2
1998 1998 dirstate-v2: yes
1999 1999
2000 2000 downgrade it from dirstate-v2 automatically
2001 2001
2002 2002 $ hg status -R auto-upgrade \
2003 2003 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2004 2004 > --config format.use-dirstate-v2=no
2005 2005 automatically downgrading repository from the `dirstate-v2` feature
2006 2006 (see `hg help config.format.use-dirstate-v2` for details)
2007 2007 $ hg debugformat -R auto-upgrade | grep dirstate-v2
2008 2008 dirstate-v2: no
2009 2009
2010 2010
2011 2011 For multiple change at the same time
2012 2012 ------------------------------------
2013 2013
2014 2014 $ hg debugformat -R auto-upgrade | egrep '(dirstate-v2|tracked|share-safe)'
2015 2015 dirstate-v2: no
2016 2016 tracked-hint: yes
2017 2017 share-safe: no
2018 2018
2019 2019 $ hg status -R auto-upgrade \
2020 2020 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2021 2021 > --config format.use-dirstate-v2=yes \
2022 2022 > --config format.use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories=yes \
2023 2023 > --config format.use-dirstate-tracked-hint=no\
2024 2024 > --config format.use-share-safe.automatic-upgrade-of-mismatching-repositories=yes \
2025 2025 > --config format.use-share-safe=yes
2026 2026 automatically upgrading repository to the `dirstate-v2` feature
2027 2027 (see `hg help config.format.use-dirstate-v2` for details)
2028 2028 automatically upgrading repository to the `share-safe` feature
2029 2029 (see `hg help config.format.use-share-safe` for details)
2030 2030 automatically downgrading repository from the `tracked-hint` feature
2031 2031 (see `hg help config.format.use-dirstate-tracked-hint` for details)
2032 2032 $ hg debugformat -R auto-upgrade | egrep '(dirstate-v2|tracked|share-safe)'
2033 2033 dirstate-v2: yes
2034 2034 tracked-hint: no
2035 2035 share-safe: yes
2036 2036
2037 2037 Quiet upgrade and downgrade
2038 2038 ---------------------------
2039 2039
2040 2040
2041 2041 $ hg debugformat -R auto-upgrade | egrep '(dirstate-v2|tracked|share-safe)'
2042 2042 dirstate-v2: yes
2043 2043 tracked-hint: no
2044 2044 share-safe: yes
2045 2045 $ hg status -R auto-upgrade \
2046 2046 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2047 2047 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2048 2048 > --config format.use-dirstate-v2=no \
2049 2049 > --config format.use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories=yes \
2050 2050 > --config format.use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2051 2051 > --config format.use-dirstate-tracked-hint=yes \
2052 2052 > --config format.use-share-safe.automatic-upgrade-of-mismatching-repositories=yes \
2053 2053 > --config format.use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2054 2054 > --config format.use-share-safe=no
2055 2055
2056 2056 $ hg debugformat -R auto-upgrade | egrep '(dirstate-v2|tracked|share-safe)'
2057 2057 dirstate-v2: no
2058 2058 tracked-hint: yes
2059 2059 share-safe: no
2060 2060
2061 2061 $ hg status -R auto-upgrade \
2062 2062 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2063 2063 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2064 2064 > --config format.use-dirstate-v2=yes \
2065 2065 > --config format.use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories=yes \
2066 2066 > --config format.use-dirstate-tracked-hint.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2067 2067 > --config format.use-dirstate-tracked-hint=no\
2068 2068 > --config format.use-share-safe.automatic-upgrade-of-mismatching-repositories=yes \
2069 2069 > --config format.use-share-safe.automatic-upgrade-of-mismatching-repositories:quiet=yes \
2070 2070 > --config format.use-share-safe=yes
2071 2071 $ hg debugformat -R auto-upgrade | egrep '(dirstate-v2|tracked|share-safe)'
2072 2072 dirstate-v2: yes
2073 2073 tracked-hint: no
2074 2074 share-safe: yes
2075 2075
2076 2076 Attempting Auto-upgrade on a read-only repository
2077 2077 -------------------------------------------------
2078 2078
2079 2079 $ chmod -R a-w auto-upgrade
2080 2080
2081 2081 $ hg status -R auto-upgrade \
2082 2082 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2083 2083 > --config format.use-dirstate-v2=no
2084 2084 $ hg debugformat -R auto-upgrade | grep dirstate-v2
2085 2085 dirstate-v2: yes
2086 2086
2087 2087 $ chmod -R u+w auto-upgrade
2088 2088
2089 2089 Attempting Auto-upgrade on a locked repository
2090 2090 ----------------------------------------------
2091 2091
2092 2092 $ hg -R auto-upgrade debuglock --set-lock --quiet &
2093 2093 $ echo $! >> $DAEMON_PIDS
2094 2094 $ $RUNTESTDIR/testlib/wait-on-file 10 auto-upgrade/.hg/store/lock
2095 2095 $ hg status -R auto-upgrade \
2096 2096 > --config format.use-dirstate-v2.automatic-upgrade-of-mismatching-repositories=yes \
2097 2097 > --config format.use-dirstate-v2=no
2098 2098 $ hg debugformat -R auto-upgrade | grep dirstate-v2
2099 2099 dirstate-v2: yes
2100 2100
2101 2101 $ killdaemons.py
General Comments 0
You need to be logged in to leave comments. Login now