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