429 'dotencode', |
429 'dotencode', |
430 'fncache', |
430 'fncache', |
431 'generaldelta', |
431 'generaldelta', |
432 ]) |
432 ]) |
433 |
433 |
|
434 deficiency = 'deficiency' |
|
435 optimisation = 'optimization' |
|
436 |
|
437 class upgradeimprovement(object): |
|
438 """Represents an improvement that can be made as part of an upgrade. |
|
439 |
|
440 The following attributes are defined on each instance: |
|
441 |
|
442 name |
|
443 Machine-readable string uniquely identifying this improvement. It |
|
444 will be mapped to an action later in the upgrade process. |
|
445 |
|
446 type |
|
447 Either ``deficiency`` or ``optimisation``. A deficiency is an obvious |
|
448 problem. An optimization is an action (sometimes optional) that |
|
449 can be taken to further improve the state of the repository. |
|
450 |
|
451 description |
|
452 Message intended for humans explaining the improvement in more detail, |
|
453 including the implications of it. For ``deficiency`` types, should be |
|
454 worded in the present tense. For ``optimisation`` types, should be |
|
455 worded in the future tense. |
|
456 |
|
457 upgrademessage |
|
458 Message intended for humans explaining what an upgrade addressing this |
|
459 issue will do. Should be worded in the future tense. |
|
460 |
|
461 fromdefault (``deficiency`` types only) |
|
462 Boolean indicating whether the current (deficient) state deviates |
|
463 from Mercurial's default configuration. |
|
464 |
|
465 fromconfig (``deficiency`` types only) |
|
466 Boolean indicating whether the current (deficient) state deviates |
|
467 from the current Mercurial configuration. |
|
468 """ |
|
469 def __init__(self, name, type, description, upgrademessage, **kwargs): |
|
470 self.name = name |
|
471 self.type = type |
|
472 self.description = description |
|
473 self.upgrademessage = upgrademessage |
|
474 |
|
475 for k, v in kwargs.items(): |
|
476 setattr(self, k, v) |
|
477 |
|
478 def upgradefindimprovements(repo): |
|
479 """Determine improvements that can be made to the repo during upgrade. |
|
480 |
|
481 Returns a list of ``upgradeimprovement`` describing repository deficiencies |
|
482 and optimizations. |
|
483 """ |
|
484 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil |
|
485 from . import localrepo |
|
486 |
|
487 newreporeqs = localrepo.newreporequirements(repo) |
|
488 |
|
489 improvements = [] |
|
490 |
|
491 # We could detect lack of revlogv1 and store here, but they were added |
|
492 # in 0.9.2 and we don't support upgrading repos without these |
|
493 # requirements, so let's not bother. |
|
494 |
|
495 if 'fncache' not in repo.requirements: |
|
496 improvements.append(upgradeimprovement( |
|
497 name='fncache', |
|
498 type=deficiency, |
|
499 description=_('long and reserved filenames may not work correctly; ' |
|
500 'repository performance is sub-optimal'), |
|
501 upgrademessage=_('repository will be more resilient to storing ' |
|
502 'certain paths and performance of certain ' |
|
503 'operations should be improved'), |
|
504 fromdefault=True, |
|
505 fromconfig='fncache' in newreporeqs)) |
|
506 |
|
507 if 'dotencode' not in repo.requirements: |
|
508 improvements.append(upgradeimprovement( |
|
509 name='dotencode', |
|
510 type=deficiency, |
|
511 description=_('storage of filenames beginning with a period or ' |
|
512 'space may not work correctly'), |
|
513 upgrademessage=_('repository will be better able to store files ' |
|
514 'beginning with a space or period'), |
|
515 fromdefault=True, |
|
516 fromconfig='dotencode' in newreporeqs)) |
|
517 |
|
518 if 'generaldelta' not in repo.requirements: |
|
519 improvements.append(upgradeimprovement( |
|
520 name='generaldelta', |
|
521 type=deficiency, |
|
522 description=_('deltas within internal storage are unable to ' |
|
523 'choose optimal revisions; repository is larger and ' |
|
524 'slower than it could be; interaction with other ' |
|
525 'repositories may require extra network and CPU ' |
|
526 'resources, making "hg push" and "hg pull" slower'), |
|
527 upgrademessage=_('repository storage will be able to create ' |
|
528 'optimal deltas; new repository data will be ' |
|
529 'smaller and read times should decrease; ' |
|
530 'interacting with other repositories using this ' |
|
531 'storage model should require less network and ' |
|
532 'CPU resources, making "hg push" and "hg pull" ' |
|
533 'faster'), |
|
534 fromdefault=True, |
|
535 fromconfig='generaldelta' in newreporeqs)) |
|
536 |
|
537 # Mercurial 4.0 changed changelogs to not use delta chains. Search for |
|
538 # changelogs with deltas. |
|
539 cl = repo.changelog |
|
540 for rev in cl: |
|
541 chainbase = cl.chainbase(rev) |
|
542 if chainbase != rev: |
|
543 improvements.append(upgradeimprovement( |
|
544 name='removecldeltachain', |
|
545 type=deficiency, |
|
546 description=_('changelog storage is using deltas instead of ' |
|
547 'raw entries; changelog reading and any ' |
|
548 'operation relying on changelog data are slower ' |
|
549 'than they could be'), |
|
550 upgrademessage=_('changelog storage will be reformated to ' |
|
551 'store raw entries; changelog reading will be ' |
|
552 'faster; changelog size may be reduced'), |
|
553 fromdefault=True, |
|
554 fromconfig=True)) |
|
555 break |
|
556 |
|
557 # Now for the optimizations. |
|
558 |
|
559 # These are unconditionally added. There is logic later that figures out |
|
560 # which ones to apply. |
|
561 |
|
562 improvements.append(upgradeimprovement( |
|
563 name='redeltaparent', |
|
564 type=optimisation, |
|
565 description=_('deltas within internal storage will be recalculated to ' |
|
566 'choose an optimal base revision where this was not ' |
|
567 'already done; the size of the repository may shrink and ' |
|
568 'various operations may become faster; the first time ' |
|
569 'this optimization is performed could slow down upgrade ' |
|
570 'execution considerably; subsequent invocations should ' |
|
571 'not run noticeably slower'), |
|
572 upgrademessage=_('deltas within internal storage will choose a new ' |
|
573 'base revision if needed'))) |
|
574 |
|
575 improvements.append(upgradeimprovement( |
|
576 name='redeltamultibase', |
|
577 type=optimisation, |
|
578 description=_('deltas within internal storage will be recalculated ' |
|
579 'against multiple base revision and the smallest ' |
|
580 'difference will be used; the size of the repository may ' |
|
581 'shrink significantly when there are many merges; this ' |
|
582 'optimization will slow down execution in proportion to ' |
|
583 'the number of merges in the repository and the amount ' |
|
584 'of files in the repository; this slow down should not ' |
|
585 'be significant unless there are tens of thousands of ' |
|
586 'files and thousands of merges'), |
|
587 upgrademessage=_('deltas within internal storage will choose an ' |
|
588 'optimal delta by computing deltas against multiple ' |
|
589 'parents; may slow down execution time ' |
|
590 'significantly'))) |
|
591 |
|
592 improvements.append(upgradeimprovement( |
|
593 name='redeltaall', |
|
594 type=optimisation, |
|
595 description=_('deltas within internal storage will always be ' |
|
596 'recalculated without reusing prior deltas; this will ' |
|
597 'likely make execution run several times slower; this ' |
|
598 'optimization is typically not needed'), |
|
599 upgrademessage=_('deltas within internal storage will be fully ' |
|
600 'recomputed; this will likely drastically slow down ' |
|
601 'execution time'))) |
|
602 |
|
603 return improvements |
|
604 |
|
605 def upgradedetermineactions(repo, improvements, sourcereqs, destreqs, |
|
606 optimize): |
|
607 """Determine upgrade actions that will be performed. |
|
608 |
|
609 Given a list of improvements as returned by ``upgradefindimprovements``, |
|
610 determine the list of upgrade actions that will be performed. |
|
611 |
|
612 The role of this function is to filter improvements if needed, apply |
|
613 recommended optimizations from the improvements list that make sense, |
|
614 etc. |
|
615 |
|
616 Returns a list of action names. |
|
617 """ |
|
618 newactions = [] |
|
619 |
|
620 knownreqs = upgradesupporteddestrequirements(repo) |
|
621 |
|
622 for i in improvements: |
|
623 name = i.name |
|
624 |
|
625 # If the action is a requirement that doesn't show up in the |
|
626 # destination requirements, prune the action. |
|
627 if name in knownreqs and name not in destreqs: |
|
628 continue |
|
629 |
|
630 if i.type == deficiency: |
|
631 newactions.append(name) |
|
632 |
|
633 newactions.extend(o for o in sorted(optimize) if o not in newactions) |
|
634 |
|
635 # FUTURE consider adding some optimizations here for certain transitions. |
|
636 # e.g. adding generaldelta could schedule parent redeltas. |
|
637 |
|
638 return newactions |
|
639 |
434 def upgraderepo(ui, repo, run=False, optimize=None): |
640 def upgraderepo(ui, repo, run=False, optimize=None): |
435 """Upgrade a repository in place.""" |
641 """Upgrade a repository in place.""" |
436 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil |
642 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil |
437 from . import localrepo |
643 from . import localrepo |
438 |
644 |
|
645 optimize = set(optimize or []) |
439 repo = repo.unfiltered() |
646 repo = repo.unfiltered() |
440 |
647 |
441 # Ensure the repository can be upgraded. |
648 # Ensure the repository can be upgraded. |
442 missingreqs = upgraderequiredsourcerequirements(repo) - repo.requirements |
649 missingreqs = upgraderequiredsourcerequirements(repo) - repo.requirements |
443 if missingreqs: |
650 if missingreqs: |
486 ui.write(_(' added: %s\n') % |
712 ui.write(_(' added: %s\n') % |
487 _(', ').join(sorted(newreqs - repo.requirements))) |
713 _(', ').join(sorted(newreqs - repo.requirements))) |
488 |
714 |
489 ui.write('\n') |
715 ui.write('\n') |
490 |
716 |
|
717 def printupgradeactions(): |
|
718 for action in actions: |
|
719 for i in improvements: |
|
720 if i.name == action: |
|
721 ui.write('%s\n %s\n\n' % |
|
722 (i.name, i.upgrademessage)) |
|
723 |
491 if not run: |
724 if not run: |
|
725 fromdefault = [] |
|
726 fromconfig = [] |
|
727 optimizations = [] |
|
728 |
|
729 for i in improvements: |
|
730 assert i.type in (deficiency, optimisation) |
|
731 if i.type == deficiency: |
|
732 if i.fromdefault: |
|
733 fromdefault.append(i) |
|
734 if i.fromconfig: |
|
735 fromconfig.append(i) |
|
736 else: |
|
737 optimizations.append(i) |
|
738 |
|
739 if fromdefault or fromconfig: |
|
740 fromconfignames = set(x.name for x in fromconfig) |
|
741 onlydefault = [i for i in fromdefault |
|
742 if i.name not in fromconfignames] |
|
743 |
|
744 if fromconfig: |
|
745 ui.write(_('repository lacks features recommended by ' |
|
746 'current config options:\n\n')) |
|
747 for i in fromconfig: |
|
748 ui.write('%s\n %s\n\n' % (i.name, i.description)) |
|
749 |
|
750 if onlydefault: |
|
751 ui.write(_('repository lacks features used by the default ' |
|
752 'config options:\n\n')) |
|
753 for i in onlydefault: |
|
754 ui.write('%s\n %s\n\n' % (i.name, i.description)) |
|
755 |
|
756 ui.write('\n') |
|
757 else: |
|
758 ui.write(_('(no feature deficiencies found in existing ' |
|
759 'repository)\n')) |
|
760 |
492 ui.write(_('performing an upgrade with "--run" will make the following ' |
761 ui.write(_('performing an upgrade with "--run" will make the following ' |
493 'changes:\n\n')) |
762 'changes:\n\n')) |
494 |
763 |
495 printrequirements() |
764 printrequirements() |
|
765 printupgradeactions() |
|
766 |
|
767 unusedoptimize = [i for i in improvements |
|
768 if i.name not in actions and i.type == optimisation] |
|
769 if unusedoptimize: |
|
770 ui.write(_('additional optimizations are available by specifying ' |
|
771 '"--optimize <name>":\n\n')) |
|
772 for i in unusedoptimize: |
|
773 ui.write(_('%s\n %s\n\n') % (i.name, i.description)) |