Exemplo n.º 1
0
	def __init__( self, name = None, parent = None ):
		MApplication.__init__( self, name, parent )

		self.__params = SimpleCiParameters()
		self.__params.parse()
		self.__buildStatus = BuildStatus()
Exemplo n.º 2
0
class SimpleCiBase( MApplication ):
	"""SimpleCI implements a trivial Continuous Integration process that performs builds for a number of Make-O-Matic build scripts.
	SimpleCIBase implements the common logic of the simple_ci master and slave processes.
	"""

	def __init__( self, name = None, parent = None ):
		MApplication.__init__( self, name, parent )

		self.__params = SimpleCiParameters()
		self.__params.parse()
		self.__buildStatus = BuildStatus()

	def preFlightCheck( self ):
		'''Perform the pre-flight check.'''
		self._setBaseDir( os.getcwd() )
		super( SimpleCiBase, self ).preFlightCheck()

	def getParameters( self ):
		'''Access the command line parameters.'''
		return self.__params

	def getBuildStatus( self ):
		'''Access the build status object.
		The BuildStatus object is the interface to the database of revisions and the build results.'''
		return self.__buildStatus

	def getToolName( self ):
		'''The tool name is used to select configuration files.'''
		raise NotImplementedError()

	def getInstanceName( self ):
		'''Instance name can be used if multiple independent SimpleCI instances are running on the same machine
		(since configuration files are usually loaded by host name).'''
		name = make_foldername_from_string( self.getName() )
		return name

	def getInstanceDir( self ):
		'''The instance directory contains all instance specific data.'''
		path = self.getSettings().getUserFolder( self.getToolName() )
		if not os.path.isdir( path ):
			try:
				os.makedirs( path )
				mApp().debug( self, 'instance directory "{0}" created.'.format( path ) )
			except OSError as e:
				raise ConfigurationError( 'cannot create instance directory "{0}": {1}!'.format( path, e ) )
		return path

	def getDataDir( self ):
		'''The data directory contains the build status database.'''
		path = os.path.join( self.getInstanceDir(), '{0}-data'.format( self.getInstanceName() ) )
		if not os.path.isdir( path ):
			try:
				os.makedirs( path )
				mApp().debug( self, 'instance data directory "{0}" created.'.format( path ) )
			except OSError as e:
				raise ConfigurationError( 'cannot create instance data directory "{0}": {1}!'.format( path, e ) )
		return path

	def build( self ):
		'''Execute the tool.'''
		settings = self.getSettings()
		settings.set( Settings.ScriptLogLevel, self.getParameters().getDebugLevel() )
		self.addLogger( ConsoleLogger() )
		# parse settings:
		settings.evalConfigurationFiles( self.getToolName() )
		settings.set( Settings.ScriptLogLevel, self.getParameters().getDebugLevel() )
		self.debug( self, 'debug level is {0}'.format( self.getParameters().getDebugLevel() ) )
		database = os.path.join( self.getDataDir(), 'buildstatus.sqlite' )
		self.debug( self, 'using database: {0}'.format( database ) )
		self.getBuildStatus().setDatabaseFilename( database )
		MApplication.build( self ) # call base class implementation

	def performBuilds( self, buildScripts ):
		'''PerformBuilds is the central method of a SimpleCI run. 
		It retrieves new revisions, and calls the build scripts.'''
		error = []
		x = 0
		# register all revisions committed since the last run in the database:
		if self.getParameters().getFindRevisions():
			self.debug( self, 'build control: discovering new revisions' )
			for buildScript in buildScripts:
				try:
					self.getBuildStatus().registerNewRevisions( buildScript )
				except MomError as e:
					error.append( 'error while processing build script "{0}": {1}'.format( buildScript, e ) )
					msg = 'error while processing build script "{0}", continuing: {1}'.format( buildScript, e )
					self.message( self, msg )
		else:
			self.debugN( self, 2, 'build control: skipping discovery of new revisions' )
		if self.getParameters().getPerformBuilds():
			cap = self.getSettings().get( Settings.SimpleCIBuildJobCap )
			self.debug( self, 'build control: performing up to {0} builds for new revisions'.format( cap ) )
			self.getBuildStatus().listNewBuildInfos()
			for x in range( cap ):
				if not self.getBuildStatus().takeBuildInfoAndBuild( buildScripts ):
					break
			return x
		else:
			self.debugN( self, 2, 'build control: skipping build phase' )
		if error:
			raise MomError( '. '.join( error ) )
		return x

	def checkBuildScripts( self, buildScripts ):
		'''Verify that the build scripts are working as expected.
		The method checks that the build script can be called with basic parameters.
		@return all build scripts that passed the test
		'''
		buildNames = []
		goodScripts = []
		for buildScript in buildScripts:
			iface = BuildScriptInterface( buildScript )
			try:
				name = iface.querySetting( Settings.ScriptBuildName )
				if name and name not in buildNames:
					buildNames.append( name )
					goodScripts.append( buildScript )
				else:
					self.error( self, 'Error in build script "{0}": The build name "{1}" is already used by another '
								'build script. Build script disregarded.'.format( buildScript, name ) )
			except MomError, e:
				self.error( self, 'Error in build script "{0}": Error querying the build name. Build script disregarded. Reason: {1}'
					.format( buildScript, e ) )
		return goodScripts