def _setUserConfigOptions(config):
    """
        Writes the dict 'config' in ASCII yet Pythonic style to the user's
        configfile, so that it can be edited manually and read-in using
        FastScript.execFile().
    """
    from ToolBOSCore.Packages.CopyrightHeader import getCopyrightHeader

    Any.requireIsDict(config)

    content = getCopyrightHeader('python', 'User-preferences for ToolBOS SDK')

    for key, value in config.items():
        if Any.isText(value):
            value = "'%s'" % value  # write Python string, not just value

        content += '%s = %s\n\n' % (key, str(value))

    content += '\n# EOF\n'

    fileName = getSettingsFile_user()
    dirName = os.path.dirname(fileName)

    FastScript.mkdir(dirName)
    FastScript.setFileContent(fileName, content)
示例#2
0
def merge(orig, toMerge, position):
    """
    Commodity function that merges two IndexableOrderedDicts at `position`.

    `position` is the position where toMerge will be inserted in orig. Original
    ordering for both dicts is preserved.

    :param orig: Original dict
    :param toMerge: Dict whose contents are to be merged in 'orig'
    :param position: Position where the merge should be performed
    """

    Any.requireIsDict(orig)
    Any.requireIsDict(toMerge)

    keys = list(orig.keys())[:position] + list(toMerge.keys()) + list(
        orig.keys())[position:]
    values = list(orig.values())[:position] + list(toMerge.values()) + list(
        orig.values())[position:]

    retVal = IndexableOrderedDict()

    for i, key in enumerate(keys):
        retVal[key] = values[i]

    return retVal
    def _dependencyUpgrade( self, dryRun, replacementMap, ticketID ):
        """
            Patches the CMakeLists.txt / packageVar.cmake / ...
            files (if necessary) to include different packages.
        """
        Any.requireIsBool( dryRun )
        Any.requireIsDict( replacementMap )
        Any.requireIsTextNonEmpty( ticketID )

        status1  = False
        status2  = False
        status3  = False
        modified = []

        for old, new in replacementMap.items():
            status1 |= self._replace( 'CMakeLists.txt',   old, old, new, ticketID, dryRun )
            status2 |= self._replace( 'packageVar.cmake', old, old, new, ticketID, dryRun )
            status3 |= self._replace( 'pkgInfo.py',       old, old, new, ticketID, dryRun )

        if status1:
            modified.append( 'CMakeLists.txt' )

        if status2:
            modified.append( 'packageVar.cmake' )

        if status3:
            modified.append( 'pkgInfo.py' )

        return modified
    def __init__(self, packageName, packageVersion, values=None, outputDir=''):
        Any.requireIsTextNonEmpty(packageName)
        Any.requireIsTextNonEmpty(packageVersion)
        Any.requireIsText(outputDir)

        self.packageName = packageName
        self.packageVersion = packageVersion
        self.templateDir = templateDir
        self.templateDir_core = templateDir_core
        self.outputDir = outputDir
        self.dstDir = os.path.join(outputDir, packageName, packageVersion)

        # replacement map passed to templating engine
        self.values = {
            'packageName': packageName,
            'PACKAGENAME': packageName.upper(),
            'packageVersion': packageVersion
        }

        try:
            if values is None:
                self.force = False
            else:
                Any.requireIsDict(values)
                Any.requireIsBool(values['force'])
                self.force = values['force']
        except KeyError:  # not defined
            self.force = False

        if os.path.exists(self.dstDir) and not self.force:
            raise ValueError('%s: directory already exists' % self.dstDir)

        if values:
            Any.requireIsDict(values)
            self.values.update(values)
示例#5
0
    def setConfiguredUserName(self):
        """
            If a particular account has to be used to log into the server
            this function will auto-insert the username found in ToolBOS.conf
            for this server (if any).

            If no username was configured for the given server fall back to
            clean URL without any username (even if there was one before).
        """
        Any.requireIsTextNonEmpty(self._hostName)

        mapping = ToolBOSSettings.getConfigOption('serverAccounts')
        Any.requireIsDict(mapping)

        userName = None

        for candidate, account in mapping.items():

            if self._hostName.find(candidate) != -1:
                userName = account
                logging.info('found configured username=%s for server=%s',
                             userName, self._hostName)
                break

        self.setUserName(userName)
        logging.debug('modified URL: %s', self.url)
