python3
[build.git] / module-log.py
index 2241460..c9f7771 100755 (executable)
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-# -*- mode:python; var: python-guess-indent:false; python-indent:4; -*-
+#!/usr/bin/python3
 
 import os
 import sys
@@ -7,190 +6,204 @@ import re
 from optparse import OptionParser
 
 modules_map = {
-    'general' : [ 'build', 'tests', ],
-    'server' : ['Monitor', 'MyPLC', 'PLCAPI', 'PLCRT', 'PLCWWW', 'PLEWWW', 'www-register-wizard', 
-               'PXEService', 'drupal', 'plcmdline',],
-    'node': [ 'linux-2.6', 'util-vserver', 'util-vserver-pl', 'chopstix-L0', 
-             'BootCD', 'BootManager', 'BootstrapFS', 'VserverReference', 
-             'DistributedRateLimiting', 'Mom', 'PingOfDeath', 
-             'NodeManager', 'NodeManager-optin', 'NodeManager-topo', 
-             'NodeUpdate', 'CoDemux', 
-             'nodeconfig', 'pl_sshd', 
-             'libnl', 'pypcilib', 'pyplnet',],
-    'wifi' : ['madwifi', 'PlanetBridge', 'hostapd',],
+    'general': ['build', 'tests', ],
+    'server': ['Monitor', 'MyPLC', 'PLCAPI', 'PLCRT', 'PLCWWW', 'PLEWWW', 'www-register-wizard',
+               'PXEService', 'drupal', 'plcmdline', ],
+    'node': ['linux-2.6', 'util-vserver', 'util-vserver-pl', 'chopstix-L0',
+             'BootCD', 'BootManager', 'BootstrapFS', 'VserverReference',
+             'DistributedRateLimiting', 'Mom', 'PingOfDeath',
+             'NodeManager', 'NodeManager-optin', 'NodeManager-topo',
+             'NodeUpdate', 'CoDemux',
+             'nodeconfig', 'pl_sshd',
+             'libnl', 'pypcilib', 'pyplnet', ],
+    'wifi': ['madwifi', 'PlanetBridge', 'hostapd', ],
     'emulation': ['dummynet_image', 'ipfw', ],
-    'netflow' : [ 'fprobe-ulog', 'pf2gui', 'pf2monitor', 'pf2slice', 'iproute2', 'iptables', 'silk',],
-    'sfa' : [ 'sfa', 'xmlrspecs', 'pyopenssl', ],
-    'vsys' : ['vsys', 'vsys-scripts', 'vsys-wrappers', 'inotify-tools'],
-    'deprecated' : [ 'proper', 'libhttpd++', 'oombailout', 'ulogd', 'patchdep', 'pdelta', 
-                    'sandbox', 'playground', 'infrastructure', 'util-python', 'vnetspec', 
-                    ],
-    }
+    'netflow': ['fprobe-ulog', 'pf2gui', 'pf2monitor', 'pf2slice', 'iproute2', 'iptables', 'silk', ],
+    'sfa': ['sfa', 'xmlrspecs', 'pyopenssl', ],
+    'vsys': ['vsys', 'vsys-scripts', 'vsys-wrappers', 'inotify-tools'],
+    'deprecated': ['proper', 'libhttpd++', 'oombailout', 'ulogd', 'patchdep', 'pdelta',
+                   'sandbox', 'playground', 'infrastructure', 'util-python', 'vnetspec',
+                   ],
+}
+
+epoch = '{2007-07-01}'
 
-epoch='{2007-07-01}'
 
 class ModuleHistory:
 
-    def __init__ (self, name, options):
-       self.name=name
-       self.options=options
-       self.user_commits=[]
-       self.user_revs={}
-       self.current_rev=None
-       self.current_user=None
-       
-    valid=re.compile('\Ar[0-9]+ \|')
-    tagging=re.compile('\ATagging|\ASetting tag')
+    def __init__(self, name, options):
+        self.name = name
+        self.options = options
+        self.user_commits = []
+        self.user_revs = {}
+        self.current_rev = None
+        self.current_user = None
+
+    valid = re.compile(r'\Ar[0-9]+ \|')
+    tagging = re.compile(r'\ATagging|\ASetting tag')
 
     @staticmethod
-    def sort ( (u1,c1), (u2,c2) ): return c2-c1
+    def sort_key(u, c):
+        return c
 
