308 'topics', 'topic', namemap=_namemap, nodemap=_nodemap, |
308 'topics', 'topic', namemap=_namemap, nodemap=_nodemap, |
309 listnames=lambda repo: repo.topics)) |
309 listnames=lambda repo: repo.topics)) |
310 |
310 |
311 @command('topics', [ |
311 @command('topics', [ |
312 ('', 'clear', False, 'clear active topic if any'), |
312 ('', 'clear', False, 'clear active topic if any'), |
313 ('r', 'rev', '', 'revset of existing revisions', _('REV')), |
313 ('r', 'rev', [], 'revset of existing revisions', _('REV')), |
314 ('l', 'list', False, 'show the stack of changeset in the topic'), |
314 ('l', 'list', False, 'show the stack of changeset in the topic'), |
315 ('', 'age', False, 'show when you last touched the topics'), |
315 ('', 'age', False, 'show when you last touched the topics'), |
316 ('', 'current', None, 'display the current topic only'), |
316 ('', 'current', None, 'display the current topic only'), |
317 ] + commands.formatteropts, |
317 ] + commands.formatteropts, |
318 _('hg topics [TOPIC]')) |
318 _('hg topics [TOPIC]')) |
351 raise error.Abort(_("cannot use --current when setting a topic")) |
351 raise error.Abort(_("cannot use --current when setting a topic")) |
352 if current and clear: |
352 if current and clear: |
353 raise error.Abort(_("cannot use --current and --clear")) |
353 raise error.Abort(_("cannot use --current and --clear")) |
354 if clear and topic: |
354 if clear and topic: |
355 raise error.Abort(_("cannot use --clear when setting a topic")) |
355 raise error.Abort(_("cannot use --clear when setting a topic")) |
|
356 |
|
357 touchedrevs = set() |
|
358 if rev: |
|
359 touchedrevs = scmutil.revrange(repo, rev) |
356 |
360 |
357 if topic: |
361 if topic: |
358 topic = topic.strip() |
362 topic = topic.strip() |
359 if not topic: |
363 if not topic: |
360 raise error.Abort(_("topic name cannot consist entirely of whitespaces")) |
364 raise error.Abort(_("topic name cannot consist entirely of whitespaces")) |
368 topic = repo.currenttopic |
372 topic = repo.currenttopic |
369 if not topic: |
373 if not topic: |
370 raise error.Abort(_('no active topic to list')) |
374 raise error.Abort(_('no active topic to list')) |
371 return stack.showstack(ui, repo, topic=topic, opts=opts) |
375 return stack.showstack(ui, repo, topic=topic, opts=opts) |
372 |
376 |
373 if rev: |
377 if touchedrevs: |
374 if not obsolete.isenabled(repo, obsolete.createmarkersopt): |
378 if not obsolete.isenabled(repo, obsolete.createmarkersopt): |
375 raise error.Abort(_('must have obsolete enabled to change topics')) |
379 raise error.Abort(_('must have obsolete enabled to change topics')) |
376 if clear: |
380 if clear: |
377 topic = None |
381 topic = None |
378 elif opts.get('current'): |
382 elif opts.get('current'): |
379 topic = repo.currenttopic |
383 topic = repo.currenttopic |
380 elif not topic: |
384 elif not topic: |
381 raise error.Abort('changing topic requires a topic name or --clear') |
385 raise error.Abort('changing topic requires a topic name or --clear') |
382 if any(not c.mutable() for c in repo.set('%r and public()', rev)): |
386 if repo.revs('%ld and public()', touchedrevs): |
383 raise error.Abort("can't change topic of a public change") |
387 raise error.Abort("can't change topic of a public change") |
384 wl = l = txn = None |
388 wl = l = txn = None |
385 try: |
389 try: |
386 wl = repo.wlock() |
390 wl = repo.wlock() |
387 l = repo.lock() |
391 l = repo.lock() |
388 txn = repo.transaction('rewrite-topics') |
392 txn = repo.transaction('rewrite-topics') |
389 rewrote = _changetopics(ui, repo, rev, topic) |
393 rewrote = _changetopics(ui, repo, touchedrevs, topic) |
390 txn.close() |
394 txn.close() |
391 ui.status('changed topic on %d changes\n' % rewrote) |
395 ui.status('changed topic on %d changes\n' % rewrote) |
392 finally: |
396 finally: |
393 lockmod.release(txn, l, wl) |
397 lockmod.release(txn, l, wl) |
394 repo.invalidate() |
398 repo.invalidate() |
444 f.write(newtopic) |
448 f.write(newtopic) |
445 else: |
449 else: |
446 if repo.vfs.exists('topic'): |
450 if repo.vfs.exists('topic'): |
447 repo.vfs.unlink('topic') |
451 repo.vfs.unlink('topic') |
448 |
452 |
449 def _changetopics(ui, repo, revset, newtopic): |
453 def _changetopics(ui, repo, revs, newtopic): |
450 """ Changes topic to newtopic of all the revisions in the revset and return |
454 """ Changes topic to newtopic of all the revisions in the revset and return |
451 the count of revisions whose topic has been changed. |
455 the count of revisions whose topic has been changed. |
452 """ |
456 """ |
453 rewrote = 0 |
457 rewrote = 0 |
454 p1 = None |
458 p1 = None |
455 p2 = None |
459 p2 = None |
456 successors = {} |
460 successors = {} |
457 for c in repo.set('%r', revset): |
461 for r in revs: |
|
462 c = repo[r] |
|
463 |
458 def filectxfn(repo, ctx, path): |
464 def filectxfn(repo, ctx, path): |
459 try: |
465 try: |
460 return c[path] |
466 return c[path] |
461 except error.ManifestLookupError: |
467 except error.ManifestLookupError: |
462 return None |
468 return None |