You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gump.apache.org by bo...@apache.org on 2009/02/17 14:10:15 UTC
svn commit: r745037 [1/2] - in /gump/live: cron/
python/gump/actor/document/xdocs/ python/gump/commands/
python/gump/core/model/ python/gump/core/run/ python/gump/core/runner/
python/gump/core/update/ python/gump/test/ python/gump/util/ python/misc/
sr...
Author: bodewig
Date: Tue Feb 17 13:10:13 2009
New Revision: 745037
URL: http://svn.apache.org/viewvc?rev=745037&view=rev
Log:
Merge SCM refactoring and GIT support from trunk
Added:
gump/live/python/gump/core/update/git.py
- copied, changed from r741429, gump/trunk/python/gump/core/update/git.py
gump/live/python/gump/core/update/scmupdater.py
- copied, changed from r744794, gump/trunk/python/gump/core/update/scmupdater.py
Modified:
gump/live/cron/gump.py (contents, props changed)
gump/live/python/gump/actor/document/xdocs/documenter.py
gump/live/python/gump/commands/__init__.py
gump/live/python/gump/commands/build.py
gump/live/python/gump/core/model/module.py
gump/live/python/gump/core/model/repository.py
gump/live/python/gump/core/run/gumpenv.py
gump/live/python/gump/core/runner/__init__.py
gump/live/python/gump/core/runner/demand.py
gump/live/python/gump/core/update/__init__.py
gump/live/python/gump/core/update/cvs.py
gump/live/python/gump/core/update/p4.py
gump/live/python/gump/core/update/svn.py
gump/live/python/gump/core/update/updater.py
gump/live/python/gump/test/model.py
gump/live/python/gump/test/testExample.py
gump/live/python/gump/util/sync.py
gump/live/python/misc/pgrp.py (contents, props changed)
gump/live/src/documentation/content/xdocs/bylaws.xml
gump/live/src/documentation/content/xdocs/mail.xml
Modified: gump/live/cron/gump.py
URL: http://svn.apache.org/viewvc/gump/live/cron/gump.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
Binary files - no diff available.
Propchange: gump/live/cron/gump.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: gump/live/cron/gump.py
('svn:mime-type' removed)
Modified: gump/live/python/gump/actor/document/xdocs/documenter.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/actor/document/xdocs/documenter.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/actor/document/xdocs/documenter.py (original)
+++ gump/live/python/gump/actor/document/xdocs/documenter.py Tue Feb 17 13:10:13 2009
@@ -1645,31 +1645,38 @@
module, \
repoList.createEntry( "Repository: ") )
- if module.hasCvs():
- if module.cvs.hasModule():
- repoList.createEntry( "CVS Module: ", module.cvs.getModule())
+ scm = module.getScm()
+ if scm:
+ scmName = scm.getScmName()
+ if scm.hasDir():
+ repoList.createEntry(scmName + " Directory: ", scm.getDir())
+ if scm.getScmType() == 'cvs':
+ if scm.hasModule():
+ repoList.createEntry(scmName + " Module: ",
+ scm.getModule())
- if module.cvs.hasTag():
- repoList.createEntry( "CVS Tag: ", module.cvs.getTag())
-
- if module.cvs.hasDir():
- repoList.createEntry( "CVS Dir: ", module.cvs.getDir())
-
- if module.cvs.hasHostPrefix():
- repoList.createEntry( "CVS Host Prefix: ", module.cvs.getHostPrefix())
+ if scm.hasTag():
+ repoList.createEntry(scmName + " Tag: ", scm.getTag())
+
+ if scm.hasHostPrefix():
+ repoList.createEntry(scmName + " Host Prefix: ",
+ scm.getHostPrefix())
- repoList.createEntry( "CVSROOT: ", module.cvs.getCvsRoot())
+ repoList.createEntry("CVSROOT: ", scm.getCvsRoot())
+
+ elif scm.getScmType() == 'p4':
+ if scm.hasTag():
+ repoList.createEntry(scmName + " Tag: ", scm.getTag())
+
+ repoList.createEntry(scmName + " Port: ", scm.getPort())
+ repoList.createEntry(scmName + " Clientspec: ",
+ scm.getClientspec())
- if module.hasSvn():
- if module.svn.hasDir():
- repoList.createEntry( "SVN Directory: ", module.svn.getDir())
- repoList.createEntry( "SVN URL: ", module.svn.getRootUrl())
+ repoList.createEntry(scmName + " URL: ", scm.getRootUrl())
- if module.hasArtifacts():
- if module.artifacts.hasUrl():
- repoList.createEntry( "Jars URL: ", module.artifacts.getUrl())
- repoList.createEntry('Redistributable: ', module.isRedistributable())
+ repoList.createEntry('Redistributable: ',
+ module.isRedistributable())
document.serialize()
document=None
Modified: gump/live/python/gump/commands/__init__.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/commands/__init__.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/commands/__init__.py (original)
+++ gump/live/python/gump/commands/__init__.py Tue Feb 17 13:10:13 2009
@@ -22,4 +22,4 @@
# tell Python what modules make up this package
# NOTE: this is used by the command line processing routines so keep it up to date!
-__all__ = ["env","build","check"]
\ No newline at end of file
+__all__ = ["env","build","check"]
Modified: gump/live/python/gump/commands/build.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/commands/build.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/commands/build.py (original)
+++ gump/live/python/gump/commands/build.py Tue Feb 17 13:10:13 2009
@@ -52,4 +52,4 @@
# Perform this integration run...
return getRunner(run).perform()
-
\ No newline at end of file
+
Modified: gump/live/python/gump/core/model/module.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/model/module.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/model/module.py (original)
+++ gump/live/python/gump/core/model/module.py Tue Feb 17 13:10:13 2009
@@ -32,17 +32,47 @@
from gump.util.note import transferAnnotations, Annotatable
from gump.util.domutils import *
-class ModuleCvs(ModelObject):
+class ModuleScm(ModelObject):
def __init__(self,dom,repository):
ModelObject.__init__(self,dom)
- self.repository=repository
+ # Reference to the shared repository
+ self.repository = repository
+
+ # Extract settings
+ self.dir = self.getDomAttributeValue('dir')
+ self.type = self.element.tagName
+
+ def getRootUrl(self):
+ url = self.repository.getUrl()
+ if url and self.hasDir():
+ url += self.getDir()
+ return url
+
+ def hasDir(self):
+ if self.dir: return True
+ return False
+
+ def getDir(self):
+ return self.dir
+
+ def getViewUrl(self):
+ return self.getRootUrl()
+
+ def getScmType(self):
+ return self.type
+
+ def getScmName(self):
+ return self.repository.getType()
+
+class ModuleCvs(ModuleScm):
+ def __init__(self,dom,repository):
+ ModuleScm.__init__(self, dom, repository)
# Extract settings
- self.tag = self.getDomAttributeValue('tag')
- self.module = self.getDomAttributeValue('module')
- self.hostPrefix = self.getDomAttributeValue('host-prefix')
- self.dir = self.getDomAttributeValue('dir','')
+ self.tag = self.getDomAttributeValue('tag')
+ self.module = self.getDomAttributeValue('module')
+ self.hostPrefix = self.getDomAttributeValue('host-prefix')
def getCvsRoot(self):
"""Construct the CVS root for this set of information"""
@@ -82,13 +112,6 @@
def getHostPrefix(self):
return str(self.hostPrefix)
- def hasDir(self):
- if self.dir: return True
- return False
-
- def getDir(self):
- return str(self.dir)
-
def hasModule(self):
if self.module: return True
return False
@@ -105,38 +128,11 @@
url=self.repostory.getCvsWeb()+'/'+self.module.getName()
return url
-class ModuleSvn(ModelObject):
- def __init__(self,dom,repository):
- ModelObject.__init__(self,dom)
-
- # Reference to the shared repository
- self.repository=repository
-
- # Extract settings
- self.dir = self.getDomAttributeValue('dir')
-
- def getRootUrl(self):
- url=self.repository.getUrl()
- if self.hasDir():
- url+=self.getDir()
- return url
-
- def hasDir(self):
- if self.dir: return True
- return False
-
- def getDir(self):
- return self.dir
-
- def getViewUrl(self):
- return self.getRootUrl()
-
-class ModuleP4(ModelObject):
+class ModuleP4(ModuleScm):
def __init__(self,dom,repository):
- ModelObject.__init__(self,dom)
+ ModuleScm.__init__(self, dom, repository)
# Reference to the shared repository
- self.repository=repository
self.hostname='perforce:1666'
if repository.hasDomChild('root'):
root=repository.getDomChild('root')
@@ -149,9 +145,6 @@
self.tag=self.getDomAttributeValue('tag')
- # Extract settings
- self.dir=self.getDomAttributeValue('dir')
-
def getPort(self):
return str(self.hostname)
@@ -171,22 +164,6 @@
def getTag(self):
return str(self.tag)
- def getRootUrl(self):
- url=self.repository.getUrl()
- if self.hasDir():
- url+=self.getDir()
- return url
-
- def hasDir(self):
- if self.dir: return True
- return False
-
- def getDir(self):
- return self.dir
-
- def getViewUrl(self):
- return self.getRootUrl()
-
class ModuleArtifacts(ModelObject):
def __init__(self,dom,repository):
ModelObject.__init__(self,dom)
@@ -217,36 +194,33 @@
class Module(NamedModelObject, Statable, Resultable, Positioned):
"""Set of Modules (which contain projects)"""
def __init__(self,name,dom,owner):
- NamedModelObject.__init__(self,name,dom,owner)
-
- Statable.__init__(self)
- Resultable.__init__(self)
- Positioned.__init__(self)
-
- self.totalDepends=[]
- self.totalDependees=[]
+ NamedModelObject.__init__(self,name,dom,owner)
+
+ Statable.__init__(self)
+ Resultable.__init__(self)
+ Positioned.__init__(self)
+
+ self.totalDepends=[]
+ self.totalDependees=[]
- self.projects={}
-
+ self.projects={}
+
self.notifys=[]
- self.repository=None
- self.cvs=None
- self.svn=None
- self.artifacts=None
- self.p4=None
-
- self.packaged = False
+ self.repository=None
+ self.scm = None
+
+ self.packaged = False
self.redistributable= False
# Changes were found (when updating)
- self.modified = False
-
- # The task of updating has occured..
- self.updated = False
-
- self.affected = 0
-
+ self.modified = False
+
+ # The task of updating has occured..
+ self.updated = False
+
+ self.affected = 0
+
# Extract settings
self.tag=''
@@ -261,7 +235,7 @@
def getObjectForTag(self,tag,dom,name=None):
"""
- Get a new (or spliced) object for this tag
+ Get a new (or spliced) object for this tag
"""
object=None
@@ -284,10 +258,10 @@
return object
def resolve(self):
- """
- Resolving requires creating objects (in the correct lists/maps) for
- certain high level XML elements, e.g. <project.
- """
+ """
+ Resolving requires creating objects (in the correct lists/maps) for
+ certain high level XML elements, e.g. <project.
+ """
if self.isResolved(): return
@@ -406,9 +380,9 @@
`packageCount` + '.)')
# Determine source directory
- self.absWorkingDir= \
+ self.absWorkingDir= \
os.path.abspath(
- os.path.join(workspace.getBaseDirectory(),
+ os.path.join(workspace.getBaseDirectory(),
self.workdir))
self.absSrcCtlDir= \
@@ -422,70 +396,8 @@
os.path.join( workspace.getSourceControlStagingDirectory(),
self.getName() + '.lock'))
- # :TODO: Consolidate this code, less cut-n-paste but also
- # check the 'type' of the repository is appropriate for the
- # use (eg. type='cvs' if referenced by CVS).
if not packaged:
- # We have a CVS entry, expand it...
- if self.hasDomChild('cvs'):
- cvs=self.getDomChild('cvs')
- repoName=getDomAttributeValue(cvs,'repository')
- if repoName:
- if workspace.hasRepository(repoName):
- # It references this repository...
- repo=workspace.getRepository(repoName)
- self.repository=repo
- repo.addModule(self)
- self.cvs=ModuleCvs(cvs,repo)
- else:
- self.changeState(STATE_FAILED,REASON_CONFIG_FAILED)
- self.addError('No such repository ['+ str(repoName) +'] in workspace on [' \
- + self.getName() + ']')
-
- elif self.hasDomChild('svn'):
- rdom=self.getDomChild('svn')
- repoName=getDomAttributeValue(rdom,'repository')
- if repoName:
- if workspace.hasRepository(repoName):
- # It references this repository...
- repo=workspace.getRepository(repoName)
- self.repository=repo
- repo.addModule(self)
- self.svn=ModuleSvn(rdom,repo)
- else:
- self.changeState(STATE_FAILED,REASON_CONFIG_FAILED)
- self.addError('No such repository ['+ str(repoName) +'] in workspace on [' \
- + self.getName() + ']')
-
- elif self.hasDomChild('p4'):
- p4dom=self.getDomChild('p4')
- repoName=getDomAttributeValue(p4dom,'repository')
- if repoName:
- if workspace.hasRepository(repoName):
- # It references this repository
- repo=workspace.getRepository(repoName)
- self.repository=repo
- repo.addModule(self)
- self.p4=ModuleP4(p4dom,repo)
- else:
- self.changeState(STATE_FAILED,REASON_CONFIG_FAILED)
- self.addError('No such repository ['+ str(repoName) + '] in workspace on [' \
- + self.getName() + ']')
-
- elif self.hasDomChild('artifacts'):
- adom=self.getDomChild('artifacts')
- repoName=getDomAttributeValue(adom,'repository')
- if repoName:
- if workspace.hasRepository(repoName):
- # It references this repository...
- repo=workspace.getRepository(repoName)
- self.repository=repo
- repo.addModule(self)
- self.artifacts=ModuleArtifacts(adom,repo)
- else:
- self.changeState(STATE_FAILED,REASON_CONFIG_FAILED)
- self.addError('No such repository ['+ str(repoName) +'] in workspace on [' \
- + self.getName() + ']')
+ self.parseScm()
# Grab all notifications
for notifyEntry in self.getDomChildIterator('nag'):
@@ -520,6 +432,44 @@
self.setComplete(True)
+ def parseScm(self):
+ """
+ Parses the child element that holds SCM information
+ """
+
+ # sorted by priority, the first matching SCM element wins
+ supportedScms = ['cvs', 'svn', 'p4', 'git', 'artifacts']
+ for s in supportedScms:
+ if self.hasDomChild(s):
+ dom = self.getDomChild(s)
+ repoName = getDomAttributeValue(dom, 'repository')
+ if repoName:
+ if self.workspace.hasRepository(repoName):
+ # It references this repository...
+ repo = self.workspace.getRepository(repoName)
+ self.repository = repo
+ repo.addModule(self)
+ self.scm = self.createScmInstance(s, dom, repo)
+ else:
+ self.changeState(STATE_FAILED,REASON_CONFIG_FAILED)
+ self.addError('No such repository ['+ str(repoName) \
+ +'] in workspace on [' \
+ + self.getName() + ']')
+ return
+
+
+ def createScmInstance(self, type, dom, repo):
+ """
+ Factory method for matching ModuleScm subclass of given SCM
+ """
+ if type == 'cvs':
+ return ModuleCvs(dom, repo)
+ elif type == 'p4':
+ return ModuleP4(dom, repo)
+ elif type == 'artifacts':
+ return ModuleArtifacts(dom, repo)
+ return ModuleScm(dom, repo)
+
def hasNotifys(self):
if self.notifys: return True
return False
@@ -537,7 +487,7 @@
def addProject(self,project):
"""
- Associate this module with this project, and vice verse.
+ Associate this module with this project, and vice verse.
"""
name=project.getName()
@@ -729,24 +679,9 @@
return 'http://svn.apache.org/repos/asf/gump/metadata/' + location
def isUpdatable(self):
- return self.hasCvs() or self.hasSvn() or self.hasArtifacts()
-
- def hasCvs(self):
- if self.cvs: return True
- return False
-
- def hasSvn(self):
- if self.svn: return True
+ if self.scm: return True
return False
-
- def hasP4(self):
- if self.p4: return True
- return False
-
- def hasArtifacts(self):
- if self.artifacts: return True
- return False
-
+
# Where the contents (at the repository) Modified?
def isModified(self):
return self.modified
@@ -768,12 +703,12 @@
return self.repository
def getViewUrl(self):
- if self.hasCvs():
- return self.cvs.getViewUrl()
- elif self.hasSvn():
- return self.svn.getViewUrl()
- elif self.hasP4():
- return self.p4.getViewUrl()
+ scm = getScm(self);
+ if scm:
+ return scm.getViewUrl()
+
+ def getScm(self):
+ return self.scm
class ModuleStatistics(Statistics):
"""
Modified: gump/live/python/gump/core/model/repository.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/model/repository.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/model/repository.py (original)
+++ gump/live/python/gump/core/model/repository.py Tue Feb 17 13:10:13 2009
@@ -30,7 +30,7 @@
class Repository(NamedModelObject, Statable):
"""
- A named repository (CVS|SVN|Artifacts)
+ A named repository (CVS|SVN|Perforce|Artifacts|GIT)
"""
def __init__(self,name,dom,workspace):
@@ -38,10 +38,17 @@
self.url=None
+ typeToLabel = {'cvs':'CVS', 'svn':'Subversion', 'artifact':'Artifact',
+ 'p4':'Perforce', 'git':'Git'}
+
type=self.getDomAttributeValue('type')
+ try:
+ self.type = typeToLabel[type]
+ except:
+ raise RuntimeError, 'Invalid Repository Type:' + str(xml.type)
+
if 'cvs'==type:
- self.type='CVS'
self.web=self.getDomChildValue('cvsweb') or \
self.getDomChildValue('web')
if self.hasDomChild('root'):
@@ -52,33 +59,25 @@
self.path=getDomChildValue(root,'path')
self.hostname=getDomChildValue(root,'hostname')
else:
- raise RuntimeError, 'No XML <root on repository: ' + self.getName()
- elif 'svn'==type:
- self.type='Subversion'
- if self.hasDomChild('url'):
- self.url=self.getDomChildValue('url')
- else:
- raise RuntimeError, 'No URL on SVN repository: ' + self.getName()
- self.web=self.getDomChildValue('web')
- self.user=self.getDomChildValue('user')
- self.password=self.getDomChildValue('password')
- elif 'artifact'==type:
- self.type='Artifacts'
- if self.hasDomChild('url'):
- self.url=self.getDomChildValue('url')
- else:
- raise RuntimeError, 'No URL on Jars repository: ' + self.getName()
- self.web=self.getDomChildValue('web')
+ raise RuntimeError, 'No XML <root on repository: ' \
+ + self.getName()
elif 'p4'==type:
- self.type='Perforce'
if self.hasDomChild('root'):
root=self.getDomChild('root')
self.p4port=getDomChildValue(root,'hostname')
else:
- raise RuntimeError, 'No Perforce server on P4 repository: ' + self.getName()
+ raise RuntimeError, 'No Perforce server on P4 repository: ' \
+ + self.getName()
self.web=self.getDomChildValue('web')
else:
- raise RuntimeError, 'Invalid Repository Type:' + str(xml.type)
+ if self.hasDomChild('url'):
+ self.url=self.getDomChildValue('url')
+ else:
+ raise RuntimeError, 'No URL on ' + self.type + ' repository: ' \
+ + self.getName()
+ self.web=self.getDomChildValue('web')
+ self.user=self.getDomChildValue('user')
+ self.password=self.getDomChildValue('password')
# Modules referencing this repository
self.modules=[]
Modified: gump/live/python/gump/core/run/gumpenv.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/run/gumpenv.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/run/gumpenv.py (original)
+++ gump/live/python/gump/core/run/gumpenv.py Tue Feb 17 13:10:13 2009
@@ -82,6 +82,10 @@
self.noJavac = False
self.noMake = False
self.noMvnRepoProxy = False
+ self.noGit = False
+ self.noDarcs = False
+ self.noHg = False
+ self.noBzr = False
self.javaProperties = None
@@ -157,43 +161,42 @@
if not self.noJavac and not self._checkExecutable('java com.sun.tools.javac.Main','-help',False,False,'check_java_compiler'):
self.noJavac=True
- if not self.noCvs and not self._checkExecutable('cvs','--version',False):
- self.noCvs=True
- self.addWarning('"cvs" command not found, no CVS repository updates')
-
- if not self.noSvn and not self._checkExecutable('svn','--version',False):
- self.noSvn=True
- self.addWarning('"svn" command not found, no SVN repository updates')
+ self.noCvs = self._checkWithDashVersion('cvs',
+ 'no CVS repository updates')
+
+ self.noSvn = self._checkWithDashVersion('svn',
+ 'no svn repository updates')
- if not self.noP4 and not self._checkExecutable('p4','-V',False):
- self.noP4=True
- self.addWarning('"p4" command not found, no Perforce repository updates')
+ self.noP4 = self._checkWithDashVersion('p4',
+ 'no Perforce repository updates',
+ '-V')
- if not self.noMaven and \
- not self._checkExecutable('maven','--version',False,False,'check_maven'):
- self.noMaven=True
- self.addWarning('"maven" command not found, no Maven builds')
-
- if not self.noMaven2 and \
- not self._checkExecutable('mvn','--version',False,False,'check_maven2'):
- self.noMaven=True
- self.addWarning('"mvn" command not found, no Maven2 builds')
-
- if not self.noNAnt and \
- not self._checkExecutable('NAnt','-help',False,False,'check_NAnt'):
- self.noNAnt=True
- self.addWarning('"NAnt" command not found, no NAnt builds')
-
- if not self.noMono and \
- not self._checkExecutable('mono','--help',False,False,'check_mono'):
- self.noMono=True
- self.addWarning('"Mono" command not found, no Mono runtime')
+ self.noMaven = not self.noMaven and not \
+ self._checkWithDashVersion('maven', "no Maven 1.x builds")
+
- if not self.noMake and \
- not self._checkExecutable('make','--help',False,False,'check_Make'):
- self.noMake=True
- self.addWarning('"make" command not found, no make builds')
+ self.noMaven2 = not self.noMaven2 and not \
+ self._checkWithDashVersion('mvn', "no Maven 2.x builds")
+
+ self.noNAnt = self._checkWithDashVersion('NAnt', "no NAnt builds")
+
+ self.noMono = self._checkWithDashVersion('mono', "no Mono runtime")
+
+ self.noMake = self._checkWithDashVersion('make', "no make builds")
+ self.noGit = self._checkWithDashVersion('git',
+ 'no git repository updates')
+
+ self.noDarcs = self._checkWithDashVersion('darcs',
+ 'no darcs repository updates')
+
+ self.noHg = self._checkWithDashVersion('hg',
+ 'no Mercurial repository updates')
+
+ self.noBzr = self._checkWithDashVersion('bzr',
+ 'no Bazar repository updates')
+
+
self.checked = True
self.changeState(STATE_SUCCESS)
@@ -270,6 +273,18 @@
return self.javaProperties
+ def _checkWithDashVersion(self,commandName,consequence,version='--version'):
+ """
+ Determine whether a particular command is or is not available
+ by using the --version switch
+ """
+ ok = self._checkExecutable(commandName, version, False, False,
+ 'check_' + commandName)
+ if not ok:
+ self.addWarning('"' + commandName + '" command not found, '
+ + consequence)
+ return ok
+
def _checkExecutable(self,command,options,mandatory,logOutput=False,name=None):
"""
Determine whether a particular command is or is not available.
Modified: gump/live/python/gump/core/runner/__init__.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/runner/__init__.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/runner/__init__.py (original)
+++ gump/live/python/gump/core/runner/__init__.py Tue Feb 17 13:10:13 2009
@@ -26,4 +26,4 @@
behaviour like multithreading and/or which actors are run.
Which runner to use is determined using the gump.runner.getRunner() method.
-"""
\ No newline at end of file
+"""
Modified: gump/live/python/gump/core/runner/demand.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/runner/demand.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/runner/demand.py (original)
+++ gump/live/python/gump/core/runner/demand.py Tue Feb 17 13:10:13 2009
@@ -76,7 +76,7 @@
def performUpdate(self,module):
"""
- Perform the (cvs,svn) update of a single module.
+ Perform the SCM update of a single module.
The module is locked during the update. Most of the actual work
is delegated to the updater that's provided by the parent GumpRunner
Modified: gump/live/python/gump/core/update/__init__.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/__init__.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/update/__init__.py (original)
+++ gump/live/python/gump/core/update/__init__.py Tue Feb 17 13:10:13 2009
@@ -17,6 +17,6 @@
# limitations under the License.
# tell Python what modules make up the gump.test package
-__all__ = ["updater","cvs","svn","jars"]
+__all__ = ["updater","cvs","svn","jars", "git", "scmupdater"]
Modified: gump/live/python/gump/core/update/cvs.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/cvs.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/update/cvs.py (original)
+++ gump/live/python/gump/core/update/cvs.py Tue Feb 17 13:10:13 2009
@@ -15,228 +15,97 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-
-"""
-
-import os.path
-import sys
-from fnmatch import fnmatch
-
-from gump import log
-from gump.core.run.gumprun import *
-from gump.core.config import dir, default, basicConfig
-
-from gump.util import dump, display, getIndent, logResourceUtilization, \
- invokeGarbageCollection
-from gump.util.note import Annotatable
-from gump.util.work import *
-
-from gump.util.tools import *
-
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.project import Project
-from gump.core.model.depend import ProjectDependency
-from gump.core.model.stats import *
-from gump.core.model.state import *
-
-from gump.tool.integration.cvs import *
-
+from gump.core.model.workspace import Cmd
+from gump.core.update.scmupdater import ScmUpdater
+from gump.tool.integration.cvs import readLogins, loginToRepositoryOnDemand
+
+def maybe_add_tag(module, cmd):
+ # Determine if a tag is set, on <cvs or on <module
+ tag = None
+ if module.getScm().hasTag():
+ tag = module.getScm().getTag()
+ elif module.hasTag():
+ tag = module.getTag()
+ if tag:
+ cmd.addParameter('-r', tag, ' ')
###############################################################################
# Classes
###############################################################################
-class CvsUpdater(RunSpecific):
+class CvsUpdater(ScmUpdater):
+ """
+ Updater for CVS
+ """
- def __init__(self,run):
- RunSpecific.__init__(self,run)
+ def __init__(self, run):
+ ScmUpdater.__init__(self, run)
#
# A stash of known logins.
#
- self.logins=readLogins()
+ self.logins = readLogins()
- def updateModule(self,module):
+ def getCheckoutCommand(self, module):
"""
-
- Perform a CVS update on a module
-
+ Build the appropriate CVS command for checkout
"""
-
- #log.info('Perform CVS Update on #[' + `module.getPosition()` + \
- # '] : ' + module.getName())
+ self.maybeLogin(module)
- # Did we 'CVS checkout' already?
- exists = os.path.exists(module.getSourceControlStagingDirectory())
-
- # Doesn't tell us much...
- #if exists:
- # self.performStatus(module)
-
- self.performUpdate(module,exists)
-
- return module.okToPerformWork()
-
- def performStatus(self,module):
- # Get the Update Command
- (repository, root, cmd ) = self.getUpdateCommand(module, True, True)
-
- # Provide CVS logins, if not already there
- loginToRepositoryOnDemand(repository,root,self.logins)
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
-
- if not cmdResult.isOk():
- log.error('Failed to checkout/update module: ' + module.name)
-
- def performUpdate(self,module,exists):
- """
- Update this module (checking out if needed)
- """
- # Get the Update Command
- (repository, root, cmd ) = self.getUpdateCommand(module, exists)
-
- #log.debug("CVS Update Module " + module.getName() + \
- # ", Repository Name: " + str(module.repository.getName()))
-
- # Provide CVS logins, if not already there
- loginToRepositoryOnDemand(repository,root,self.logins)
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
- repository.performedWork(work.clone())
-
- # Update Context w/ Results
- if not cmdResult.isOk():
- log.error('Failed w/ CVS Root ' + root + ' for %s on Repository %s.' \
- % (module.name, module.repository.getName()))
- if not exists:
- module.changeState(STATE_FAILED,REASON_UPDATE_FAILED)
- else:
- module.addError('*** Failed to update from source control. Stale contents ***')
-
- # Black mark for this repository
- repository=module.getRepository()
- repository.addError('*** Failed to update %s from source control. Stale contents ***' \
- % module.getName())
-
- # Kinda bogus, but better than nowt (for now)
- module.changeState(STATE_SUCCESS,REASON_UPDATE_FAILED)
+ cmd = Cmd('cvs', 'update_' + module.getName(),
+ module.getWorkspace().getSourceControlStagingDirectory())
+ self.setupCommonParameters(module, cmd)
+
+ # do a cvs checkout
+ cmd.addParameter('checkout')
+ cmd.addParameter('-P')
+ maybe_add_tag(module, cmd)
+
+ if not module.getScm().hasModule() or \
+ not module.getScm().getModule() == module.getName():
+ cmd.addParameter('-d', module.getName(), ' ')
+
+ if module.getScm().hasModule():
+ cmd.addParameter(module.getScm().getModule())
else:
- module.changeState(STATE_SUCCESS)
-
- # We run CVS as -q (quiet) so any output means
- # updates occured...
- if cmdResult.hasOutput():
- log.info('Update(s) received via CVS on #[' \
- + `module.getPosition()` + \
- '] : ' + module.getName())
-
- def preview(self,module):
-
- (repository, root, command ) = self.getUpdateCommand(module,False)
- command.dump()
-
- # Doesn't tell us much...
- #(repository, root, command ) = self.getUpdateCommand(module,True,True)
- #command.dump()
-
- (repository, root, command ) = self.getUpdateCommand(module,True)
- command.dump()
-
-
- def getUpdateCommand(self,module,exists=False,nowork=False):
- """
- Format a commandline for doing the CVS update
+ cmd.addParameter(module.getName())
+
+ return cmd
+
+ def getUpdateCommand(self, module):
+ """
+ Build the appropriate CVS command for update
"""
-
- if nowork and not exists:
- raise RuntimeException('Not coded for this combo.')
-
- root=module.cvs.getCvsRoot()
+
+ self.maybeLogin(module)
- # Prepare CVS checkout/update command...
- prefix='update'
- directory=module.getWorkspace().getSourceControlStagingDirectory()
- if exists:
- directory=module.getSourceControlStagingDirectory()
- if nowork:
- prefix='status'
-
- cmd=Cmd( 'cvs',
- prefix+'_'+module.getName(),
- directory)
+ cmd = Cmd('cvs', 'update_' + module.getName(),
+ module.getSourceControlStagingDirectory())
+ self.setupCommonParameters(module, cmd)
- # Be 'quiet' (but not silent) unless requested otherwise.
- if not module.isDebug() \
- and not module.isVerbose() \
- and not module.cvs.isDebug() \
- and not module.cvs.isVerbose():
+ # Do a cvs update
+ cmd.addParameter('update')
+ cmd.addParameter('-P')
+ cmd.addParameter('-d')
+ maybe_add_tag(module, cmd)
+
+ return cmd
+
+ def setupCommonParameters(self, module, cmd):
+ if self.shouldBeQuiet(module):
cmd.addParameter('-q')
-
- if nowork:
- cmd.addParameter('-n')
-
- # Allow trace for debug
- if module.isDebug():
+ elif module.isDebug():
cmd.addParameter('-t')
-
# Request compression
cmd.addParameter('-z3')
# Set the CVS root
- cmd.addParameter('-d', root)
-
- # Determine if a tag is set, on <cvs or on <module
- tag=None
- if module.cvs.hasTag():
- tag=module.cvs.getTag()
- elif module.hasTag():
- tag=module.getTag()
-
- if exists:
-
- # Do a cvs update
- cmd.addParameter('update')
- cmd.addParameter('-P')
- cmd.addParameter('-d')
- if tag:
- cmd.addParameter('-r',tag,' ')
- else:
- cmd.addParameter('-A')
- #cmd.addParameter(module.getName())
+ cmd.addParameter('-d', module.getScm().getCvsRoot())
- else:
+ def maybeLogin(self, module):
+ repository = module.repository
+ root = module.getScm().getCvsRoot()
+
+ # Provide CVS logins, if not already there
+ loginToRepositoryOnDemand(repository, root, self.logins)
- # do a cvs checkout
- cmd.addParameter('checkout')
- cmd.addParameter('-P')
- if tag:
- cmd.addParameter('-r',tag,' ')
-
- if not module.cvs.hasModule() or \
- not module.cvs.getModule() == module.getName():
- cmd.addParameter('-d',module.getName(),' ')
-
- if module.cvs.hasModule():
- cmd.addParameter(module.cvs.getModule())
- else:
- cmd.addParameter(module.getName())
-
- return (module.repository, root, cmd)
-
Copied: gump/live/python/gump/core/update/git.py (from r741429, gump/trunk/python/gump/core/update/git.py)
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/git.py?p2=gump/live/python/gump/core/update/git.py&p1=gump/trunk/python/gump/core/update/git.py&r1=741429&r2=745037&rev=745037&view=diff
==============================================================================
--- gump/trunk/python/gump/core/update/git.py (original)
+++ gump/live/python/gump/core/update/git.py Tue Feb 17 13:10:13 2009
@@ -16,191 +16,52 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-
-"""
-
-import os.path
-import sys
-from fnmatch import fnmatch
-
from gump import log
-from gump.core.run.gumprun import *
-from gump.core.config import dir, default, basicConfig
+from gump.core.model.workspace import Cmd
+from gump.core.update.scmupdater import ScmUpdater
-from gump.util import dump, display, getIndent, logResourceUtilization, \
- invokeGarbageCollection
-from gump.util.note import Annotatable
-from gump.util.work import *
-
-from gump.util.tools import *
-
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.project import Project
-from gump.core.model.depend import ProjectDependency
-from gump.core.model.stats import *
-from gump.core.model.state import *
+def log_repository_and_url(module):
+ repository = module.repository
+ url = module.getScm().getRootUrl()
+ log.debug("GIT URL: [" + url + "] on Repository: " + \
+ repository.getName())
+
###############################################################################
# Classes
###############################################################################
-class GitUpdater(RunSpecific):
+class GitUpdater(ScmUpdater):
+ """
+ Updater for GIT
+ """
- def __init__(self,run):
- RunSpecific.__init__(self,run)
+ def __init__(self, run):
+ ScmUpdater.__init__(self, run)
- def updateModule(self,module):
- """
- Perform a GIT update on a module
- """
-
- log.info('Perform GIT Update on #[' + `module.getPosition()` + \
- '] : ' + module.getName())
-
- # Did we 'GIT checkout' already?
- exists = os.path.exists(module.getSourceControlStagingDirectory())
-
- self.performUpdate(module, exists)
-
- return module.okToPerformWork()
-
- def performStatus(self,module):
+ def getCheckoutCommand(self, module):
"""
-
- Do a status comparison between our copy and server
-
+ Build the appropriate GIT command for clone
"""
-
- # need to look up how to do that with git
+ log_repository_and_url(module)
+ cmd = Cmd('git-clone', 'update_' + module.getName(),
+ module.getWorkspace().getSourceControlStagingDirectory())
+ self.maybeMakeQuiet(module, cmd)
+ cmd.addParameter(module.getScm().getRootUrl())
+ cmd.addParameter(module.getName())
+ return cmd
- def getStatusCommand(self,module):
+ def getUpdateCommand(self, module):
"""
-
- Build the 'git status --show-updates --non-interative' command
-
+ Build the appropriate GIT command for pull
"""
-
- # need to look up how to do that with git, this is certainly wrong
-
- log.debug("Git Module Status : " + module.getName() + \
- ", Repository Name: " + str(module.repository.getName()))
-
- url=module.git.getRootUrl()
-
- log.debug("GIT URL: [" + url + "] on Repository: " + module.repository.getName())
-
- #
- # Prepare GIT checkout/update command...
- #
- cmd=Cmd('git', 'status_'+module.getName(),
- module.getSourceControlStagingDirectory())
-
- #
- # Be 'quiet' (but not silent) unless requested otherwise.
- #
- if not module.isDebug() \
- and not module.isVerbose() \
- and not module.git.isDebug() \
- and not module.git.isVerbose():
- cmd.addParameter('--quiet')
-
- #
- # Allow trace for debug
- #
- # if module.isDebug() or module.git.isDebug():
- # cmd.addParameter('--verbose')
-
- # do an GIT status
- cmd.addParameter('status')
-
+ log_repository_and_url(module)
+ cmd = Cmd('git-pull', 'update_' + module.getName(),
+ module.getSourceControlStagingDirectory())
+ self.maybeMakeQuiet(module, cmd)
return cmd
-
- def performUpdate(self,module,exists):
- """
-
- Clone or Pull from GIT
-
- """
-
- # Get the Update Command
- (repository, url, cmd ) = self.getUpdateCommand(module, exists)
-
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
- repository.performedWork(work.clone())
-
- # Update Context w/ Results
- if not cmdResult.isOk():
- log.error('Failed to clone/pull module: ' + module.name)
- module.changeState(STATE_FAILED,REASON_UPDATE_FAILED)
- else:
- module.changeState(STATE_SUCCESS)
-
-
- def preview(self,module):
- (repository, url, command ) = self.getUpdateCommand(module,0)
- command.dump()
-
- (repository, url, command ) = self.getUpdateCommand(module,1)
- command.dump()
-
- def getUpdateCommand(self,module,exists=0):
- """
- Build the appropriate GIT command for clone/pull
- """
- repository=module.repository
-
- log.debug("Git Module Update : " + module.getName() + \
- ", Repository Name: " + repository.getName())
-
- url=module.git.getRootUrl()
-
- log.debug("GIT URL: [" + url + "] on Repository: " + repository.getName())
-
- #
- # Prepare GIT clone/pull command...
- #
-
- if exists:
- # do a GIT pull inside working copy
- cmd=Cmd('git-pull', 'update_'+module.getName(),
- module.getSourceControlStagingDirectory())
- else:
- # do a GIT clone
- cmd=Cmd('git-clone', 'update_'+module.getName(),
- module.getWorkspace().getSourceControlStagingDirectory())
-
- #
- # Be 'quiet' (but not silent) unless requested otherwise.
- #
- if not module.isDebug() \
- and not module.isVerbose() \
- and not module.git.isDebug() \
- and not module.git.isVerbose():
+ def maybeMakeQuiet(self, module, cmd):
+ if self.shouldBeQuiet(module):
cmd.addParameter('--quiet')
-
- #
- # Allow trace for debug
- #
- # if module.isDebug() or module.git.isDebug():
- # cmd.addParameter('--verbose')
-
- if not exists:
- # do an GIT pull
- cmd.addParameter(url)
- cmd.addParameter(module.getName())
-
- return (module.repository, url, cmd)
-
-
Modified: gump/live/python/gump/core/update/p4.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/p4.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/update/p4.py (original)
+++ gump/live/python/gump/core/update/p4.py Tue Feb 17 13:10:13 2009
@@ -15,195 +15,58 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-"""
+from gump.core.model.workspace import Cmd
+from gump.core.update.scmupdater import ScmUpdater
-import os.path
-import sys
-from fnmatch import fnmatch
-
-from gump import log
-from gump.core.run.gumprun import *
-from gump.core.config import dir, default, basicConfig
-
-from gump.util import dump, display, getIndent, logResourceUtilization, \
- invokeGarbageCollection
-from gump.util.note import Annotatable
-from gump.util.work import *
-
-from gump.util.tools import *
-
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.project import Project
-from gump.core.model.depend import ProjectDependency
-from gump.core.model.stats import *
-from gump.core.model.state import *
+def getP4Command(module):
+ """
+ Update this module (checking out if needed)
+ """
+ cmd = Cmd('p4', 'update_' + module.getName(),
+ module.getWorkspace().getSourceControlStagingDirectory())
+
+ # Determine if a tag is set, on <p4 or on <module
+ tag = None
+ if module.getScm().hasTag():
+ tag = module.getScm().getTag()
+ elif module.hasTag():
+ tag = module.getTag()
+
+ # Do a p4 sync
+ cmd.addParameter('-p', module.getScm().getPort())
+ cmd.addParameter('-u', module.getScm().getUser())
+ cmd.addParameter('-P', module.getScm().getPassword())
+ cmd.addParameter('-c', module.getScm().getClientspec())
+ cmd.addParameter('sync')
+ if tag:
+ cmd.addParameter(module.getName() + '/...@', tag, ' ')
+ else:
+ cmd.addParameter(module.getName() + '/...')
+ return cmd
###############################################################################
# Classes
###############################################################################
-class P4Updater(RunSpecific):
+class P4Updater(ScmUpdater):
+ """
+ Updater for Perforce
+ """
- def __init__(self,run):
- RunSpecific.__init__(self,run)
-
- #
- # A stash of known logins.
- #
- #self.logins=readLogins()
+ def __init__(self, run):
+ ScmUpdater.__init__(self, run)
- def updateModule(self,module):
+ def getCheckoutCommand(self, module):
"""
-
- Perform a P4 sync on a module
-
+ Checkout this module
"""
-
- #log.info('Perform P4 Sync on #[' + `module.getPosition()` + \
- # '] : ' + module.getName())
-
- ## Did we 'P4 checkout' already?
- exists = os.path.exists(module.getSourceControlStagingDirectory())
-
- # Doesn't tell us much...
- if exists:
- self.performStatus(module)
-
- self.performUpdate(module,exists)
-
- return module.okToPerformWork()
-
- def performStatus(self,module):
- # Get the Update Command
- (repository, root, cmd ) = self.getUpdateCommand(module, True, True)
-
- ## Provide P4 logins, if not already there
- #loginToRepositoryOnDemand(repository,root,self.logins)
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
-
- if not cmdResult.isOk():
- log.error('Failed to checkout/update module: ' + module.name)
-
- def performUpdate(self,module,exists):
- """
- Update this module (checking out if needed)
+ return getP4Command(module)
+
+ def getUpdateCommand(self, module):
"""
- # Get the Update Command
- (repository, root, cmd ) = self.getUpdateCommand(module, exists)
-
- #log.debug("P4 Sync Module " + module.getName() + \
- # ", Repository Name: " + str(module.repository.getName()))
-
- ## Provide P4 logins, if not already there
- #loginToRepositoryOnDemand(repository,root,self.logins)
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
- repository.performedWork(work.clone())
-
- # Update Context w/ Results
- if not cmdResult.isOk():
- log.error('Failed w/ P4 Root ' + root + ' for %s on Repository %s.' \
- % (module.name, module.repository.getName()))
- if not exists:
- module.changeState(STATE_FAILED,REASON_UPDATE_FAILED)
- else:
- module.addError('*** Failed to update from source control. Stale contents ***')
-
- # Black mark for this repository
- repository=module.getRepository()
- repository.addError('*** Failed to update %s from source control. Stale contents ***' \
- % module.getName())
-
- # Kinda bogus, but better than nowt (for now)
- module.changeState(STATE_SUCCESS,REASON_UPDATE_FAILED)
- else:
- module.changeState(STATE_SUCCESS)
-
- # We run P4 so any output means updates occured...
- if cmdResult.hasOutput():
- log.info('Update(s) received via P4 on #[' \
- + `module.getPosition()` + \
- '] : ' + module.getName())
-
- def preview(self,module):
-
- (repository, root, command ) = self.getUpdateCommand(module,False)
- command.dump()
-
- # Doesn't tell us much...
- #(repository, root, command ) = self.getUpdateCommand(module,True,True)
- #command.dump()
-
- (repository, root, command ) = self.getUpdateCommand(module,True)
- command.dump()
-
-
- def getUpdateCommand(self,module,exists=False,nowork=False):
- """
- Format a commandline for doing the P4 update
+ Update this module
"""
- if nowork and not exists:
- raise RuntimeException('Not coded for this combo.')
-
- root=module.p4.getClientspec()
- # Prepare P4 sync command...
- prefix='update'
- directory=module.getWorkspace().getSourceControlStagingDirectory()
- #if exists:
- # directory=module.getSourceControlStagingDirectory()
- if nowork:
- prefix='status'
-
- cmd=Cmd( 'p4',
- prefix+'_'+module.getName(),
- directory)
-
- ## Allow trace for debug
- #if module.isDebug():
- # cmd.addParameter('-t')
-
- ## Request compression
- #cmd.addParameter('-z3')
-
- # Determine if a tag is set, on <p4 or on <module
- tag=None
- if module.p4.hasTag():
- tag=module.p4.getTag()
- elif module.hasTag():
- tag=module.getTag()
-
- # Do a p4 sync
- cmd.addParameter('-p',module.p4.getPort())
- cmd.addParameter('-u',module.p4.getUser())
- cmd.addParameter('-P',module.p4.getPassword())
- cmd.addParameter('-c',root)
- cmd.addParameter('sync')
- if nowork:
- cmd.addParameter('-n')
- if tag:
- cmd.addParameter(module.getName()+'/...@',tag,' ')
- else:
- cmd.addParameter(module.getName()+'/...')
- #cmd.addParameter(module.getName())
+ return getP4Command(module)
- return (module.repository, root, cmd)
-
Copied: gump/live/python/gump/core/update/scmupdater.py (from r744794, gump/trunk/python/gump/core/update/scmupdater.py)
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/scmupdater.py?p2=gump/live/python/gump/core/update/scmupdater.py&p1=gump/trunk/python/gump/core/update/scmupdater.py&r1=744794&r2=745037&rev=745037&view=diff
==============================================================================
--- gump/trunk/python/gump/core/update/scmupdater.py (original)
+++ gump/live/python/gump/core/update/scmupdater.py Tue Feb 17 13:10:13 2009
@@ -17,16 +17,12 @@
# limitations under the License.
import os.path
-import sys
from gump import log
-from gump.core.run.gumprun import *
-from gump.util.note import Annotatable
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.stats import *
-from gump.core.model.state import *
+from gump.core.model.workspace import CommandWorkItem, execute, \
+ REASON_UPDATE_FAILED, STATE_FAILED, STATE_SUCCESS, WORK_TYPE_UPDATE
+from gump.core.run.gumprun import RunSpecific
###############################################################################
# Classes
@@ -38,7 +34,7 @@
Provides helpers and template method implementations.
"""
- def __init__(self,run):
+ def __init__(self, run):
RunSpecific.__init__(self, run)
#
@@ -69,12 +65,13 @@
if cmd:
if isUpdate:
- log.debug(module.getScm().getScmName() + " Module Update : " +\
+ log.debug(module.getScm().getScmName() + " Module Update : " + \
module.getName() + ", Repository Name: " + \
module.repository.getName())
else:
- log.debug(module.getScm().getScmName() + " Module Checkout : " +\
- module.getName() + ", Repository Name: " + \
+ log.debug(module.getScm().getScmName() + \
+ " Module Checkout : " + module.getName() + \
+ ", Repository Name: " + \
module.repository.getName())
# Execute the command and capture results
@@ -88,13 +85,35 @@
# Update Context w/ Results
if not cmdResult.isOk():
log.error('Failed to checkout/update module: ' + module.name)
- module.changeState(STATE_FAILED, REASON_UPDATE_FAILED)
+
+ #
+ # Here the live branch differs from trunk: while live
+ # will mark the module as failed (and not build any
+ # projects contained in it), live will go on if the
+ # directory exists and assume it is a transient error
+ #
+ if not isUpdate:
+ module.changeState(STATE_FAILED, REASON_UPDATE_FAILED)
+ else:
+ module.addError('*** Failed to update from source control.' \
+ + 'Stale contents ***')
+
+ # Black mark for this repository
+ repository = module.getRepository()
+ repository.addError('*** Failed to update %s from source' + \
+ ' control. Stale contents ***' \
+ % module.getName())
+
+ # Kinda bogus, but better than nowt (for now)
+ module.changeState(STATE_SUCCESS, REASON_UPDATE_FAILED)
+
else:
module.changeState(STATE_SUCCESS)
return module.okToPerformWork()
- log.error("Don't know how to to checkout/update module: " + module.name)
+ log.error("Don't know how to to checkout/update module: " + \
+ module.name)
module.changeState(STATE_FAILED, REASON_UPDATE_FAILED)
return False
Modified: gump/live/python/gump/core/update/svn.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/svn.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/update/svn.py (original)
+++ gump/live/python/gump/core/update/svn.py Tue Feb 17 13:10:13 2009
@@ -16,224 +16,60 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-
-"""
-
-import os.path
-import sys
-from fnmatch import fnmatch
-
from gump import log
-from gump.core.run.gumprun import *
-from gump.core.config import dir, default, basicConfig
-
-from gump.util import dump, display, getIndent, logResourceUtilization, \
- invokeGarbageCollection
-from gump.util.note import Annotatable
-from gump.util.work import *
-
-from gump.util.tools import *
-
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.project import Project
-from gump.core.model.depend import ProjectDependency
-from gump.core.model.stats import *
-from gump.core.model.state import *
+from gump.core.model.workspace import Cmd
+from gump.core.update.scmupdater import ScmUpdater
###############################################################################
# Classes
###############################################################################
-class SvnUpdater(RunSpecific):
+class SvnUpdater(ScmUpdater):
+ """
+ Updater for Subversion
+ """
- def __init__(self,run):
- RunSpecific.__init__(self,run)
+ def __init__(self, run):
+ ScmUpdater.__init__(self, run)
- def updateModule(self,module):
- """
- Perform a SVN update on a module
+ def getCheckoutCommand(self, module):
"""
-
- log.info('Perform SVN Update on #[' + `module.getPosition()` + \
- '] : ' + module.getName())
-
- # Did we 'SVN checkout' already?
- exists = os.path.exists(module.getSourceControlStagingDirectory())
-
- # Doesn't teach us much
- #if exists:
- # self.performStatus(module)
-
- self.performUpdate(module, exists)
-
- return module.okToPerformWork()
-
- def performStatus(self,module):
- """
-
- Do a status comparison between our copy and server
-
+ Build the appropriate SVN command for checkout
"""
-
- # Get the Update Command
- cmd = self.getStatusCommand(module)
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
-
- # Store this as work
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
-
- # Update Context w/ Results
- if not cmdResult.isOk():
- message='Failed to \'status --show-updates\' module: ' + module.getName()
- module.addWarning(message)
- log.error(message)
+ return self.getCommand(module, False)
- def getStatusCommand(self,module):
+ def getUpdateCommand(self, module):
"""
-
- Build the 'svn status --show-updates --non-interative' command
-
+ Build the appropriate SVN command for update
"""
- log.debug("SubVersion Module Status : " + module.getName() + \
- ", Repository Name: " + str(module.repository.getName()))
-
- url=module.svn.getRootUrl()
-
- log.debug("SVN URL: [" + url + "] on Repository: " + module.repository.getName())
-
- #
- # Prepare SVN checkout/update command...
- #
- cmd=Cmd('svn', 'status_'+module.getName(),
- module.getSourceControlStagingDirectory())
-
- #
- # Be 'quiet' (but not silent) unless requested otherwise.
- #
- if not module.isDebug() \
- and not module.isVerbose() \
- and not module.svn.isDebug() \
- and not module.svn.isVerbose():
- cmd.addParameter('--quiet')
-
- #
- # Allow trace for debug
- #
- # SVN complains about -v|--verbose, don't ask me why
- #
- # if module.isDebug() or module.svn.isDebug():
- # cmd.addParameter('--verbose')
-
- # do an SVN status --show-updates
- cmd.addParameter('status')
- cmd.addParameter('--show-updates')
-
- #
- # Request non-interactive
- #
- cmd.addParameter('--non-interactive')
+ return self.getCommand(module, True)
- return cmd
-
-
- def performUpdate(self,module,exists):
+ def getCommand(self, module, forUpdate):
"""
-
- Check-out or Update from SVN
-
+ Build the appropriate SVN command for checkout or update
"""
-
- # Get the Update Command
- (repository, url, cmd ) = self.getUpdateCommand(module, exists)
-
-
- # Execute the command and capture results
- cmdResult=execute(cmd, module.getWorkspace().tmpdir)
+ repository = module.repository
+ url = module.getScm().getRootUrl()
- #
- # Store this as work, on both the module and (cloned) on the repo
- #
- work=CommandWorkItem(WORK_TYPE_UPDATE,cmd,cmdResult)
- module.performedWork(work)
- repository.performedWork(work.clone())
-
- # Update Context w/ Results
- if not cmdResult.isOk():
- log.error('Failed to checkout/update module: ' + module.name)
- if not exists:
- module.changeState(STATE_FAILED,REASON_UPDATE_FAILED)
- else:
- module.addError('*** Failed to update from source control. Stale contents ***')
-
- # Black mark for this repository
- repository=module.getRepository()
- repository.addError('*** Failed to update %s from source control. Stale contents ***' \
- % module.getName())
-
- # Kinda bogus, but better than nowt (for now)
- module.changeState(STATE_SUCCESS,REASON_UPDATE_FAILED)
- else:
- module.changeState(STATE_SUCCESS)
-
-
- def preview(self,module):
- (repository, url, command ) = self.getUpdateCommand(module,0)
- command.dump()
-
- # Doesn't teach us much
- # command = self.getStatusCommand(module)
- # command.dump()
-
- (repository, url, command ) = self.getUpdateCommand(module,1)
- command.dump()
-
- def getUpdateCommand(self,module,exists=0):
- """
- Build the appropriate SVN command for checkout/update
- """
- repository=module.repository
-
- log.debug("SubVersion Module Update : " + module.getName() + \
- ", Repository Name: " + repository.getName())
-
- url=module.svn.getRootUrl()
-
- log.debug("SVN URL: [" + url + "] on Repository: " + repository.getName())
+ log.debug("SVN URL: [" + url + "] on Repository: "\
+ + repository.getName())
#
# Prepare SVN checkout/update command...
#
- cmd=Cmd('svn', 'update_'+module.getName(),
- module.getWorkspace().getSourceControlStagingDirectory())
+ cmd = Cmd('svn', 'update_'+module.getName(),
+ module.getWorkspace().getSourceControlStagingDirectory())
#
# Be 'quiet' (but not silent) unless requested otherwise.
#
- if not module.isDebug() \
- and not module.isVerbose() \
- and not module.svn.isDebug() \
- and not module.svn.isVerbose():
+ if self.shouldBeQuiet(module):
cmd.addParameter('--quiet')
- #
- # Allow trace for debug
- #
- # SVN complains about -v|--verbose, don't ask me why
- #
- # if module.isDebug() or module.svn.isDebug():
- # cmd.addParameter('--verbose')
-
- if exists:
- # do an SVN update
+ if forUpdate:
cmd.addParameter('update')
else:
- # do an SVN checkout
cmd.addParameter('checkout', url)
#
@@ -251,10 +87,8 @@
# If module name != SVN directory, tell SVN to put it into
# a directory named after our module
#
- if not module.svn.hasDir() or \
- not module.svn.getDir() == module.getName():
+ if not module.getScm().hasDir() or \
+ not module.getScm().getDir() == module.getName():
cmd.addParameter(module.getName())
- return (module.repository, url, cmd)
-
-
+ return cmd
Modified: gump/live/python/gump/core/update/updater.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/core/update/updater.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/core/update/updater.py (original)
+++ gump/live/python/gump/core/update/updater.py Tue Feb 17 13:10:13 2009
@@ -21,31 +21,70 @@
"""
import os.path
-import sys
from gump import log
-
-from gump.core.run.gumprun import *
-from gump.core.config import dir, default, basicConfig
-
+from gump.core.model.workspace import catFileToFileHolder, \
+ EXIT_CODE_FAILED, EXIT_CODE_SUCCESS, FILE_TYPE_LOG, \
+ gumpSafeName, logResourceUtilization, \
+ STATE_FAILED, STATE_SUCCESS, syncDirectories, REASON_SYNC_FAILED
+from gump.core.run.gumprun import RunSpecific
from gump.core.update.cvs import CvsUpdater
-from gump.core.update.svn import SvnUpdater
+from gump.core.update.git import GitUpdater
from gump.core.update.p4 import P4Updater
+from gump.core.update.svn import SvnUpdater
+
+def syncModule(module):
+ """
+
+ Synchronize the storage area with the build area
+
+ """
+ workspace = module.getWorkspace()
+
+ sourcedir = module.getSourceControlStagingDirectory()
+ destdir = module.getWorkingDirectory()
+
+ # Perform the sync...
+ try:
+ # Store changes next to updates log
+ changesFile = os.path.abspath(os.path.join(workspace.tmpdir,
+ 'changes_to_' + \
+ gumpSafeName(module.getName()) + \
+ '.txt'))
+
+ # Perform the operation.
+ (actions, modified, cleaned) = syncDirectories(sourcedir, destdir, \
+ module, \
+ changesFile)
-from gump.util import dump, display, getIndent, logResourceUtilization, \
- invokeGarbageCollection
-from gump.util.note import Annotatable
-from gump.util.work import *
-
-from gump.util.tools import *
-
-from gump.core.model.workspace import *
-from gump.core.model.module import Module
-from gump.core.model.project import Project
-from gump.core.model.depend import ProjectDependency
-from gump.core.model.stats import *
-from gump.core.model.state import *
+ # We are good to go...
+ module.changeState(STATE_SUCCESS)
+
+ # Were the contents of the repository modified?
+ if modified:
+
+ #
+ # Use 'incoming changes' to note that the module
+ # was modified.
+ #
+ module.setModified(True)
+ log.info('Update(s) received via on #[' \
+ + `module.getPosition()` + \
+ '] : ' + module.getName())
+
+
+ except Exception, details:
+ module.changeState(STATE_FAILED, REASON_SYNC_FAILED)
+ message = 'Synchronize Failed: ' + str(details)
+ module.addError(message)
+ log.error(message, exc_info=1)
+
+
+ # Might help even with sync failures.
+ if os.path.exists(changesFile):
+ catFileToFileHolder(module, changesFile, FILE_TYPE_LOG)
+ return module.okToPerformWork()
###############################################################################
# Classes
@@ -53,34 +92,30 @@
class GumpUpdater(RunSpecific):
- def __init__(self,run):
+ def __init__(self, run):
RunSpecific.__init__(self, run)
- self.cvs=CvsUpdater(run)
- self.svn=SvnUpdater(run)
- self.p4=P4Updater(run)
+ self.updaters = {'cvs' : CvsUpdater(run), 'svn' : SvnUpdater(run),
+ 'p4' : P4Updater(run), 'git' : GitUpdater(run)}
- """
-
- ******************************************************************
-
- THE UPDATE INTERFACE
-
- ******************************************************************
-
- """
+
+ # ******************************************************************
+ #
+ # THE UPDATE INTERFACE
+ #
+ # ******************************************************************
def update(self):
logResourceUtilization('Before update')
#
# Doing a full build?
#
- all=not self.run.getOptions().isQuick()
+ all = not self.run.getOptions().isQuick()
if all:
- modules=self.run.getGumpSet().getModuleSequence()
+ modules = self.run.getGumpSet().getModuleSequence()
else:
- modules=self.run.getGumpSet().getModules()
+ modules = self.run.getGumpSet().getModules()
#
# Checkout from source code repositories
@@ -100,13 +135,14 @@
workspace = self.run.getWorkspace()
- log.debug("Workspace CVS|SVN|P4 Directory: " + workspace.getSourceControlStagingDirectory())
+ log.debug("Workspace CVS|SVN|P4|GIT Directory: " \
+ + workspace.getSourceControlStagingDirectory())
- # Update all the modules that have CVS repositories
+ # Update all the modules that have repositories
for module in list:
self.updateModule(module)
- def updateModule(self,module):
+ def updateModule(self, module):
# if module.isPackaged():
# # Not sure we have anything to do right now
@@ -122,85 +158,36 @@
if module.okToPerformWork():
ok = 0
- if module.hasCvs():
- ok=self.cvs.updateModule(module)
- elif module.hasSvn():
- ok=self.svn.updateModule(module)
- if module.hasP4():
- ok=self.p4.updateModule(module)
+ scmUpdater = self.getScmUpdater(module)
+ if scmUpdater:
+ ok = scmUpdater.updateModule(module)
else:
# :TODO: Now what?
pass
# Synchronize the files...
if ok:
- self.syncModule(module)
+ syncModule(module)
- def syncModule(self,module):
+ def getScmUpdater(self, module):
"""
-
- Synchronize the storage area with the build area
-
+ Finds the correct SCM updater for a given module
"""
- workspace = module.getWorkspace()
-
- sourcedir = module.getSourceControlStagingDirectory()
- destdir = module.getWorkingDirectory()
-
- # Perform the sync...
- try:
- # Store changes next to updates log
- changesFile = os.path.abspath( \
- os.path.join( \
- workspace.tmpdir, \
- 'changes_to_'+gumpSafeName(module.getName())+'.txt'))
-
- # Perform the operation.
- (actions,modified,cleaned)=syncDirectories(sourcedir,destdir,module,changesFile)
-
- # We are good to go...
- module.changeState(STATE_SUCCESS)
-
- # Were the contents of the repository modified?
- if modified:
-
- #
- # Use 'incoming changes' to note that the module
- # was modified.
- #
- module.setModified(True)
- log.info('Update(s) received via on #[' \
- + `module.getPosition()` + \
- '] : ' + module.getName())
-
-
- except Exception, details:
- module.changeState(STATE_FAILED,REASON_SYNC_FAILED)
- message='Synchronize Failed: ' + str(details)
- module.addError(message)
- log.error(message, exc_info=1)
-
-
- # Might help even with sync failures.
- if os.path.exists(changesFile):
- catFileToFileHolder(module, changesFile, FILE_TYPE_LOG)
-
- return module.okToPerformWork()
-
+ scm = module.getScm()
+ if scm:
+ return self.updaters.get(scm.getScmType())
+ return None
- def preview(self,module):
+ def preview(self, module):
"""
Preview what ought occur for this
"""
- if module.hasCvs():
- ok=self.cvs.preview(module)
- elif module.hasSvn():
- ok=self.svn.preview(module)
- elif module.hasP4():
- ok=self.p4.preview(module)
+ scmUpdater = self.getScmUpdater(module)
+ if scmUpdater:
+ scmUpdater.preview(module)
else:
print 'No updater for module: ' + module.getName()
Modified: gump/live/python/gump/test/model.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/test/model.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/test/model.py (original)
+++ gump/live/python/gump/test/model.py Tue Feb 17 13:10:13 2009
@@ -166,8 +166,8 @@
module1=self.module1
module2=self.module2
- self.assertTrue('Module has CVS', module1.hasCvs())
- self.assertFalse('Module has NOT SVN', module1.hasSvn())
+ self.assertTrue('Module has CVS',
+ module1.getScm().getScmType() == 'cvs')
self.assertNonZeroString('CVSROOT',module1.cvs.getCvsRoot())
self.assertNonZeroString('Has Tag',module1.cvs.getTag())
self.assertNonZeroString('Has Tag',module2.getTag())
@@ -175,8 +175,8 @@
def testSvn(self):
svnmodule1= self.workspace.getModule('svn_module1')
- self.assertTrue('Module has SVN', svnmodule1.hasSvn())
- self.assertFalse('Module has NOT CVS', svnmodule1.hasCvs())
+ self.assertTrue('Module has SVN',
+ module1.getScm().getScmType() == 'svn')
self.assertNonZeroString('SVN URL',svnmodule1.svn.getRootUrl())
self.assertTrue('SVN Dir',svnmodule1.svn.hasDir())
Modified: gump/live/python/gump/test/testExample.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/test/testExample.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/test/testExample.py (original)
+++ gump/live/python/gump/test/testExample.py Tue Feb 17 13:10:13 2009
@@ -51,4 +51,4 @@
# this allows us to run this test by itself from the commandline
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
Modified: gump/live/python/gump/util/sync.py
URL: http://svn.apache.org/viewvc/gump/live/python/gump/util/sync.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/gump/util/sync.py (original)
+++ gump/live/python/gump/util/sync.py Tue Feb 17 13:10:13 2009
@@ -198,8 +198,8 @@
linkto = os.readlink(srcname)
os.symlink(linkto, dstname)
elif os.path.isdir(srcname):
- # Copy directories, but not CVS/SVN stuff
- if not name in ['CVS','.svn']:
+ # Copy directories, but not CVS/SVN/GIT stuff
+ if not name in ['CVS','.svn','.git']:
self.copytree(srcname, dstname, symlinks)
else:
# Selectively copy file
Modified: gump/live/python/misc/pgrp.py
URL: http://svn.apache.org/viewvc/gump/live/python/misc/pgrp.py?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/python/misc/pgrp.py (original)
+++ gump/live/python/misc/pgrp.py Tue Feb 17 13:10:13 2009
@@ -1,69 +1,69 @@
-
-import os
-import sys
-import time
-import logging
-import signal
-
-def shutdownProcessAndProcessGroup(pid):
- """
- Kill this group (i.e. instigator and all child processes).
- """
- print 'Kill process group (anything launched by PID' + str(pid) + ')'
- try:
- pgrpID=os.getpgid(pid)
- if -1 != pgrpID:
- print 'Kill process group : (' + str(pgrpID) + ')'
- os.killpg(pgrpID,signal.SIGHUP)
- else:
- print 'No such PID' + str(pid) + '.'
- except Exception, details:
- print 'Failed to dispatch signal ' + str(details)
-
-def hup(sig,stack):
- print "HUP : %s:%s" % ( os.getpgrp(), os.getpid() )
- sys.exit(1)
-
-if __name__=='__main__':
- forkPID = os.fork();
-
- # Child gets PID = 0
- if 0 == forkPID:
-
- # Become a process group leader
- os.setpgrp()
-
- signal.signal( signal.SIGHUP, hup )
-
- # First Grandchild get's 0
- forkPID = os.fork()
-
- if 0 == forkPID:
- os.fork()
- os.fork()
- os.fork()
- os.system('sleep 100000')
- else:
- os.waitpid(forkPID,0)
-
- print 'Child Exit : %s' % os.getpid()
-
- # Parent gets real PID
- else:
- # Timeout support
- timer = None
- timeout = 10
- if timeout:
- import threading
- timer = threading.Timer(timeout, shutdownProcessAndProcessGroup, [forkPID])
- timer.start()
-
- # Run the command
- waitcode = os.waitpid(forkPID,0)
-
- print 'Wait Code : %s : %s ' % ( waitcode, timer )
-
- # Stop timer (if still running)
- if timer and timer.isAlive(): timer.cancel()
-
+
+import os
+import sys
+import time
+import logging
+import signal
+
+def shutdownProcessAndProcessGroup(pid):
+ """
+ Kill this group (i.e. instigator and all child processes).
+ """
+ print 'Kill process group (anything launched by PID' + str(pid) + ')'
+ try:
+ pgrpID=os.getpgid(pid)
+ if -1 != pgrpID:
+ print 'Kill process group : (' + str(pgrpID) + ')'
+ os.killpg(pgrpID,signal.SIGHUP)
+ else:
+ print 'No such PID' + str(pid) + '.'
+ except Exception, details:
+ print 'Failed to dispatch signal ' + str(details)
+
+def hup(sig,stack):
+ print "HUP : %s:%s" % ( os.getpgrp(), os.getpid() )
+ sys.exit(1)
+
+if __name__=='__main__':
+ forkPID = os.fork();
+
+ # Child gets PID = 0
+ if 0 == forkPID:
+
+ # Become a process group leader
+ os.setpgrp()
+
+ signal.signal( signal.SIGHUP, hup )
+
+ # First Grandchild get's 0
+ forkPID = os.fork()
+
+ if 0 == forkPID:
+ os.fork()
+ os.fork()
+ os.fork()
+ os.system('sleep 100000')
+ else:
+ os.waitpid(forkPID,0)
+
+ print 'Child Exit : %s' % os.getpid()
+
+ # Parent gets real PID
+ else:
+ # Timeout support
+ timer = None
+ timeout = 10
+ if timeout:
+ import threading
+ timer = threading.Timer(timeout, shutdownProcessAndProcessGroup, [forkPID])
+ timer.start()
+
+ # Run the command
+ waitcode = os.waitpid(forkPID,0)
+
+ print 'Wait Code : %s : %s ' % ( waitcode, timer )
+
+ # Stop timer (if still running)
+ if timer and timer.isAlive(): timer.cancel()
+
print 'Exit : %s:%s' % ( os.getpgrp(), os.getpid() )
\ No newline at end of file
Propchange: gump/live/python/misc/pgrp.py
------------------------------------------------------------------------------
svn:eol-style = native
Modified: gump/live/src/documentation/content/xdocs/bylaws.xml
URL: http://svn.apache.org/viewvc/gump/live/src/documentation/content/xdocs/bylaws.xml?rev=745037&r1=745036&r2=745037&view=diff
==============================================================================
--- gump/live/src/documentation/content/xdocs/bylaws.xml (original)
+++ gump/live/src/documentation/content/xdocs/bylaws.xml Tue Feb 17 13:10:13 2009
@@ -378,4 +378,4 @@
</section>
</section>
</body>
-</document>
\ No newline at end of file
+</document>