You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@gump.apache.org by aj...@apache.org on 2003/12/01 18:34:08 UTC

cvs commit: jakarta-gump/python/gump/output rss.py

ajack       2003/12/01 09:34:08

  Modified:    python/gump engine.py gumprun.py
               python/gump/model module.py rawmodel.py ant.py project.py
               python/gump/document resolver.py text.py documenter.py
                        forrest.py
               python/gump/test model.py pyunit.py
               python/gump/test/resources/full1 profile.xml
               python/gump/output rss.py
  Added:       python/gump/test integrator.py maven.py syndicator.py
               python/gump/test/resources/full1 maven1.xml
  Log:
  1) First stab at adding a Maven command (setting build.properties)
  2) Created a per workspace/module/project RSS feed [user choice]
  3) Added a descriptor for directory-naming in incubator SVN
  
  Revision  Changes    Path
  1.29      +10 -2     jakarta-gump/python/gump/engine.py
  
  Index: engine.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/engine.py,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- engine.py	26 Nov 2003 20:01:15 -0000	1.28
  +++ engine.py	1 Dec 2003 17:34:07 -0000	1.29
  @@ -32,7 +32,7 @@
   from gump.output.statsdb import *
   from gump.output.repository import JarRepository
   from gump.output.nag import nag
  -from gump.output.rss import rss
  +from gump.output.rss import syndicate
   
   ###############################################################################
   # Initialize
  @@ -122,7 +122,7 @@
               nag(run)
     
               # Provide a news feed
  -            rss(run)
  +            syndicate(run)
   
           # Return an exit code based off success
           # :TODO: Move onto run
  @@ -421,6 +421,14 @@
                       log.error('PerformMkdir Failed', exc_info=1)    
                       project.changeState(STATE_FAILED,REASON_PREBUILD_FAILED)
                   
  +                
  +        if project.okToPerformWork() and project.hasMaven():
  +            try:
  +                project.generateMavenProperties()
  +            except:
  +                log.error('GenerateMavenProperties Failed', exc_info=1)    
  +                project.changeState(STATE_FAILED,REASON_PREBUILD_FAILED)
  +            
           if not project.okToPerformWork():
               log.warn('Failed to perform prebuild on project [' + project.getName() + ']')
   
  
  
  
  1.5       +9 -4      jakarta-gump/python/gump/gumprun.py
  
  Index: gumprun.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/gumprun.py,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- gumprun.py	24 Nov 2003 18:32:19 -0000	1.4
  +++ gumprun.py	1 Dec 2003 17:34:07 -0000	1.5
  @@ -24,11 +24,10 @@
   from gump.model.depend import  ProjectDependency
   from gump.model.state import *
   
  +from gump.document.text import TextDocumenter
   
   from gump.output.statsdb import *
   from gump.output.repository import JarRepository
  -from gump.output.nag import nag
  -from gump.output.rss import rss
   
   ###############################################################################
   # Initialize
  @@ -312,13 +311,16 @@
           self.verbose=0	
           
           
  -        self.documenter=None
  +        self.documenter=TextDocumenter()
   
       def setDocumenter(self, documenter):
           self.documenter = documenter
       
       def getDocumenter(self):
           return self.documenter
  +
  +    def getResolver(self):
  +        return self.getDocumenter().getResolver(self)
           
   class GumpRun(Workable,Annotatable,Stateful):
       def __init__(self,workspace,expr=None,options=None):
  @@ -335,7 +337,10 @@
           #
           # The run options
           #
  -        self.options=options
  +        if options:
  +            self.options=options
  +        else:
  +            self.options=GumpRunOptions()
           
           #
           # A repository interface...
  
  
  
  1.19      +13 -14    jakarta-gump/python/gump/model/module.py
  
  Index: module.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/model/module.py,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- module.py	25 Nov 2003 21:11:45 -0000	1.18
  +++ module.py	1 Dec 2003 17:34:07 -0000	1.19
  @@ -606,18 +606,7 @@
           # Prepare SVN checkout/update command...
           # 
           cmd=Cmd('svn','update_'+self.getName(),self.getWorkspace().cvsdir)
  -    
  -        if exists:
  -
  -            # do a cvs update
  -            cmd.addParameter('update')
  -
  -        else:
  -
  -            # do a cvs checkout
  -            cmd.addParameter('checkout')
  -            cmd.addParameter(url)
  -          
  +       
           #
           # Be 'quiet' (but not silent) unless requested otherwise.
           #
  @@ -626,14 +615,24 @@
               and not self.svn.isDebug()	\
               and not self.svn.isVerbose():    
               cmd.addParameter('--quiet')
  -          
  -          
  +                  
           #
           # Allow trace for debug
           #
           if self.isDebug() or  self.svn.isDebug():
               cmd.addParameter('--verbose')
               
  +        if exists:
  +
  +            # do a cvs update
  +            cmd.addParameter('update')
  +
  +        else:
  +
  +            # do a cvs checkout
  +            cmd.addParameter('checkout')
  +            cmd.addParameter(url)
  +       
           #
           # Request non-interactive
           #
  
  
  
  1.6       +8 -0      jakarta-gump/python/gump/model/rawmodel.py
  
  Index: rawmodel.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/model/rawmodel.py,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- rawmodel.py	23 Nov 2003 06:16:39 -0000	1.5
  +++ rawmodel.py	1 Dec 2003 17:34:07 -0000	1.6
  @@ -165,6 +165,7 @@
     list={}
     def init(self):
       self.ant=Single(XMLAnt)
  +    self.maven=Single(XMLAnt)
       self.script=Single(XMLScript)
       self.depend=Multiple(XMLDepend)
       self.description=Single(GumpXMLModelObject)
  @@ -189,6 +190,13 @@
     
   # represents an <ant/> element
   class XMLAnt(GumpXMLModelObject):
  +  def init(self):  
  +    self.depend=Multiple(XMLDepend)
  +    self.property=Multiple(XMLProperty)
  +    self.jvmarg=Multiple(GumpXMLModelObject)
  +
  +# represents a <maven/> element
  +class XMLMaven(GumpXMLModelObject):
     def init(self):  
       self.depend=Multiple(XMLDepend)
       self.property=Multiple(XMLProperty)
  
  
  
  1.8       +42 -15    jakarta-gump/python/gump/model/ant.py
  
  Index: ant.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/model/ant.py,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ant.py	20 Nov 2003 20:51:48 -0000	1.7
  +++ ant.py	1 Dec 2003 17:34:07 -0000	1.8
  @@ -76,21 +76,15 @@
          
   
   # represents an <ant/> element
  -class Ant(ModelObject, PropertyContainer):
  +class AntBuilder(ModelObject, PropertyContainer):
       """ An Ant command (within a project)"""
       def __init__(self,xml,project):
       	ModelObject.__init__(self,xml,project)
       	PropertyContainer.__init__(self)
  -    
  -        # Import the target
  -    	self.target='gump'
  -    	if xml.target:
  -    	    self.target=xml.target
  +        	    
       	    
  -        # Import the buildfile
  -    	self.buildfile='build.xml'
  -    	if xml.buildfile:
  -    	    self.buildfile=xml.buildfile    	
  +        # Store owning project
  +        self.project=project
       	
       	
       #
  @@ -173,11 +167,6 @@
               # Store it
               self.expandProperty(property,project,workspace)      
   
  -    def getTarget(self):
  -        return self.target
  -        
  -    def getBuildFile(self):
  -        return self.buildfile
           
       #
       # complete the definition - it is safe to reference other projects
  @@ -206,3 +195,41 @@
           PropertyContainer.dump(self,indent+1,output)
    
    
  +       
  +
  +# represents an <ant/> element
  +class Ant(AntBuilder):
  +    """ An Ant command (within a project)"""
  +    def __init__(self,xml,project):
  +    	AntBuilder.__init__(self,xml,project)
  +      
  +        # Import the target
  +    	self.target='gump'
  +    	if xml.target:
  +    	    self.target=xml.target
  +    	    
  +        # Import the buildfile
  +    	self.buildfile='build.xml'
  +    	if xml.buildfile:
  +    	    self.buildfile=xml.buildfile    
  +    	    
  +    def getTarget(self):
  +        return self.target
  +        
  +    def getBuildFile(self):
  +        return self.buildfile
  +
  +# represents an <maven/> element
  +class Maven(AntBuilder):
  +    """ A Maven command (within a project)"""
  +    def __init__(self,xml,project):
  +    	AntBuilder.__init__(self,xml,project)
  +    	
  +        # Import the goal
  +    	self.goal='gump'
  +    	if xml.goal:
  +    	    self.goal=xml.goal
  +            	    
  +    def getGoal(self):
  +        return self.goal
  +    	
  \ No newline at end of file
  
  
  
  1.18      +167 -12   jakarta-gump/python/gump/model/project.py
  
  Index: project.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/model/project.py,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- project.py	26 Nov 2003 01:26:28 -0000	1.17
  +++ project.py	1 Dec 2003 17:34:07 -0000	1.18
  @@ -68,7 +68,7 @@
   from gump.model.object import ModelObject, NamedModelObject, Jar
   from gump.model.stats import Statable, Statistics
   from gump.model.property import Property
  -from gump.model.ant import Ant
  +from gump.model.ant import Ant,Maven
   from gump.model.rawmodel import Single
   from gump.utils import getIndent
   from gump.model.depend import *
  @@ -79,7 +79,8 @@
   #
   class AnnotatedPath:
       """Contains a Path plus optional 'contributor' """
  -    def __init__(self,path,contributor=None,instigator=None,note=None):
  +    def __init__(self,id,path,contributor=None,instigator=None,note=None):
  +        self.id=id
           self.path=path
           self.contributor=contributor
           self.instigator=instigator
  @@ -109,13 +110,22 @@
           return c
           
       def hasContributor(self):
  -        return self.contributor
  +        if self.contributor: return 1
  +        return 0
           
       def getContributor(self):
           return self.contributor
           
  +    def hasId(self):
  +        if self.id: return 1
  +        return 0
  +        
  +    def getId(self):
  +        return self.id
  +        
       def hasInstigator(self):
  -        return self.instigator
  +        if self.instigator: return 1
  +        return 0
           
       def getInstigator(self):
           return self.instigator
  @@ -196,6 +206,7 @@
       	# Sub-Components
       	#
       	self.ant=None
  +    	self.maven=None
       	self.script=None
   
       	
  @@ -209,9 +220,25 @@
       	#        
           self.honoraryPackage=0
           
  +    def hasAnt(self):
  +        if hasattr(self,'ant'): return 1
  +        return 0
  +        
  +    def hasMaven(self):
  +        if hasattr(self,'maven'): return 1
  +        return 0
  +        
  +    def hasScript(self):
  +        if hasattr(self,'script'): return 1
  +        return 0
  +    
  +      
       def getAnt(self):
           return self.ant
           
  +    def getMaven(self):
  +        return self.maven
  +        
       def getScript(self):
           return self.script
       
  @@ -347,6 +374,10 @@
           if self.xml.ant and not packaged:
               self.ant = Ant(self.xml.ant,self)
           
  +        # Import any <maven part [if not packaged]
  +        if self.xml.maven and not packaged:
  +            self.maven = Maven(self.xml.maven,self)
  +        
           # :TODO: Scripts
           
           # Compute home directory
  @@ -394,8 +425,9 @@
   
           # Expand <ant <depends/<properties...
           if self.ant: self.ant.expand(self,workspace)
  +        if self.maven: self.maven.expand(self,workspace)
   
  -        # Build Dependencies Map [including depends from <ant/<property/<depend
  +        # Build Dependencies Map [including depends from <ant|maven/<property/<depend
           if not packaged:
               (badDepends, badOptions) = self.buildDependenciesMap(workspace)
           
  @@ -405,6 +437,7 @@
           
               # complete properties
               if self.ant: self.ant.complete(self,workspace)
  +            if self.maven: self.maven.complete(self,workspace)
       
               #
               # TODO -- move these back?
  @@ -481,7 +514,7 @@
                   badOptions.append(xmloption)
           
           #
  -        # Provide backwards links  [Note: ant might have added some
  +        # Provide backwards links  [Note: ant|maven might have added some
           # dependencies, so this is done here * not just with the direct
           # xml depend/option elements]
           #
  @@ -556,7 +589,7 @@
       def hasBuildCommand(self):
           hasBuild=0
           # I.e has an <ant or <script element
  -        if self.xml.ant or self.xml.script: hasBuild=1    
  +        if self.xml.ant or self.xml.script or self.xml.maven: hasBuild=1    
           return hasBuild
   
       def getBuildCommand(self):
  @@ -564,15 +597,20 @@
           # get the ant element (if it exests)
           ant=self.xml.ant
   
  +        # get the maven element (if it exests)
  +        maven=self.xml.maven
  +
           # get the script element (if it exists)
           script=self.xml.script
   
  -        if not (script or ant):
  -          #  log.debug('Not building ' + project.name + ' (no <ant/> or <script/> specified)')
  +        if not (script or ant or maven):
  +          #  log.debug('Not building ' + project.name + ' (no <ant/> or <maven/> or <script/> specified)')
             return None
   
           if script and script.name:
               return self.getScriptCommand()
  +        elif maven :
  +            return self.getMavenCommand()
           else:
               return self.getAntCommand()
           
  @@ -661,6 +699,77 @@
       
           return cmd
   
  +    #
  +    # Build an ANT command for this project
  +    #        
  +    def getMavenCommand(self):
  +        maven=self.xml.maven
  +    
  +        # The ant goal (or none == ant default goal)
  +        goal=maven.goal or ''
  +    
  +        # Optional 'verbose' or 'debug'
  +        verbose=maven.verbose
  +        debug=maven.debug
  +    
  +        #
  +        # Where to run this:
  +        #
  +        #	The module src directory (if exists) or Gump base
  +        #	plus:
  +        #	The specifier for ANT, or nothing.
  +        #
  +        basedir = os.path.normpath(os.path.join(self.getModule().getSourceDirectory() or dir.base,	\
  +                                                    maven.basedir or ''))
  +    
  +        #
  +        # Build a classpath (based upon dependencies)
  +        #
  +        (classpath,bootclasspath)=self.getClasspaths()
  +    
  +        #
  +        # Get properties
  +        #
  +        jvmargs=self.getJVMArgs()
  +   
  +        #
  +        # Run java on apache Ant...
  +        #
  +        cmd=Cmd(self.getWorkspace().getJavaCommand(),'build_'+self.getModule().getName()+'_'+self.getName(),\
  +            basedir,{'CLASSPATH':classpath})
  +            
  +        # Set this as a system property. Setting it here helps JDK1.4+
  +        # AWT implementations cope w/o an X11 server running (e.g. on
  +        # Linux)
  +        cmd.addPrefixedParameter('-D','java.awt.headless','true','=')
  +    
  +        #
  +        # Add BOOTCLASSPATH
  +        #
  +        if bootclasspath:
  +            cmd.addPrefixedParameter('-X','bootclasspath/p',bootclasspath,':')
  +            
  +        if jvmargs:
  +            cmd.addParameters(jvmargs)
  +            
  +        cmd.addParameter('org.apache.tools.ant.Main')  
  +    
  +        #
  +        # Allow ant-level debugging...
  +        #
  +        if debug: cmd.addParameter('--debug')  
  +        if verbose: cmd.addParameter('--exception')  
  +        
  +        #
  +        #	This sets the *defaults*, a workspace could override them.
  +        #
  +        cmd.addPrefixedParameter('-D','build.sysclasspath','only','=')
  +    
  +        # End with the goal...
  +        if goal: cmd.addParameter(goal)
  +    
  +        return cmd
  +
   
       def getJVMArgs(self):
           """Get JVM arguments for a project"""
  @@ -680,6 +789,52 @@
               properties.addPrefixedNamedParameter('-D',property.name,property.value,'=')
           return properties
   
  +    def generateMavenProperties(self):
  +        """Set properties for a project"""
  +        
  +        propertiesFile=os.path.abspath(os.path.join(\
  +                self.getModule().getSourceDirectory(),'build.properties'))
  +        
  +        if os.path.exists(propertiesFile):
  +            self.addWarning('Overriding Maven properties: ['+propertiesFile+']')
  +    
  +        
  +        props=open(propertiesFile,'w')
  +        
  +        props.write("""# ------------------------------------------------------------------------
  +# Gump generated properties file
  +# ------------------------------------------------------------------------
  +""")
  +        
  +        #
  +        # Output basic properties
  +        #
  +        for property in self.getWorkspace().getProperties()+self.getMaven().getProperties():
  +            props.write(('%s=%s\n') % (property.name,property.value))            
  +        
  +        #
  +        # Output classpath properties
  +        #
  +        props.write("""
  +        # ------------------------------------------------------------------------
  +# M A V E N  J A R  O V E R R I D E
  +# ------------------------------------------------------------------------
  +maven.jar.override = on
  +
  +# ------------------------------------------------------------------------
  +# Jars set explicity by path.
  +# ------------------------------------------------------------------------
  +        """)
  +        
  +        (classpath,bootclasspath)=self.getClasspathLists()
  +        # :TODO: write...
  +        for annotatedPath in classpath.getPathParts():
  +            if isinstance(annotatedPath,AnnotatedPath):
  +                id=annotatedPath.getId()
  +                path=annotatedPath.getPath()
  +                props.write(('maven.jar.%s=%s') % (id,path))
  +
  +
       def getScriptCommand(self):
           """ Return the command object for a <script entry """
           script=self.xml.script 
  @@ -744,7 +899,7 @@
           outputs=[]
           for jar in self.getJars():
               jarpath=jar.getPath()
  -            outputs.append(AnnotatedPath(jar,self,None,"Project output"))                    
  +            outputs.append(AnnotatedPath(jar.getId(),jarpath,self,None,"Project output"))                    
           return outputs
                    
       #
  @@ -824,7 +979,7 @@
   
               if path:
                   if debug: print "Work Entity:   " + path               
  -                classpath.addPathPart(AnnotatedPath(path,self,None,'Work Entity'))
  +                classpath.addPathPart(AnnotatedPath('',path,self,None,'Work Entity'))
                 
           # Append dependent projects (including optional)
           visited=[]
  @@ -915,7 +1070,7 @@
               # If 'all' or in ids list:
               if (not ids) or (jar.getId() in ids):   
                   if ids: dependStr += ' Id = ' + jar.getId()
  -                path=AnnotatedPath(jar.path,project,dependency.getOwnerProject(),dependStr) 
  +                path=AnnotatedPath(jar.getId(),jar.path,project,dependency.getOwnerProject(),dependStr) 
             
                   # Add to CLASSPATH
                   if not jar.getType() == 'boot':
  
  
  
  1.4       +4 -4      jakarta-gump/python/gump/document/resolver.py
  
  Index: resolver.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/document/resolver.py,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- resolver.py	20 Nov 2003 20:51:50 -0000	1.3
  +++ resolver.py	1 Dec 2003 17:34:07 -0000	1.4
  @@ -354,9 +354,9 @@
       def getDirectoryUrl(self,object):
           return self.getAbsoluteDirectory(object)
           
  -    def getFile(self,object,documentName=None):
  -        return self.getAbsoluteFile(object,documentName)
  +    def getFile(self,object,documentName=None,extn='.xml'):
  +        return self.getAbsoluteFile(object,documentName,extn)
           
  -    def getUrl(self,object,documentName=None):
  -        return self.getAbsoluteUrl(object,documentName=None)
  +    def getUrl(self,object,documentName=None,extn='.html'):
  +        return self.getAbsoluteUrl(object,documentName,extn)
           
  
  
  
  1.3       +8 -1      jakarta-gump/python/gump/document/text.py
  
  Index: text.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/document/text.py,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- text.py	20 Nov 2003 20:51:50 -0000	1.2
  +++ text.py	1 Dec 2003 17:34:07 -0000	1.3
  @@ -75,12 +75,19 @@
   from gump.model.state import *
   
   from gump.document.documenter import Documenter
  +from gump.document.resolver import *
   
   class TextDocumenter(Documenter):
       
  -    def __init__(self,output=sys.stdout):
  +    def __init__(self,output=sys.stdout, dirBase='.', urlBase='.'):
           Documenter.__init__(self)
           self.output=output
  +        
  +        # Hack, ought return a non-hierarchical one
  +        self.resolver=Resolver(dirBase,urlBase)
  +        
  +    def getResolverForRun(self,run):
  +        return self.resolver
       
       def documentRun(self, run):    
           indent=' '
  
  
  
  1.6       +10 -1     jakarta-gump/python/gump/document/documenter.py
  
  Index: documenter.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/document/documenter.py,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- documenter.py	20 Nov 2003 20:51:50 -0000	1.5
  +++ documenter.py	1 Dec 2003 17:34:07 -0000	1.6
  @@ -85,4 +85,13 @@
           
           log.info('Document run using [' + `self` + ']')
           
  -        self.documentRun(run)
  \ No newline at end of file
  +        self.documentRun(run)
  +        
  +    def getResolver(self,run):
  +        if not hasattr(self,'getResolverForRun'):
  +            raise RuntimeException, 'Complete [' + self.__class__ + '] with getResolverForRun(self,run)'
  +        
  +        if not callable(self.getResolverForRun):
  +            raise RuntimeException, 'Complete [' + self.__class__ + '] with a callable getResolverForRun(self,run)'
  +            
  +        return self.getResolverForRun(run)
  \ No newline at end of file
  
  
  
  1.20      +3 -0      jakarta-gump/python/gump/document/forrest.py
  
  Index: forrest.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/document/forrest.py,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- forrest.py	26 Nov 2003 20:01:16 -0000	1.19
  +++ forrest.py	1 Dec 2003 17:34:07 -0000	1.20
  @@ -97,6 +97,9 @@
       def __init__(self, dirBase, urlBase):
           Documenter.__init__(self)            
           self.resolver=Resolver(dirBase,urlBase)
  +        
  +    def getResolverForRun(self,run):
  +        return self.resolver
       
       def documentRun(self, run):
       
  
  
  
  1.8       +6 -0      jakarta-gump/python/gump/test/model.py
  
  Index: model.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/test/model.py,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- model.py	24 Nov 2003 23:05:37 -0000	1.7
  +++ model.py	1 Dec 2003 17:34:08 -0000	1.8
  @@ -95,6 +95,7 @@
           self.project4=self.workspace.getProject('project4')
           self.project5=self.workspace.getProject('project5')
           self.alias1=self.workspace.getProject('alias1')
  +        self.maven1=self.workspace.getProject('maven1')
           
           self.packagedModule1=self.workspace.getModule('package1')        
           self.module1=self.workspace.getModule('module1')
  @@ -199,4 +200,9 @@
           (classpath,bootclasspath)=self.project5.getClasspaths(1)        
           print "Classpath:" + classpath     
           print "Bootclasspath:" + bootclasspath
  +        
  +    def testMaven(self):
  +                
  +        self.assertTrue('Maven project has a Maven object', self.maven1.hasMaven())
  +        
           
  
  
  
  1.10      +9 -0      jakarta-gump/python/gump/test/pyunit.py
  
  Index: pyunit.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/test/pyunit.py,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- pyunit.py	26 Nov 2003 01:26:28 -0000	1.9
  +++ pyunit.py	1 Dec 2003 17:34:08 -0000	1.10
  @@ -320,6 +320,15 @@
       from gump.test.updater import UpdaterTestSuite  
       runner.addSuite(UpdaterTestSuite())
       
  +    from gump.test.syndicator import SyndicatorTestSuite  
  +    runner.addSuite(SyndicatorTestSuite())
  +    
  +    from gump.test.maven import MavenTestSuite  
  +    runner.addSuite(MavenTestSuite())
  +    
  +    #from gump.test.integrator import IntegratorTestSuite  
  +    #runner.addSuite(IntegratorTestSuite())
  +    
       # Any args are pattern matches
       patterns=list(sys.argv)
       del patterns[0:1]
  
  
  
  1.1                  jakarta-gump/python/gump/test/integrator.py
  
  Index: integrator.py
  ===================================================================
  #!/usr/bin/env python
  # $Header:  1.7 2003/05/10 18:20:36 nicolaken Exp $
  # $Revision: 1.7 $
  # $Date: 2003/05/10 18:20:36 $
  #
  # ====================================================================
  #
  # The Apache Software License, Version 1.1
  #
  # Copyright (c) 2003 The Apache Software Foundation.  All rights
  # reserved.
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions
  # are met:
  #
  # 1. Redistributions of source code must retain the above copyright
  #    notice, this list of conditions and the following disclaimer.
  #
  # 2. Redistributions in binary form must reproduce the above copyright
  #    notice, this list of conditions and the following disclaimer in
  #    the documentation and/or other materials provided with the
  #    distribution.
  #
  # 3. The end-user documentation included with the redistribution, if
  #    any, must include the following acknowlegement:
  #       "This product includes software developed by the
  #        Apache Software Foundation (http://www.apache.org/)."
  #    Alternately, this acknowlegement may appear in the software itself,
  #    if and wherever such third-party acknowlegements normally appear.
  #
  # 4. The names "The Jakarta Project", "Alexandria", and "Apache Software
  #    Foundation" must not be used to endorse or promote products derived
  #    from this software without prior written permission. For written
  #    permission, please contact apache@apache.org.
  #
  # 5. Products derived from this software may not be called "Apache"
  #    nor may "Apache" appear in their names without prior written
  #    permission of the Apache Group.
  #
  # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  # DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  # SUCH DAMAGE.
  # ====================================================================
  #
  # This software consists of voluntary contributions made by many
  # individuals on behalf of the Apache Software Foundation.  For more
  # information on the Apache Software Foundation, please see
  # <http://www.apache.org/>.
  
  """
      Model Testing
  """
  
  import os
  import logging
  import types, StringIO
  
  from gump import log
  import gump.config
  from gump.gumprun import GumpRun
  from gump.engine import GumpEngine
  from gump.output.rss import syndicate
  from gump.test import getWorkedTestWorkspace
  from gump.test.pyunit import UnitTestSuite
  
  class IntegratorTestSuite(UnitTestSuite):
      def __init__(self):
          UnitTestSuite.__init__(self)
          
      def suiteSetUp(self):
          #
          # Load a decent Workspace
          #
          self.workspace=getWorkedTestWorkspace()          
          self.assertNotNone('Needed a workspace', self.workspace)
          self.run=GumpRun(self.workspace)
          
      def testIntegrate(self):   
          #
          #    Perform this integration run...
          #
          result = GumpEngine().integrate(self.run)
          
  
  
  1.1                  jakarta-gump/python/gump/test/maven.py
  
  Index: maven.py
  ===================================================================
  #!/usr/bin/env python
  # $Header:  1.7 2003/05/10 18:20:36 nicolaken Exp $
  # $Revision: 1.7 $
  # $Date: 2003/05/10 18:20:36 $
  #
  # ====================================================================
  #
  # The Apache Software License, Version 1.1
  #
  # Copyright (c) 2003 The Apache Software Foundation.  All rights
  # reserved.
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions
  # are met:
  #
  # 1. Redistributions of source code must retain the above copyright
  #    notice, this list of conditions and the following disclaimer.
  #
  # 2. Redistributions in binary form must reproduce the above copyright
  #    notice, this list of conditions and the following disclaimer in
  #    the documentation and/or other materials provided with the
  #    distribution.
  #
  # 3. The end-user documentation included with the redistribution, if
  #    any, must include the following acknowlegement:
  #       "This product includes software developed by the
  #        Apache Software Foundation (http://www.apache.org/)."
  #    Alternately, this acknowlegement may appear in the software itself,
  #    if and wherever such third-party acknowlegements normally appear.
  #
  # 4. The names "The Jakarta Project", "Alexandria", and "Apache Software
  #    Foundation" must not be used to endorse or promote products derived
  #    from this software without prior written permission. For written
  #    permission, please contact apache@apache.org.
  #
  # 5. Products derived from this software may not be called "Apache"
  #    nor may "Apache" appear in their names without prior written
  #    permission of the Apache Group.
  #
  # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  # DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  # SUCH DAMAGE.
  # ====================================================================
  #
  # This software consists of voluntary contributions made by many
  # individuals on behalf of the Apache Software Foundation.  For more
  # information on the Apache Software Foundation, please see
  # <http://www.apache.org/>.
  
  """
      Model Testing
  """
  
  import os
  import logging
  import types, StringIO
  
  from gump import log
  import gump.config
  from gump.model.state import *
  from gump.model.loader import WorkspaceLoader
  from gump.utils import *
  from gump.test import getWorkedTestWorkspace
  from gump.test.pyunit import UnitTestSuite
  
  class MavenTestSuite(UnitTestSuite):
      def __init__(self):
          UnitTestSuite.__init__(self)
          
      def suiteSetUp(self):
          #
          # Load a decent Workspace
          #
          self.workspace=getWorkedTestWorkspace() 
           
          self.assertNotNone('Needed a workspace', self.workspace)            
          self.maven1=self.workspace.getProject('maven1')            
          
          
      def testMavenProperties(self):
                  
          self.assertTrue('Maven project has a Maven object', self.maven1.hasMaven())
          
          self.maven1.generateMavenProperties()
          
          
  
  
  1.1                  jakarta-gump/python/gump/test/syndicator.py
  
  Index: syndicator.py
  ===================================================================
  #!/usr/bin/env python
  # $Header:  1.7 2003/05/10 18:20:36 nicolaken Exp $
  # $Revision: 1.7 $
  # $Date: 2003/05/10 18:20:36 $
  #
  # ====================================================================
  #
  # The Apache Software License, Version 1.1
  #
  # Copyright (c) 2003 The Apache Software Foundation.  All rights
  # reserved.
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions
  # are met:
  #
  # 1. Redistributions of source code must retain the above copyright
  #    notice, this list of conditions and the following disclaimer.
  #
  # 2. Redistributions in binary form must reproduce the above copyright
  #    notice, this list of conditions and the following disclaimer in
  #    the documentation and/or other materials provided with the
  #    distribution.
  #
  # 3. The end-user documentation included with the redistribution, if
  #    any, must include the following acknowlegement:
  #       "This product includes software developed by the
  #        Apache Software Foundation (http://www.apache.org/)."
  #    Alternately, this acknowlegement may appear in the software itself,
  #    if and wherever such third-party acknowlegements normally appear.
  #
  # 4. The names "The Jakarta Project", "Alexandria", and "Apache Software
  #    Foundation" must not be used to endorse or promote products derived
  #    from this software without prior written permission. For written
  #    permission, please contact apache@apache.org.
  #
  # 5. Products derived from this software may not be called "Apache"
  #    nor may "Apache" appear in their names without prior written
  #    permission of the Apache Group.
  #
  # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  # DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  # SUCH DAMAGE.
  # ====================================================================
  #
  # This software consists of voluntary contributions made by many
  # individuals on behalf of the Apache Software Foundation.  For more
  # information on the Apache Software Foundation, please see
  # <http://www.apache.org/>.
  
  """
      Model Testing
  """
  
  import os
  import logging
  import types, StringIO
  
  from gump import log
  import gump.config
  from gump.gumprun import GumpRun
  from gump.output.rss import syndicate
  from gump.test import getWorkedTestWorkspace
  from gump.test.pyunit import UnitTestSuite
  
  class SyndicatorTestSuite(UnitTestSuite):
      def __init__(self):
          UnitTestSuite.__init__(self)
          
      def suiteSetUp(self):
          #
          # Load a decent Workspace
          #
          self.workspace=getWorkedTestWorkspace()          
          self.assertNotNone('Needed a workspace', self.workspace)
          self.run=GumpRun(self.workspace)
          
      def testRSS(self):
          syndicate(self.run)
          
  
  
  1.3       +3 -0      jakarta-gump/python/gump/test/resources/full1/profile.xml
  
  Index: profile.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/test/resources/full1/profile.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- profile.xml	24 Nov 2003 01:45:15 -0000	1.2
  +++ profile.xml	1 Dec 2003 17:34:08 -0000	1.3
  @@ -2,13 +2,16 @@
   
     <module href="package1.xml"/>
     <module href="download1.xml"/>
  +  
     <module href="alias1.xml"/>
     <module href="module1.xml"/>
     <module href="module2.xml"/>
     <module href="module3.xml"/>
     <module href="module4.xml"/>
     <module href="module5.xml"/>
  +  
     <module href="svn_module1.xml"/>
  +  <module href="maven1.xml"/>
   
     <!-- Repository definitions -->
   
  
  
  
  1.1                  jakarta-gump/python/gump/test/resources/full1/maven1.xml
  
  Index: maven1.xml
  ===================================================================
  <module name="maven1">
  
    <url  href="http://ant.apache.org/index.html"/>
    <description>
      Java based build tool
    </description>
  
    <cvs repository="repository1"/>
  
    <project name="maven1">
      <package>org.apache.tools.ant</package>
  
      <maven target="gump"/>
  
      <option project="random"/>
  
      <home nested="dist"/>
  
      <jar name="lib/output1.jar" id="output1"/>
  
      <license name="LICENSE"/>
  
      <nag from="Gump Integration Build &lt;dev@ant.apache.org&gt;"
           to="dev@ant.apache.org"/>
    </project>
  </module>
  
  
  
  
  1.7       +226 -63   jakarta-gump/python/gump/output/rss.py
  
  Index: rss.py
  ===================================================================
  RCS file: /home/cvs/jakarta-gump/python/gump/output/rss.py,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- rss.py	20 Nov 2003 20:51:48 -0000	1.6
  +++ rss.py	1 Dec 2003 17:34:08 -0000	1.7
  @@ -65,6 +65,8 @@
   import os
   import time
   
  +from xml.sax.saxutils import escape
  +
   from gump import log
   from gump.model.state import *
   from gump.model.project import ProjectStatistics
  @@ -77,85 +79,246 @@
   
   ###############################################################################
   
  -def rss(run):
  -    
  -    workspace=run.getWorkspace() 
  +class Image:
  +    def __init__(self,url,title,link):
  +        self.url=url    
  +        self.title=title
  +        self.link=link
  +                
  +    def startItem(self):
  +        self.rssStream.write('   <image>\n')
  +        
  +        # Mandatory Fields
  +        self.rssStream.write(('  <url>%s</url>\n') %(escape(self.url)))
  +        self.rssStream.write(('  <link>%s</link>\n') %(escape(self.link)))
  +        self.rssStream.write(('  <title>%s</title>\n') %(escape(self.title)))
               
  -    rssFile=os.path.abspath(os.path.join(workspace.logdir,'index.rss'))
  -    
  -    gumprss = open(rssFile,'w')
  -    gumprss.write(("""<rss version="2.0"
  -  xmlns:admin="http://webns.net/mvcb/" 
  -  xmlns:dc="http://purl.org/dc/elements/1.1/" 
  -  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  -  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
  -
  -  <channel>
  -    <title>Jakarta Gump : %s</title>
  -    <link>http://jakarta.apache.org/gump/</link>
  -    <description>Life is like a box of chocolates</description>
  +    def endItem(self):
  +        self.rssStream.write('  </image>\n')
  +        
  +    def serialize(self,rssStream):
  +        self.rssStream = rssStream
  +        
  +        self.rssStream.write('   <image>\n')
  +        
  +        # Mandatory Fields
  +        self.rssStream.write(('  <url>%s</url>\n') %(escape(self.url)))
  +        self.rssStream.write(('  <link>%s</link>\n') %(escape(self.link)))
  +        self.rssStream.write(('  <title>%s</title>\n') %(escape(self.title)))
  +            
  +        self.rssStream.write('  </image>\n')
   
  +class Item:
  +    def __init__(self,title,link,description,subject,date,url=None,image=None):
  +        self.title=title
  +        self.link=link
  +        self.description=description
  +        self.subject=subject
  +        self.date=date
  +        self.url=url
  +        self.image=image
  +        
  +    def serialize(self,rssStream):
  +        self.rssStream = rssStream       
  +        
  +        self.rssStream.write('   <item>\n')
  +        
  +        # Mandatory Fields
  +        self.rssStream.write(('    <title>Jakarta Gump: %s</title>\n') %(escape(self.title)))
  +        self.rssStream.write(('    <link>%s</link>\n') %(escape(self.link)))
  +        self.rssStream.write(('    <description>%s</description>\n') %(escape(self.description)))
  +        self.rssStream.write(('      <dc:subject>%s</dc:subject>\n') %(escape(self.subject)))
  +        self.rssStream.write(('      <dc:date>%s</dc:date>\n') %(escape(self.date)))
  +        
  +        # Optional Fields
  +        if self.image:
  +            self.rssStream.write(('  <image>%s</image>\n') %(escape(self.image)))
  +        if self.url:
  +            self.rssStream.write(('  <url>%s</url>\n') %(escape(self.url)))
  +            
  +        self.rssStream.write('  </item>\n')
  +    
  +class Channel:
  +    def __init__(self,title,link,description,image=None):
  +        self.title=title
  +        self.link=link
  +        self.description=description
  +        self.image=image
  +        
  +        self.items=[]
  +            
  +        
  +    def startChannel(self): 
  +        
  +        self.rssStream.write('  <channel>\n')
  +        
  +        # Mandatory Fields
  +        self.rssStream.write(('  <title>Jakarta Gump: %s</title>\n') %(escape(self.title)))
  +        self.rssStream.write(('  <link>%s</link>\n') %(escape(self.link)))
  +        self.rssStream.write(('  <description>%s</description>\n') %(escape(self.description)))
  +        
  +        # Optional Fields
  +        if self.image:
  +            self.image.serialize(self.rssStream)
  +        
  +        # Admin stuff
  +        self.rssStream.write("""
       <admin:generatorAgent rdf:resource="http://cvs.apache.org/viewcvs/jakarta-gump/python/gump/output/rss.py"/>
       <admin:errorReportsTo rdf:resource="mailto:gump@jakarta.apache.org"/>
   
       <sy:updateFrequency>1</sy:updateFrequency>
  -    <sy:updatePeriod>daily</sy:updatePeriod>""") % \
  -        ( workspace.prefix ) )
  +    <sy:updatePeriod>daily</sy:updatePeriod>
  +""")
  +            
  +    def endChannel(self):
  +        self.rssStream.write('  </channel>\n')
  +        
  +    def serialize(self,rssStream):
  +        self.rssStream = rssStream
  +        
  +        self.startChannel()
  +        
  +        # Serialize all items
  +        for item in self.items:
  +            item.serialize(self.rssStream)
  +            
  +        self.endChannel()
  +        
  +    def addItem(self,item):
  +        self.items.append(item)
  +    
  +class RSS:
  +    def __init__(self,file,channel=None):
  +        self.rssFile=file
  +        
  +        self.channels=[]
           
  -    for module in workspace.getModules():
  -        if not module.isSuccess():
  -                for project in module.getProjects():                            
  +        if channel: self.addChannel(channel)
  +
  +    def startRSS(self):
  +        self.rssStream.write("""<rss version="2.0"
  +  xmlns:admin="http://webns.net/mvcb/" 
  +  xmlns:dc="http://purl.org/dc/elements/1.1/" 
  +  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  +  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">""")
                   
  -                    s=project.getStats()
  -                    
  -                    # State changes that are newsworthy...
  -                    if 	s.sequenceInState == 1	\
  -                        and not s.currentState == STATE_PREREQ_FAILED \
  -                        and not s.currentState == STATE_NONE \
  -                        and not s.currentState == STATE_COMPLETE :
  -                            
  -                        log.info("RSS written for " + project.getName()); 
  +    def endRSS(self):                    
  +        # complete the rss feed
  +        self.rssStream.write('</rss>')
  +                
  +        log.info("RSS Newsfeed written to : " + self.rssFile);          
  +        
  +    def serialize(self):
  +        log.info("RSS Newsfeed to : " + self.rssFile);         
  +        self.rssStream = open(self.rssFile,'w')
  +        
  +        self.startRSS()
  +        
  +        for channel in self.channels:
  +            channel.serialize(self.rssStream)
  +        
  +        self.endRSS()
  +        
  +        # Close the file.
  +        self.rssStream.close()  
  +  
  +    def addChannel(self,channel):
  +        self.channels.append(channel)
  +        
  +    def getCurrentChannel(self):
  +        return self.channels[len(self.channels)-1]
  +        
  +    def addItem(self,item,channel=None):
  +        if not channel: channel = self.getCurrentChannel()
  +        channel.addItem(item)
  +           
  +class Syndicator:
  +    def __init__(self):
  +        pass
  +        
  +    def syndicate(self,run):
  +        
  +        # Main syndication document
  +        self.run = run
  +        self.workspace=run.getWorkspace()   
  +        self.rssFile=os.path.abspath(os.path.join(	\
  +                    self.workspace.logdir,'index.rss'))
  +    
  +        self.rss=RSS(self.rssFile,	\
  +            Channel(self.workspace.logurl,	\
  +                    'Jakarta Gump',		\
  +                    """Life is like a box of chocolates""", \
  +                Image('http://jakarta.apache.org/images/bench.png',	\
  +                    'Jakarta Gump', \
  +                    'http://jakarta.apache.org/')))
  +        
  +        # build information 
  +        for module in self.workspace.getModules():
  +            self.syndicateModule(module,self.rss)
  +            
  +        self.rss.serialize()
  +        
  +    def syndicateModule(self,module,mainRSS):
  +        
  +        rssFile=self.run.getOptions().getResolver().getFile(module,'index','.rss')
  +        moduleURL=self.run.getOptions().getResolver().getFile(module)
  +        
  +        moduleRSS=RSS(rssFile,	\
  +            Channel(moduleURL,\
  +                    'Jakarta Gump : Module ' + escape(module.getName()),	\
  +                    escape(module.getDescription())))
  +        
  +        for project in module.getProjects():  
  +            self.syndicateProject(project,moduleRSS,mainRSS)      
  +                  
  +        moduleRSS.serialize()        
       
  -                        link = workspace.logurl + '/' + gumpSafeName(module.getName()) + '/' + gumpSafeName(project.getName()) + '.html'                       
  -                        datestr=time.strftime('%Y-%m-%d')
  -                        timestr=time.strftime('%H%M')
  +    def syndicateProject(self,project,moduleRSS,mainRSS):
  +                
  +        rssFile=self.run.getOptions().getResolver().getFile(project,project.getName(),'.rss')
  +        projectURL=self.run.getOptions().getResolver().getFile(project)
  +        
  +        projectRSS=RSS(rssFile,	\
  +            Channel(projectURL,\
  +                    'Jakarta Gump : Project ' + escape(project.getName()),	\
  +                    escape(project.getDescription())))
                       
  -                        content='Project ' + project.getName() \
  +        s=project.getStats()
  +        datestr=time.strftime('%Y-%m-%d')
  +        timestr=time.strftime('%H%M')
  +                    
  +        content='Project ' + project.getName() \
                                   + ' : ' \
                                   + project.getStateDescription() \
                                   + ' ' \
                                   + project.getReasonDescription() \
  -                                + "\n\n"
  +                                + '\n\n'
                           
  -                        content += 'Previous state: ' \
  +        content += 'Previous state: ' \
                                   + stateName(s.previousState)  \
  -                                + "\n\n"
  +                                + '\n\n'
                        
  -                        for note in project.annotations:
  -                            content += ("   - " + str(note) + "\n")
  -                        
  -                        # write out the item to the rss feed
  -                        gumprss.write("""
  -                            <item>
  -                              <title>%s %s %s</title>
  -                              <link>%s</link>
  -                              <description>&lt;pre&gt;%s&lt;/pre;&gt;</description>
  -                              <dc:subject>%s</dc:subject>
  -                              <dc:date>%sT%s%s</dc:date>
  -                            </item>""" % \
  -                          (project.getName(),project.getStateDescription(),datestr, link, \
  -                               content, \
  -                               module.getName() + ":" + project.getName(), \
  -                               datestr,timestr,TZ))
  +        for note in project.annotations:
  +                content += ("   - " + str(note) + "\n")
                           
  -    # complete the rss feed
  -    gumprss.write("""
  -      </channel>
  -    </rss>
  -    """)
  -    gumprss.close()                                 
  -    
  -    log.info("RSS Newsfeed written to : " + rssFile);          
  -    
  -    return rssFile 
  +        item=Item(('%s %s %s') % (project.getName(),project.getStateDescription(),datestr), \
  +                  projectURL, \
  +                  content, \
  +                  project.getModule().getName() + ":" + project.getName(), \
  +                  ('%sT%s%s') % (datestr,timestr,TZ))
  +
  +        projectRSS.addItem(item)
  +        moduleRSS.addItem(item)  
  +
  +        # State changes that are newsworthy...
  +        if 	s.sequenceInState == 1	\
  +            and not s.currentState == STATE_PREREQ_FAILED \
  +            and not s.currentState == STATE_NONE \
  +            and not s.currentState == STATE_COMPLETE :       
  +            mainRSS.addItem(item)
  +                                                        
  +        projectRSS.serialize()
       
  +def syndicate(run):
  +    simple=Syndicator()
  +    simple.syndicate(run)
  \ No newline at end of file