def runMakoEngine(srcFile, dstFile, values):
    """
        Runs the templating engine, applying the given values
        onto the template file 'srcFile', writing results into 'dstFile'.
    """
    Any.requireIsFile(srcFile)
    Any.requireIsText(dstFile)
    Any.requireIsDict(values)

    logging.info('processing %s' % dstFile)

    # First determine the directory of the template file, and tell Mako
    # to search there. In a second step tell Mako to search for a template
    # file in this search path.
    #
    # This is the only solution to get Mako's "include" working.

    lookup = TemplateLookup(directories=[os.path.dirname(srcFile)])
    template = lookup.get_template(os.path.basename(srcFile))

    dstContent = template.render(**values)
    Any.requireIsText(dstContent)

    FastScript.mkdir(os.path.dirname(dstFile))  # ensure dst dir. exists
    FastScript.setFileContent(dstFile, dstContent)
    Any.requireIsFile(dstFile)

    # Mako does not set the executable-flag on the generated output file.
    if os.access(srcFile, os.X_OK):  # if executable
        os.chmod(dstFile, os.stat(srcFile)[0])  # copy mode bits
示例#7
0
    def setSQComments(self, value):
        Any.requireIsDict(value)

        if value:
            self._bstpkg_src.pkgInfo_set('sqComments', value)
        else:
            self._bstpkg_src.pkgInfo_remove('sqComments')
示例#8
0
def getFlatDependencies(canonicalPaths, cache=None, sitPath=None):
    """
        Resolves all dependencies recursively and converts them to a flat
        set of overall dependencies.

        This function might be handy to determine all SIT packages that
        need to transferred to another site.
    """
    cache = {} if cache is None else cache
    sitPath = SIT.getPath() if sitPath is None else sitPath

    Any.requireIsIterable(canonicalPaths)
    Any.requireIsDict(cache)
    Any.requireIsTextNonEmpty(sitPath)

    result = set()

    for canonicalPath in canonicalPaths:
        requireIsCanonicalPath(canonicalPath)

        result.add('sit://' + canonicalPath)

        deps = getDependencies(canonicalPath,
                               recursive=True,
                               cache=cache,
                               systemPackages=False,
                               sitPath=sitPath)

        flatDeps = FastScript.flattenList(deps)

        for item in flatDeps:
            result.add(item)

    return result
    def runCommon(self, templateName, verbatim, templatize):
        import subprocess

        from ToolBOSCore.Platforms.Platforms import getHostPlatform
        from ToolBOSCore.Tools import SVN

        Any.requireIsTextNonEmpty(templateName)
        Any.requireIsSet(verbatim)
        Any.requireIsDict(templatize)

        hostPlatform = getHostPlatform()

        if not 'buildDir' in self.values:
            self.values['buildDir'] = os.path.join('build', hostPlatform)

        if not 'MAKEFILE_PLATFORM' in self.values:
            self.values['MAKEFILE_PLATFORM'] = hostPlatform

        srcDir = os.path.join(self.templateDir, templateName)
        dstDir = self.outputDir

        for item in verbatim:
            srcFile = os.path.join(srcDir, item)
            dstFile = os.path.join(dstDir, item)
            self.copyVerbatim(srcFile, dstFile)

        for key, value in templatize.items():
            srcFile = os.path.join(srcDir, key)
            dstFile = os.path.join(dstDir, value)
            self.templatize(srcFile, dstFile)

        # enable VCS integration if SVN information found
        try:
            wc = SVN.WorkingCopy()
            url = wc.getRepositoryURL()

        except subprocess.CalledProcessError as details:
            # most likely is no working copy --> ignore
            url = None
            logging.debug(details)

        srcFile = os.path.join(srcDir, 'misc.xml.mako')
        dstFile = os.path.join(dstDir, 'misc.xml')

        if url:
            logging.info('VCS integration enabled')
            self.values['repositoryUrl'] = url
        else:
            self.values['repositoryUrl'] = ''
            logging.info('VCS integration disabled (not an SVN working copy)')

        self.templatize(srcFile, dstFile)