-    def record(self,user,rev):
-       try:
-           self.user_revs[user].append(rev)
-       except:
-           self.user_revs[user] = [rev]
-       self.current_rev=rev
-       self.current_user=user
+    def record(self, user, rev):
+        try:
+            self.user_revs[user].append(rev)
+        except:
+            self.user_revs[user] = [rev]
+        self.current_rev = rev
+        self.current_user = user
 
     def ignore(self):
-       if (not self.current_user) or (not self.current_rev): return
-       user_list=self.user_revs[self.current_user]
-       if len(user_list) >= 1 and user_list[-1] == self.current_rev:
-           user_list.pop()
-
-    def scan (self):
-       cmd =  "svn log -r %s:%s http://svn.planet-lab.org/svn/%s " % (self.options.fromv,self.options.tov,self.name)
-       if self.options.verbose:
-           print 'running',cmd
-       f = os.popen(cmd)
-       for line in f:
-           if not self.valid.match(line): 
-               # mostly ignore commit body, except for ignoring the current commit if -i is set
-               if self.options.ignore_tags and self.tagging.match(line):
-                   # roll back these changes
-                   self.ignore()
-               continue
-           fields = line.split('|')
-           fields = [field.strip() for field in fields]
-           [rev,user,ctime,size] = fields[:4]
-           self.record(user,rev)
-       # translate into a list of tuples
-       user_commits = [ (user,len(revs)) for (user,revs) in self.user_revs.items() ]
-       user_commits.sort(self.sort)
-       self.user_commits=user_commits
+        if (not self.current_user) or (not self.current_rev):
+            return
+        user_list = self.user_revs[self.current_user]
+        if len(user_list) >= 1 and user_list[-1] == self.current_rev:
+            user_list.pop()
+
+    def scan(self):
+        cmd = "svn log -r %s:%s http://svn.planet-lab.org/svn/%s " % (
+            self.options.fromv, self.options.tov, self.name)
+        if self.options.verbose:
+            print('running', cmd)
+        f = os.popen(cmd)
+        for line in f:
+            if not self.valid.match(line):
+                # mostly ignore commit body, except for ignoring the current commit if -i is set
+                if self.options.ignore_tags and self.tagging.match(line):
+                    # roll back these changes
+                    self.ignore()
+                continue
+            fields = line.split('|')
+            fields = [field.strip() for field in fields]
+            [rev, user, ctime, size] = fields[:4]
+            self.record(user, rev)
+        # translate into a list of tuples
+        user_commits = [(user, len(revs))
+                        for (user, revs) in list(self.user_revs.items())]
+        user_commits.sort(key=self.sort_key)
+        self.user_commits = user_commits
 
     def show(self):
-       if len(self.user_commits) ==0: return
-       print '%s [%s-%s]'%(self.name,self.options.fromv,self.options.tov),
-       if self.options.ignore_tags:
-           print ' - Ignored tag commits'
-       else:
-           print ''
-       for (u,c) in self.user_commits:
-           print "\t",u,c
+        if len(self.user_commits) == 0:
+            return
+        print('%s [%s-%s]' %
+              (self.name, self.options.fromv, self.options.tov), end=' ')
+        if self.options.ignore_tags:
+            print(' - Ignored tag commits')
+        else:
+            print('')
+        for (u, c) in self.user_commits:
+            print("\t", u, c)
+
 
 class Aggregate:
 
-    def __init__ (self,options):
-       # key=user, value=commits
-       self.options=options
-       self.user_commits_dict={}
-       self.user_commits=[]
-
-    def merge (self, modulehistory):
-       for (u,c) in modulehistory.user_commits:
-           try:
-               self.user_commits_dict[u] += c
-           except:
-               self.user_commits_dict[u] = c
-
-    def sort (self):
-       user_commits = [ (u,c) for (u,c) in self.user_commits_dict.items() ]
-       user_commits.sort(ModuleHistory.sort)
-       self.user_commits=user_commits
-       
+    def __init__(self, options):
+        # key=user, value=commits
+        self.options = options
+        self.user_commits_dict = {}
+        self.user_commits = []
+
+    def merge(self, modulehistory):
+        for (u, c) in modulehistory.user_commits:
+            try:
+                self.user_commits_dict[u] += c
+            except:
+                self.user_commits_dict[u] = c
+
+    def sort(self):
+        user_commits = [(u, c)
+                        for (u, c) in list(self.user_commits_dict.items())]
+        user_commits.sort(ModuleHistory.sort)
+        self.user_commits = user_commits
+
     def show(self):
