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)
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)
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
def setSQComments(self, value): Any.requireIsDict(value) if value: self._bstpkg_src.pkgInfo_set('sqComments', value) else: self._bstpkg_src.pkgInfo_remove('sqComments')
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)
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
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')