changeset 2731:d39942773163

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.
author Pulkit Goyal <7895pulkit@gmail.com>
date Tue, 11 Jul 2017 21:39:39 +0530
parents 7fbb7a5d359f
children 4b5caa509df8
files hgext3rd/topic/__init__.py tests/test-topic.t
diffstat 2 files changed, 89 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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 " +
--- 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