# HG changeset patch # User Pulkit Goyal <7895pulkit@gmail.com> # Date 1499789379 -19800 # Node ID d3994277316326dbe78216c4f29894bc89fe71e0 # Parent 7fbb7a5d359f9e1fd4c0737025818ef41fc07834 topics: add a new flag --age which will show last touched time for topics This adds a new flag `--age` to `hg topic` command which will show topics sorted by their last touched time and will also show the last touched time for them. This patch also adds a simple test to make sure the flag does not breaks by future changes. Adding more tests showing output like "3 hours ago", "2 minutes ago" etc will change as the code takes time.time() into account which will increase with time, and hence the output will change, so we need some static output like a date. diff -r 7fbb7a5d359f -r d39942773163 hgext3rd/topic/__init__.py --- a/hgext3rd/topic/__init__.py Tue Jul 11 11:24:43 2017 +0200 +++ b/hgext3rd/topic/__init__.py Tue Jul 11 21:39:39 2017 +0530 @@ -53,6 +53,7 @@ from __future__ import absolute_import import re +import time from mercurial.i18n import _ from mercurial import ( @@ -68,9 +69,11 @@ namespaces, node, obsolete, + obsutil, patch, phases, registrar, + templatefilters, util, ) @@ -297,6 +300,7 @@ ('', 'clear', False, 'clear active topic if any'), ('r', 'rev', '', 'revset of existing revisions', _('REV')), ('l', 'list', False, 'show the stack of changeset in the topic'), + ('', 'age', False, 'show when you last touched the topics') ] + commands.formatteropts) def topics(ui, repo, topic='', clear=False, rev=None, list=False, **opts): """View current topic, set current topic, change topic for a set of revisions, or see all topics. @@ -316,6 +320,9 @@ List of topics: `hg topics` + List of topics with their last touched time sorted according to it: + `hg topic --age` + The active topic (if any) will be prepended with a "*". The --verbose version of this command display various information on the state of each topic.""" @@ -442,6 +449,11 @@ def _listtopics(ui, repo, opts): fm = ui.formatter('topics', opts) + showlast = opts.get('age') + if showlast: + # we have a new function as plugging logic into existing function is + # pretty much difficult + return _showlasttouched(repo, fm, opts) activetopic = repo.currenttopic namemask = '%s' if repo.topics and ui.verbose: @@ -494,6 +506,76 @@ fm.plain('\n') fm.end() +def _showlasttouched(repo, fm, opts): + topics = repo.topics + timedict = _getlasttouched(repo, topics) + times = timedict.keys() + times.sort() + if topics: + maxwidth = max(len(t) for t in topics) + namemask = '%%-%is' % maxwidth + activetopic = repo.currenttopic + for timevalue in times: + curtopics = timedict[timevalue][1] + for topic in curtopics: + fm.startitem() + marker = ' ' + label = 'topic' + active = (topic == activetopic) + if active: + marker = '*' + label = 'topic.active' + fm.plain(' %s ' % marker, label=label) + fm.write('topic', namemask, topic, label=label) + fm.data(active=active) + fm.plain(' (') + if timevalue == -1: + timestr = 'not yet touched' + else: + timestr = templatefilters.age(timedict[timevalue][0]) + fm.write('lasttouched', '%s', timestr, label='topic.list.time') + fm.plain(')') + fm.plain('\n') + fm.end() + +def _getlasttouched(repo, topics): + """ + Calculates the last time a topic was used. Returns a dictionary of seconds + passed from current time for a topic as keys and topic name as values. + """ + topicstime = {} + curtime = time.time() + for t in topics: + maxtime = (0, 0) + trevs = repo.revs("topic(%s)", t) + # Need to check for the time of all changesets in the topic, whether + # they are obsolete of non-heads + # XXX: can we just rely on the max rev number for this + for revs in trevs: + rt = repo[revs].date() + if rt[0] > maxtime[0]: + # Can store the rev to gather more info + # latesthead = revs + maxtime = rt + # looking on the markers also to get more information and accurate + # last touch time. + obsmarkers = obsutil.getmarkers(repo, [repo[revs].node()]) + for marker in obsmarkers: + rt = marker.date() + if rt[0] > maxtime[0]: + maxtime = rt + # is the topic still yet untouched + if not trevs: + secspassed = -1 + else: + secspassed = (curtime - maxtime[0]) + try: + topicstime[secspassed][1].append(t) + except KeyError: + topicstime[secspassed] = (maxtime, [t]) + + return topicstime + def panicforuntopicedcommit(): msg = _("no active topic") hint = _("set a current topic or use '--config " + diff -r 7fbb7a5d359f -r d39942773163 tests/test-topic.t --- a/tests/test-topic.t Tue Jul 11 11:24:43 2017 +0200 +++ b/tests/test-topic.t Tue Jul 11 21:39:39 2017 +0530 @@ -33,6 +33,9 @@ List of topics: 'hg topics' + List of topics with their last touched time sorted according to it: + 'hg topic --age' + The active topic (if any) will be prepended with a "*". The --verbose version of this command display various information on the @@ -43,6 +46,7 @@ --clear clear active topic if any -r --rev REV revset of existing revisions -l --list show the stack of changeset in the topic + --age show when you last touched the topics (some details hidden, use --verbose to show complete help) $ hg topics @@ -821,6 +825,9 @@ t1: start on fran t0^ Add file delta (base) + $ hg topics --age + * changewut (1970-01-01) + $ cd .. Testing the new config knob to forbid untopiced commit