示例#10
0
    def _readFiles(self):
        """
            Reads the config files into memory.

            The master-list of available config options is defined in
            the fallback list shipped with the application.
        """
        self._allSettings = {}

        # do in reverse order (starting from default), and update step-by-step
        # with the higher-priority settings
        order = self._getEvalOrder()
        order.reverse()

        for filePath in order:
            fileSettings = self._readFile(filePath)
            Any.requireIsDict(fileSettings)

            # merge settings into overall dict
            self._allSettings.update(fileSettings)

            if filePath is self._cwdFile:
                self._cwdSettings = fileSettings

            elif filePath is self._userFile:
                self._userSettings = fileSettings

            elif filePath is self._machineFile:
                self._machineSettings = fileSettings

            elif filePath is self._defaultFile:
                self._defaultSettings = fileSettings

            elif filePath in self._addFiles:
                logging.debug('merging default settings from: %s', filePath)
                self._defaultSettings.update(fileSettings)

            else:
                logging.warning('unexpected config file: %s', filePath)

        Any.requireIsDictNonEmpty(self._allSettings)
    def __init__(self, appName=None, parent=None):
        super(PreferencesDialog, self).__init__(parent)

        self._conf = ToolBOSConf()
        self._allData = self._conf.getConfigOptions()
        self._appName = appName
        self._userData = self._conf.getUserConfigOptions()
        self._labels = {}
        self._fields = {}
        self._revert = {}
        i = 0
        table = QWidget()
        layout = QGridLayout()

        Any.requireIsDictNonEmpty(self._allData)
        Any.requireIsDict(self._userData)

        for name, value in sorted(self._allData.items()):

            if appName is not None and not name.startswith(appName):
                continue

            if appName:
                label = QLabel(name.replace(appName + "_", ''))
            else:
                label = QLabel(name)

            field = QLineEdit(repr(value))
            revert = QPushButton()

            # by default long lines would be scrolled to see the end
            # of the text, however we want to see the beginning of
            # long settings
            field.setCursorPosition(0)

            # highlight user-modified entries
            changed = name in self._userData

            if changed:
                style = self._styleChanged
            else:
                style = self._styleUnchanged

            label.setStyleSheet(style)
            field.setStyleSheet(style)

            field.textChanged.connect(functools.partial(self._onChange, name))

            revert.setIcon(IconProvider.getIcon('edit-undo'))
            revert.setMaximumHeight(field.sizeHint().height())
            revert.pressed.connect(functools.partial(self._onRevert, name))
            revert.setToolTip('revert to default')
            revert.setEnabled(changed)

            layout.addWidget(label, i, 0)
            layout.addWidget(field, i, 1)
            layout.addWidget(revert, i, 2)

            self._labels[name] = label
            self._fields[name] = field
            self._revert[name] = revert

            i += 1

        table.setLayout(layout)

        scrollArea = QScrollArea()
        scrollArea.setWidget(table)
        scrollArea.setWidgetResizable(True)

        self._saveButton = QPushButton('&Save')
        self._quitButton = QPushButton('&Quit')

        self._submitLayout = QHBoxLayout()
        self._submitLayout.setContentsMargins(0, 0, 0, 0)
        self._submitLayout.addStretch(1)
        self._submitLayout.addWidget(self._saveButton)
        self._submitLayout.addWidget(self._quitButton)

        self._submitWidget = QWidget()
        self._submitWidget.setLayout(self._submitLayout)

        self._dialogLayout = QVBoxLayout()
        self._dialogLayout.addWidget(scrollArea)
        self._dialogLayout.addWidget(self._submitWidget)

        self.setLayout(self._dialogLayout)
        self.setWindowIcon(IconProvider.getIcon('ToolBOS'))
        self.setModal(True)

        if appName:
            self.setWindowTitle('%s Preferences' % appName)
        else:
            self.setWindowTitle('ToolBOS SDK Preferences')

        # hack: no appname means show full list --> resize geometry,
        #       with name we assume to get a small widget only --> auto-geometry
        if appName is None:
            screen = QApplication.desktop().screenGeometry()
            dialogWidth = screen.width() / 5 * 3
            dialogHeight = screen.height() / 5 * 3

            self.resize(dialogWidth, dialogHeight)
            self.move(screen.center() - self.rect().center())  # center

        self._saveButton.pressed.connect(self._onSave)
        self._quitButton.pressed.connect(self.close)
    def setCache(self, cache):
        Any.requireIsDict(cache)

        self._cache = cache
