##// END OF EJS Templates
upgrade: avoid a traceback in case of unrecognized revlog...
marmoute -
r48460:aa229689 default
parent child Browse files
Show More
@@ -1,643 +1,648 b''
1 1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 2 #
3 3 # Copyright (c) 2016-present, Gregory Szorc
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import stat
11 11
12 12 from ..i18n import _
13 13 from ..pycompat import getattr
14 14 from .. import (
15 15 changelog,
16 16 error,
17 17 filelog,
18 18 manifest,
19 19 metadata,
20 20 pycompat,
21 21 requirements,
22 22 scmutil,
23 23 store,
24 24 util,
25 25 vfs as vfsmod,
26 26 )
27 27 from ..revlogutils import (
28 28 constants as revlogconst,
29 29 flagutil,
30 30 nodemap,
31 31 sidedata as sidedatamod,
32 32 )
33 33 from . import actions as upgrade_actions
34 34
35 35
36 36 def get_sidedata_helpers(srcrepo, dstrepo):
37 37 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
38 38 sequential = pycompat.iswindows or not use_w
39 39 if not sequential:
40 40 srcrepo.register_sidedata_computer(
41 41 revlogconst.KIND_CHANGELOG,
42 42 sidedatamod.SD_FILES,
43 43 (sidedatamod.SD_FILES,),
44 44 metadata._get_worker_sidedata_adder(srcrepo, dstrepo),
45 45 flagutil.REVIDX_HASCOPIESINFO,
46 46 replace=True,
47 47 )
48 48 return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata)
49 49
50 50
51 51 def _revlogfrompath(repo, rl_type, path):
52 52 """Obtain a revlog from a repo path.
53 53
54 54 An instance of the appropriate class is returned.
55 55 """
56 56 if rl_type & store.FILEFLAGS_CHANGELOG:
57 57 return changelog.changelog(repo.svfs)
58 58 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
59 59 mandir = b''
60 60 if b'/' in path:
61 61 mandir = path.rsplit(b'/', 1)[0]
62 62 return manifest.manifestrevlog(
63 63 repo.nodeconstants, repo.svfs, tree=mandir
64 64 )
65 65 else:
66 66 # drop the extension and the `data/` prefix
67 path = path.rsplit(b'.', 1)[0].split(b'/', 1)[1]
67 path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
68 if len(path_part) < 2:
69 msg = _('cannot recognize revlog from filename: %s')
70 msg %= path
71 raise error.Abort(msg)
72 path = path_part[1]
68 73 return filelog.filelog(repo.svfs, path)
69 74
70 75
71 76 def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname):
72 77 """copy all relevant files for `oldrl` into `destrepo` store
73 78
74 79 Files are copied "as is" without any transformation. The copy is performed
75 80 without extra checks. Callers are responsible for making sure the copied
76 81 content is compatible with format of the destination repository.
77 82 """
78 83 oldrl = getattr(oldrl, '_revlog', oldrl)
79 84 newrl = _revlogfrompath(destrepo, rl_type, unencodedname)
80 85 newrl = getattr(newrl, '_revlog', newrl)
81 86
82 87 oldvfs = oldrl.opener
83 88 newvfs = newrl.opener
84 89 oldindex = oldvfs.join(oldrl._indexfile)
85 90 newindex = newvfs.join(newrl._indexfile)
86 91 olddata = oldvfs.join(oldrl._datafile)
87 92 newdata = newvfs.join(newrl._datafile)
88 93
89 94 with newvfs(newrl._indexfile, b'w'):
90 95 pass # create all the directories
91 96
92 97 util.copyfile(oldindex, newindex)
93 98 copydata = oldrl.opener.exists(oldrl._datafile)
94 99 if copydata:
95 100 util.copyfile(olddata, newdata)
96 101
97 102 if rl_type & store.FILEFLAGS_FILELOG:
98 103 destrepo.svfs.fncache.add(unencodedname)
99 104 if copydata:
100 105 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
101 106
102 107
103 108 UPGRADE_CHANGELOG = b"changelog"
104 109 UPGRADE_MANIFEST = b"manifest"
105 110 UPGRADE_FILELOGS = b"all-filelogs"
106 111
107 112 UPGRADE_ALL_REVLOGS = frozenset(
108 113 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
109 114 )
110 115
111 116
112 117 def matchrevlog(revlogfilter, rl_type):
113 118 """check if a revlog is selected for cloning.
114 119
115 120 In other words, are there any updates which need to be done on revlog
116 121 or it can be blindly copied.
117 122
118 123 The store entry is checked against the passed filter"""
119 124 if rl_type & store.FILEFLAGS_CHANGELOG:
120 125 return UPGRADE_CHANGELOG in revlogfilter
121 126 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
122 127 return UPGRADE_MANIFEST in revlogfilter
123 128 assert rl_type & store.FILEFLAGS_FILELOG
124 129 return UPGRADE_FILELOGS in revlogfilter
125 130
126 131
127 132 def _perform_clone(
128 133 ui,
129 134 dstrepo,
130 135 tr,
131 136 old_revlog,
132 137 rl_type,
133 138 unencoded,
134 139 upgrade_op,
135 140 sidedata_helpers,
136 141 oncopiedrevision,
137 142 ):
138 143 """returns the new revlog object created"""
139 144 newrl = None
140 145 if matchrevlog(upgrade_op.revlogs_to_process, rl_type):
141 146 ui.note(
142 147 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
143 148 )
144 149 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
145 150 old_revlog.clone(
146 151 tr,
147 152 newrl,
148 153 addrevisioncb=oncopiedrevision,
149 154 deltareuse=upgrade_op.delta_reuse_mode,
150 155 forcedeltabothparents=upgrade_op.force_re_delta_both_parents,
151 156 sidedata_helpers=sidedata_helpers,
152 157 )
153 158 else:
154 159 msg = _(b'blindly copying %s containing %i revisions\n')
155 160 ui.note(msg % (unencoded, len(old_revlog)))
156 161 _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded)
157 162
158 163 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
159 164 return newrl
160 165
161 166
162 167 def _clonerevlogs(
163 168 ui,
164 169 srcrepo,
165 170 dstrepo,
166 171 tr,
167 172 upgrade_op,
168 173 ):
169 174 """Copy revlogs between 2 repos."""
170 175 revcount = 0
171 176 srcsize = 0
172 177 srcrawsize = 0
173 178 dstsize = 0
174 179 fcount = 0
175 180 frevcount = 0
176 181 fsrcsize = 0
177 182 frawsize = 0
178 183 fdstsize = 0
179 184 mcount = 0
180 185 mrevcount = 0
181 186 msrcsize = 0
182 187 mrawsize = 0
183 188 mdstsize = 0
184 189 crevcount = 0
185 190 csrcsize = 0
186 191 crawsize = 0
187 192 cdstsize = 0
188 193
189 194 alldatafiles = list(srcrepo.store.walk())
190 195 # mapping of data files which needs to be cloned
191 196 # key is unencoded filename
192 197 # value is revlog_object_from_srcrepo
193 198 manifests = {}
194 199 changelogs = {}
195 200 filelogs = {}
196 201
197 202 # Perform a pass to collect metadata. This validates we can open all
198 203 # source files and allows a unified progress bar to be displayed.
199 204 for rl_type, unencoded, encoded, size in alldatafiles:
200 205 if not rl_type & store.FILEFLAGS_REVLOG_MAIN:
201 206 continue
202 207
203 208 # the store.walk function will wrongly pickup transaction backup and
204 209 # get confused. As a quick fix for 5.9 release, we ignore those.
205 210 # (this is not a module constants because it seems better to keep the
206 211 # hack together)
207 212 skip_undo = (
208 213 b'undo.backup.00changelog.i',
209 214 b'undo.backup.00manifest.i',
210 215 )
211 216 if unencoded in skip_undo:
212 217 continue
213 218
214 219 rl = _revlogfrompath(srcrepo, rl_type, unencoded)
215 220
216 221 info = rl.storageinfo(
217 222 exclusivefiles=True,
218 223 revisionscount=True,
219 224 trackedsize=True,
220 225 storedsize=True,
221 226 )
222 227
223 228 revcount += info[b'revisionscount'] or 0
224 229 datasize = info[b'storedsize'] or 0
225 230 rawsize = info[b'trackedsize'] or 0
226 231
227 232 srcsize += datasize
228 233 srcrawsize += rawsize
229 234
230 235 # This is for the separate progress bars.
231 236 if rl_type & store.FILEFLAGS_CHANGELOG:
232 237 changelogs[unencoded] = (rl_type, rl)
233 238 crevcount += len(rl)
234 239 csrcsize += datasize
235 240 crawsize += rawsize
236 241 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
237 242 manifests[unencoded] = (rl_type, rl)
238 243 mcount += 1
239 244 mrevcount += len(rl)
240 245 msrcsize += datasize
241 246 mrawsize += rawsize
242 247 elif rl_type & store.FILEFLAGS_FILELOG:
243 248 filelogs[unencoded] = (rl_type, rl)
244 249 fcount += 1
245 250 frevcount += len(rl)
246 251 fsrcsize += datasize
247 252 frawsize += rawsize
248 253 else:
249 254 error.ProgrammingError(b'unknown revlog type')
250 255
251 256 if not revcount:
252 257 return
253 258
254 259 ui.status(
255 260 _(
256 261 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
257 262 b'%d in changelog)\n'
258 263 )
259 264 % (revcount, frevcount, mrevcount, crevcount)
260 265 )
261 266 ui.status(
262 267 _(b'migrating %s in store; %s tracked data\n')
263 268 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
264 269 )
265 270
266 271 # Used to keep track of progress.
267 272 progress = None
268 273
269 274 def oncopiedrevision(rl, rev, node):
270 275 progress.increment()
271 276
272 277 sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo)
273 278
274 279 # Migrating filelogs
275 280 ui.status(
276 281 _(
277 282 b'migrating %d filelogs containing %d revisions '
278 283 b'(%s in store; %s tracked data)\n'
279 284 )
280 285 % (
281 286 fcount,
282 287 frevcount,
283 288 util.bytecount(fsrcsize),
284 289 util.bytecount(frawsize),
285 290 )
286 291 )
287 292 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
288 293 for unencoded, (rl_type, oldrl) in sorted(filelogs.items()):
289 294 newrl = _perform_clone(
290 295 ui,
291 296 dstrepo,
292 297 tr,
293 298 oldrl,
294 299 rl_type,
295 300 unencoded,
296 301 upgrade_op,
297 302 sidedata_helpers,
298 303 oncopiedrevision,
299 304 )
300 305 info = newrl.storageinfo(storedsize=True)
301 306 fdstsize += info[b'storedsize'] or 0
302 307 ui.status(
303 308 _(
304 309 b'finished migrating %d filelog revisions across %d '
305 310 b'filelogs; change in size: %s\n'
306 311 )
307 312 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
308 313 )
309 314
310 315 # Migrating manifests
311 316 ui.status(
312 317 _(
313 318 b'migrating %d manifests containing %d revisions '
314 319 b'(%s in store; %s tracked data)\n'
315 320 )
316 321 % (
317 322 mcount,
318 323 mrevcount,
319 324 util.bytecount(msrcsize),
320 325 util.bytecount(mrawsize),
321 326 )
322 327 )
323 328 if progress:
324 329 progress.complete()
325 330 progress = srcrepo.ui.makeprogress(
326 331 _(b'manifest revisions'), total=mrevcount
327 332 )
328 333 for unencoded, (rl_type, oldrl) in sorted(manifests.items()):
329 334 newrl = _perform_clone(
330 335 ui,
331 336 dstrepo,
332 337 tr,
333 338 oldrl,
334 339 rl_type,
335 340 unencoded,
336 341 upgrade_op,
337 342 sidedata_helpers,
338 343 oncopiedrevision,
339 344 )
340 345 info = newrl.storageinfo(storedsize=True)
341 346 mdstsize += info[b'storedsize'] or 0
342 347 ui.status(
343 348 _(
344 349 b'finished migrating %d manifest revisions across %d '
345 350 b'manifests; change in size: %s\n'
346 351 )
347 352 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
348 353 )
349 354
350 355 # Migrating changelog
351 356 ui.status(
352 357 _(
353 358 b'migrating changelog containing %d revisions '
354 359 b'(%s in store; %s tracked data)\n'
355 360 )
356 361 % (
357 362 crevcount,
358 363 util.bytecount(csrcsize),
359 364 util.bytecount(crawsize),
360 365 )
361 366 )
362 367 if progress:
363 368 progress.complete()
364 369 progress = srcrepo.ui.makeprogress(
365 370 _(b'changelog revisions'), total=crevcount
366 371 )
367 372 for unencoded, (rl_type, oldrl) in sorted(changelogs.items()):
368 373 newrl = _perform_clone(
369 374 ui,
370 375 dstrepo,
371 376 tr,
372 377 oldrl,
373 378 rl_type,
374 379 unencoded,
375 380 upgrade_op,
376 381 sidedata_helpers,
377 382 oncopiedrevision,
378 383 )
379 384 info = newrl.storageinfo(storedsize=True)
380 385 cdstsize += info[b'storedsize'] or 0
381 386 progress.complete()
382 387 ui.status(
383 388 _(
384 389 b'finished migrating %d changelog revisions; change in size: '
385 390 b'%s\n'
386 391 )
387 392 % (crevcount, util.bytecount(cdstsize - csrcsize))
388 393 )
389 394
390 395 dstsize = fdstsize + mdstsize + cdstsize
391 396 ui.status(
392 397 _(
393 398 b'finished migrating %d total revisions; total change in store '
394 399 b'size: %s\n'
395 400 )
396 401 % (revcount, util.bytecount(dstsize - srcsize))
397 402 )
398 403
399 404
400 405 def _files_to_copy_post_revlog_clone(srcrepo):
401 406 """yields files which should be copied to destination after revlogs
402 407 are cloned"""
403 408 for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
404 409 # don't copy revlogs as they are already cloned
405 410 if store.revlog_type(path) is not None:
406 411 continue
407 412 # Skip transaction related files.
408 413 if path.startswith(b'undo'):
409 414 continue
410 415 # Only copy regular files.
411 416 if kind != stat.S_IFREG:
412 417 continue
413 418 # Skip other skipped files.
414 419 if path in (b'lock', b'fncache'):
415 420 continue
416 421 # TODO: should we skip cache too?
417 422
418 423 yield path
419 424
420 425
421 426 def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op):
422 427 """Replace the stores after current repository is upgraded
423 428
424 429 Creates a backup of current repository store at backup path
425 430 Replaces upgraded store files in current repo from upgraded one
426 431
427 432 Arguments:
428 433 currentrepo: repo object of current repository
429 434 upgradedrepo: repo object of the upgraded data
430 435 backupvfs: vfs object for the backup path
431 436 upgrade_op: upgrade operation object
432 437 to be used to decide what all is upgraded
433 438 """
434 439 # TODO: don't blindly rename everything in store
435 440 # There can be upgrades where store is not touched at all
436 441 if upgrade_op.backup_store:
437 442 util.rename(currentrepo.spath, backupvfs.join(b'store'))
438 443 else:
439 444 currentrepo.vfs.rmtree(b'store', forcibly=True)
440 445 util.rename(upgradedrepo.spath, currentrepo.spath)
441 446
442 447
443 448 def finishdatamigration(ui, srcrepo, dstrepo, requirements):
444 449 """Hook point for extensions to perform additional actions during upgrade.
445 450
446 451 This function is called after revlogs and store files have been copied but
447 452 before the new store is swapped into the original location.
448 453 """
449 454
450 455
451 456 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
452 457 """Do the low-level work of upgrading a repository.
453 458
454 459 The upgrade is effectively performed as a copy between a source
455 460 repository and a temporary destination repository.
456 461
457 462 The source repository is unmodified for as long as possible so the
458 463 upgrade can abort at any time without causing loss of service for
459 464 readers and without corrupting the source repository.
460 465 """
461 466 assert srcrepo.currentwlock()
462 467 assert dstrepo.currentwlock()
463 468 backuppath = None
464 469 backupvfs = None
465 470
466 471 ui.status(
467 472 _(
468 473 b'(it is safe to interrupt this process any time before '
469 474 b'data migration completes)\n'
470 475 )
471 476 )
472 477
473 478 if upgrade_actions.dirstatev2 in upgrade_op.upgrade_actions:
474 479 ui.status(_(b'upgrading to dirstate-v2 from v1\n'))
475 480 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v1', b'v2')
476 481 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatev2)
477 482
478 483 if upgrade_actions.dirstatev2 in upgrade_op.removed_actions:
479 484 ui.status(_(b'downgrading from dirstate-v2 to v1\n'))
480 485 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v2', b'v1')
481 486 upgrade_op.removed_actions.remove(upgrade_actions.dirstatev2)
482 487
483 488 if not (upgrade_op.upgrade_actions or upgrade_op.removed_actions):
484 489 return
485 490
486 491 if upgrade_op.requirements_only:
487 492 ui.status(_(b'upgrading repository requirements\n'))
488 493 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
489 494 # if there is only one action and that is persistent nodemap upgrade
490 495 # directly write the nodemap file and update requirements instead of going
491 496 # through the whole cloning process
492 497 elif (
493 498 len(upgrade_op.upgrade_actions) == 1
494 499 and b'persistent-nodemap' in upgrade_op.upgrade_actions_names
495 500 and not upgrade_op.removed_actions
496 501 ):
497 502 ui.status(
498 503 _(b'upgrading repository to use persistent nodemap feature\n')
499 504 )
500 505 with srcrepo.transaction(b'upgrade') as tr:
501 506 unfi = srcrepo.unfiltered()
502 507 cl = unfi.changelog
503 508 nodemap.persist_nodemap(tr, cl, force=True)
504 509 # we want to directly operate on the underlying revlog to force
505 510 # create a nodemap file. This is fine since this is upgrade code
506 511 # and it heavily relies on repository being revlog based
507 512 # hence accessing private attributes can be justified
508 513 nodemap.persist_nodemap(
509 514 tr, unfi.manifestlog._rootstore._revlog, force=True
510 515 )
511 516 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
512 517 elif (
513 518 len(upgrade_op.removed_actions) == 1
514 519 and [
515 520 x
516 521 for x in upgrade_op.removed_actions
517 522 if x.name == b'persistent-nodemap'
518 523 ]
519 524 and not upgrade_op.upgrade_actions
520 525 ):
521 526 ui.status(
522 527 _(b'downgrading repository to not use persistent nodemap feature\n')
523 528 )
524 529 with srcrepo.transaction(b'upgrade') as tr:
525 530 unfi = srcrepo.unfiltered()
526 531 cl = unfi.changelog
527 532 nodemap.delete_nodemap(tr, srcrepo, cl)
528 533 # check comment 20 lines above for accessing private attributes
529 534 nodemap.delete_nodemap(
530 535 tr, srcrepo, unfi.manifestlog._rootstore._revlog
531 536 )
532 537 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
533 538 else:
534 539 with dstrepo.transaction(b'upgrade') as tr:
535 540 _clonerevlogs(
536 541 ui,
537 542 srcrepo,
538 543 dstrepo,
539 544 tr,
540 545 upgrade_op,
541 546 )
542 547
543 548 # Now copy other files in the store directory.
544 549 for p in _files_to_copy_post_revlog_clone(srcrepo):
545 550 srcrepo.ui.status(_(b'copying %s\n') % p)
546 551 src = srcrepo.store.rawvfs.join(p)
547 552 dst = dstrepo.store.rawvfs.join(p)
548 553 util.copyfile(src, dst, copystat=True)
549 554
550 555 finishdatamigration(ui, srcrepo, dstrepo, requirements)
551 556
552 557 ui.status(_(b'data fully upgraded in a temporary repository\n'))
553 558
554 559 if upgrade_op.backup_store:
555 560 backuppath = pycompat.mkdtemp(
556 561 prefix=b'upgradebackup.', dir=srcrepo.path
557 562 )
558 563 backupvfs = vfsmod.vfs(backuppath)
559 564
560 565 # Make a backup of requires file first, as it is the first to be modified.
561 566 util.copyfile(
562 567 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
563 568 )
564 569
565 570 # We install an arbitrary requirement that clients must not support
566 571 # as a mechanism to lock out new clients during the data swap. This is
567 572 # better than allowing a client to continue while the repository is in
568 573 # an inconsistent state.
569 574 ui.status(
570 575 _(
571 576 b'marking source repository as being upgraded; clients will be '
572 577 b'unable to read from repository\n'
573 578 )
574 579 )
575 580 scmutil.writereporequirements(
576 581 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
577 582 )
578 583
579 584 ui.status(_(b'starting in-place swap of repository data\n'))
580 585 if upgrade_op.backup_store:
581 586 ui.status(
582 587 _(b'replaced files will be backed up at %s\n') % backuppath
583 588 )
584 589
585 590 # Now swap in the new store directory. Doing it as a rename should make
586 591 # the operation nearly instantaneous and atomic (at least in well-behaved
587 592 # environments).
588 593 ui.status(_(b'replacing store...\n'))
589 594 tstart = util.timer()
590 595 _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op)
591 596 elapsed = util.timer() - tstart
592 597 ui.status(
593 598 _(
594 599 b'store replacement complete; repository was inconsistent for '
595 600 b'%0.1fs\n'
596 601 )
597 602 % elapsed
598 603 )
599 604
600 605 # We first write the requirements file. Any new requirements will lock
601 606 # out legacy clients.
602 607 ui.status(
603 608 _(
604 609 b'finalizing requirements file and making repository readable '
605 610 b'again\n'
606 611 )
607 612 )
608 613 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
609 614
610 615 if upgrade_op.backup_store:
611 616 # The lock file from the old store won't be removed because nothing has a
612 617 # reference to its new location. So clean it up manually. Alternatively, we
613 618 # could update srcrepo.svfs and other variables to point to the new
614 619 # location. This is simpler.
615 620 assert backupvfs is not None # help pytype
616 621 backupvfs.unlink(b'store/lock')
617 622
618 623 return backuppath
619 624
620 625
621 626 def upgrade_dirstate(ui, srcrepo, upgrade_op, old, new):
622 627 if upgrade_op.backup_store:
623 628 backuppath = pycompat.mkdtemp(
624 629 prefix=b'upgradebackup.', dir=srcrepo.path
625 630 )
626 631 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
627 632 backupvfs = vfsmod.vfs(backuppath)
628 633 util.copyfile(
629 634 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
630 635 )
631 636 util.copyfile(
632 637 srcrepo.vfs.join(b'dirstate'), backupvfs.join(b'dirstate')
633 638 )
634 639
635 640 assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
636 641 srcrepo.dirstate._map._use_dirstate_tree = True
637 642 srcrepo.dirstate._map.preload()
638 643 srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
639 644 srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
640 645 srcrepo.dirstate._dirty = True
641 646 srcrepo.dirstate.write(None)
642 647
643 648 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
General Comments 0
You need to be logged in to leave comments. Login now