Setting tag sfa-1.0-20
[build.git] / module-tools.py
index 1470852..ba45bf2 100755 (executable)
@@ -3,6 +3,7 @@
 import sys, os
 import re
 import time
 import sys, os
 import re
 import time
+import tempfile
 from glob import glob
 from optparse import OptionParser
 
 from glob import glob
 from optparse import OptionParser
 
@@ -11,7 +12,16 @@ from optparse import OptionParser
 # Moving to git we decided to rename some of the repositories. Here is
 # a map of name changes applied in git repositories.
 RENAMED_SVN_MODULES = {
 # Moving to git we decided to rename some of the repositories. Here is
 # a map of name changes applied in git repositories.
 RENAMED_SVN_MODULES = {
-    "PLEWWW": "plewww"
+    "PLEWWW": "plewww",
+    "PLCAPI": "plcapi",
+    "BootManager": "bootmanager",
+    "BootCD": "bootcd",
+    "VserverReference": "vserver-reference",
+    "BootstrapFS": "bootstrapfs",
+    "MyPLC": "myplc",
+    "CoDemux": "codemux",
+    "NodeManager": "nodemanager",
+    "NodeUpdate": "nodeupdate"
     }
 
 def svn_to_git_name(module):
     }
 
 def svn_to_git_name(module):
@@ -183,7 +193,7 @@ class SvnRepository:
         url = "%s/tags/%s" % (self.repo_root(), tagname)
         return SvnRepository.remote_exists(url)
 
         url = "%s/tags/%s" % (self.repo_root(), tagname)
         return SvnRepository.remote_exists(url)
 
-    def update(self, subdir="", recursive=True):
+    def update(self, subdir="", recursive=True, branch=None):
         path = os.path.join(self.path, subdir)
         if recursive:
             svncommand = "svn up %s" % path
         path = os.path.join(self.path, subdir)
         if recursive:
             svncommand = "svn up %s" % path
@@ -194,7 +204,7 @@ class SvnRepository:
     def commit(self, logfile):
         # add all new files to the repository
         Command("svn status %s | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\\ /g' | xargs svn add" %
     def commit(self, logfile):
         # add all new files to the repository
         Command("svn status %s | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\\ /g' | xargs svn add" %
-                self.path, self.options).run_silent()
+                self.path, self.options).output_of()
         Command("svn commit -F %s %s" % (logfile, self.path), self.options).run_fatal()
 
     def to_branch(self, branch):
         Command("svn commit -F %s %s" % (logfile, self.path), self.options).run_fatal()
 
     def to_branch(self, branch):
@@ -250,17 +260,22 @@ class GitRepository:
         return os.path.basename(self.path)
 
     def url(self):
         return os.path.basename(self.path)
 
     def url(self):
-        self.repo_root()
+        return self.repo_root()
+
+    def gitweb(self):
+        c = Command("git show | grep commit | awk '{print $2;}'", self.options)
+        out = self.__run_in_repo(c.output_of).strip()
+        return "http://git.onelab.eu/?p=%s.git;a=commit;h=%s" % (self.name(), out)
 
     def repo_root(self):
         c = Command("git remote show origin", self.options)
         out = self.__run_in_repo(c.output_of)
         for line in out.split('\n'):
             if line.strip().startswith("Fetch URL:"):
 
     def repo_root(self):
         c = Command("git remote show origin", self.options)
         out = self.__run_in_repo(c.output_of)
         for line in out.split('\n'):
             if line.strip().startswith("Fetch URL:"):
-                repo = line.split()[2]
+                return line.split()[2]
 
     @classmethod
 
     @classmethod
-    def checkout(cls, remote, local, options, depth=1):
+    def checkout(cls, remote, local, options, depth=0):
         Command("rm -rf %s" % local, options).run_silent()
         Command("git clone --depth %d %s %s" % (depth, remote, local), options).run_fatal()
         return GitRepository(local, options)
         Command("rm -rf %s" % local, options).run_silent()
         Command("git clone --depth %d %s %s" % (depth, remote, local), options).run_fatal()
         return GitRepository(local, options)