-       print 'Overall',
-       if self.options.ignore_tags:
-           print ' - Ignored tag commits'
-       else:
-           print ''
-       for (u,c) in self.user_commits:
-           print "\t",u,c
+        print('Overall', end=' ')
+        if self.options.ignore_tags:
+            print(' - Ignored tag commits')
+        else:
+            print('')
+        for (u, c) in self.user_commits:
+            print("\t", u, c)
+
 
 class Modules:
-    
-    def __init__ (self,map):
-       self.map=map
+
+    def __init__(self, map):
+        self.map = map
 
     def categories(self):
-       return self.map.keys()
-
-    def all_modules(self,categories=None):
-       if not categories: categories=self.categories()
-       elif not isinstance(categories,list): categories=[categories]
-       result=[]
-       for category in categories:
-           result += self.map[category]
-       return result
-
-    def locate (self,keywords):
-       result=[]
-       for kw in keywords:
-           if self.map.has_key(kw):
-               result += self.map[kw]
-           else:
-               result += [kw]
-       return result
-
-    def list(self,scope):
-       for (cat,mod_list) in self.map.items():
-           for mod in mod_list:
-               if mod in scope:
-                   print cat,mod
-
-def main ():
-    usage="%prog [module_or_category ...]"
+        return list(self.map.keys())
+
+    def all_modules(self, categories=None):
+        if not categories:
+            categories = self.categories()
+        elif not isinstance(categories, list):
+            categories = [categories]
+        result = []
+        for category in categories:
+            result += self.map[category]
+        return result
+
+    def locate(self, keywords):
+        result = []
+        for kw in keywords:
+            if kw in self.map:
+                result += self.map[kw]
+            else:
+                result += [kw]
+        return result
+
+    def list(self, scope):
+        for (cat, mod_list) in list(self.map.items()):
+            for mod in mod_list:
+                if mod in scope:
+                    print(cat, mod)
+
+
+def main():
+    usage = "%prog [module_or_category ...]"
     parser = OptionParser(usage=usage)
-    parser.add_option("-f", "--from", action = "store", dest='fromv',
-                     default = epoch, help = "The revision to start from, default %s"%epoch)
-    parser.add_option("-t", "--to", action = "store", dest='tov',
-                     default = 'HEAD', help = "The revision to end with, default HEAD")
-    parser.add_option("-n","--no-aggregate", action='store_false',dest='aggregate',default=True,
-                     help='Do not aggregate over modules')
-    parser.add_option("-v","--verbose", action='store_true',dest='verbose',default=False,
-                     help='Run in verbose/debug mode')
-    parser.add_option("-i","--ignore-tags",action='store_true',dest='ignore_tags',
-                     help='ignore commits related to tagging')
-    parser.add_option("-l","--list",action='store_true',dest='list_modules',
-                     help='list available modules and categories')
+    parser.add_option("-f", "--from", action="store", dest='fromv',
+                      default=epoch, help="The revision to start from, default %s" % epoch)
+    parser.add_option("-t", "--to", action="store", dest='tov',
+                      default='HEAD', help="The revision to end with, default HEAD")
+    parser.add_option("-n", "--no-aggregate", action='store_false', dest='aggregate', default=True,
+                      help='Do not aggregate over modules')
+    parser.add_option("-v", "--verbose", action='store_true', dest='verbose', default=False,
+                      help='Run in verbose/debug mode')
+    parser.add_option("-i", "--ignore-tags", action='store_true', dest='ignore_tags',
+                      help='ignore commits related to tagging')
+    parser.add_option("-l", "--list", action='store_true', dest='list_modules',
+                      help='list available modules and categories')
     # pass this to the invoked shell if any
     (options, args) = parser.parse_args()
 
-    map=Modules(modules_map)
+    map = Modules(modules_map)
     if not args:
-       modules=map.all_modules()
+        modules = map.all_modules()
     else:
-       modules=map.locate(args)
+        modules = map.locate(args)
 
     if options.list_modules:
-       map.list(modules)
-       return
+        map.list(modules)
+        return
 
-    if len(modules) <=1:
-       options.aggregate=False
+    if len(modules) <= 1:
+        options.aggregate = False
 
     aggregate = Aggregate(options)
     for module in modules:
-       history=ModuleHistory(module,options)
-       history.scan()
-       history.show()
-       aggregate.merge(history)
+        history = ModuleHistory(module, options)
+        history.scan()
+        history.show()
+        aggregate.merge(history)
 
     if options.aggregate:
-       aggregate.sort()
-       aggregate.show()
+        aggregate.sort()
+        aggregate.show()
+
 
 if __name__ == '__main__':
     main()