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