@@ -289,16 +304,34 @@ class GitRepository:
         else:
             return self.__run_in_repo(c.run_fatal)
 
         else:
             return self.__run_in_repo(c.run_fatal)
 
-    def update(self, subdir=None, recursive=None):
-        self.__run_command_in_repo("git pull")
-        self.__run_command_in_repo("git pull --tags")
+    def __is_commit_id(self, id):
+        c = Command("git show %s | grep commit | awk '{print $2;}'" % id, self.options)
+        ret = self.__run_in_repo(c.output_of, with_stderr=False)
+        if ret.strip() == id:
+            return True
+        return False
+
+    def update(self, subdir=None, recursive=None, branch="master"):
+        if branch == "master":
+            self.__run_command_in_repo("git checkout %s" % branch)
+        else:
+            self.to_branch(branch, remote=True)
+        self.__run_command_in_repo("git fetch origin --tags")
+        self.__run_command_in_repo("git fetch origin")
+        if not self.__is_commit_id(branch):
+            # we don't need to merge anythign for commit ids.
+            self.__run_command_in_repo("git merge --ff origin/%s" % branch)
 
     def to_branch(self, branch, remote=True):
 
     def to_branch(self, branch, remote=True):
+        self.revert()
         if remote:
         if remote:
-            branch = "origin/%s" % branch
+            command = "git branch --track %s origin/%s" % (branch, branch)
+            c = Command(command, self.options)
+            self.__run_in_repo(c.output_of, with_stderr=True)
         return self.__run_command_in_repo("git checkout %s" % branch)
 
     def to_tag(self, tag):
         return self.__run_command_in_repo("git checkout %s" % branch)
 
     def to_tag(self, tag):
+        self.revert()
         return self.__run_command_in_repo("git checkout %s" % tag)
 
     def tag(self, tagname, logfile):
         return self.__run_command_in_repo("git checkout %s" % tag)
 
     def tag(self, tagname, logfile):
@@ -313,10 +346,14 @@ class GitRepository:
         c = Command("git diff %s" % tagname, self.options)
         return self.__run_in_repo(c.output_of, with_stderr=True)
 
         c = Command("git diff %s" % tagname, self.options)
         return self.__run_in_repo(c.output_of, with_stderr=True)
 
-    def commit(self, logfile):
-        self.__run_command_in_repo("git add -A", ignore_errors=True)
+    def commit(self, logfile, branch="master"):
+        self.__run_command_in_repo("git add .", ignore_errors=True)
+        self.__run_command_in_repo("git add -u", ignore_errors=True)
         self.__run_command_in_repo("git commit -F  %s" % logfile, ignore_errors=True)
         self.__run_command_in_repo("git commit -F  %s" % logfile, ignore_errors=True)
-        self.__run_command_in_repo("git push")
+        if branch == "master" or self.__is_commit_id(branch):
+            self.__run_command_in_repo("git push")
+        else:
+            self.__run_command_in_repo("git push origin %s:%s" % (branch, branch))
         self.__run_command_in_repo("git push --tags")
 
     def revert(self, f=""):
         self.__run_command_in_repo("git push --tags")
 
     def revert(self, f=""):
@@ -351,9 +388,12 @@ class Repository:
                 break
 
     @classmethod
                 break
 
     @classmethod
-    def has_moved_to_git(cls, module, svnpath):
-        module = git_to_svn_name(module)
-        return SvnRepository.remote_exists("%s/%s/aaaa-has-moved-to-git" % (svnpath, module))
+    def has_moved_to_git(cls, module, config):
+        module = svn_to_git_name(module)
+        # check if the module is already in Git
+#        return SvnRepository.remote_exists("%s/%s/aaaa-has-moved-to-git" % (config['svnpath'], module))
+        return GitRepository.remote_exists(Module.git_remote_dir(module))
+
 
     @classmethod
     def remote_exists(cls, remote):
 
     @classmethod
     def remote_exists(cls, remote):
