示例#1
0
	def _retrieveRevisionInfo( self ):
		# check if specified revision is in cache. do not check for 'HEAD'
		if self.getRevision() in self.__revisionInfoCache:
			return self.__revisionInfoCache[self.getRevision()]

		info = RevisionInfo( "SvnRevisionInfo" )

		revisionParameter = ['-r', str( self.getRevision() )] if self.getRevision() else []
		cmd = [ self.getCommand(), '--non-interactive', 'log', '--xml', '--limit', '1', self.getUrl() ] + revisionParameter
		runner = RunCommand( cmd, searchPaths = self.getCommandSearchPaths() )
		runner.run()

		if runner.getReturnCode() == 0:
			xmldoc = minidom.parseString( runner.getStdOut().encode( "utf-8" ) )
			logentries = xmldoc.getElementsByTagName( 'logentry' )
			assert len( logentries ) == 1
			results = parse_log_entry( logentries[0] )
			( info.committerName, info.commitMessage, info.revision, info.commitTime, info.commitTimeReadable ) = results
			info.shortRevision = info.revision

			if self.getSCMUidMapper():
				email = self.getSCMUidMapper().getEmail( info.committerName )
				mApp().debugN( self, 5, "E-Mail address for {0} from SCM uid mapper: {1}".format( info.committerName, email ) )
				info.committerEmail = email

		# add to cache. do not add 'HEAD'
		if self.getRevision():
			self.__revisionInfoCache[self.getRevision()] = info

		return info
示例#2
0
	def resolveCommand( self ):
		# if no command specified, do not run check
		if not self.getCommand():
			return

		runCommand = RunCommand( [ self.getCommand() ], searchPaths = self.__commandSearchPaths )
		runCommand.checkVersion()
示例#3
0
	def testCheckCMakeVersion( self ):
		# cmake example
		cmakeCommand = RunCommand( [ "cmake" ] )
		self.assertRaises( ConfigurationError, cmakeCommand.checkVersion, expectedReturnCode = -1 ) # cmake returns 0

		version = cmakeCommand.checkVersion( expectedReturnCode = 0 )
		self.assertTrue( "cmake version" in version )
示例#4
0
	def testCheckQMakeVersion( self ):
		# qmake example
		qmakeCommand = RunCommand( [ "qmake" ] )
		self.assertRaises( ConfigurationError, qmakeCommand.checkVersion, expectedReturnCode = 1 ) # qmake returns 0

		version = qmakeCommand.checkVersion( expectedReturnCode = 0 )
		self.assertTrue( "QMake version" in version )
	def testPrintCurrentRevision( self ):
		cmd = [ sys.executable, SimpleProjectTests.BuildScriptName, 'print', 'current-revision' ]
		runner = RunCommand( cmd )
		runner.run()
		self.assertEquals( runner.getReturnCode(), 0 )
		line = runner.getStdOutAsString().strip()
		# we cannot know what the current revision is, but if the return code is not zero, it should not be empty:
		self.assertTrue( line )
示例#6
0
	def testCheckReturnCodes( self ):
		'''Check that RunCommand returns the actual return value of the called process.'''
		for timeout in [ None, 1 ]:
			for captureOutput in [ False, True ]:
				for code in range( 3 ):
					cmd = [ sys.executable, RunCommandTests.EXECUTABLE, str( code ) ]
					runner = RunCommand( cmd, timeoutSeconds = timeout, captureOutput = captureOutput )
					runner.run()
					self.assertEquals( runner.getReturnCode(), code )
示例#7
0
	def queryCurrentRevision( self ):
		cmd = [ sys.executable, self.getBuildScript(), 'print', 'current-revision' ] + self.getParameters()
		runner = RunCommand( cmd, 1800 )
		runner.run()
		if runner.getReturnCode() != 0:
			raise MomError( 'Cannot get initial revision for build script "{0}".'.format( self.getBuildScript() ) )

		revision = runner.getStdOutAsString().strip()
		return revision
示例#8
0
	def __getSummarizedDiffForRevision( self, url, revision ):
		previous = revision - 1
		cmd = [ self.getCommand(), 'diff', '--summarize', '-r', str( previous ) + ':' + str( revision ), url ]
		runner = RunCommand( cmd, 3600, searchPaths = self.getCommandSearchPaths() )
		runner.run()
		if runner.getReturnCode() != 0:
			# maybe the location did not exist earlier on: 
			mApp().debugN( self, 2, 'cannot retrieve summarized diff for revision "{0}"'.format( revision ) )
			return None
		else:
			return runner.getStdOut().encode( "utf-8" ).split( '\n' )
示例#9
0
	def executeWithArgs( self, timeout = 24 * 60 * 60, args = None, captureOutput = False ):
		cmd = [ sys.executable, os.path.abspath( self.getBuildScript() ) ]
		if args:
			cmd.extend( args )
		mApp().message( self, 'invoking build script: {0}'.format( ' '.join( cmd ) ) )
		runner = RunCommand( cmd, timeoutSeconds = timeout, captureOutput = captureOutput )
		with EnvironmentSaver():
			extend_debug_prefix( 'script>' )
			runner.run()
		mApp().debugN( self, 2, 'build script finished, return code is {0}.'.format( runner.getReturnCode() ) )
		return runner
示例#10
0
	def __getCurrentRevisionOfUrl( self, url ):
		cmd = [ self.getCommand(), '--non-interactive', 'log', '--xml', '--limit', '1', url ]
		runner = RunCommand( cmd, searchPaths = self.getCommandSearchPaths() )
		runner.run()

		if runner.getReturnCode() == 0:
			xmldoc = minidom.parseString( runner.getStdOut().encode( "utf-8" ) )
			logentries = xmldoc.getElementsByTagName( 'logentry' )
			assert len( logentries ) == 1
			result = parse_log_entry( logentries[0] )
			return result[2]
		else:
			raise ConfigurationError( 'cannot get log for "{0}"'.format( url ) )
示例#11
0
class ShellCommandAction( Action ):
	"""ShellCommandAction encapsulates the execution of one command in the Step class. 
	It is mostly used internally, but can be of general use as well."""

	def __init__( self, command = None, timeout = None, combineOutput = True, searchPaths = None ):
		Action.__init__( self )
		self.setCommand( command, timeout, searchPaths )
		self.__combineOutput = combineOutput
		self.__runner = None

	def getLogDescription( self ):
		"""Provide a textual description for the Action that can be added to the execution log file."""
		return '{0}'.format( ' '.join( self.getCommand() ) )

	def setCommand( self, command, timeOutPeriod = None, searchPaths = None ):
		"""Set the shell command"""
		check_for_list_of_paths( command, "The shell command must be a list of strings or paths." )
		if timeOutPeriod != None:
			check_for_nonnegative_int( timeOutPeriod, 'invalid timeout period, valid periods are [0..inf] or None for no timeout' )
		if searchPaths is None:
			searchPaths = []
		check_for_list_of_paths( searchPaths, "The search paths need to be a list of strings." )
		self.__command = command
		self.__timeOutPeriod = timeOutPeriod
		self.__searchPaths = searchPaths

	def getCommand( self ):
		"""Returns the command"""
		return map( lambda x: str( x ) , self.__command )

	def _getRunner( self ):
		if self.__runner == None:
			raise MomError( "The command runner was not initialized before being queried" )
		return self.__runner

	def run( self ):
		"""Executes the shell command. Needs a command to be set."""
		self.__runner = RunCommand( self.__command, self.__timeOutPeriod, self.__combineOutput, self.__searchPaths )
		if self.getWorkingDirectory() != None:
			self.__runner.setWorkingDir( self.getWorkingDirectory() )
		self._getRunner().run()
		self._setStdOut( self._getRunner().getStdOut() )
		self._setStdErr( self._getRunner().getStdErr() )
		return self._getRunner().getReturnCode()

	def hasTimedOut( self ):
		"""Returns True if the shell command process timed out, e.g., was not completed within the timeout period.
		Can only be called after execution."""
		if not self.__started:
			raise MomError( 'timedOut() queried before the command was executed' )
		return self._getRunner().getTimedOut()
示例#12
0
	def runUploadFiles( self ):
		fromDir = self._makeCygwinPathForRsync( '{0}{1}'.format( self.getSourcePath(), os.sep ) )
		toDir = os.path.join( self.getDestinationPath(), *self._getExtraUploadSubdirsAsString() )
		args = [ '-avz', '-e', 'ssh -o BatchMode=yes', fromDir, toDir ]
		if 'Windows' in platform.platform(): #On windows, fake source permissions to be 755
			args = [ '--chmod=ugo=rwx' ] + args
		cmd = [ "rsync" ] + args
		searchPaths = [ "C:/Program Files/cwRsync/bin" ]
		runner = RunCommand( cmd, timeoutSeconds = 7200, searchPaths = searchPaths )
		if runner.run() != 0:
			mApp().debugN( self, 1, 'Uploading from "{0}" to "{1}" failed!'.format( fromDir, toDir ) )
			return runner.getReturnCode()
		else:
			mApp().debugN( self, 3, 'Uploaded "{0}" to "{1}".'.format( fromDir, toDir ) )
			return 0
示例#13
0
	def run( self ):
		"""Executes the shell command. Needs a command to be set.

		\return 0 if minimum score is met, otherwise 1"""

		cmd = [ self._getPyLintChecker().getCommand() ]
		paths = self._getPyLintChecker().getCommandSearchPaths()

		args = [ ]
		if self._getPyLintChecker().getPyLintRcFile():
			args.append( '--rcfile={0}'.format( self._getPyLintChecker().getPyLintRcFile() ) )

		# Check if the source and output path exist, since this action will be executed even if there was an error before (since 
		# the source code can be checked even if, for example, a unit test failed)
		targetPath = os.path.dirname( str( self._getPyLintChecker().getHtmlOutputPath() ) )
		if not os.path.isdir( targetPath ) \
			or not os.path.isdir( str( self.getWorkingDirectory() ) ):
			self._getPyLintChecker().setReport( 'not executed because of previous failures' )
			return 0
		# First, run PyLint with parseable output, and retrieve the score and comment:
		parseableCommand = cmd + [ '--output-format=parseable' ] + args + self._getPyLintChecker().getModules()
		runner1 = RunCommand( parseableCommand, 1800, searchPaths = paths )
		runner1.run()
		if runner1.getReturnCode() >= 32:
			mApp().debugN( self, 2, 'error running pylint to produce the parseable report' )
			return 1

		# parse output
		self._getPyLintChecker().parsePyLintOutput( runner1.getStdOut() )

		# Second step, run pylint again, to produce the full HTML report:
		if self._getPyLintChecker().getHtmlOutputPath():
			htmlCommand = cmd + [ '--output-format=html' ] + args + self._getPyLintChecker().getModules()
			runner2 = RunCommand( htmlCommand )
			runner2.run()
			if runner2.getReturnCode() >= 32:
				mApp().debugN( self, 2, 'error running pylint to generate the HTML report' )
				return 1
			path = str( self._getPyLintChecker().getHtmlOutputPath() )
			try:
				with open( path, 'w' ) as file:
					file.write( runner2.getStdOut() )
				mApp().debugN( self, 2, 'pylint html report is at "{0}"'.format( path ) )
			except IOError as e:
				mApp().debug( self, 'ERROR saving pylint html report to "{0}": {1}'.format( path, e ) )
				return 1

		return ( 0 if self._getPyLintChecker().isScoreOkay() else 1 )
示例#14
0
	def queryRevisionsSince( self, revision ):
		'''Execute the build script, and return the lines it outputs for "query revisions-since"'''

		cmd = [ sys.executable, self.getBuildScript(), 'print', 'revisions-since', str( revision ) ] + self.getParameters()
		runner = RunCommand( cmd, 1800 )
		runner.run()
		if runner.getReturnCode() != 0:
			msg = 'Cannot get revision list for build script "{0}", continuing with next project.'\
				.format( self.getBuildScript() )
			raise MomError( msg )

		output = runner.getStdOut()
		if not output:
			return []

		lines = output.decode().split( '\n' )
		return lines
示例#15
0
	def run( self ):
		"""Executes the shell command. Needs a command to be set."""
		self.__runner = RunCommand( self.__command, self.__timeOutPeriod, self.__combineOutput, self.__searchPaths )
		if self.getWorkingDirectory() != None:
			self.__runner.setWorkingDir( self.getWorkingDirectory() )
		self._getRunner().run()
		self._setStdOut( self._getRunner().getStdOut() )
		self._setStdErr( self._getRunner().getStdErr() )
		return self._getRunner().getReturnCode()
示例#16
0
	def runCreateDirectories( self ):
		# no need to create directories if no extra sub directories specified
		if not self.getExtraUploadSubDirs():
			return 0

		path = os.path.join( *self._getExtraUploadSubdirsAsString() )
		tempDir = tempfile.mkdtemp( prefix = 'mom_buildscript-', suffix = '-rsync-path' )
		fullpath = os.path.join( tempDir, path )
		os.makedirs( fullpath )
		uploadLocation = self.getDestinationPath()
		args = [ '-avz', '-e', 'ssh -o BatchMode=yes', tempDir + os.sep, uploadLocation ]
		cmd = [ "rsync" ] + args
		searchPaths = [ "C:/Program Files/cwRsync/bin" ]

		runner = RunCommand( cmd, timeoutSeconds = 1200, searchPaths = searchPaths )
		if runner.run() != 0:
			mApp().debugN( self, 1, 'Creating extra sub directories {0} on the upload server failed!'.format( path ) )
			return runner.getReturnCode()
		else:
			mApp().debugN( self, 3, 'Created extra sub directories {0} on the upload server.'.format( path ) )
			return 0
