Mercurial > evolve
comparison hgext3rd/topic/__init__.py @ 4814:48b30ff742cb
python3: use format-source to run byteify-strings in .py files
Using the format-source extension smooth out the pain of merging after
auto-formatting.
This change makes all of the Evolve test suite pass under python3 and has
added benefit of being 100% automated using mercurial's `byteify-strings`
script version 1.0 (revision 11498aa91c036c6d70f7ac5ee5af2664a84a1130).
How to benefit from the help of format-source is explained in the README.
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Tue, 06 Aug 2019 15:06:38 +0200 |
parents | 67567d7f1174 |
children | 6f5d3f58fbe4 |
comparison
equal
deleted
inserted
replaced
4812:67567d7f1174 | 4814:48b30ff742cb |
---|---|
158 topicmap, | 158 topicmap, |
159 ) | 159 ) |
160 | 160 |
161 cmdtable = {} | 161 cmdtable = {} |
162 command = registrar.command(cmdtable) | 162 command = registrar.command(cmdtable) |
163 colortable = {'topic.active': 'green', | 163 colortable = {b'topic.active': b'green', |
164 'topic.list.unstablecount': 'red', | 164 b'topic.list.unstablecount': b'red', |
165 'topic.list.headcount.multiple': 'yellow', | 165 b'topic.list.headcount.multiple': b'yellow', |
166 'topic.list.behindcount': 'cyan', | 166 b'topic.list.behindcount': b'cyan', |
167 'topic.list.behinderror': 'red', | 167 b'topic.list.behinderror': b'red', |
168 'stack.index': 'yellow', | 168 b'stack.index': b'yellow', |
169 'stack.index.base': 'none dim', | 169 b'stack.index.base': b'none dim', |
170 'stack.desc.base': 'none dim', | 170 b'stack.desc.base': b'none dim', |
171 'stack.shortnode.base': 'none dim', | 171 b'stack.shortnode.base': b'none dim', |
172 'stack.state.base': 'dim', | 172 b'stack.state.base': b'dim', |
173 'stack.state.clean': 'green', | 173 b'stack.state.clean': b'green', |
174 'stack.index.current': 'cyan', # random pick | 174 b'stack.index.current': b'cyan', # random pick |
175 'stack.state.current': 'cyan bold', # random pick | 175 b'stack.state.current': b'cyan bold', # random pick |
176 'stack.desc.current': 'cyan', # random pick | 176 b'stack.desc.current': b'cyan', # random pick |
177 'stack.shortnode.current': 'cyan', # random pick | 177 b'stack.shortnode.current': b'cyan', # random pick |
178 'stack.state.orphan': 'red', | 178 b'stack.state.orphan': b'red', |
179 'stack.state.content-divergent': 'red', | 179 b'stack.state.content-divergent': b'red', |
180 'stack.state.phase-divergent': 'red', | 180 b'stack.state.phase-divergent': b'red', |
181 'stack.summary.behindcount': 'cyan', | 181 b'stack.summary.behindcount': b'cyan', |
182 'stack.summary.behinderror': 'red', | 182 b'stack.summary.behinderror': b'red', |
183 'stack.summary.headcount.multiple': 'yellow', | 183 b'stack.summary.headcount.multiple': b'yellow', |
184 # default color to help log output and thg | 184 # default color to help log output and thg |
185 # (first pick I could think off, update as needed | 185 # (first pick I could think off, update as needed |
186 'log.topic': 'green_background', | 186 b'log.topic': b'green_background', |
187 'topic.active': 'green', | 187 b'topic.active': b'green', |
188 } | 188 } |
189 | 189 |
190 __version__ = b'0.17.0.dev' | 190 __version__ = b'0.17.0.dev' |
191 | 191 |
192 testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0 5.1' | 192 testedwith = b'4.5.2 4.6.2 4.7 4.8 4.9 5.0 5.1' |
193 minimumhgversion = b'4.5' | 193 minimumhgversion = b'4.5' |
198 from mercurial import configitems | 198 from mercurial import configitems |
199 | 199 |
200 configtable = {} | 200 configtable = {} |
201 configitem = registrar.configitem(configtable) | 201 configitem = registrar.configitem(configtable) |
202 | 202 |
203 configitem('experimental', 'enforce-topic', | 203 configitem(b'experimental', b'enforce-topic', |
204 default=False, | 204 default=False, |
205 ) | 205 ) |
206 configitem('experimental', 'enforce-single-head', | 206 configitem(b'experimental', b'enforce-single-head', |
207 default=False, | 207 default=False, |
208 ) | 208 ) |
209 configitem('experimental', 'topic-mode', | 209 configitem(b'experimental', b'topic-mode', |
210 default=None, | 210 default=None, |
211 ) | 211 ) |
212 configitem('experimental', 'topic.publish-bare-branch', | 212 configitem(b'experimental', b'topic.publish-bare-branch', |
213 default=False, | 213 default=False, |
214 ) | 214 ) |
215 configitem('experimental', 'topic.allow-publish', | 215 configitem(b'experimental', b'topic.allow-publish', |
216 default=configitems.dynamicdefault, | 216 default=configitems.dynamicdefault, |
217 ) | 217 ) |
218 configitem('_internal', 'keep-topic', | 218 configitem(b'_internal', b'keep-topic', |
219 default=False, | 219 default=False, |
220 ) | 220 ) |
221 configitem('experimental', 'topic-mode.server', | 221 configitem(b'experimental', b'topic-mode.server', |
222 default=configitems.dynamicdefault, | 222 default=configitems.dynamicdefault, |
223 ) | 223 ) |
224 | 224 |
225 def extsetup(ui): | 225 def extsetup(ui): |
226 # register config that strictly belong to other code (thg, core, etc) | 226 # register config that strictly belong to other code (thg, core, etc) |
227 # | 227 # |
228 # To ensure all config items we used are registered, we register them if | 228 # To ensure all config items we used are registered, we register them if |
229 # nobody else did so far. | 229 # nobody else did so far. |
230 from mercurial import configitems | 230 from mercurial import configitems |
231 extraitem = functools.partial(configitems._register, ui._knownconfig) | 231 extraitem = functools.partial(configitems._register, ui._knownconfig) |
232 if ('experimental' not in ui._knownconfig | 232 if (b'experimental' not in ui._knownconfig |
233 or not ui._knownconfig['experimental'].get('thg.displaynames')): | 233 or not ui._knownconfig[b'experimental'].get(b'thg.displaynames')): |
234 extraitem('experimental', 'thg.displaynames', | 234 extraitem(b'experimental', b'thg.displaynames', |
235 default=None, | 235 default=None, |
236 ) | 236 ) |
237 if ('devel' not in ui._knownconfig | 237 if (b'devel' not in ui._knownconfig |
238 or not ui._knownconfig['devel'].get('random')): | 238 or not ui._knownconfig[b'devel'].get(b'random')): |
239 extraitem('devel', 'randomseed', | 239 extraitem(b'devel', b'randomseed', |
240 default=None, | 240 default=None, |
241 ) | 241 ) |
242 | 242 |
243 # we need to do old style declaration for <= 4.5 | 243 # we need to do old style declaration for <= 4.5 |
244 templatekeyword = registrar.templatekeyword() | 244 templatekeyword = registrar.templatekeyword() |
245 post45template = r'requires=' in templatekeyword.__doc__ | 245 post45template = r'requires=' in templatekeyword.__doc__ |
246 | 246 |
247 def _contexttopic(self, force=False): | 247 def _contexttopic(self, force=False): |
248 if not (force or self.mutable()): | 248 if not (force or self.mutable()): |
249 return '' | 249 return b'' |
250 return self.extra().get(constants.extrakey, '') | 250 return self.extra().get(constants.extrakey, b'') |
251 context.basectx.topic = _contexttopic | 251 context.basectx.topic = _contexttopic |
252 | 252 |
253 def _contexttopicidx(self): | 253 def _contexttopicidx(self): |
254 topic = self.topic() | 254 topic = self.topic() |
255 if not topic or self.obsolete(): | 255 if not topic or self.obsolete(): |
273 revs = None | 273 revs = None |
274 if stackrev.match(name): | 274 if stackrev.match(name): |
275 idx = int(name[1:]) | 275 idx = int(name[1:]) |
276 tname = topic = repo.currenttopic | 276 tname = topic = repo.currenttopic |
277 if topic: | 277 if topic: |
278 ttype = 'topic' | 278 ttype = b'topic' |
279 revs = list(stack.stack(repo, topic=topic)) | 279 revs = list(stack.stack(repo, topic=topic)) |
280 else: | 280 else: |
281 ttype = 'branch' | 281 ttype = b'branch' |
282 tname = branch = repo[None].branch() | 282 tname = branch = repo[None].branch() |
283 revs = list(stack.stack(repo, branch=branch)) | 283 revs = list(stack.stack(repo, branch=branch)) |
284 elif topicrev.match(name): | 284 elif topicrev.match(name): |
285 idx = int(name[1:]) | 285 idx = int(name[1:]) |
286 ttype = 'topic' | 286 ttype = b'topic' |
287 tname = topic = repo.currenttopic | 287 tname = topic = repo.currenttopic |
288 if not tname: | 288 if not tname: |
289 raise error.Abort(_('cannot resolve "%s": no active topic') % name) | 289 raise error.Abort(_(b'cannot resolve "%s": no active topic') % name) |
290 revs = list(stack.stack(repo, topic=topic)) | 290 revs = list(stack.stack(repo, topic=topic)) |
291 | 291 |
292 if revs is not None: | 292 if revs is not None: |
293 try: | 293 try: |
294 r = revs[idx] | 294 r = revs[idx] |
295 except IndexError: | 295 except IndexError: |
296 if ttype == 'topic': | 296 if ttype == b'topic': |
297 msg = _('cannot resolve "%s": %s "%s" has only %d changesets') | 297 msg = _(b'cannot resolve "%s": %s "%s" has only %d changesets') |
298 elif ttype == 'branch': | 298 elif ttype == b'branch': |
299 msg = _('cannot resolve "%s": %s "%s" has only %d non-public changesets') | 299 msg = _(b'cannot resolve "%s": %s "%s" has only %d non-public changesets') |
300 raise error.Abort(msg % (name, ttype, tname, len(revs) - 1)) | 300 raise error.Abort(msg % (name, ttype, tname, len(revs) - 1)) |
301 # t0 or s0 can be None | 301 # t0 or s0 can be None |
302 if r == -1 and idx == 0: | 302 if r == -1 and idx == 0: |
303 msg = _('the %s "%s" has no %s') | 303 msg = _(b'the %s "%s" has no %s') |
304 raise error.Abort(msg % (ttype, tname, name)) | 304 raise error.Abort(msg % (ttype, tname, name)) |
305 return [repo[r].node()] | 305 return [repo[r].node()] |
306 if name not in repo.topics: | 306 if name not in repo.topics: |
307 return [] | 307 return [] |
308 node = repo.changelog.node | 308 node = repo.changelog.node |
309 return [node(rev) for rev in repo.revs('topic(%s)', name)] | 309 return [node(rev) for rev in repo.revs(b'topic(%s)', name)] |
310 | 310 |
311 def _nodemap(repo, node): | 311 def _nodemap(repo, node): |
312 ctx = repo[node] | 312 ctx = repo[node] |
313 t = ctx.topic() | 313 t = ctx.topic() |
314 if t and ctx.phase() > phases.public: | 314 if t and ctx.phase() > phases.public: |
319 destination.modsetup(ui) | 319 destination.modsetup(ui) |
320 discovery.modsetup(ui) | 320 discovery.modsetup(ui) |
321 topicmap.modsetup(ui) | 321 topicmap.modsetup(ui) |
322 setupimportexport(ui) | 322 setupimportexport(ui) |
323 | 323 |
324 extensions.afterloaded('rebase', _fixrebase) | 324 extensions.afterloaded(b'rebase', _fixrebase) |
325 | 325 |
326 flow.installpushflag(ui) | 326 flow.installpushflag(ui) |
327 | 327 |
328 entry = extensions.wrapcommand(commands.table, 'commit', commitwrap) | 328 entry = extensions.wrapcommand(commands.table, b'commit', commitwrap) |
329 entry[1].append(('t', 'topic', '', | 329 entry[1].append((b't', b'topic', b'', |
330 _("use specified topic"), _('TOPIC'))) | 330 _(b"use specified topic"), _(b'TOPIC'))) |
331 | 331 |
332 entry = extensions.wrapcommand(commands.table, 'push', pushoutgoingwrap) | 332 entry = extensions.wrapcommand(commands.table, b'push', pushoutgoingwrap) |
333 entry[1].append(('t', 'topic', '', | 333 entry[1].append((b't', b'topic', b'', |
334 _("topic to push"), _('TOPIC'))) | 334 _(b"topic to push"), _(b'TOPIC'))) |
335 | 335 |
336 entry = extensions.wrapcommand(commands.table, 'outgoing', | 336 entry = extensions.wrapcommand(commands.table, b'outgoing', |
337 pushoutgoingwrap) | 337 pushoutgoingwrap) |
338 entry[1].append(('t', 'topic', '', | 338 entry[1].append((b't', b'topic', b'', |
339 _("topic to push"), _('TOPIC'))) | 339 _(b"topic to push"), _(b'TOPIC'))) |
340 | 340 |
341 extensions.wrapfunction(cmdutil, 'buildcommittext', committextwrap) | 341 extensions.wrapfunction(cmdutil, 'buildcommittext', committextwrap) |
342 extensions.wrapfunction(merge, 'update', mergeupdatewrap) | 342 extensions.wrapfunction(merge, 'update', mergeupdatewrap) |
343 # We need to check whether t0 or b0 or s0 is passed to override the default update | 343 # We need to check whether t0 or b0 or s0 is passed to override the default update |
344 # behaviour of changing topic and I can't find a better way | 344 # behaviour of changing topic and I can't find a better way |
345 # to do that as scmutil.revsingle returns the rev number and hence we can't | 345 # to do that as scmutil.revsingle returns the rev number and hence we can't |
346 # plug into logic for this into mergemod.update(). | 346 # plug into logic for this into mergemod.update(). |
347 extensions.wrapcommand(commands.table, 'update', checkt0) | 347 extensions.wrapcommand(commands.table, b'update', checkt0) |
348 | 348 |
349 try: | 349 try: |
350 evolve = extensions.find('evolve') | 350 evolve = extensions.find(b'evolve') |
351 extensions.wrapfunction(evolve.rewriteutil, "presplitupdate", | 351 extensions.wrapfunction(evolve.rewriteutil, "presplitupdate", |
352 presplitupdatetopic) | 352 presplitupdatetopic) |
353 except (KeyError, AttributeError): | 353 except (KeyError, AttributeError): |
354 pass | 354 pass |
355 | 355 |
356 cmdutil.summaryhooks.add('topic', summaryhook) | 356 cmdutil.summaryhooks.add(b'topic', summaryhook) |
357 | 357 |
358 if not post45template: | 358 if not post45template: |
359 templatekw.keywords['topic'] = topickw | 359 templatekw.keywords[b'topic'] = topickw |
360 templatekw.keywords['topicidx'] = topicidxkw | 360 templatekw.keywords[b'topicidx'] = topicidxkw |
361 # Wrap workingctx extra to return the topic name | 361 # Wrap workingctx extra to return the topic name |
362 extensions.wrapfunction(context.workingctx, '__init__', wrapinit) | 362 extensions.wrapfunction(context.workingctx, '__init__', wrapinit) |
363 # Wrap changelog.add to drop empty topic | 363 # Wrap changelog.add to drop empty topic |
364 extensions.wrapfunction(changelog.changelog, 'add', wrapadd) | 364 extensions.wrapfunction(changelog.changelog, 'add', wrapadd) |
365 | 365 |
367 if not isinstance(repo, localrepo.localrepository): | 367 if not isinstance(repo, localrepo.localrepository): |
368 return # this can be a peer in the ssh case (puzzling) | 368 return # this can be a peer in the ssh case (puzzling) |
369 | 369 |
370 repo = repo.unfiltered() | 370 repo = repo.unfiltered() |
371 | 371 |
372 if repo.ui.config('experimental', 'thg.displaynames') is None: | 372 if repo.ui.config(b'experimental', b'thg.displaynames') is None: |
373 repo.ui.setconfig('experimental', 'thg.displaynames', 'topics', | 373 repo.ui.setconfig(b'experimental', b'thg.displaynames', b'topics', |
374 source='topic-extension') | 374 source=b'topic-extension') |
375 | 375 |
376 class topicrepo(repo.__class__): | 376 class topicrepo(repo.__class__): |
377 | 377 |
378 # attribute for other code to distinct between repo with topic and repo without | 378 # attribute for other code to distinct between repo with topic and repo without |
379 hastopicext = True | 379 hastopicext = True |
380 | 380 |
381 def _restrictcapabilities(self, caps): | 381 def _restrictcapabilities(self, caps): |
382 caps = super(topicrepo, self)._restrictcapabilities(caps) | 382 caps = super(topicrepo, self)._restrictcapabilities(caps) |
383 caps.add('topics') | 383 caps.add(b'topics') |
384 return caps | 384 return caps |
385 | 385 |
386 def commit(self, *args, **kwargs): | 386 def commit(self, *args, **kwargs): |
387 backup = self.ui.backupconfig('ui', 'allowemptycommit') | 387 backup = self.ui.backupconfig(b'ui', b'allowemptycommit') |
388 try: | 388 try: |
389 if self.currenttopic != self['.'].topic(): | 389 if self.currenttopic != self[b'.'].topic(): |
390 # bypass the core "nothing changed" logic | 390 # bypass the core "nothing changed" logic |
391 self.ui.setconfig('ui', 'allowemptycommit', True) | 391 self.ui.setconfig(b'ui', b'allowemptycommit', True) |
392 return super(topicrepo, self).commit(*args, **kwargs) | 392 return super(topicrepo, self).commit(*args, **kwargs) |
393 finally: | 393 finally: |
394 self.ui.restoreconfig(backup) | 394 self.ui.restoreconfig(backup) |
395 | 395 |
396 def commitctx(self, ctx, error=None): | 396 def commitctx(self, ctx, error=None): |
402 if isinstance(ctx, context.workingcommitctx): | 402 if isinstance(ctx, context.workingcommitctx): |
403 current = self.currenttopic | 403 current = self.currenttopic |
404 if current: | 404 if current: |
405 ctx.extra()[constants.extrakey] = current | 405 ctx.extra()[constants.extrakey] = current |
406 if (isinstance(ctx, context.memctx) | 406 if (isinstance(ctx, context.memctx) |
407 and ctx.extra().get('amend_source') | 407 and ctx.extra().get(b'amend_source') |
408 and ctx.topic() | 408 and ctx.topic() |
409 and not self.currenttopic): | 409 and not self.currenttopic): |
410 # we are amending and need to remove a topic | 410 # we are amending and need to remove a topic |
411 del ctx.extra()[constants.extrakey] | 411 del ctx.extra()[constants.extrakey] |
412 return super(topicrepo, self).commitctx(ctx, error=error) | 412 return super(topicrepo, self).commitctx(ctx, error=error) |
413 | 413 |
414 @property | 414 @property |
415 def topics(self): | 415 def topics(self): |
416 if self._topics is not None: | 416 if self._topics is not None: |
417 return self._topics | 417 return self._topics |
418 topics = set(['', self.currenttopic]) | 418 topics = set([b'', self.currenttopic]) |
419 for c in self.set('not public()'): | 419 for c in self.set(b'not public()'): |
420 topics.add(c.topic()) | 420 topics.add(c.topic()) |
421 topics.remove('') | 421 topics.remove(b'') |
422 self._topics = topics | 422 self._topics = topics |
423 return topics | 423 return topics |
424 | 424 |
425 @property | 425 @property |
426 def currenttopic(self): | 426 def currenttopic(self): |
427 return self.vfs.tryread('topic') | 427 return self.vfs.tryread(b'topic') |
428 | 428 |
429 # overwritten at the instance level by topicmap.py | 429 # overwritten at the instance level by topicmap.py |
430 _autobranchmaptopic = True | 430 _autobranchmaptopic = True |
431 | 431 |
432 def branchmap(self, topic=None): | 432 def branchmap(self, topic=None): |
439 | 439 |
440 def branchheads(self, branch=None, start=None, closed=False): | 440 def branchheads(self, branch=None, start=None, closed=False): |
441 if branch is None: | 441 if branch is None: |
442 branch = self[None].branch() | 442 branch = self[None].branch() |
443 if self.currenttopic: | 443 if self.currenttopic: |
444 branch = "%s:%s" % (branch, self.currenttopic) | 444 branch = b"%s:%s" % (branch, self.currenttopic) |
445 return super(topicrepo, self).branchheads(branch=branch, | 445 return super(topicrepo, self).branchheads(branch=branch, |
446 start=start, | 446 start=start, |
447 closed=closed) | 447 closed=closed) |
448 | 448 |
449 def invalidatevolatilesets(self): | 449 def invalidatevolatilesets(self): |
462 return peer | 462 return peer |
463 | 463 |
464 def transaction(self, desc, *a, **k): | 464 def transaction(self, desc, *a, **k): |
465 ctr = self.currenttransaction() | 465 ctr = self.currenttransaction() |
466 tr = super(topicrepo, self).transaction(desc, *a, **k) | 466 tr = super(topicrepo, self).transaction(desc, *a, **k) |
467 if desc in ('strip', 'repair') or ctr is not None: | 467 if desc in (b'strip', b'repair') or ctr is not None: |
468 return tr | 468 return tr |
469 | 469 |
470 reporef = weakref.ref(self) | 470 reporef = weakref.ref(self) |
471 if self.ui.configbool('experimental', 'enforce-single-head'): | 471 if self.ui.configbool(b'experimental', b'enforce-single-head'): |
472 if util.safehasattr(tr, 'validator'): # hg <= 4.7 | 472 if util.safehasattr(tr, 'validator'): # hg <= 4.7 |
473 origvalidator = tr.validator | 473 origvalidator = tr.validator |
474 else: | 474 else: |
475 origvalidator = tr._validator | 475 origvalidator = tr._validator |
476 | 476 |
482 if util.safehasattr(tr, 'validator'): # hg <= 4.7 | 482 if util.safehasattr(tr, 'validator'): # hg <= 4.7 |
483 tr.validator = validator | 483 tr.validator = validator |
484 else: | 484 else: |
485 tr._validator = validator | 485 tr._validator = validator |
486 | 486 |
487 topicmodeserver = self.ui.config('experimental', | 487 topicmodeserver = self.ui.config(b'experimental', |
488 'topic-mode.server', 'ignore') | 488 b'topic-mode.server', b'ignore') |
489 ispush = (desc.startswith('push') or desc.startswith('serve')) | 489 ispush = (desc.startswith(b'push') or desc.startswith(b'serve')) |
490 if (topicmodeserver != 'ignore' and ispush): | 490 if (topicmodeserver != b'ignore' and ispush): |
491 if util.safehasattr(tr, 'validator'): # hg <= 4.7 | 491 if util.safehasattr(tr, 'validator'): # hg <= 4.7 |
492 origvalidator = tr.validator | 492 origvalidator = tr.validator |
493 else: | 493 else: |
494 origvalidator = tr._validator | 494 origvalidator = tr._validator |
495 | 495 |
500 if util.safehasattr(tr, 'validator'): # hg <= 4.7 | 500 if util.safehasattr(tr, 'validator'): # hg <= 4.7 |
501 tr.validator = validator | 501 tr.validator = validator |
502 else: | 502 else: |
503 tr._validator = validator | 503 tr._validator = validator |
504 | 504 |
505 elif (self.ui.configbool('experimental', 'topic.publish-bare-branch') | 505 elif (self.ui.configbool(b'experimental', b'topic.publish-bare-branch') |
506 and (desc.startswith('push') | 506 and (desc.startswith(b'push') |
507 or desc.startswith('serve')) | 507 or desc.startswith(b'serve')) |
508 ): | 508 ): |
509 origclose = tr.close | 509 origclose = tr.close |
510 trref = weakref.ref(tr) | 510 trref = weakref.ref(tr) |
511 | 511 |
512 def close(): | 512 def close(): |
513 repo = reporef() | 513 repo = reporef() |
514 tr2 = trref() | 514 tr2 = trref() |
515 flow.publishbarebranch(repo, tr2) | 515 flow.publishbarebranch(repo, tr2) |
516 origclose() | 516 origclose() |
517 tr.close = close | 517 tr.close = close |
518 allow_publish = self.ui.configbool('experimental', | 518 allow_publish = self.ui.configbool(b'experimental', |
519 'topic.allow-publish', | 519 b'topic.allow-publish', |
520 True) | 520 True) |
521 if not allow_publish: | 521 if not allow_publish: |
522 if util.safehasattr(tr, 'validator'): # hg <= 4.7 | 522 if util.safehasattr(tr, 'validator'): # hg <= 4.7 |
523 origvalidator = tr.validator | 523 origvalidator = tr.validator |
524 else: | 524 else: |
545 # check active topic emptiness | 545 # check active topic emptiness |
546 repo = reporef() | 546 repo = reporef() |
547 csetcount = stack.stack(repo, topic=ct).changesetcount | 547 csetcount = stack.stack(repo, topic=ct).changesetcount |
548 empty = csetcount == 0 | 548 empty = csetcount == 0 |
549 if empty and not ctwasempty: | 549 if empty and not ctwasempty: |
550 ui.status("active topic '%s' is now empty\n" % ct) | 550 ui.status(b"active topic '%s' is now empty\n" % ct) |
551 trnames = getattr(tr, 'names', getattr(tr, '_names', ())) | 551 trnames = getattr(tr, 'names', getattr(tr, '_names', ())) |
552 if ('phase' in trnames | 552 if (b'phase' in trnames |
553 or any(n.startswith('push-response') | 553 or any(n.startswith(b'push-response') |
554 for n in trnames)): | 554 for n in trnames)): |
555 ui.status(_("(use 'hg topic --clear' to clear it if needed)\n")) | 555 ui.status(_(b"(use 'hg topic --clear' to clear it if needed)\n")) |
556 hint = _("(see 'hg help topics' for more information)\n") | 556 hint = _(b"(see 'hg help topics' for more information)\n") |
557 if ctwasempty and not empty: | 557 if ctwasempty and not empty: |
558 if csetcount == 1: | 558 if csetcount == 1: |
559 msg = _("active topic '%s' grew its first changeset\n%s") | 559 msg = _(b"active topic '%s' grew its first changeset\n%s") |
560 ui.status(msg % (ct, hint)) | 560 ui.status(msg % (ct, hint)) |
561 else: | 561 else: |
562 msg = _("active topic '%s' grew its %s first changesets\n%s") | 562 msg = _(b"active topic '%s' grew its %s first changesets\n%s") |
563 ui.status(msg % (ct, csetcount, hint)) | 563 ui.status(msg % (ct, csetcount, hint)) |
564 | 564 |
565 tr.addpostclose('signalcurrenttopicempty', currenttopicempty) | 565 tr.addpostclose(b'signalcurrenttopicempty', currenttopicempty) |
566 return tr | 566 return tr |
567 | 567 |
568 repo.__class__ = topicrepo | 568 repo.__class__ = topicrepo |
569 repo._topics = None | 569 repo._topics = None |
570 if util.safehasattr(repo, 'names'): | 570 if util.safehasattr(repo, 'names'): |
571 repo.names.addnamespace(namespaces.namespace( | 571 repo.names.addnamespace(namespaces.namespace( |
572 'topics', 'topic', namemap=_namemap, nodemap=_nodemap, | 572 b'topics', b'topic', namemap=_namemap, nodemap=_nodemap, |
573 listnames=lambda repo: repo.topics)) | 573 listnames=lambda repo: repo.topics)) |
574 | 574 |
575 if post45template: | 575 if post45template: |
576 @templatekeyword(b'topic', requires={b'ctx'}) | 576 @templatekeyword(b'topic', requires={b'ctx'}) |
577 def topickw(context, mapping): | 577 def topickw(context, mapping): |
578 """:topic: String. The topic of the changeset""" | 578 """:topic: String. The topic of the changeset""" |
579 ctx = context.resource(mapping, 'ctx') | 579 ctx = context.resource(mapping, b'ctx') |
580 return ctx.topic() | 580 return ctx.topic() |
581 | 581 |
582 @templatekeyword(b'topicidx', requires={b'ctx'}) | 582 @templatekeyword(b'topicidx', requires={b'ctx'}) |
583 def topicidxkw(context, mapping): | 583 def topicidxkw(context, mapping): |
584 """:topicidx: Integer. Index of the changeset as a stack alias""" | 584 """:topicidx: Integer. Index of the changeset as a stack alias""" |
585 ctx = context.resource(mapping, 'ctx') | 585 ctx = context.resource(mapping, b'ctx') |
586 return ctx.topicidx() | 586 return ctx.topicidx() |
587 else: | 587 else: |
588 def topickw(**args): | 588 def topickw(**args): |
589 """:topic: String. The topic of the changeset""" | 589 """:topic: String. The topic of the changeset""" |
590 return args['ctx'].topic() | 590 return args[b'ctx'].topic() |
591 | 591 |
592 def topicidxkw(**args): | 592 def topicidxkw(**args): |
593 """:topicidx: Integer. Index of the changeset as a stack alias""" | 593 """:topicidx: Integer. Index of the changeset as a stack alias""" |
594 return args['ctx'].topicidx() | 594 return args[b'ctx'].topicidx() |
595 | 595 |
596 def wrapinit(orig, self, repo, *args, **kwargs): | 596 def wrapinit(orig, self, repo, *args, **kwargs): |
597 orig(self, repo, *args, **kwargs) | 597 orig(self, repo, *args, **kwargs) |
598 if not hastopicext(repo): | 598 if not hastopicext(repo): |
599 return | 599 return |
600 if constants.extrakey not in self._extra: | 600 if constants.extrakey not in self._extra: |
601 if getattr(repo, 'currenttopic', ''): | 601 if getattr(repo, 'currenttopic', b''): |
602 self._extra[constants.extrakey] = repo.currenttopic | 602 self._extra[constants.extrakey] = repo.currenttopic |
603 else: | 603 else: |
604 # Empty key will be dropped from extra by another hack at the changegroup level | 604 # Empty key will be dropped from extra by another hack at the changegroup level |
605 self._extra[constants.extrakey] = '' | 605 self._extra[constants.extrakey] = b'' |
606 | 606 |
607 def wrapadd(orig, cl, manifest, files, desc, transaction, p1, p2, user, | 607 def wrapadd(orig, cl, manifest, files, desc, transaction, p1, p2, user, |
608 date=None, extra=None, p1copies=None, p2copies=None, | 608 date=None, extra=None, p1copies=None, p2copies=None, |
609 filesadded=None, filesremoved=None): | 609 filesadded=None, filesremoved=None): |
610 if constants.extrakey in extra and not extra[constants.extrakey]: | 610 if constants.extrakey in extra and not extra[constants.extrakey]: |
677 rev = opts.get('rev') | 677 rev = opts.get('rev') |
678 current = opts.get('current') | 678 current = opts.get('current') |
679 age = opts.get('age') | 679 age = opts.get('age') |
680 | 680 |
681 if current and topic: | 681 if current and topic: |
682 raise error.Abort(_("cannot use --current when setting a topic")) | 682 raise error.Abort(_(b"cannot use --current when setting a topic")) |
683 if current and clear: | 683 if current and clear: |
684 raise error.Abort(_("cannot use --current and --clear")) | 684 raise error.Abort(_(b"cannot use --current and --clear")) |
685 if clear and topic: | 685 if clear and topic: |
686 raise error.Abort(_("cannot use --clear when setting a topic")) | 686 raise error.Abort(_(b"cannot use --clear when setting a topic")) |
687 if age and topic: | 687 if age and topic: |
688 raise error.Abort(_("cannot use --age while setting a topic")) | 688 raise error.Abort(_(b"cannot use --age while setting a topic")) |
689 | 689 |
690 touchedrevs = set() | 690 touchedrevs = set() |
691 if rev: | 691 if rev: |
692 touchedrevs = scmutil.revrange(repo, rev) | 692 touchedrevs = scmutil.revrange(repo, rev) |
693 | 693 |
694 if topic: | 694 if topic: |
695 topic = topic.strip() | 695 topic = topic.strip() |
696 if not topic: | 696 if not topic: |
697 raise error.Abort(_("topic name cannot consist entirely of whitespaces")) | 697 raise error.Abort(_(b"topic name cannot consist entirely of whitespaces")) |
698 # Have some restrictions on the topic name just like bookmark name | 698 # Have some restrictions on the topic name just like bookmark name |
699 scmutil.checknewlabel(repo, topic, 'topic') | 699 scmutil.checknewlabel(repo, topic, b'topic') |
700 | 700 |
701 rmatch = re.match(br'[-_.\w]+', topic) | 701 rmatch = re.match(br'[-_.\w]+', topic) |
702 if not rmatch or rmatch.group(0) != topic: | 702 if not rmatch or rmatch.group(0) != topic: |
703 helptxt = _("topic names can only consist of alphanumeric, '-'" | 703 helptxt = _(b"topic names can only consist of alphanumeric, '-'" |
704 " '_' and '.' characters") | 704 b" '_' and '.' characters") |
705 raise error.Abort(_("invalid topic name: '%s'") % topic, hint=helptxt) | 705 raise error.Abort(_(b"invalid topic name: '%s'") % topic, hint=helptxt) |
706 | 706 |
707 if list: | 707 if list: |
708 ui.pager('topics') | 708 ui.pager(b'topics') |
709 if clear or rev: | 709 if clear or rev: |
710 raise error.Abort(_("cannot use --clear or --rev with --list")) | 710 raise error.Abort(_(b"cannot use --clear or --rev with --list")) |
711 if not topic: | 711 if not topic: |
712 topic = repo.currenttopic | 712 topic = repo.currenttopic |
713 if not topic: | 713 if not topic: |
714 raise error.Abort(_('no active topic to list')) | 714 raise error.Abort(_(b'no active topic to list')) |
715 return stack.showstack(ui, repo, topic=topic, | 715 return stack.showstack(ui, repo, topic=topic, |
716 opts=pycompat.byteskwargs(opts)) | 716 opts=pycompat.byteskwargs(opts)) |
717 | 717 |
718 if touchedrevs: | 718 if touchedrevs: |
719 if not obsolete.isenabled(repo, obsolete.createmarkersopt): | 719 if not obsolete.isenabled(repo, obsolete.createmarkersopt): |
720 raise error.Abort(_('must have obsolete enabled to change topics')) | 720 raise error.Abort(_(b'must have obsolete enabled to change topics')) |
721 if clear: | 721 if clear: |
722 topic = None | 722 topic = None |
723 elif opts.get('current'): | 723 elif opts.get('current'): |
724 topic = repo.currenttopic | 724 topic = repo.currenttopic |
725 elif not topic: | 725 elif not topic: |
726 raise error.Abort('changing topic requires a topic name or --clear') | 726 raise error.Abort(b'changing topic requires a topic name or --clear') |
727 if repo.revs('%ld and public()', touchedrevs): | 727 if repo.revs(b'%ld and public()', touchedrevs): |
728 raise error.Abort("can't change topic of a public change") | 728 raise error.Abort(b"can't change topic of a public change") |
729 wl = lock = txn = None | 729 wl = lock = txn = None |
730 try: | 730 try: |
731 wl = repo.wlock() | 731 wl = repo.wlock() |
732 lock = repo.lock() | 732 lock = repo.lock() |
733 txn = repo.transaction('rewrite-topics') | 733 txn = repo.transaction(b'rewrite-topics') |
734 rewrote = _changetopics(ui, repo, touchedrevs, topic) | 734 rewrote = _changetopics(ui, repo, touchedrevs, topic) |
735 txn.close() | 735 txn.close() |
736 if topic is None: | 736 if topic is None: |
737 ui.status('cleared topic on %d changesets\n' % rewrote) | 737 ui.status(b'cleared topic on %d changesets\n' % rewrote) |
738 else: | 738 else: |
739 ui.status('changed topic on %d changesets to "%s"\n' % (rewrote, | 739 ui.status(b'changed topic on %d changesets to "%s"\n' % (rewrote, |
740 topic)) | 740 topic)) |
741 finally: | 741 finally: |
742 lockmod.release(txn, lock, wl) | 742 lockmod.release(txn, lock, wl) |
743 repo.invalidate() | 743 repo.invalidate() |
744 return | 744 return |
745 | 745 |
746 ct = repo.currenttopic | 746 ct = repo.currenttopic |
747 if clear: | 747 if clear: |
748 if ct: | 748 if ct: |
749 st = stack.stack(repo, topic=ct) | 749 st = stack.stack(repo, topic=ct) |
750 if not st: | 750 if not st: |
751 ui.status(_('clearing empty topic "%s"\n') % ct) | 751 ui.status(_(b'clearing empty topic "%s"\n') % ct) |
752 return _changecurrenttopic(repo, None) | 752 return _changecurrenttopic(repo, None) |
753 | 753 |
754 if topic: | 754 if topic: |
755 if not ct: | 755 if not ct: |
756 ui.status(_('marked working directory as topic: %s\n') % topic) | 756 ui.status(_(b'marked working directory as topic: %s\n') % topic) |
757 return _changecurrenttopic(repo, topic) | 757 return _changecurrenttopic(repo, topic) |
758 | 758 |
759 ui.pager('topics') | 759 ui.pager(b'topics') |
760 # `hg topic --current` | 760 # `hg topic --current` |
761 ret = 0 | 761 ret = 0 |
762 if current and not ct: | 762 if current and not ct: |
763 ui.write_err(_('no active topic\n')) | 763 ui.write_err(_(b'no active topic\n')) |
764 ret = 1 | 764 ret = 1 |
765 elif current: | 765 elif current: |
766 fm = ui.formatter('topic', pycompat.byteskwargs(opts)) | 766 fm = ui.formatter(b'topic', pycompat.byteskwargs(opts)) |
767 namemask = '%s\n' | 767 namemask = b'%s\n' |
768 label = 'topic.active' | 768 label = b'topic.active' |
769 fm.startitem() | 769 fm.startitem() |
770 fm.write('topic', namemask, ct, label=label) | 770 fm.write(b'topic', namemask, ct, label=label) |
771 fm.end() | 771 fm.end() |
772 else: | 772 else: |
773 _listtopics(ui, repo, opts) | 773 _listtopics(ui, repo, opts) |
774 return ret | 774 return ret |
775 | 775 |
776 @command('stack', [ | 776 @command(b'stack', [ |
777 ('c', 'children', None, | 777 (b'c', b'children', None, |
778 _('display data about children outside of the stack')) | 778 _(b'display data about children outside of the stack')) |
779 ] + commands.formatteropts, | 779 ] + commands.formatteropts, |
780 _('hg stack [TOPIC]')) | 780 _(b'hg stack [TOPIC]')) |
781 def cmdstack(ui, repo, topic='', **opts): | 781 def cmdstack(ui, repo, topic=b'', **opts): |
782 """list all changesets in a topic and other information | 782 """list all changesets in a topic and other information |
783 | 783 |
784 List the current topic by default. | 784 List the current topic by default. |
785 | 785 |
786 The --verbose version shows short nodes for the commits also. | 786 The --verbose version shows short nodes for the commits also. |
790 branch = None | 790 branch = None |
791 if topic is None and repo.currenttopic: | 791 if topic is None and repo.currenttopic: |
792 topic = repo.currenttopic | 792 topic = repo.currenttopic |
793 if topic is None: | 793 if topic is None: |
794 branch = repo[None].branch() | 794 branch = repo[None].branch() |
795 ui.pager('stack') | 795 ui.pager(b'stack') |
796 return stack.showstack(ui, repo, branch=branch, topic=topic, | 796 return stack.showstack(ui, repo, branch=branch, topic=topic, |
797 opts=pycompat.byteskwargs(opts)) | 797 opts=pycompat.byteskwargs(opts)) |
798 | 798 |
799 @command('debugcb|debugconvertbookmark', [ | 799 @command(b'debugcb|debugconvertbookmark', [ |
800 ('b', 'bookmark', '', _('bookmark to convert to topic')), | 800 (b'b', b'bookmark', b'', _(b'bookmark to convert to topic')), |
801 ('', 'all', None, _('convert all bookmarks to topics')), | 801 (b'', b'all', None, _(b'convert all bookmarks to topics')), |
802 ], | 802 ], |
803 _('[-b BOOKMARK] [--all]')) | 803 _(b'[-b BOOKMARK] [--all]')) |
804 def debugconvertbookmark(ui, repo, **opts): | 804 def debugconvertbookmark(ui, repo, **opts): |
805 """Converts a bookmark to a topic with the same name. | 805 """Converts a bookmark to a topic with the same name. |
806 """ | 806 """ |
807 | 807 |
808 bookmark = opts.get('bookmark') | 808 bookmark = opts.get('bookmark') |
809 convertall = opts.get('all') | 809 convertall = opts.get('all') |
810 | 810 |
811 if convertall and bookmark: | 811 if convertall and bookmark: |
812 raise error.Abort(_("cannot use '--all' and '-b' together")) | 812 raise error.Abort(_(b"cannot use '--all' and '-b' together")) |
813 if not (convertall or bookmark): | 813 if not (convertall or bookmark): |
814 raise error.Abort(_("you must specify either '--all' or '-b'")) | 814 raise error.Abort(_(b"you must specify either '--all' or '-b'")) |
815 | 815 |
816 bmstore = repo._bookmarks | 816 bmstore = repo._bookmarks |
817 | 817 |
818 nodetobook = {} | 818 nodetobook = {} |
819 for book, revnode in bmstore.items(): | 819 for book, revnode in bmstore.items(): |
834 lock = repo.lock() | 834 lock = repo.lock() |
835 if bookmark: | 835 if bookmark: |
836 try: | 836 try: |
837 node = bmstore[bookmark] | 837 node = bmstore[bookmark] |
838 except KeyError: | 838 except KeyError: |
839 raise error.Abort(_("no such bookmark exists: '%s'") % bookmark) | 839 raise error.Abort(_(b"no such bookmark exists: '%s'") % bookmark) |
840 | 840 |
841 revnum = repo[node].rev() | 841 revnum = repo[node].rev() |
842 if len(nodetobook[node]) > 1: | 842 if len(nodetobook[node]) > 1: |
843 ui.status(_("skipping revision '%d' as it has multiple bookmarks " | 843 ui.status(_(b"skipping revision '%d' as it has multiple bookmarks " |
844 "on it\n") % revnum) | 844 b"on it\n") % revnum) |
845 return | 845 return |
846 targetrevs = _findconvertbmarktopic(repo, bookmark) | 846 targetrevs = _findconvertbmarktopic(repo, bookmark) |
847 if targetrevs: | 847 if targetrevs: |
848 actions[(bookmark, revnum)] = targetrevs | 848 actions[(bookmark, revnum)] = targetrevs |
849 | 849 |
851 for bmark, revnode in sorted(bmstore.items()): | 851 for bmark, revnode in sorted(bmstore.items()): |
852 revnum = repo[revnode].rev() | 852 revnum = repo[revnode].rev() |
853 if revnum in skipped: | 853 if revnum in skipped: |
854 continue | 854 continue |
855 if len(nodetobook[revnode]) > 1: | 855 if len(nodetobook[revnode]) > 1: |
856 ui.status(_("skipping '%d' as it has multiple bookmarks on" | 856 ui.status(_(b"skipping '%d' as it has multiple bookmarks on" |
857 " it\n") % revnum) | 857 b" it\n") % revnum) |
858 skipped.append(revnum) | 858 skipped.append(revnum) |
859 continue | 859 continue |
860 if bmark == '@': | 860 if bmark == b'@': |
861 continue | 861 continue |
862 targetrevs = _findconvertbmarktopic(repo, bmark) | 862 targetrevs = _findconvertbmarktopic(repo, bmark) |
863 if targetrevs: | 863 if targetrevs: |
864 actions[(bmark, revnum)] = targetrevs | 864 actions[(bmark, revnum)] = targetrevs |
865 | 865 |
866 if actions: | 866 if actions: |
867 try: | 867 try: |
868 tr = repo.transaction('debugconvertbookmark') | 868 tr = repo.transaction(b'debugconvertbookmark') |
869 for ((bmark, revnum), targetrevs) in sorted(actions.items()): | 869 for ((bmark, revnum), targetrevs) in sorted(actions.items()): |
870 _applyconvertbmarktopic(ui, repo, targetrevs, revnum, bmark, tr) | 870 _applyconvertbmarktopic(ui, repo, targetrevs, revnum, bmark, tr) |
871 tr.close() | 871 tr.close() |
872 finally: | 872 finally: |
873 tr.release() | 873 tr.release() |
874 finally: | 874 finally: |
875 lockmod.release(lock, wlock) | 875 lockmod.release(lock, wlock) |
876 | 876 |
877 # inspired from mercurial.repair.stripbmrevset | 877 # inspired from mercurial.repair.stripbmrevset |
878 CONVERTBOOKREVSET = """ | 878 CONVERTBOOKREVSET = b""" |
879 not public() and ( | 879 not public() and ( |
880 ancestors(bookmark(%s)) | 880 ancestors(bookmark(%s)) |
881 and not ancestors( | 881 and not ancestors( |
882 ( | 882 ( |
883 (head() and not bookmark(%s)) | 883 (head() and not bookmark(%s)) |
911 # returned an empty set of revisions, so let's skip deleting the | 911 # returned an empty set of revisions, so let's skip deleting the |
912 # bookmark corresponding to which we didn't put a topic on any | 912 # bookmark corresponding to which we didn't put a topic on any |
913 # changeset | 913 # changeset |
914 if rewrote == 0: | 914 if rewrote == 0: |
915 return | 915 return |
916 ui.status(_('changed topic to "%s" on %d revisions\n') % (bmark, | 916 ui.status(_(b'changed topic to "%s" on %d revisions\n') % (bmark, |
917 rewrote)) | 917 rewrote)) |
918 ui.debug('removing bookmark "%s" from "%d"' % (bmark, old)) | 918 ui.debug(b'removing bookmark "%s" from "%d"' % (bmark, old)) |
919 bookmarks.delete(repo, tr, [bmark]) | 919 bookmarks.delete(repo, tr, [bmark]) |
920 | 920 |
921 def _changecurrenttopic(repo, newtopic): | 921 def _changecurrenttopic(repo, newtopic): |
922 """changes the current topic.""" | 922 """changes the current topic.""" |
923 | 923 |
924 if newtopic: | 924 if newtopic: |
925 with repo.wlock(): | 925 with repo.wlock(): |
926 with repo.vfs.open(b'topic', b'w') as f: | 926 with repo.vfs.open(b'topic', b'w') as f: |
927 f.write(newtopic) | 927 f.write(newtopic) |
928 else: | 928 else: |
929 if repo.vfs.exists('topic'): | 929 if repo.vfs.exists(b'topic'): |
930 repo.vfs.unlink('topic') | 930 repo.vfs.unlink(b'topic') |
931 | 931 |
932 def _changetopics(ui, repo, revs, newtopic): | 932 def _changetopics(ui, repo, revs, newtopic): |
933 """ Changes topic to newtopic of all the revisions in the revset and return | 933 """ Changes topic to newtopic of all the revisions in the revset and return |
934 the count of revisions whose topic has been changed. | 934 the count of revisions whose topic has been changed. |
935 """ | 935 """ |
944 try: | 944 try: |
945 return c[path] | 945 return c[path] |
946 except error.ManifestLookupError: | 946 except error.ManifestLookupError: |
947 return None | 947 return None |
948 fixedextra = dict(c.extra()) | 948 fixedextra = dict(c.extra()) |
949 ui.debug('old node id is %s\n' % node.hex(c.node())) | 949 ui.debug(b'old node id is %s\n' % node.hex(c.node())) |
950 ui.debug('origextra: %r\n' % fixedextra) | 950 ui.debug(b'origextra: %r\n' % fixedextra) |
951 oldtopic = fixedextra.get(constants.extrakey, None) | 951 oldtopic = fixedextra.get(constants.extrakey, None) |
952 if oldtopic == newtopic: | 952 if oldtopic == newtopic: |
953 continue | 953 continue |
954 if newtopic is None: | 954 if newtopic is None: |
955 del fixedextra[constants.extrakey] | 955 del fixedextra[constants.extrakey] |
956 else: | 956 else: |
957 fixedextra[constants.extrakey] = newtopic | 957 fixedextra[constants.extrakey] = newtopic |
958 fixedextra[constants.changekey] = c.hex() | 958 fixedextra[constants.changekey] = c.hex() |
959 if 'amend_source' in fixedextra: | 959 if b'amend_source' in fixedextra: |
960 # TODO: right now the commitctx wrapper in | 960 # TODO: right now the commitctx wrapper in |
961 # topicrepo overwrites the topic in extra if | 961 # topicrepo overwrites the topic in extra if |
962 # amend_source is set to support 'hg commit | 962 # amend_source is set to support 'hg commit |
963 # --amend'. Support for amend should be adjusted | 963 # --amend'. Support for amend should be adjusted |
964 # to not be so invasive. | 964 # to not be so invasive. |
965 del fixedextra['amend_source'] | 965 del fixedextra[b'amend_source'] |
966 ui.debug('changing topic of %s from %s to %s\n' % ( | 966 ui.debug(b'changing topic of %s from %s to %s\n' % ( |
967 c, oldtopic or '<none>', newtopic or '<none>')) | 967 c, oldtopic or b'<none>', newtopic or b'<none>')) |
968 ui.debug('fixedextra: %r\n' % fixedextra) | 968 ui.debug(b'fixedextra: %r\n' % fixedextra) |
969 # While changing topic of set of linear commits, make sure that | 969 # While changing topic of set of linear commits, make sure that |
970 # we base our commits on new parent rather than old parent which | 970 # we base our commits on new parent rather than old parent which |
971 # was obsoleted while changing the topic | 971 # was obsoleted while changing the topic |
972 p1 = c.p1().node() | 972 p1 = c.p1().node() |
973 p2 = c.p2().node() | 973 p2 = c.p2().node() |
984 date=c.date(), | 984 date=c.date(), |
985 extra=fixedextra) | 985 extra=fixedextra) |
986 | 986 |
987 # phase handling | 987 # phase handling |
988 commitphase = c.phase() | 988 commitphase = c.phase() |
989 overrides = {('phases', 'new-commit'): commitphase} | 989 overrides = {(b'phases', b'new-commit'): commitphase} |
990 with repo.ui.configoverride(overrides, 'changetopic'): | 990 with repo.ui.configoverride(overrides, b'changetopic'): |
991 newnode = repo.commitctx(mc) | 991 newnode = repo.commitctx(mc) |
992 | 992 |
993 successors[c.node()] = (newnode,) | 993 successors[c.node()] = (newnode,) |
994 ui.debug('new node id is %s\n' % node.hex(newnode)) | 994 ui.debug(b'new node id is %s\n' % node.hex(newnode)) |
995 rewrote += 1 | 995 rewrote += 1 |
996 | 996 |
997 # create obsmarkers and move bookmarks | 997 # create obsmarkers and move bookmarks |
998 # XXX we should be creating marker as we go instead of only at the end, | 998 # XXX we should be creating marker as we go instead of only at the end, |
999 # this makes the operations more modulars | 999 # this makes the operations more modulars |
1000 scmutil.cleanupnodes(repo, successors, 'changetopics') | 1000 scmutil.cleanupnodes(repo, successors, b'changetopics') |
1001 | 1001 |
1002 # move the working copy too | 1002 # move the working copy too |
1003 wctx = repo[None] | 1003 wctx = repo[None] |
1004 # in-progress merge is a bit too complex for now. | 1004 # in-progress merge is a bit too complex for now. |
1005 if len(wctx.parents()) == 1: | 1005 if len(wctx.parents()) == 1: |
1007 if newid is not None: | 1007 if newid is not None: |
1008 hg.update(repo, newid[0], quietempty=True) | 1008 hg.update(repo, newid[0], quietempty=True) |
1009 return rewrote | 1009 return rewrote |
1010 | 1010 |
1011 def _listtopics(ui, repo, opts): | 1011 def _listtopics(ui, repo, opts): |
1012 fm = ui.formatter('topics', pycompat.byteskwargs(opts)) | 1012 fm = ui.formatter(b'topics', pycompat.byteskwargs(opts)) |
1013 activetopic = repo.currenttopic | 1013 activetopic = repo.currenttopic |
1014 namemask = '%s' | 1014 namemask = b'%s' |
1015 if repo.topics: | 1015 if repo.topics: |
1016 maxwidth = max(len(t) for t in repo.topics) | 1016 maxwidth = max(len(t) for t in repo.topics) |
1017 namemask = '%%-%is' % maxwidth | 1017 namemask = b'%%-%is' % maxwidth |
1018 if opts.get('age'): | 1018 if opts.get('age'): |
1019 # here we sort by age and topic name | 1019 # here we sort by age and topic name |
1020 topicsdata = sorted(_getlasttouched(repo, repo.topics)) | 1020 topicsdata = sorted(_getlasttouched(repo, repo.topics)) |
1021 else: | 1021 else: |
1022 # here we sort by topic name only | 1022 # here we sort by topic name only |
1024 (None, topic, None, None) | 1024 (None, topic, None, None) |
1025 for topic in sorted(repo.topics) | 1025 for topic in sorted(repo.topics) |
1026 ) | 1026 ) |
1027 for age, topic, date, user in topicsdata: | 1027 for age, topic, date, user in topicsdata: |
1028 fm.startitem() | 1028 fm.startitem() |
1029 marker = ' ' | 1029 marker = b' ' |
1030 label = 'topic' | 1030 label = b'topic' |
1031 active = (topic == activetopic) | 1031 active = (topic == activetopic) |
1032 if active: | 1032 if active: |
1033 marker = '*' | 1033 marker = b'*' |
1034 label = 'topic.active' | 1034 label = b'topic.active' |
1035 if not ui.quiet: | 1035 if not ui.quiet: |
1036 # registering the active data is made explicitly later | 1036 # registering the active data is made explicitly later |
1037 fm.plain(' %s ' % marker, label=label) | 1037 fm.plain(b' %s ' % marker, label=label) |
1038 fm.write('topic', namemask, topic, label=label) | 1038 fm.write(b'topic', namemask, topic, label=label) |
1039 fm.data(active=active) | 1039 fm.data(active=active) |
1040 | 1040 |
1041 if ui.quiet: | 1041 if ui.quiet: |
1042 fm.plain('\n') | 1042 fm.plain(b'\n') |
1043 continue | 1043 continue |
1044 fm.plain(' (') | 1044 fm.plain(b' (') |
1045 if date: | 1045 if date: |
1046 if age == -1: | 1046 if age == -1: |
1047 timestr = 'empty and active' | 1047 timestr = b'empty and active' |
1048 else: | 1048 else: |
1049 timestr = templatefilters.age(date) | 1049 timestr = templatefilters.age(date) |
1050 fm.write('lasttouched', '%s', timestr, label='topic.list.time') | 1050 fm.write(b'lasttouched', b'%s', timestr, label=b'topic.list.time') |
1051 if user: | 1051 if user: |
1052 fm.write('usertouched', ' by %s', user, label='topic.list.user') | 1052 fm.write(b'usertouched', b' by %s', user, label=b'topic.list.user') |
1053 if date: | 1053 if date: |
1054 fm.plain(', ') | 1054 fm.plain(b', ') |
1055 data = stack.stack(repo, topic=topic) | 1055 data = stack.stack(repo, topic=topic) |
1056 if ui.verbose: | 1056 if ui.verbose: |
1057 fm.write('branches+', 'on branch: %s', | 1057 fm.write(b'branches+', b'on branch: %s', |
1058 '+'.join(data.branches), # XXX use list directly after 4.0 is released | 1058 b'+'.join(data.branches), # XXX use list directly after 4.0 is released |
1059 label='topic.list.branches') | 1059 label=b'topic.list.branches') |
1060 | 1060 |
1061 fm.plain(', ') | 1061 fm.plain(b', ') |
1062 fm.write('changesetcount', '%d changesets', data.changesetcount, | 1062 fm.write(b'changesetcount', b'%d changesets', data.changesetcount, |
1063 label='topic.list.changesetcount') | 1063 label=b'topic.list.changesetcount') |
1064 | 1064 |
1065 if data.unstablecount: | 1065 if data.unstablecount: |
1066 fm.plain(', ') | 1066 fm.plain(b', ') |
1067 fm.write('unstablecount', '%d unstable', | 1067 fm.write(b'unstablecount', b'%d unstable', |
1068 data.unstablecount, | 1068 data.unstablecount, |
1069 label='topic.list.unstablecount') | 1069 label=b'topic.list.unstablecount') |
1070 | 1070 |
1071 headcount = len(data.heads) | 1071 headcount = len(data.heads) |
1072 if 1 < headcount: | 1072 if 1 < headcount: |
1073 fm.plain(', ') | 1073 fm.plain(b', ') |
1074 fm.write('headcount', '%d heads', | 1074 fm.write(b'headcount', b'%d heads', |
1075 headcount, | 1075 headcount, |
1076 label='topic.list.headcount.multiple') | 1076 label=b'topic.list.headcount.multiple') |
1077 | 1077 |
1078 if ui.verbose: | 1078 if ui.verbose: |
1079 # XXX we should include the data even when not verbose | 1079 # XXX we should include the data even when not verbose |
1080 | 1080 |
1081 behindcount = data.behindcount | 1081 behindcount = data.behindcount |
1082 if 0 < behindcount: | 1082 if 0 < behindcount: |
1083 fm.plain(', ') | 1083 fm.plain(b', ') |
1084 fm.write('behindcount', '%d behind', | 1084 fm.write(b'behindcount', b'%d behind', |
1085 behindcount, | 1085 behindcount, |
1086 label='topic.list.behindcount') | 1086 label=b'topic.list.behindcount') |
1087 elif -1 == behindcount: | 1087 elif -1 == behindcount: |
1088 fm.plain(', ') | 1088 fm.plain(b', ') |
1089 fm.write('behinderror', '%s', | 1089 fm.write(b'behinderror', b'%s', |
1090 _('ambiguous destination: %s') % data.behinderror, | 1090 _(b'ambiguous destination: %s') % data.behinderror, |
1091 label='topic.list.behinderror') | 1091 label=b'topic.list.behinderror') |
1092 fm.plain(')\n') | 1092 fm.plain(b')\n') |
1093 fm.end() | 1093 fm.end() |
1094 | 1094 |
1095 def _getlasttouched(repo, topics): | 1095 def _getlasttouched(repo, topics): |
1096 """ | 1096 """ |
1097 Calculates the last time a topic was used. Returns a generator of 4-tuples: | 1097 Calculates the last time a topic was used. Returns a generator of 4-tuples: |
1100 curtime = time.time() | 1100 curtime = time.time() |
1101 for topic in topics: | 1101 for topic in topics: |
1102 age = -1 | 1102 age = -1 |
1103 user = None | 1103 user = None |
1104 maxtime = (0, 0) | 1104 maxtime = (0, 0) |
1105 trevs = repo.revs("topic(%s)", topic) | 1105 trevs = repo.revs(b"topic(%s)", topic) |
1106 # Need to check for the time of all changesets in the topic, whether | 1106 # Need to check for the time of all changesets in the topic, whether |
1107 # they are obsolete of non-heads | 1107 # they are obsolete of non-heads |
1108 # XXX: can we just rely on the max rev number for this | 1108 # XXX: can we just rely on the max rev number for this |
1109 for revs in trevs: | 1109 for revs in trevs: |
1110 rt = repo[revs].date() | 1110 rt = repo[revs].date() |
1117 # last touch time. | 1117 # last touch time. |
1118 obsmarkers = compat.getmarkers(repo, [repo[revs].node()]) | 1118 obsmarkers = compat.getmarkers(repo, [repo[revs].node()]) |
1119 for marker in obsmarkers: | 1119 for marker in obsmarkers: |
1120 rt = marker.date() | 1120 rt = marker.date() |
1121 if rt[0] > maxtime[0]: | 1121 if rt[0] > maxtime[0]: |
1122 user = marker.metadata().get('user', user) | 1122 user = marker.metadata().get(b'user', user) |
1123 maxtime = rt | 1123 maxtime = rt |
1124 | 1124 |
1125 username = stack.parseusername(user) | 1125 username = stack.parseusername(user) |
1126 if trevs: | 1126 if trevs: |
1127 age = curtime - maxtime[0] | 1127 age = curtime - maxtime[0] |
1128 | 1128 |
1129 yield (age, topic, maxtime, username) | 1129 yield (age, topic, maxtime, username) |
1130 | 1130 |
1131 def summaryhook(ui, repo): | 1131 def summaryhook(ui, repo): |
1132 t = getattr(repo, 'currenttopic', '') | 1132 t = getattr(repo, 'currenttopic', b'') |
1133 if not t: | 1133 if not t: |
1134 return | 1134 return |
1135 # i18n: column positioning for "hg summary" | 1135 # i18n: column positioning for "hg summary" |
1136 ui.write(_("topic: %s\n") % ui.label(t, 'topic.active')) | 1136 ui.write(_(b"topic: %s\n") % ui.label(t, b'topic.active')) |
1137 | 1137 |
1138 _validmode = [ | 1138 _validmode = [ |
1139 'ignore', | 1139 b'ignore', |
1140 'warning', | 1140 b'warning', |
1141 'enforce', | 1141 b'enforce', |
1142 'enforce-all', | 1142 b'enforce-all', |
1143 'random', | 1143 b'random', |
1144 'random-all', | 1144 b'random-all', |
1145 ] | 1145 ] |
1146 | 1146 |
1147 def _configtopicmode(ui): | 1147 def _configtopicmode(ui): |
1148 """ Parse the config to get the topicmode | 1148 """ Parse the config to get the topicmode |
1149 """ | 1149 """ |
1150 topicmode = ui.config('experimental', 'topic-mode') | 1150 topicmode = ui.config(b'experimental', b'topic-mode') |
1151 | 1151 |
1152 # Fallback to read enforce-topic | 1152 # Fallback to read enforce-topic |
1153 if topicmode is None: | 1153 if topicmode is None: |
1154 enforcetopic = ui.configbool('experimental', 'enforce-topic') | 1154 enforcetopic = ui.configbool(b'experimental', b'enforce-topic') |
1155 if enforcetopic: | 1155 if enforcetopic: |
1156 topicmode = "enforce" | 1156 topicmode = b"enforce" |
1157 if topicmode not in _validmode: | 1157 if topicmode not in _validmode: |
1158 topicmode = _validmode[0] | 1158 topicmode = _validmode[0] |
1159 | 1159 |
1160 return topicmode | 1160 return topicmode |
1161 | 1161 |
1165 with repo.wlock(): | 1165 with repo.wlock(): |
1166 topicmode = _configtopicmode(ui) | 1166 topicmode = _configtopicmode(ui) |
1167 ismergecommit = len(repo[None].parents()) == 2 | 1167 ismergecommit = len(repo[None].parents()) == 2 |
1168 | 1168 |
1169 notopic = not repo.currenttopic | 1169 notopic = not repo.currenttopic |
1170 mayabort = (topicmode == "enforce" and not ismergecommit) | 1170 mayabort = (topicmode == b"enforce" and not ismergecommit) |
1171 maywarn = (topicmode == "warning" | 1171 maywarn = (topicmode == b"warning" |
1172 or (topicmode == "enforce" and ismergecommit)) | 1172 or (topicmode == b"enforce" and ismergecommit)) |
1173 | 1173 |
1174 mayrandom = False | 1174 mayrandom = False |
1175 if topicmode == "random": | 1175 if topicmode == b"random": |
1176 mayrandom = not ismergecommit | 1176 mayrandom = not ismergecommit |
1177 elif topicmode == "random-all": | 1177 elif topicmode == b"random-all": |
1178 mayrandom = True | 1178 mayrandom = True |
1179 | 1179 |
1180 if topicmode == 'enforce-all': | 1180 if topicmode == b'enforce-all': |
1181 ismergecommit = False | 1181 ismergecommit = False |
1182 mayabort = True | 1182 mayabort = True |
1183 maywarn = False | 1183 maywarn = False |
1184 | 1184 |
1185 hint = _("see 'hg help -e topic.topic-mode' for details") | 1185 hint = _(b"see 'hg help -e topic.topic-mode' for details") |
1186 if opts.get('topic'): | 1186 if opts.get('topic'): |
1187 t = opts['topic'] | 1187 t = opts['topic'] |
1188 with repo.vfs.open(b'topic', b'w') as f: | 1188 with repo.vfs.open(b'topic', b'w') as f: |
1189 f.write(t) | 1189 f.write(t) |
1190 elif opts.get('amend'): | 1190 elif opts.get('amend'): |
1191 pass | 1191 pass |
1192 elif notopic and mayabort: | 1192 elif notopic and mayabort: |
1193 msg = _("no active topic") | 1193 msg = _(b"no active topic") |
1194 raise error.Abort(msg, hint=hint) | 1194 raise error.Abort(msg, hint=hint) |
1195 elif notopic and maywarn: | 1195 elif notopic and maywarn: |
1196 ui.warn(_("warning: new draft commit without topic\n")) | 1196 ui.warn(_(b"warning: new draft commit without topic\n")) |
1197 if not ui.quiet: | 1197 if not ui.quiet: |
1198 ui.warn(("(%s)\n") % hint) | 1198 ui.warn((b"(%s)\n") % hint) |
1199 elif notopic and mayrandom: | 1199 elif notopic and mayrandom: |
1200 with repo.vfs.open(b'topic', b'w') as f: | 1200 with repo.vfs.open(b'topic', b'w') as f: |
1201 f.write(randomname.randomtopicname(ui)) | 1201 f.write(randomname.randomtopicname(ui)) |
1202 return orig(ui, repo, *args, **opts) | 1202 return orig(ui, repo, *args, **opts) |
1203 | 1203 |
1204 def committextwrap(orig, repo, ctx, subs, extramsg): | 1204 def committextwrap(orig, repo, ctx, subs, extramsg): |
1205 ret = orig(repo, ctx, subs, extramsg) | 1205 ret = orig(repo, ctx, subs, extramsg) |
1206 if hastopicext(repo): | 1206 if hastopicext(repo): |
1207 t = repo.currenttopic | 1207 t = repo.currenttopic |
1208 if t: | 1208 if t: |
1209 ret = ret.replace("\nHG: branch", | 1209 ret = ret.replace(b"\nHG: branch", |
1210 "\nHG: topic '%s'\nHG: branch" % t) | 1210 b"\nHG: topic '%s'\nHG: branch" % t) |
1211 return ret | 1211 return ret |
1212 | 1212 |
1213 def pushoutgoingwrap(orig, ui, repo, *args, **opts): | 1213 def pushoutgoingwrap(orig, ui, repo, *args, **opts): |
1214 if opts.get('topic'): | 1214 if opts.get('topic'): |
1215 topicrevs = repo.revs('topic(%s) - obsolete()', opts['topic']) | 1215 topicrevs = repo.revs(b'topic(%s) - obsolete()', opts['topic']) |
1216 opts.setdefault('rev', []).extend(topicrevs) | 1216 opts.setdefault('rev', []).extend(topicrevs) |
1217 return orig(ui, repo, *args, **opts) | 1217 return orig(ui, repo, *args, **opts) |
1218 | 1218 |
1219 def mergeupdatewrap(orig, repo, node, branchmerge, force, *args, **kwargs): | 1219 def mergeupdatewrap(orig, repo, node, branchmerge, force, *args, **kwargs): |
1220 matcher = kwargs.get('matcher') | 1220 matcher = kwargs.get('matcher') |
1230 # current topic. This is right for merge but wrong for rebase. We check | 1230 # current topic. This is right for merge but wrong for rebase. We check |
1231 # if rebase is running and update the currenttopic to topic of new | 1231 # if rebase is running and update the currenttopic to topic of new |
1232 # rebased commit. We have explicitly stored in config if rebase is | 1232 # rebased commit. We have explicitly stored in config if rebase is |
1233 # running. | 1233 # running. |
1234 ot = repo.currenttopic | 1234 ot = repo.currenttopic |
1235 if repo.ui.hasconfig('experimental', 'topicrebase'): | 1235 if repo.ui.hasconfig(b'experimental', b'topicrebase'): |
1236 isrebase = True | 1236 isrebase = True |
1237 if repo.ui.configbool('_internal', 'keep-topic'): | 1237 if repo.ui.configbool(b'_internal', b'keep-topic'): |
1238 ist0 = True | 1238 ist0 = True |
1239 if ((not partial and not branchmerge) or isrebase) and not ist0: | 1239 if ((not partial and not branchmerge) or isrebase) and not ist0: |
1240 t = '' | 1240 t = b'' |
1241 pctx = repo[node] | 1241 pctx = repo[node] |
1242 if pctx.phase() > phases.public: | 1242 if pctx.phase() > phases.public: |
1243 t = pctx.topic() | 1243 t = pctx.topic() |
1244 with repo.vfs.open(b'topic', b'w') as f: | 1244 with repo.vfs.open(b'topic', b'w') as f: |
1245 f.write(t) | 1245 f.write(t) |
1246 if t and t != ot: | 1246 if t and t != ot: |
1247 repo.ui.status(_("switching to topic %s\n") % t) | 1247 repo.ui.status(_(b"switching to topic %s\n") % t) |
1248 if ot and not t: | 1248 if ot and not t: |
1249 st = stack.stack(repo, topic=ot) | 1249 st = stack.stack(repo, topic=ot) |
1250 if not st: | 1250 if not st: |
1251 repo.ui.status(_('clearing empty topic "%s"\n') % ot) | 1251 repo.ui.status(_(b'clearing empty topic "%s"\n') % ot) |
1252 elif ist0: | 1252 elif ist0: |
1253 repo.ui.status(_("preserving the current topic '%s'\n") % ot) | 1253 repo.ui.status(_(b"preserving the current topic '%s'\n") % ot) |
1254 return ret | 1254 return ret |
1255 finally: | 1255 finally: |
1256 wlock.release() | 1256 wlock.release() |
1257 | 1257 |
1258 def checkt0(orig, ui, repo, node=None, rev=None, *args, **kwargs): | 1258 def checkt0(orig, ui, repo, node=None, rev=None, *args, **kwargs): |
1259 | 1259 |
1260 thezeros = set(['t0', 'b0', 's0']) | 1260 thezeros = set([b't0', b'b0', b's0']) |
1261 backup = repo.ui.backupconfig('_internal', 'keep-topic') | 1261 backup = repo.ui.backupconfig(b'_internal', b'keep-topic') |
1262 try: | 1262 try: |
1263 if node in thezeros or rev in thezeros: | 1263 if node in thezeros or rev in thezeros: |
1264 repo.ui.setconfig('_internal', 'keep-topic', 'yes', | 1264 repo.ui.setconfig(b'_internal', b'keep-topic', b'yes', |
1265 source='topic-extension') | 1265 source=b'topic-extension') |
1266 return orig(ui, repo, node=node, rev=rev, *args, **kwargs) | 1266 return orig(ui, repo, node=node, rev=rev, *args, **kwargs) |
1267 finally: | 1267 finally: |
1268 repo.ui.restoreconfig(backup) | 1268 repo.ui.restoreconfig(backup) |
1269 | 1269 |
1270 def _fixrebase(loaded): | 1270 def _fixrebase(loaded): |
1274 def savetopic(ctx, extra): | 1274 def savetopic(ctx, extra): |
1275 if ctx.topic(): | 1275 if ctx.topic(): |
1276 extra[constants.extrakey] = ctx.topic() | 1276 extra[constants.extrakey] = ctx.topic() |
1277 | 1277 |
1278 def setrebaseconfig(orig, ui, repo, **opts): | 1278 def setrebaseconfig(orig, ui, repo, **opts): |
1279 repo.ui.setconfig('experimental', 'topicrebase', 'yes', | 1279 repo.ui.setconfig(b'experimental', b'topicrebase', b'yes', |
1280 source='topic-extension') | 1280 source=b'topic-extension') |
1281 return orig(ui, repo, **opts) | 1281 return orig(ui, repo, **opts) |
1282 | 1282 |
1283 def new_init(orig, *args, **kwargs): | 1283 def new_init(orig, *args, **kwargs): |
1284 runtime = orig(*args, **kwargs) | 1284 runtime = orig(*args, **kwargs) |
1285 | 1285 |
1287 runtime.extrafns.append(savetopic) | 1287 runtime.extrafns.append(savetopic) |
1288 | 1288 |
1289 return runtime | 1289 return runtime |
1290 | 1290 |
1291 try: | 1291 try: |
1292 rebase = extensions.find("rebase") | 1292 rebase = extensions.find(b"rebase") |
1293 extensions.wrapfunction(rebase.rebaseruntime, '__init__', new_init) | 1293 extensions.wrapfunction(rebase.rebaseruntime, '__init__', new_init) |
1294 # This exists to store in the config that rebase is running so that we can | 1294 # This exists to store in the config that rebase is running so that we can |
1295 # update the topic according to rebase. This is a hack and should be removed | 1295 # update the topic according to rebase. This is a hack and should be removed |
1296 # when we have better options. | 1296 # when we have better options. |
1297 extensions.wrapcommand(rebase.cmdtable, 'rebase', setrebaseconfig) | 1297 extensions.wrapcommand(rebase.cmdtable, b'rebase', setrebaseconfig) |
1298 except KeyError: | 1298 except KeyError: |
1299 pass | 1299 pass |
1300 | 1300 |
1301 ## preserve topic during import/export | 1301 ## preserve topic during import/export |
1302 | 1302 |
1303 def _exporttopic(seq, ctx): | 1303 def _exporttopic(seq, ctx): |
1304 topic = ctx.topic() | 1304 topic = ctx.topic() |
1305 if topic: | 1305 if topic: |
1306 return 'EXP-Topic %s' % topic | 1306 return b'EXP-Topic %s' % topic |
1307 return None | 1307 return None |
1308 | 1308 |
1309 def _importtopic(repo, patchdata, extra, opts): | 1309 def _importtopic(repo, patchdata, extra, opts): |
1310 if 'topic' in patchdata: | 1310 if b'topic' in patchdata: |
1311 extra['topic'] = patchdata['topic'] | 1311 extra[b'topic'] = patchdata[b'topic'] |
1312 | 1312 |
1313 def setupimportexport(ui): | 1313 def setupimportexport(ui): |
1314 """run at ui setup time to install import/export logic""" | 1314 """run at ui setup time to install import/export logic""" |
1315 cmdutil.extraexport.append('topic') | 1315 cmdutil.extraexport.append(b'topic') |
1316 cmdutil.extraexportmap['topic'] = _exporttopic | 1316 cmdutil.extraexportmap[b'topic'] = _exporttopic |
1317 cmdutil.extrapreimport.append('topic') | 1317 cmdutil.extrapreimport.append(b'topic') |
1318 cmdutil.extrapreimportmap['topic'] = _importtopic | 1318 cmdutil.extrapreimportmap[b'topic'] = _importtopic |
1319 patch.patchheadermap.append(('EXP-Topic', 'topic')) | 1319 patch.patchheadermap.append((b'EXP-Topic', b'topic')) |
1320 | 1320 |
1321 ## preserve topic during split | 1321 ## preserve topic during split |
1322 | 1322 |
1323 def presplitupdatetopic(original, repo, ui, prev, ctx): | 1323 def presplitupdatetopic(original, repo, ui, prev, ctx): |
1324 # Save topic of revision | 1324 # Save topic of revision |