@@ -386,7 +426,7 @@ class Module:
     configKeys=[ ('svnpath',"Enter your toplevel svnpath",
                   "svn+ssh://%s@svn.planet-lab.org/svn/"%commands.getoutput("id -un")),
                  ('gitserver', "Enter your git server's hostname", "git.onelab.eu"),
     configKeys=[ ('svnpath',"Enter your toplevel svnpath",
                   "svn+ssh://%s@svn.planet-lab.org/svn/"%commands.getoutput("id -un")),
                  ('gitserver', "Enter your git server's hostname", "git.onelab.eu"),
-                 ('gituser', "Enter your user name (login name) on git server", os.getlogin()),
+                 ('gituser', "Enter your user name (login name) on git server", commands.getoutput("id -un")),
                  ("build", "Enter the name of your build module","build"),
                  ('username',"Enter your firstname and lastname for changelogs",""),
                  ("email","Enter your email address for changelogs",""),
                  ("build", "Enter the name of your build module","build"),
                  ('username',"Enter your firstname and lastname for changelogs",""),
                  ("email","Enter your email address for changelogs",""),
@@ -403,27 +443,41 @@ class Module:
             while not cls.config[key]:
                 cls.prompt_config_option(key, message, default)
 
             while not cls.config[key]:
                 cls.prompt_config_option(key, message, default)
 
-
     # for parsing module spec name:branch
     matcher_branch_spec=re.compile("\A(?P<name>[\w\.-]+):(?P<branch>[\w\.-]+)\Z")
     # special form for tagged module - for Build
     # for parsing module spec name:branch
     matcher_branch_spec=re.compile("\A(?P<name>[\w\.-]+):(?P<branch>[\w\.-]+)\Z")
     # special form for tagged module - for Build
-    matcher_tag_spec=re.compile("\A(?P<name>[\w-]+)@(?P<tagname>[\w\.-]+)\Z")
+    matcher_tag_spec=re.compile("\A(?P<name>[\w\.-]+)@(?P<tagname>[\w\.-]+)\Z")
     # parsing specfiles
     matcher_rpm_define=re.compile("%(define|global)\s+(\S+)\s+(\S*)\s*")
 
     # parsing specfiles
     matcher_rpm_define=re.compile("%(define|global)\s+(\S+)\s+(\S*)\s*")
 
-    def __init__ (self,module_spec,options):
-        # parse module spec
+    @classmethod
+    def parse_module_spec(cls, module_spec):
+        name = branch_or_tagname = module_type = ""
+
         attempt=Module.matcher_branch_spec.match(module_spec)
         if attempt:
         attempt=Module.matcher_branch_spec.match(module_spec)
         if attempt:
-            self.name=attempt.group('name')
-            self.branch=attempt.group('branch')
+            module_type = "branch"
+            name=attempt.group('name')
+            branch_or_tagname=attempt.group('branch')
         else:
             attempt=Module.matcher_tag_spec.match(module_spec)
             if attempt:
         else:
             attempt=Module.matcher_tag_spec.match(module_spec)
             if attempt:
-                self.name=attempt.group('name')
-                self.tagname=attempt.group('tagname')
+                module_type = "tag"
+                name=attempt.group('name')
+                branch_or_tagname=attempt.group('tagname')
             else:
             else:
-                self.name=module_spec
+                name=module_spec
+        return name, branch_or_tagname, module_type
+
+
+    def __init__ (self,module_spec,options):
+        # parse module spec
+        self.name, branch_or_tagname, module_type = self.parse_module_spec(module_spec)
+
+        if module_type == "branch":
+            self.branch=branch_or_tagname
+        elif module_type == "tag":
+            self.tagname=branch_or_tagname
 
         # when available prefer to use git module name internally
         self.name = svn_to_git_name(self.name)
 
         # when available prefer to use git module name internally
         self.name = svn_to_git_name(self.name)
@@ -566,7 +620,7 @@ that for other purposes than tagging""" % options.workdir
             print 'Checking for',self.module_dir
 
         if not os.path.isdir (self.module_dir):
             print 'Checking for',self.module_dir
 
         if not os.path.isdir (self.module_dir):
-            if Repository.has_moved_to_git(self.name, Module.config['svnpath']):
+            if Repository.has_moved_to_git(self.name, Module.config):
                 self.repository = GitRepository.checkout(self.git_remote_dir(self.name),
                                                          self.module_dir,
                                                          self.options)
                 self.repository = GitRepository.checkout(self.git_remote_dir(self.name),
                                                          self.module_dir,
                                                          self.options)
@@ -579,7 +633,7 @@ that for other purposes than tagging""" % options.workdir
         self.repository = Repository(self.module_dir, self.options)
         if self.repository.type == "svn":
             # check if module has moved to git    
         self.repository = Repository(self.module_dir, self.options)
         if self.repository.type == "svn":
             # check if module has moved to git    
-            if Repository.has_moved_to_git(self.name, Module.config['svnpath']):
+            if Repository.has_moved_to_git(self.name, Module.config):
                 Command("rm -rf %s" % self.module_dir, self.options).run_silent()
                 self.init_module_dir()
             # check if we have the required branch/tag
                 Command("rm -rf %s" % self.module_dir, self.options).run_silent()
                 self.init_module_dir()
             # check if we have the required branch/tag
@@ -613,7 +667,13 @@ that for other purposes than tagging""" % options.workdir
             return
         if self.options.verbose:
             print 'Updating', self.module_dir
             return
         if self.options.verbose:
             print 'Updating', self.module_dir
-        self.repository.update()
+
+        if hasattr(self,'branch'):
+            self.repository.update(branch=self.branch)
+        elif hasattr(self,'tagname'):
+            self.repository.update(branch=self.tagname)
+        else:
+            self.repository.update()
 
     def main_specname (self):
         attempt="%s/%s.spec"%(self.module_dir,self.name)
 
     def main_specname (self):
         attempt="%s/%s.spec"%(self.module_dir,self.name)
@@ -775,7 +835,7 @@ that for other purposes than tagging""" % options.workdir
 
 ##############################
     # using fine_grain means replacing only those instances that currently refer to this tag
 
 ##############################
     # using fine_grain means replacing only those instances that currently refer to this tag
-    # otherwise, <module>-SVNPATH is replaced unconditionnally
+    # otherwise, <module>-{SVNPATH,GITPATH} is replaced unconditionnally
     def patch_tags_file (self, tagsfile, oldname, newname,fine_grain=True):
         newtagsfile=tagsfile+".new"
         tags=open (tagsfile)
     def patch_tags_file (self, tagsfile, oldname, newname,fine_grain=True):
         newtagsfile=tagsfile+".new"
         tags=open (tagsfile)
@@ -797,17 +857,21 @@ that for other purposes than tagging""" % options.workdir
         # brute-force : change uncommented lines that define <module>-SVNPATH
         else:
             if self.options.verbose:
         # brute-force : change uncommented lines that define <module>-SVNPATH
         else:
             if self.options.verbose:
-                print 'Searching for -SVNPATH lines referring to /%s/\n\tin %s .. '%(self.name,tagsfile),
-            pattern="\A\s*(?P<make_name>[^\s]+)-SVNPATH\s*(=|:=)\s*(?P<url_main>[^\s]+)/%s/[^\s]+"\
-                                          %(self.name)
+                print 'Searching for -SVNPATH or -GITPATH lines referring to /%s/\n\tin %s .. '%(self.name,tagsfile),
+            pattern="\A\s*%s-(SVNPATH|GITPATH)\s*(=|:=)\s*(?P<url_main>[^\s]+)/%s[^\s]+"\
+                                          %(self.name,self.name)
             matcher_module=re.compile(pattern)
             for line in tags.readlines():
                 attempt=matcher_module.match(line)
                 if attempt:
             matcher_module=re.compile(pattern)
             for line in tags.readlines():
                 attempt=matcher_module.match(line)
                 if attempt:
-                    svnpath="%s-SVNPATH"%(attempt.group('make_name'))
+                    if line.find("-GITPATH") >= 0:
+                        modulepath = "%s-GITPATH"%self.name
+                        replacement = "%-32s:= %s/%s.git@%s\n"%(modulepath,attempt.group('url_main'),self.name,newname)
+                    else:
+                        modulepath = "%s-SVNPATH"%self.name
+                        replacement = "%-32s:= %s/%s/tags/%s\n"%(modulepath,attempt.group('url_main'),self.name,newname)
                     if self.options.verbose:
                     if self.options.verbose:
-                        print ' '+svnpath, 
-                    replacement = "%-32s:= %s/%s/tags/%s\n"%(svnpath,attempt.group('url_main'),self.name,newname)
+                        print ' ' + modulepath, 
                     new.write(replacement)
                     matches += 1
                 else:
                     new.write(replacement)
                     matches += 1
                 else:
@@ -944,14 +1008,14 @@ Please write a changelog for this new tag in the section above
                     elif choice == 'f':
                         self.patch_tags_file(tagsfile,old_tag_name,new_tag_name,fine_grain=False)
                     elif choice == 'd':
                     elif choice == 'f':
                         self.patch_tags_file(tagsfile,old_tag_name,new_tag_name,fine_grain=False)
                     elif choice == 'd':
-                        print build.diff(f=tagsfile)
+                        print build.diff(f=os.path.basename(tagsfile))
                     elif choice == 'r':
                         build.revert(f=tagsfile)
                     elif choice == 'c':
                         self.run("cat %s"%tagsfile)
                     else:
                         name=self.name
                     elif choice == 'r':
                         build.revert(f=tagsfile)
                     elif choice == 'c':
                         self.run("cat %s"%tagsfile)
                     else:
                         name=self.name
-                        print """y: change %(name)s-SVNPATH only if it currently refers to %(old_tag_name)s
+                        print """y: change %(name)s-{SVNPATH,GITPATH} only if it currently refers to %(old_tag_name)s
 f: unconditionnally change any line that assigns %(name)s-SVNPATH to using %(new_tag_name)s
 d: show current diff for this tag file
 r: revert that tag file
 f: unconditionnally change any line that assigns %(name)s-SVNPATH to using %(new_tag_name)s
 d: show current diff for this tag file
 r: revert that tag file
@@ -969,7 +1033,10 @@ n: move to next file"""%locals()
             print self.repository.diff()
 
         def commit_all_changes(log):
             print self.repository.diff()
 
         def commit_all_changes(log):
-            self.repository.commit(log)
+            if hasattr(self,'branch'):
+                self.repository.commit(log, branch=self.branch)
+            else:
+                self.repository.commit(log)
             build.commit(log)
 
         self.run_prompt("Review module and build", diff_all_changes)
             build.commit(log)
 
         self.run_prompt("Review module and build", diff_all_changes)
@@ -998,6 +1065,7 @@ n: move to next file"""%locals()
                 return
             else:
                 self.html_print ("%-16s %s"%(varname,spec_dict[varname]))
                 return
             else:
                 self.html_print ("%-16s %s"%(varname,spec_dict[varname]))
+        self.html_print ("%-16s %s"%('url',self.repository.url()))
         if self.options.verbose:
             self.html_print ("%-16s %s"%('main specfile:',self.main_specname()))
             self.html_print ("%-16s %s"%('specfiles:',self.all_specnames()))
         if self.options.verbose:
             self.html_print ("%-16s %s"%('main specfile:',self.main_specname()))
             self.html_print ("%-16s %s"%('specfiles:',self.all_specnames()))
@@ -1123,6 +1191,141 @@ span.error {text-weight:bold; color: red; }
             print '<p class="top">',self.html_href('#','Back to top'),'</p>'            
 
 
             print '<p class="top">',self.html_href('#','Back to top'),'</p>'            
 
 
+
+class Build(Module):
+    
+    def __get_modules(self, tagfile):
+        self.init_module_dir()
+        modules = {}
+
+        tagfile = os.path.join(self.module_dir, tagfile)
+        for line in open(tagfile):
+            try:
+                name, url = line.split(':=')
+                name, git_or_svn_path = name.rsplit('-', 1)
+                name = svn_to_git_name(name.strip())
+                modules[name] = (git_or_svn_path.strip(), url.strip())
+            except:
+                pass
+        return modules
+
+    def get_modules(self, tagfile):
+        modules = self.__get_modules(tagfile)
+        for module in modules:
+            module_type = tag_or_branch = ""
+
+            path_type, url = modules[module]
+            if path_type == "GITPATH":
+                module_spec = os.path.split(url)[-1].replace(".git","")
+                name, tag_or_branch, module_type = self.parse_module_spec(module_spec)
+            else:
+                tag_or_branch = os.path.split(url)[-1].strip()
+                if url.find('/tags/') >= 0:
+                    module_type = "tag"
+                elif url.find('/branches/') >= 0:
+                    module_type = "branch"
+            
+            modules[module] = {"module_type" : module_type,
+                               "path_type": path_type,
+                               "tag_or_branch": tag_or_branch,
+                               "url":url}
+        return modules
+                
+        
+
+def modules_diff(first, second):
+    diff = {}
+
+    for module in first:
+        if module not in second: 
+            print "=== module %s missing in right-hand side ==="%module
+            continue
+        if first[module]['tag_or_branch'] != second[module]['tag_or_branch']:
+            diff[module] = (first[module]['tag_or_branch'], second[module]['tag_or_branch'])
+
+    first_set = set(first.keys())
+    second_set = set(second.keys())
+
+    new_modules = list(second_set - first_set)
+    removed_modules = list(first_set - second_set)
+
+    return diff, new_modules, removed_modules
+
+def release_changelog(options, buildtag_old, buildtag_new):
+
+    tagfile = options.distrotags[0]
+    if not tagfile:
+        print "ERROR: provide a tagfile name (eg. onelab, onelab-k27, planetlab)"
+        return
+    tagfile = "%s-tags.mk" % tagfile
+    
+    print '----'
+    print '----'
+    print '----'
+    print '= build tag %s to %s =' % (buildtag_old, buildtag_new)
+    print '== distro %s (%s to %s) ==' % (tagfile, buildtag_old, buildtag_new)
+
+    build = Build("build@%s" % buildtag_old, options)
+    build.init_module_dir()
+    first = build.get_modules(tagfile)
+
+    print ' * from', buildtag_old, build.repository.gitweb()
+
+    build = Build("build@%s" % buildtag_new, options)
+    build.init_module_dir()
+    second = build.get_modules(tagfile)
+
+    print ' * to', buildtag_new, build.repository.gitweb()
+
+    diff, new_modules, removed_modules = modules_diff(first, second)
+
+
+    def get_module(name, tag):
+        if not tag or  tag == "trunk":
+            return Module("%s" % (module), options)
+        else:
+            return Module("%s@%s" % (module, tag), options)
+
+
+    for module in diff:
+        print '=== %s - %s to %s : package %s ===' % (tagfile, buildtag_old, buildtag_new, module)
+
+        first, second = diff[module]
+        m = get_module(module, first)
+        os.system('rm -rf %s' % m.module_dir) # cleanup module dir
+        m.init_module_dir()
+
+        if m.repository.type == "svn":
+            print ' * from', first, m.repository.url()
+        else:
+            print ' * from', first, m.repository.gitweb()
+
+        specfile = m.main_specname()
+        (tmpfd, tmpfile) = tempfile.mkstemp()
+        os.system("cp -f /%s %s" % (specfile, tmpfile))
+        
+        m = get_module(module, second)
+        m.init_module_dir()
+        specfile = m.main_specname()
+
+        if m.repository.type == "svn":
+            print ' * to', second, m.repository.url()
+        else:
+            print ' * to', second, m.repository.gitweb()
+
+        print '{{{'
+        os.system("diff -u %s %s" % (tmpfile, specfile))
+        print '}}}'
+
+        os.unlink(tmpfile)
+
+    for module in new_modules:
+        print '=== %s : new package in build %s ===' % (tagfile, module)
+
+    for module in removed_modules:
+        print '=== %s : removed package from build %s ===' % (tagfile, module)
+
+
 ##############################
 class Main:
 
 ##############################
 class Main:
 
@@ -1267,42 +1470,46 @@ Branches:
         Module.init_homedir(options)
         
 
         Module.init_homedir(options)
         
 
-        modules=[ Module(modname,options) for modname in args ]
-        # hack: create a dummy Module to store errors/warnings
-        error_module = Module('__errors__',options)
+        if mode not in Main.release_modes:
+            modules=[ Module(modname,options) for modname in args ]
+            # hack: create a dummy Module to store errors/warnings
+            error_module = Module('__errors__',options)
 
 
-        for module in modules:
-            if len(args)>1 and mode not in Main.silent_modes:
-                if not options.www:
-                    print '========================================',module.friendly_name()
-            # call the method called do_<mode>
-            method=Module.__dict__["do_%s"%mode]
-            try:
-                method(module)
-            except Exception,e:
-                if options.www:
-                    title='<span class="error"> Skipping module %s - failure: %s </span>'%\
-                        (module.friendly_name(), str(e))
-                    error_module.html_store_title(title)
-                else:
-                    import traceback
-                    traceback.print_exc()
-                    print 'Skipping module %s: '%modname,e
-
-        if options.www:
-            if mode == "diff":
-                modetitle="Changes to tag in %s"%options.www
-            elif mode == "version":
-                modetitle="Latest tags in %s"%options.www
-            modules.append(error_module)
-            error_module.html_dump_header(modetitle)
-            for module in modules:
-                module.html_dump_toc()
-            Module.html_dump_middle()
             for module in modules:
             for module in modules:
-                module.html_dump_body()
-            Module.html_dump_footer()
-
+                if len(args)>1 and mode not in Main.silent_modes:
+                    if not options.www:
+                        print '========================================',module.friendly_name()
+                # call the method called do_<mode>
+                method=Module.__dict__["do_%s"%mode]
+                try:
+                    method(module)
+                except Exception,e:
+                    if options.www:
+                        title='<span class="error"> Skipping module %s - failure: %s </span>'%\
+                            (module.friendly_name(), str(e))
+                        error_module.html_store_title(title)
+                    else:
+                        import traceback
+                        traceback.print_exc()
+                        print 'Skipping module %s: '%modname,e
+    
+            if options.www:
+                if mode == "diff":
+                    modetitle="Changes to tag in %s"%options.www
+                elif mode == "version":
+                    modetitle="Latest tags in %s"%options.www
+                modules.append(error_module)
+                error_module.html_dump_header(modetitle)
+                for module in modules:
+                    module.html_dump_toc()
+                Module.html_dump_middle()
+                for module in modules:
+                    module.html_dump_body()
+                Module.html_dump_footer()
+        else:
+            release_changelog(options, *args)
+            
+    
 ####################
 if __name__ == "__main__" :
     try:
 ####################
 if __name__ == "__main__" :
     try: