def openPackage( self, topLevelDir ): topLevelDir = str(topLevelDir) oldcwd = os.getcwd() try: Any.requireIsTextNonEmpty( topLevelDir ) FastScript.changeDirectory( topLevelDir ) BuildSystemTools.requireTopLevelDir() except ( AssertionError, OSError, RuntimeError ) as details: FastScript.changeDirectory( oldcwd ) logging.error( details ) QMessageBox().critical( self.window, "Error", str(details), "OK" ) return logging.debug( 'opening package: %s', topLevelDir ) try: self.model.open( topLevelDir ) self.projectRoot = topLevelDir except ( NameError, SyntaxError, ValueError ) as details: logging.error( 'unable to read-in pkgInfo.py:' ) logging.error( details ) return self.taskButtons.setEnabled( True ) for terminal in self.terminals.values(): terminal.setPath( topLevelDir ) terminal.clear() self._runDependencyCheck( terminal )
def makeShellfiles(projectRoot): """ Creates all the various BashSrc, pkgInfo.py etc. files. If <topLevelDir>/<fileName> exists it will be copied instead of auto-generated. This allows writing fully handcrafted files if necessary. 'topLevelDir' is assumed to be a source code working copy (including the version, e.g. "/home/foo/mycode/Spam/42.0") """ Any.requireIsDir(projectRoot) oldcwd = os.getcwd() FastScript.changeDirectory(projectRoot) # collect package details once (this function is internally multi-threaded) try: details = PackageDetector(projectRoot) details.retrieveMakefileInfo() details.retrieveVCSInfo() except AttributeError: raise ValueError('Unable to create shellfiles in path="%s", is this ' 'a package directory?' % projectRoot) except ValueError as details: raise ValueError(details) FastScript.mkdir('./install') if os.path.exists('BashSrc'): logging.info('cp BashSrc ./install/') shutil.copy2('BashSrc', './install/BashSrc') else: BashSrcWriter(details).write('./install/BashSrc') if os.path.exists('CmdSrc.bat'): logging.info('cp CmdSrc.bat ./install/') shutil.copy2('CmdSrc.bat', './install/CmdSrc.bat') else: CmdSrcWriter(details).write('./install/CmdSrc.bat') # Note: pkgInfo.py is always generated (merged) PkgInfoWriter(details).write('./install/pkgInfo.py') if os.path.exists('packageVar.cmake'): logging.info('cp packageVar.cmake ./install/') shutil.copy2('packageVar.cmake', './install/packageVar.cmake') else: # try to generate a reasonable file (put explicitly under ./install/ # to indicate it's a installation-temporary file # # if the user wants to handcraft it, he could move this # auto-generated file to ./packageVar.cmake and add it to VCS PackageVarCmakeWriter(details).write('./install/packageVar.cmake') FastScript.changeDirectory(oldcwd)
def test_proxyInstallation(self): oldcwd = os.getcwd() packageName = 'ExamplePackage' packageVersion = '1.0' category = 'Applications' projectRoot = os.path.join('.', packageName, packageVersion) output = StringIO() if Any.getDebugLevel() <= 3 else None platform = Platforms.getHostPlatform() sitPath = SIT.getPath() # build + install package FastScript.changeDirectory(projectRoot) bst = BuildSystemTools() bst.setStdOut(output) bst.setStdErr(output) bst.compile() Any.requireIsDirNonEmpty('build') Any.requireIsDirNonEmpty(os.path.join('build', platform)) Any.requireIsDirNonEmpty('examples') Any.requireIsDirNonEmpty(os.path.join('examples', platform)) for fileName in ('ThreadingExampleAtomicOperation', 'ThreadingExampleJoin', 'ThreadingExampleTraps'): Any.requireIsFileNonEmpty(os.path.join('bin', platform, fileName)) if not ProxyDir.isProxyDir(sitPath): self.skip("%s: Is not a proxy directory" % sitPath) bst.makeDocumentation() bst.proxyInstall() installRoot = os.path.join(sitPath, category, packageName, packageVersion) # check result Any.requireIsDir(installRoot) Any.requireIsDirNonEmpty(os.path.join(installRoot, 'bin', platform)) Any.requireIsDirNonEmpty(os.path.join(installRoot, 'doc/html')) Any.requireIsFileNonEmpty( os.path.join(installRoot, 'doc/html/index.html')) Any.requireIsFileNonEmpty(os.path.join(installRoot, 'pkgInfo.py')) Any.requireIsFileNonEmpty(os.path.join(installRoot, 'packageVar.cmake')) for fileName in ('ThreadingExampleAtomicOperation', 'ThreadingExampleJoin', 'ThreadingExampleTraps'): Any.requireIsFileNonEmpty( os.path.join(installRoot, 'bin', platform, fileName)) # clean-up bst.uninstall(cleanGlobalInstallation=False) bst.distclean() self.assertFalse(os.path.exists(installRoot)) FastScript.changeDirectory(oldcwd)
def test_wineMSVC( self ): oldcwd = os.getcwd() tmpDir = tempfile.mkdtemp( prefix='test-' ) packageName = 'HelloWorld' packageVersion = '42.0' projectRoot = os.path.join( tmpDir, packageName, packageVersion ) output = StringIO() if Any.getDebugLevel() <= 3 else None hostPlatform = Platforms.getHostPlatform() targetPlatform = 'windows-amd64-vs2012' if targetPlatform not in CrossCompilation.getSwitchEnvironmentList( hostPlatform ): self.skipTest( '%s to %s cross-compilation not supported' % \ ( hostPlatform, targetPlatform ) ) # create package on-the-fly PackageCreator_C_Library( packageName, packageVersion, outputDir=tmpDir ).run() # build package FastScript.changeDirectory( projectRoot ) bst = BuildSystemTools() bst.setStdOut( output ) bst.setStdErr( output ) bst.setTargetPlatform( targetPlatform ) bst.compile() # check result Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'build' ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'build', targetPlatform ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'lib' ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'lib', targetPlatform ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'src' ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'test' ) ) Any.requireIsDirNonEmpty( os.path.join( projectRoot, 'test', targetPlatform ) ) # clean-up bst.distclean() self.assertFalse( os.path.exists( os.path.join( projectRoot, 'build' ) ) ) self.assertFalse( os.path.exists( os.path.join( projectRoot, 'lib' ) ) ) FastScript.remove( tmpDir ) FastScript.changeDirectory( oldcwd )
def _cmakeConfigure( self ): requireTopLevelDir( self._sourceTree ) cmd = 'cmake -DCMAKE_MODULE_PATH=%s -DCMAKE_BUILD_TYPE=%s' % \ ( self._cmakeModPath, self._buildType ) if self._cmakeOptions is not None: cmd += ' %s' % self._cmakeOptions if self._outOfTree: cmd += ' -DBST_TOP_LEVEL_DIR=%s %s' % ( self._binaryTree, self._sourceTree ) FastScript.remove( 'CMakeCache.txt' ) FastScript.remove( 'CMakeFiles' ) FastScript.remove( 'cmake_install.cmake' ) else: cmd += ' ../..' FastScript.remove( self._buildDir ) FastScript.mkdir( self._buildDir ) FastScript.changeDirectory( self._buildDir ) try: retVal = FastScript.execProgram( cmd, stdout=self._stdout, stderr=self._stderr ) except OSError as e: if e.errno == 2: # 'cmake' not installed raise EnvironmentError( "'cmake' is not installed" ) else: raise except subprocess.CalledProcessError: retVal = -1 finally: if not self._outOfTree: FastScript.changeDirectory( self._oldCWD ) return True if retVal == 0 else False
def execInAllProjects(command): Any.requireIsTextNonEmpty(command) # determine list of packages (and versions) to visit dirList = [] oldcwd = os.getcwd() if listfile: Any.requireIsFileNonEmpty(listfile) # read subdirectories from file, and remove trailing newlines dirList = FastScript.getFileContent(listfile, splitLines=True) dirList = map(str.strip, dirList) else: noSVN = re.compile("^.svn$") for path in FastScript.getDirsInDirRecursive(excludePattern=noSVN): if os.path.isfile(os.path.join(path, 'CMakeLists.txt')): dirList.append(path) # execute the task for entry in dirList: workingDir = os.path.realpath(os.path.join(oldcwd, entry)) logging.debug('cd %s' % workingDir) logging.info('workingDir=%s', workingDir) FastScript.changeDirectory(workingDir) try: FastScript.execProgram(command) except subprocess.CalledProcessError as e: if ignoreErrors: logging.warning(e) else: raise FastScript.changeDirectory(oldcwd)
def clone(self, output=None): """ Clones the full content of the SVN repository into a local Git repository. If 'output' is a StringIO object, the command's output will be redirected there (otherwise printed on screen). """ oldcwd = os.getcwd() packageName = os.path.basename(self._svnRepo.url) Any.requireIsTextNonEmpty(packageName) FastScript.mkdir(packageName) FastScript.changeDirectory(packageName) cmd = "git svn init %s" % self._svnRepo.url FastScript.execProgram(cmd, stdout=output, stderr=output) cmd = "git svn fetch" FastScript.execProgram(cmd, stdout=output, stderr=output) FastScript.changeDirectory(oldcwd)
def _onLocalShellInput( self, command ): if six.PY2: command = Any.Utf8( command ) if not command: # f.i. just RETURN pressed terminal = self.terminals[ 'localhost' ] terminal.writeCommand( '' ) terminal.setColor( 'grey' ) elif command.startswith( 'cd' ): # 'cd' is not a command but a shell built-in, # f.i. there is no /bin/cd executable path = shlex.split( command )[1] # show original path typed by user terminal = self.terminals[ 'localhost' ] terminal.writeCommand( 'cd %s' % path ) # proceed with full path path = os.path.expanduser( path ) if os.path.exists( path ): terminal.setColor( 'green' ) terminal.setPath( path ) FastScript.changeDirectory( path ) else: terminal.setColor( 'red' ) terminal.writeText( '%s: No such directory' % path ) elif command == 'exit' or command == 'quit': self.quit() else: # execute real executable self._focusLocalTerminal() self._execProgram( self.terminals[ 'localhost' ], command )
def test_nativeCompilation(self): oldcwd = os.getcwd() tmpDir = tempfile.mkdtemp(prefix='test-') packageName = 'HelloWorld' packageVersion = '42.0' projectRoot = os.path.join(tmpDir, packageName, packageVersion) output = StringIO() if Any.getDebugLevel() <= 3 else None platform = Platforms.getHostPlatform() # create package on-the-fly PackageCreator_C_Library(packageName, packageVersion, outputDir=tmpDir).run() # build package FastScript.changeDirectory(projectRoot) bst = BuildSystemTools() bst.setStdOut(output) bst.setStdErr(output) bst.compile() # check result Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'build')) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'build', platform)) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'lib')) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'lib', platform)) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'src')) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'test')) Any.requireIsDirNonEmpty(os.path.join(projectRoot, 'test', platform)) # clean-up bst.distclean() self.assertFalse(os.path.exists(os.path.join(projectRoot, 'build'))) self.assertFalse(os.path.exists(os.path.join(projectRoot, 'lib'))) FastScript.remove(tmpDir) FastScript.changeDirectory(oldcwd)
logging.info('SVN revision = %d' % revision) except (AssertionError, IOError): logging.error('') logging.error('unable to detect last globally installed revision') logging.error('falling back to HEAD revision') logging.error('') projectName = ProjectProperties.splitPath(package)[1] Any.requireIsTextNonEmpty(projectName) # create directory with name of package when downloading a particular version, # and cd into it if not fetchAll: FastScript.mkdir(projectName) FastScript.changeDirectory(projectName) repo = SVN.SVNRepository(url) repo.checkIsOnMasterServer() try: if userName: repo.setUserName(userName) else: repo.setConfiguredUserName() repo.checkout(revision) if os.path.exists(projectName): logging.debug('chmod 0700 %s', projectName) os.chmod(projectName, 0o700)
except ValueError as details: if str(details).find('Permission denied') != -1: msg = "CANCELLED! Repository exists! (but permission denied)" FastScript.prettyPrintError(msg) # create new repository repo.create() # import content to new repository logging.info('uploading data...') cmd = 'svn import -m "initial import" %s' % repositoryURL FastScript.execProgram(cmd) # move away original directory and download fresh working copy logging.debug('cd ..') FastScript.changeDirectory('..') oldName = os.path.basename(cwd) bakName = oldName + '.bak' logging.info('renaming %s --> %s' % (oldName, bakName)) os.rename(oldName, bakName) logging.info('downloading working copy...') repo = SVN.SVNRepository(repositoryURL) repo.checkout() logging.info('SVN import successful') msg = 'Directory structure has been changed! Please go one directory ' + \ 'up ("cd ..") and call "cd %s" there to reload the ' % oldName + \ 'directory contents!'
def main( self ): self.app = QApplication( [] ) self.app.setStyle( 'fusion' ) self.window = QMainWindow() self.menuBar = MenuBar.MenuBar( self.window ) self.mainLayout = QGridLayout() self.mainWidget = QWidget() self.multiTermWidget = TerminalWidget.MultiTermWidget() self.optionsWidget = BuildOptionsWidget.BuildOptionsWidget() self.controlsLayout = QHBoxLayout() self.controlsWidget = QWidget() self.metaInfo = MetaInfoWidget.MetaInfoWidget( self.model, self.controlsWidget ) self.console = ConsoleWidget.ConsoleWidget( self.controlsWidget ) self.taskButtons = TaskButtonsWidget.TaskButtonsWidget() self.platformCBs_natLayout = QVBoxLayout() self.platformCBs_natWidget = QGroupBox( 'build natively on' ) self.platformCBs_xcmpLayout = QVBoxLayout() self.platformCBs_xcmpWidget = QGroupBox( 'cross-compile for' ) self.rightPaneLayout = QVBoxLayout() self.rightPaneWidget = QWidget() self.runningProcesses = 0 self._seqTasksRun.connect( self._onSeqTasksRun ) self._seqTasksFinished.connect( self._onSeqTasksFinished ) # create an always existing terminal for localhost commands terminal = TerminalWidget.TerminalWidget( True, parent=self.multiTermWidget ) terminal.setToolTip( 'localhost' ) terminal.setWindowTitle('localhost') self.terminals[ 'localhost' ] = terminal self.multiTermWidget.addTerminal( terminal ) BST_localPaths = tuple( ToolBOSConf.getConfigOption( 'BST_localPaths' ) ) localHostname = socket.gethostname() sshPossible = SSH.guessRemoteAccessIsPossible() sshToolTip = 'Remote compilation not possible as SSH authorized keys are not configured' onLocaldiskToolTip = 'Remote compilation not possible as project is on local disc' projectOnLocaldisk = self.projectRoot.startswith( BST_localPaths ) remoteCompilation = sshPossible and not projectOnLocaldisk xcmpPlatforms = [] crossCompileHosts = self._toolBOSConf.getConfigOption( 'BST_crossCompileHosts' ) Any.requireIsDictNonEmpty( crossCompileHosts ) for platformName, compileHost in crossCompileHosts.items(): if compileHost: xcmpPlatforms.append( platformName ) xcmpPlatforms.sort() # platform selection in right pane, # create terminals for all other platforms (hide disabled ones) nativePlatforms = Platforms.getPlatformNames() defaultNative = CrossCompilation.getNativeCompilationList() defaultXcmp = CrossCompilation.getCrossCompilationList() for platform in nativePlatforms: checkbox = QCheckBox( platform ) checkbox.setChecked( platform in defaultNative ) checkbox.stateChanged.connect( self._onPlatformSelectionChange ) compileHost = CrossCompilation.getNativeCompileHost( platform ) natHost = 'Natively compile for "%s" on "%s"' % (platform, compileHost) checkbox.setToolTip( natHost ) self.platformCBs_nat[ platform ] = checkbox self.platformCBs_natLayout.addWidget( checkbox ) if remoteCompilation or compileHost == localHostname: checkbox.setEnabled( True ) else: checkbox.setEnabled( False ) checkbox.setChecked( False ) if projectOnLocaldisk: checkbox.setToolTip( onLocaldiskToolTip ) elif not sshPossible: checkbox.setToolTip( sshToolTip ) try: compileHost = CrossCompilation.getNativeCompileHost( platform ) if compileHost: logging.debug( 'native compile-host for platform=%s: %s', platform, compileHost ) fullPlatformString = Platforms.getFullPlatformString( platform ) infoText = 'Console output for %s (%s)' % ( platform, fullPlatformString ) terminal = TerminalWidget.TerminalWidget( False, parent=self.multiTermWidget ) terminal.setHostname( compileHost ) terminal.setToolTip( infoText ) terminal.setWindowTitle( infoText ) terminal.isNative = True terminal.hostChanged.connect( functools.partial( self._onHostChange, terminal ) ) terminal.closeRequest.connect( functools.partial( self._closeTerminal, terminal, checkbox ) ) self.terminals[ 'nativ_' + platform ] = terminal else: logging.debug( 'no native compile-host for platform=%s', platform ) checkbox.setEnabled( False ) checkbox.hide() # skip non-working platforms except KeyError: logging.error( "No native compile-host for platform=%s", platform ) return False for platform in xcmpPlatforms: checkbox = QCheckBox( platform ) compileHost = CrossCompilation.getCrossCompileHost(platform) xcmp = 'Cross-compile for "%s" on "%s"' % ( platform, compileHost ) checkbox.setToolTip( xcmp ) checkbox.setChecked( platform in defaultXcmp ) checkbox.stateChanged.connect( self._onPlatformSelectionChange ) self.platformCBs_xcmp[ platform ] = checkbox self.platformCBs_xcmpLayout.addWidget( checkbox ) if remoteCompilation or compileHost == localHostname: checkbox.setEnabled( True ) else: checkbox.setEnabled( False ) checkbox.setChecked( False ) if projectOnLocaldisk: checkbox.setToolTip( onLocaldiskToolTip ) elif not sshPossible: checkbox.setToolTip( sshToolTip ) try: compileHost = CrossCompilation.getCrossCompileHost( platform ) if compileHost: logging.debug( 'cross-compile host for platform=%s: %s', platform, compileHost ) fullPlatformString = Platforms.getFullPlatformString(platform) infoText = 'Console output for %s (%s)' % ( platform, fullPlatformString ) terminal = TerminalWidget.TerminalWidget( False, parent=self.multiTermWidget ) terminal.setHostname( compileHost ) terminal.setToolTip( infoText ) terminal.setWindowTitle(infoText) terminal.isNative = False terminal.hostChanged.connect( functools.partial( self._onHostChange, terminal ) ) terminal.closeRequest.connect( functools.partial( self._closeTerminal, terminal, checkbox ) ) self.terminals[ 'xcomp_' + platform ] = terminal else: logging.debug( 'no cross-compile host for platform=%s', platform ) checkbox.setEnabled( False ) checkbox.hide() # skip non-working platforms except KeyError: logging.error( "No cross-compile host for platform=%s", platform ) return False self.terminals[ 'xcomp_' + platform ] = terminal # do this once to get initial grid configuration right # (localhost + platform terminals) self._onPlatformSelectionChange() self.externalTools = ExternalToolsWidget.ExternalToolsWidget( self.model, self.window ) self.model.updatesAvailable.connect( self.externalTools.showUpdateIndicator ) # build options in right pane self.rightPaneLayout.setContentsMargins( 0, 0, 0, 0 ) self.platformCBs_natWidget.setLayout( self.platformCBs_natLayout ) self.platformCBs_xcmpWidget.setLayout( self.platformCBs_xcmpLayout ) self.rightPaneWidget.setLayout( self.rightPaneLayout ) self.rightPaneLayout.addWidget( self.externalTools ) self.rightPaneLayout.addWidget( self.platformCBs_natWidget ) self.rightPaneLayout.addWidget( self.platformCBs_xcmpWidget ) self.rightPaneLayout.addWidget( self.optionsWidget ) self.console.localCommand.connect( self._onLocalShellInput ) self.console.remoteCommand.connect( self._onRemoteShellInput ) self.controlsLayout.addWidget( self.metaInfo ) self.controlsLayout.addWidget( self.console ) # self.terminalWidget.setLayout( self.terminalLayout ) self.controlsWidget.setLayout( self.controlsLayout ) self.controlsLayout.setContentsMargins( 0, 0, 0, 0 ) self.taskButtons.clean.connect( self.clean ) self.taskButtons.build.connect( self.build ) self.taskButtons.proxyInstall.connect( self.proxyInstall ) self.taskButtons.globalInstall.connect(self.globalInstall) self.taskButtons.test.connect( self.test ) self.taskButtons.quit.connect( self.quit ) self.menuBar.clean.connect( self.clean ) self.menuBar.build.connect( self.build ) self.menuBar.proxyInstall.connect( self.proxyInstall ) self.menuBar.globalInstall.connect(self.globalInstall) self.menuBar.test.connect( self.test ) try: Any.requireIsDir( self.projectRoot ) FastScript.changeDirectory( self.projectRoot ) BuildSystemTools.requireTopLevelDir() self.openPackage( self.projectRoot ) except ( AssertionError, OSError, RuntimeError ): self.projectRoot = None self.taskButtons.setEnabled( False ) # main window configuration self.mainLayout.setColumnStretch( 0, 5 ) self.mainLayout.addWidget( self.multiTermWidget, 0, 0 ) self.mainLayout.addWidget( self.rightPaneWidget, 0, 1 ) self.mainLayout.addWidget( self.controlsWidget, 1, 0 ) self.mainLayout.addWidget( self.taskButtons, 1, 1 ) self.mainWidget.setLayout( self.mainLayout ) screen = QDesktopWidget().availableGeometry() self.window.setWindowIcon( IconProvider.getIcon( 'ToolBOS' ) ) self.window.setWindowTitle( 'BST.py (zen build mode)' ) self.window.setMenuBar( self.menuBar ) self.window.setCentralWidget( self.mainWidget ) self.window.resize( screen.width() / 5 * 4, screen.height() / 5 * 4 ) self.window.move( screen.center() - self.window.rect().center() ) self.window.show() self.menuBar.openPackage.connect( self.openPackage ) self.menuBar.quit.connect( self.quit ) if not self.projectRoot: self.menuBar.fileOpen() self.app.aboutToQuit.connect( self.quit ) return self.app.exec_()