示例#13
0
    def _onDepDetectorFinished(self):
        logging.debug(
            'dependency detection in progress (helper-process finished)')

        self._depDetectorData.flush()

        base64payload = self._depDetectorData.getvalue()
        base64payloadSize = len(base64payload)
        base64payloadType = type(base64payload)

        logging.debug('base64payload type: %s', base64payloadType)
        logging.debug('base64payload size: %d', base64payloadSize)

        if base64payloadSize == 0:
            logging.debug('no dependency data received')
            return

        if six.PY2:
            if not Any.isInstance(base64payload, unicode):
                logging.debug('received dependency data of unexpected type')
                logging.debug(
                    '(this could come from a ~/.bashrc which prints text)')

                return

        else:
            if not Any.isInstance(base64payload, bytes):
                logging.debug('received dependency data of unexpected type')
                logging.debug(
                    '(this could come from a ~/.bashrc which prints text)')

                return

        dillPayload = base64.b64decode(base64payload)
        dillPayloadSize = len(dillPayload)
        dillPayloadType = type(dillPayload)

        logging.debug('dillPayload type: %s', dillPayloadType)
        logging.debug('dillPayload size: %d', dillPayloadSize)

        data = dill.loads(dillPayload)
        Any.requireIsDictNonEmpty(data)

        Any.requireIsInstance(data['bstpkg_src'], BSTPackage.BSTSourcePackage)
        Any.requireIsInstance(data['bstpkg_global'],
                              BSTPackage.BSTGloballyInstalledPackage)
        Any.requireIsDict(data['installStatus'])
        Any.requireIsDict(data['installStatusLocal'])
        Any.requireIsDict(data['installStatusProxy'])
        Any.requireIsDict(data['installStatusGlobal'])

        self._bstpkg_src.depSet = data['bstpkg_src'].depSet
        self._bstpkg_src.depTree = data['bstpkg_src'].depTree
        self._bstpkg_global = data['bstpkg_global']

        try:
            self._bstpkg_global.open(self.getCanonicalPath())
        except AssertionError as details:
            logging.debug(details)

        self._installStatus = data['installStatus']
        self._installStatusLocal = data['installStatusLocal']
        self._installStatusProxy = data['installStatusProxy']
        self._installStatusGlobal = data['installStatusGlobal']

        logging.debug('depSet:     %s', self._bstpkg_src.depSet)
        logging.debug('depTree:    %s', self._bstpkg_src.depTree)
        logging.debug('revDepSet:  %s', self._bstpkg_global.revDepSet)
        logging.debug('revDepTree: %s', self._bstpkg_global.revDepTree)

        self.depsDetected.emit(True)

        # retrieving direct dependencies should work, consider an error if not

        try:
            Any.requireIsSet(self._bstpkg_src.depSet)
            Any.requireIsList(self._bstpkg_src.depTree)
        except AssertionError:
            self.depsDetected.emit(False)
            logging.error('unable to retrieve dependencies')

        # while for reverse dependencies it is significant if the package is
        # installed, yet

        if self._bstpkg_global.isInstalled():
            try:
                Any.requireIsSet(self._bstpkg_global.revDepSet)
                Any.requireIsList(self._bstpkg_global.revDepTree)
            except AssertionError:
                logging.error('unable to retrieve reverse dependencies')
        else:
            logging.debug('not globally installed --> no reverse dependencies')

        logging.debug('dependency detection finished')