Example #1
0
    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 )
Example #5
0
    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)
Example #7
0
    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)
Example #8
0
    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 )
Example #9
0
    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!'
Example #12
0
    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_()