Mercurial > public > mercurial-scm > hg
comparison mercurial/upgrade_utils/actions.py @ 47319:e985a36c2aa3
upgrade: Use `improvement` subclasses everywhere, not instances
This changes the source definition of optimizations to match that of formats:
a subclass with a decorator, instead of an instance passed to a function call.
Not having any instance removes the confusion between class attributes and
instance attributes, which were used interchangeably.
Differential Revision: https://phab.mercurial-scm.org/D10768
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Fri, 21 May 2021 17:12:47 +0200 |
parents | ed0d54b20c5b |
children | a43d256c041a |
comparison
equal
deleted
inserted
replaced
47315:825d5a5907b4 | 47319:e985a36c2aa3 |
---|---|
42 FORMAT_VARIANT = b'deficiency' | 42 FORMAT_VARIANT = b'deficiency' |
43 OPTIMISATION = b'optimization' | 43 OPTIMISATION = b'optimization' |
44 | 44 |
45 | 45 |
46 class improvement(object): | 46 class improvement(object): |
47 """Represents an improvement that can be made as part of an upgrade. | 47 """Represents an improvement that can be made as part of an upgrade.""" |
48 | 48 |
49 The following attributes are defined on each instance: | 49 ### The following attributes should be defined for each subclass: |
50 | 50 |
51 name | 51 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``. |
52 Machine-readable string uniquely identifying this improvement. It | 52 # A format variant is where we change the storage format. Not all format |
53 will be mapped to an action later in the upgrade process. | 53 # variant changes are an obvious problem. |
54 | 54 # An optimization is an action (sometimes optional) that |
55 type | 55 # can be taken to further improve the state of the repository. |
56 Either ``FORMAT_VARIANT`` or ``OPTIMISATION``. | 56 type = None |
57 A format variant is where we change the storage format. Not all format | |
58 variant changes are an obvious problem. | |
59 An optimization is an action (sometimes optional) that | |
60 can be taken to further improve the state of the repository. | |
61 | |
62 description | |
63 Message intended for humans explaining the improvement in more detail, | |
64 including the implications of it. For ``FORMAT_VARIANT`` types, should be | |
65 worded in the present tense. For ``OPTIMISATION`` types, should be | |
66 worded in the future tense. | |
67 | |
68 upgrademessage | |
69 Message intended for humans explaining what an upgrade addressing this | |
70 issue will do. Should be worded in the future tense. | |
71 | |
72 postupgrademessage | |
73 Message intended for humans which will be shown post an upgrade | |
74 operation when the improvement will be added | |
75 | |
76 postdowngrademessage | |
77 Message intended for humans which will be shown post an upgrade | |
78 operation in which this improvement was removed | |
79 | |
80 touches_filelogs (bool) | |
81 Whether this improvement touches filelogs | |
82 | |
83 touches_manifests (bool) | |
84 Whether this improvement touches manifests | |
85 | |
86 touches_changelog (bool) | |
87 Whether this improvement touches changelog | |
88 | |
89 touches_requirements (bool) | |
90 Whether this improvement changes repository requirements | |
91 """ | |
92 | |
93 def __init__(self, name, type, description, upgrademessage): | |
94 self.name = name | |
95 self.type = type | |
96 self.description = description | |
97 self.upgrademessage = upgrademessage | |
98 self.postupgrademessage = None | |
99 self.postdowngrademessage = None | |
100 # By default for now, we assume every improvement touches | |
101 # all the things | |
102 self.touches_filelogs = True | |
103 self.touches_manifests = True | |
104 self.touches_changelog = True | |
105 self.touches_requirements = True | |
106 | |
107 def __eq__(self, other): | |
108 if not isinstance(other, improvement): | |
109 # This is what python tell use to do | |
110 return NotImplemented | |
111 return self.name == other.name | |
112 | |
113 def __ne__(self, other): | |
114 return not (self == other) | |
115 | |
116 def __hash__(self): | |
117 return hash(self.name) | |
118 | |
119 | |
120 allformatvariant = [] # type: List[Type['formatvariant']] | |
121 | |
122 | |
123 def registerformatvariant(cls): | |
124 allformatvariant.append(cls) | |
125 return cls | |
126 | |
127 | |
128 class formatvariant(improvement): | |
129 """an improvement subclass dedicated to repository format""" | |
130 | |
131 type = FORMAT_VARIANT | |
132 ### The following attributes should be defined for each class: | |
133 | 57 |
134 # machine-readable string uniquely identifying this improvement. it will be | 58 # machine-readable string uniquely identifying this improvement. it will be |
135 # mapped to an action later in the upgrade process. | 59 # mapped to an action later in the upgrade process. |
136 name = None | 60 name = None |
137 | 61 |
155 # Message intended for humans which will be shown post an upgrade | 79 # Message intended for humans which will be shown post an upgrade |
156 # operation in which this improvement was removed | 80 # operation in which this improvement was removed |
157 postdowngrademessage = None | 81 postdowngrademessage = None |
158 | 82 |
159 # By default for now, we assume every improvement touches all the things | 83 # By default for now, we assume every improvement touches all the things |
84 | |
85 # Whether this improvement touches filelogs | |
160 touches_filelogs = True | 86 touches_filelogs = True |
87 | |
88 # Whether this improvement touches manifests | |
161 touches_manifests = True | 89 touches_manifests = True |
90 | |
91 # Whether this improvement touches changelog | |
162 touches_changelog = True | 92 touches_changelog = True |
93 | |
94 # Whether this improvement changes repository requirements | |
163 touches_requirements = True | 95 touches_requirements = True |
164 | 96 |
165 def __init__(self): | 97 |
166 raise NotImplementedError() | 98 allformatvariant = [] # type: List[Type['formatvariant']] |
99 | |
100 | |
101 def registerformatvariant(cls): | |
102 allformatvariant.append(cls) | |
103 return cls | |
104 | |
105 | |
106 class formatvariant(improvement): | |
107 """an improvement subclass dedicated to repository format""" | |
108 | |
109 type = FORMAT_VARIANT | |
167 | 110 |
168 @staticmethod | 111 @staticmethod |
169 def fromrepo(repo): | 112 def fromrepo(repo): |
170 """current value of the variant in the repository""" | 113 """current value of the variant in the repository""" |
171 raise NotImplementedError() | 114 raise NotImplementedError() |
543 def register_optimization(obj): | 486 def register_optimization(obj): |
544 ALL_OPTIMISATIONS.append(obj) | 487 ALL_OPTIMISATIONS.append(obj) |
545 return obj | 488 return obj |
546 | 489 |
547 | 490 |
548 register_optimization( | 491 class optimization(improvement): |
549 improvement( | 492 """an improvement subclass dedicated to optimizations""" |
550 name=b're-delta-parent', | 493 |
551 type=OPTIMISATION, | 494 type = OPTIMISATION |
552 description=_( | 495 |
553 b'deltas within internal storage will be recalculated to ' | 496 |
554 b'choose an optimal base revision where this was not ' | 497 @register_optimization |
555 b'already done; the size of the repository may shrink and ' | 498 class redeltaparents(optimization): |
556 b'various operations may become faster; the first time ' | 499 name = b're-delta-parent' |
557 b'this optimization is performed could slow down upgrade ' | 500 |
558 b'execution considerably; subsequent invocations should ' | 501 type = OPTIMISATION |
559 b'not run noticeably slower' | 502 |
560 ), | 503 description = _( |
561 upgrademessage=_( | 504 b'deltas within internal storage will be recalculated to ' |
562 b'deltas within internal storage will choose a new ' | 505 b'choose an optimal base revision where this was not ' |
563 b'base revision if needed' | 506 b'already done; the size of the repository may shrink and ' |
564 ), | 507 b'various operations may become faster; the first time ' |
565 ) | 508 b'this optimization is performed could slow down upgrade ' |
566 ) | 509 b'execution considerably; subsequent invocations should ' |
567 | 510 b'not run noticeably slower' |
568 register_optimization( | 511 ) |
569 improvement( | 512 |
570 name=b're-delta-multibase', | 513 upgrademessage = _( |
571 type=OPTIMISATION, | 514 b'deltas within internal storage will choose a new ' |
572 description=_( | 515 b'base revision if needed' |
573 b'deltas within internal storage will be recalculated ' | 516 ) |
574 b'against multiple base revision and the smallest ' | 517 |
575 b'difference will be used; the size of the repository may ' | 518 |
576 b'shrink significantly when there are many merges; this ' | 519 @register_optimization |
577 b'optimization will slow down execution in proportion to ' | 520 class redeltamultibase(optimization): |
578 b'the number of merges in the repository and the amount ' | 521 name = b're-delta-multibase' |
579 b'of files in the repository; this slow down should not ' | 522 |
580 b'be significant unless there are tens of thousands of ' | 523 type = OPTIMISATION |
581 b'files and thousands of merges' | 524 |
582 ), | 525 description = _( |
583 upgrademessage=_( | 526 b'deltas within internal storage will be recalculated ' |
584 b'deltas within internal storage will choose an ' | 527 b'against multiple base revision and the smallest ' |
585 b'optimal delta by computing deltas against multiple ' | 528 b'difference will be used; the size of the repository may ' |
586 b'parents; may slow down execution time ' | 529 b'shrink significantly when there are many merges; this ' |
587 b'significantly' | 530 b'optimization will slow down execution in proportion to ' |
588 ), | 531 b'the number of merges in the repository and the amount ' |
589 ) | 532 b'of files in the repository; this slow down should not ' |
590 ) | 533 b'be significant unless there are tens of thousands of ' |
591 | 534 b'files and thousands of merges' |
592 register_optimization( | 535 ) |
593 improvement( | 536 |
594 name=b're-delta-all', | 537 upgrademessage = _( |
595 type=OPTIMISATION, | 538 b'deltas within internal storage will choose an ' |
596 description=_( | 539 b'optimal delta by computing deltas against multiple ' |
597 b'deltas within internal storage will always be ' | 540 b'parents; may slow down execution time ' |
598 b'recalculated without reusing prior deltas; this will ' | 541 b'significantly' |
599 b'likely make execution run several times slower; this ' | 542 ) |
600 b'optimization is typically not needed' | 543 |
601 ), | 544 |
602 upgrademessage=_( | 545 @register_optimization |
603 b'deltas within internal storage will be fully ' | 546 class redeltaall(optimization): |
604 b'recomputed; this will likely drastically slow down ' | 547 name = b're-delta-all' |
605 b'execution time' | 548 |
606 ), | 549 type = OPTIMISATION |
607 ) | 550 |
608 ) | 551 description = _( |
609 | 552 b'deltas within internal storage will always be ' |
610 register_optimization( | 553 b'recalculated without reusing prior deltas; this will ' |
611 improvement( | 554 b'likely make execution run several times slower; this ' |
612 name=b're-delta-fulladd', | 555 b'optimization is typically not needed' |
613 type=OPTIMISATION, | 556 ) |
614 description=_( | 557 |
615 b'every revision will be re-added as if it was new ' | 558 upgrademessage = _( |
616 b'content. It will go through the full storage ' | 559 b'deltas within internal storage will be fully ' |
617 b'mechanism giving extensions a chance to process it ' | 560 b'recomputed; this will likely drastically slow down ' |
618 b'(eg. lfs). This is similar to "re-delta-all" but even ' | 561 b'execution time' |
619 b'slower since more logic is involved.' | 562 ) |
620 ), | 563 |
621 upgrademessage=_( | 564 |
622 b'each revision will be added as new content to the ' | 565 @register_optimization |
623 b'internal storage; this will likely drastically slow ' | 566 class redeltafulladd(optimization): |
624 b'down execution time, but some extensions might need ' | 567 name = b're-delta-fulladd' |
625 b'it' | 568 |
626 ), | 569 type = OPTIMISATION |
627 ) | 570 |
628 ) | 571 description = _( |
572 b'every revision will be re-added as if it was new ' | |
573 b'content. It will go through the full storage ' | |
574 b'mechanism giving extensions a chance to process it ' | |
575 b'(eg. lfs). This is similar to "re-delta-all" but even ' | |
576 b'slower since more logic is involved.' | |
577 ) | |
578 | |
579 upgrademessage = _( | |
580 b'each revision will be added as new content to the ' | |
581 b'internal storage; this will likely drastically slow ' | |
582 b'down execution time, but some extensions might need ' | |
583 b'it' | |
584 ) | |
629 | 585 |
630 | 586 |
631 def findoptimizations(repo): | 587 def findoptimizations(repo): |
632 """Determine optimisation that could be used during upgrade""" | 588 """Determine optimisation that could be used during upgrade""" |
633 # These are unconditionally added. There is logic later that figures out | 589 # These are unconditionally added. There is logic later that figures out |