示例#17
0
	def __getXmlSvnLog( self, url, revision, cap ):
		cmd = [ self.getCommand(), '--non-interactive', 'log', '--xml' ]
		if revision == 0:
			cmd.extend( ['--limit', '1' ] )
		cmd.extend( ['-rHEAD:{0}'.format( str( revision ).strip() ), url ] )
		runner = RunCommand( cmd, 3600, searchPaths = self.getCommandSearchPaths() )
		runner.run()
		if runner.getReturnCode() == 0:
			return minidom.parseString( runner.getStdOut().encode( "utf-8" ) )
		elif runner.getTimedOut() == True:
			raise ConfigurationError( 'Getting svn log for "{0}" timed out.'.format( self.getUrl() ) )
		else:
			msg = runner.getStdErrAsString().strip()
			raise ConfigurationError( 'Getting svn log failed: "{0}"'.format( msg ) )
	def update( self, folder ):
		cmd = [ 'git', 'pull' ]
		if self.getUseRebase():
			cmd.append( '--rebase' )
		runner = RunCommand( cmd )
		runner.setWorkingDir( folder )
		runner.run()
		if runner.getReturnCode() == 0:
			mApp().debugN( self, 2, 'Updated the git repository at "{0}"'.format( folder ) )
		else:
			# we are not raising an exception, because we do not want the master to die because of, for example, a temporary 
			# network outage
			message = runner.getStdErrAsString()
			mApp().message( self, 'Updating the git repository at "{0}" failed: "{1}"'.format( folder, message ) )
示例#19
0
	def runCommand( self, cmd, description, timeout = None, zeroReturnCode = True ):
		'''Helper method to run shell commands in tests. It creates a RunCommand object, runs it,
		and returns it. If the return code is not zero, it dumps the output of the command.'''

		runner = RunCommand( cmd, timeout )
		runner.run()
		if zeroReturnCode and runner.getReturnCode() != 0:
			print( '\n' )
			print( 'command failed: {0}'.format( description ) )
			print( 'output:' )
			print( runner.getStdOutAsString() )
			print( 'error output:' )
			print( runner.getStdErrAsString() )
		self.assertEqual( runner.getReturnCode() == 0, zeroReturnCode )
		return runner
示例#20
0
	def querySetting( self, setting ):
		cmd = [ sys.executable, self.getBuildScript(), 'query', setting ] + self.getParameters()
		runner = RunCommand( cmd, 1800 )
		runner.run()
		if runner.getReturnCode() != 0:
			raise MomError( 'Cannot query setting "{0}" for build script "{1}":\n {2}!'\
				.format( setting, self.getBuildScript(), runner.getStdErrAsString() ) )

		output = runner.getStdOutAsString()
		if not output:
			raise MomError( 'The build script "{0}" did not return a value! It said:\n {1}'
				.format( self.getBuildScript(), runner.getStdErrAsString() ) )

		line = output.strip()
		groups = re.search( '^(.+?): (.+)$', line )
		if not groups:
			raise MomError( 'Did not understand this output: "{0}"!'.format( line ) )

		variable = groups.groups()[1]
		return variable
示例#21
0
	def fetchRepositoryFolder( self, remotePath ):
		# FIXME Mike abstract cache location
		path = tempfile.mkdtemp( prefix = 'mom_buildscript-', suffix = make_foldername_from_string( self.getUrl() ) )
		if not self.getRevision():
			self.setRevision( 'HEAD' )
		location = self.getUrl()
		if remotePath:
			location += '/' + remotePath
		cmd = [ self.getCommand(), 'co', '-r', self.getRevision(), location ]
		runner = RunCommand( cmd, searchPaths = self.getCommandSearchPaths() )
		runner.setWorkingDir( path )
		runner.run()
		if runner.getReturnCode() == 0:
			localPath = os.path.join( path, remotePath )
			if os.path.exists( localPath ):
				return localPath, [ path ]
		raise ConfigurationError( 'The remote path {0} was not found in the repository at revision {1}'.format( 
				remotePath, self.getRevision() ) )
	def querySetting( self, name ):
		cmd = [ sys.executable, SimpleProjectTests.BuildScriptName, 'query', name ]
		runner = RunCommand( cmd )
		runner.run()
		return runner