Mercurial > public > mercurial-scm > hg
comparison mercurial/upgrade.py @ 32031:11a2461fc9b1
upgrade: move descriptions and selection logic in individual classes
Our goal here is to get top level definition for all the format variants. Having
them defined outside of the function enabled other users of that logic.
They are two keys components of a format variant:
1) the name and various descriptions of its effect,
2) the code that checks if the repo is using this variant and if the config
enables it.
That second items make us pick a class-based approach, since different variants
requires different code (even if in practice, many can reuse the same logic).
Each variants define its own class that is then used like a singleton. The
class-based approach also clarify the definitions part a bit since each are
simple assignment in an indented block.
The 'fromdefault' and 'fromconfig' are respectively replaced by a class
attribute and a method to be called at the one place where "fromconfig"
matters.
Overall, they are many viable approach for this, but this is the one I picked.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Wed, 12 Apr 2017 16:34:05 +0200 |
parents | e47223576b8d |
children | 189778a06743 |
comparison
equal
deleted
inserted
replaced
32030:e47223576b8d | 32031:11a2461fc9b1 |
---|---|
138 | 138 |
139 def __hash__(self): | 139 def __hash__(self): |
140 return hash(self.name) | 140 return hash(self.name) |
141 | 141 |
142 class formatvariant(improvement): | 142 class formatvariant(improvement): |
143 """an improvement subclass dedicated to repository format | 143 """an improvement subclass dedicated to repository format""" |
144 | 144 type = deficiency |
145 extra attributes: | 145 ### The following attributes should be defined for each class: |
146 | 146 |
147 fromdefault (``deficiency`` types only) | 147 # machine-readable string uniquely identifying this improvement. it will be |
148 Boolean indicating whether the current (deficient) state deviates | 148 # mapped to an action later in the upgrade process. |
149 from Mercurial's default configuration. | 149 name = None |
150 | 150 |
151 fromconfig (``deficiency`` types only) | 151 # message intended for humans explaining the improvement in more detail, |
152 Boolean indicating whether the current (deficient) state deviates | 152 # including the implications of it ``deficiency`` types, should be worded |
153 from the current Mercurial configuration. | 153 # in the present tense. |
154 """ | 154 description = None |
155 | 155 |
156 def __init__(self, name, description, upgrademessage, fromdefault, | 156 # message intended for humans explaining what an upgrade addressing this |
157 fromconfig): | 157 # issue will do. should be worded in the future tense. |
158 super(formatvariant, self).__init__(name, deficiency, description, | 158 upgrademessage = None |
159 upgrademessage) | 159 |
160 self.fromdefault = fromdefault | 160 # value of current Mercurial default for new repository |
161 self.fromconfig = fromconfig | 161 default = None |
162 | |
163 def __init__(self): | |
164 raise NotImplementedError() | |
165 | |
166 @staticmethod | |
167 def fromrepo(repo): | |
168 """current value of the variant in the repository""" | |
169 raise NotImplementedError() | |
170 | |
171 @staticmethod | |
172 def fromconfig(repo): | |
173 """current value of the variant in the configuration""" | |
174 raise NotImplementedError() | |
175 | |
176 class requirementformatvariant(formatvariant): | |
177 """formatvariant based on a 'requirement' name. | |
178 | |
179 Many format variant are controlled by a 'requirement'. We define a small | |
180 subclass to factor the code. | |
181 """ | |
182 | |
183 # the requirement that control this format variant | |
184 _requirement = None | |
185 | |
186 @staticmethod | |
187 def _newreporequirements(repo): | |
188 return localrepo.newreporequirements(repo) | |
189 | |
190 @classmethod | |
191 def fromrepo(cls, repo): | |
192 assert cls._requirement is not None | |
193 return cls._requirement in repo.requirements | |
194 | |
195 @classmethod | |
196 def fromconfig(cls, repo): | |
197 assert cls._requirement is not None | |
198 return cls._requirement in cls._newreporequirements(repo) | |
199 | |
200 class fncache(requirementformatvariant): | |
201 name = 'fncache' | |
202 | |
203 _requirement = 'fncache' | |
204 | |
205 default = True | |
206 | |
207 description = _('long and reserved filenames may not work correctly; ' | |
208 'repository performance is sub-optimal') | |
209 | |
210 upgrademessage = _('repository will be more resilient to storing ' | |
211 'certain paths and performance of certain ' | |
212 'operations should be improved') | |
213 | |
214 class dotencode(requirementformatvariant): | |
215 name = 'dotencode' | |
216 | |
217 _requirement = 'dotencode' | |
218 | |
219 default = True | |
220 | |
221 description = _('storage of filenames beginning with a period or ' | |
222 'space may not work correctly') | |
223 | |
224 upgrademessage = _('repository will be better able to store files ' | |
225 'beginning with a space or period') | |
226 | |
227 class generaldelta(requirementformatvariant): | |
228 name = 'generaldelta' | |
229 | |
230 _requirement = 'generaldelta' | |
231 | |
232 default = True | |
233 | |
234 description = _('deltas within internal storage are unable to ' | |
235 'choose optimal revisions; repository is larger and ' | |
236 'slower than it could be; interaction with other ' | |
237 'repositories may require extra network and CPU ' | |
238 'resources, making "hg push" and "hg pull" slower') | |
239 | |
240 upgrademessage = _('repository storage will be able to create ' | |
241 'optimal deltas; new repository data will be ' | |
242 'smaller and read times should decrease; ' | |
243 'interacting with other repositories using this ' | |
244 'storage model should require less network and ' | |
245 'CPU resources, making "hg push" and "hg pull" ' | |
246 'faster') | |
247 | |
248 class removecldeltachain(formatvariant): | |
249 name = 'removecldeltachain' | |
250 | |
251 default = True | |
252 | |
253 description = _('changelog storage is using deltas instead of ' | |
254 'raw entries; changelog reading and any ' | |
255 'operation relying on changelog data are slower ' | |
256 'than they could be') | |
257 | |
258 upgrademessage = _('changelog storage will be reformated to ' | |
259 'store raw entries; changelog reading will be ' | |
260 'faster; changelog size may be reduced') | |
261 | |
262 @staticmethod | |
263 def fromrepo(repo): | |
264 # Mercurial 4.0 changed changelogs to not use delta chains. Search for | |
265 # changelogs with deltas. | |
266 cl = repo.changelog | |
267 chainbase = cl.chainbase | |
268 return all(rev == chainbase(rev) for rev in cl) | |
269 | |
270 @staticmethod | |
271 def fromconfig(repo): | |
272 return True | |
162 | 273 |
163 def finddeficiencies(repo): | 274 def finddeficiencies(repo): |
164 """returns a list of deficiencies that the repo suffer from""" | 275 """returns a list of deficiencies that the repo suffer from""" |
165 newreporeqs = localrepo.newreporequirements(repo) | |
166 | |
167 deficiencies = [] | 276 deficiencies = [] |
168 | 277 |
169 # We could detect lack of revlogv1 and store here, but they were added | 278 # We could detect lack of revlogv1 and store here, but they were added |
170 # in 0.9.2 and we don't support upgrading repos without these | 279 # in 0.9.2 and we don't support upgrading repos without these |
171 # requirements, so let's not bother. | 280 # requirements, so let's not bother. |
172 | 281 |
173 if 'fncache' not in repo.requirements: | 282 if not fncache.fromrepo(repo): |
174 deficiencies.append(formatvariant( | 283 deficiencies.append(fncache) |
175 name='fncache', | 284 if not dotencode.fromrepo(repo): |
176 description=_('long and reserved filenames may not work correctly; ' | 285 deficiencies.append(dotencode) |
177 'repository performance is sub-optimal'), | 286 if not generaldelta.fromrepo(repo): |
178 upgrademessage=_('repository will be more resilient to storing ' | 287 deficiencies.append(generaldelta) |
179 'certain paths and performance of certain ' | 288 if not removecldeltachain.fromrepo(repo): |
180 'operations should be improved'), | 289 deficiencies.append(removecldeltachain) |
181 fromdefault=True, | |
182 fromconfig='fncache' in newreporeqs)) | |
183 | |
184 if 'dotencode' not in repo.requirements: | |
185 deficiencies.append(formatvariant( | |
186 name='dotencode', | |
187 description=_('storage of filenames beginning with a period or ' | |
188 'space may not work correctly'), | |
189 upgrademessage=_('repository will be better able to store files ' | |
190 'beginning with a space or period'), | |
191 fromdefault=True, | |
192 fromconfig='dotencode' in newreporeqs)) | |
193 | |
194 if 'generaldelta' not in repo.requirements: | |
195 deficiencies.append(formatvariant( | |
196 name='generaldelta', | |
197 description=_('deltas within internal storage are unable to ' | |
198 'choose optimal revisions; repository is larger and ' | |
199 'slower than it could be; interaction with other ' | |
200 'repositories may require extra network and CPU ' | |
201 'resources, making "hg push" and "hg pull" slower'), | |
202 upgrademessage=_('repository storage will be able to create ' | |
203 'optimal deltas; new repository data will be ' | |
204 'smaller and read times should decrease; ' | |
205 'interacting with other repositories using this ' | |
206 'storage model should require less network and ' | |
207 'CPU resources, making "hg push" and "hg pull" ' | |
208 'faster'), | |
209 fromdefault=True, | |
210 fromconfig='generaldelta' in newreporeqs)) | |
211 | |
212 # Mercurial 4.0 changed changelogs to not use delta chains. Search for | |
213 # changelogs with deltas. | |
214 cl = repo.changelog | |
215 for rev in cl: | |
216 chainbase = cl.chainbase(rev) | |
217 if chainbase != rev: | |
218 deficiencies.append(formatvariant( | |
219 name='removecldeltachain', | |
220 description=_('changelog storage is using deltas instead of ' | |
221 'raw entries; changelog reading and any ' | |
222 'operation relying on changelog data are slower ' | |
223 'than they could be'), | |
224 upgrademessage=_('changelog storage will be reformated to ' | |
225 'store raw entries; changelog reading will be ' | |
226 'faster; changelog size may be reduced'), | |
227 fromdefault=True, | |
228 fromconfig=True)) | |
229 break | |
230 | 290 |
231 return deficiencies | 291 return deficiencies |
232 | 292 |
233 def findoptimizations(repo): | 293 def findoptimizations(repo): |
234 """Determine optimisation that could be used during upgrade""" | 294 """Determine optimisation that could be used during upgrade""" |
678 if not run: | 738 if not run: |
679 fromconfig = [] | 739 fromconfig = [] |
680 onlydefault = [] | 740 onlydefault = [] |
681 | 741 |
682 for d in deficiencies: | 742 for d in deficiencies: |
683 if d.fromconfig: | 743 if d.fromconfig(repo): |
684 fromconfig.append(d) | 744 fromconfig.append(d) |
685 elif d.fromdefault: | 745 elif d.default: |
686 onlydefault.append(d) | 746 onlydefault.append(d) |
687 | 747 |
688 if fromconfig or onlydefault: | 748 if fromconfig or onlydefault: |
689 | 749 |
690 if fromconfig: | 750 if fromconfig: |