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 setEnabled(self, status, button='all'): Any.requireIsBool(status) Any.requireIsTextNonEmpty(button) if button == 'all': self._buildButton.setEnabled(status) self._cleanButton.setEnabled(status) self._globalInstButton.setEnabled(status) self._proxyInstButton.setEnabled(status and self.hasProxy) self._testButton.setEnabled(status) elif button == 'build': self._buildButton.setEnabled(status) elif button == 'clean': self._cleanButton.setEnabled(status) elif button == 'globalInstall': self._globalInstButton.setEnabled(status) elif button == 'proxyInstall': self._proxyInstButton.setEnabled(status and self.hasProxy) elif button == 'test': self._testButton.setEnabled(status) else: raise ValueError('unknown button: %s' % button)
def setSQLevel( self, level ): Any.requireIsTextNonEmpty( level ) if level == CheckRoutine.sqLevelDefault: self.pkgInfo_remove( 'sqLevel' ) # no need to store else: self.pkgInfo_set( 'sqLevel', level )
def ensureHasDependency(content, package): """ Ensures if the direct dependencies/inclusions are present or not in the provided string (= CMakeLists.txt file content). """ Any.requireIsTextNonEmpty(content) ProjectProperties.requireIsCanonicalPath(package) logging.debug('Validating CMakeLists.txt') category, name, version = ProjectProperties.splitPath(package) pkgNoVersion = os.path.join(category, name) found = False for dep in getDependencies(content): if dep.find(pkgNoVersion) > 0: found = True logging.debug('%s dependency already present', pkgNoVersion) if found: return content else: logging.debug('inserting dependency to: %s', package) return insertDependency(content, package)
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 check( fileName ): Any.requireIsFile( fileName ) content = FastScript.getFileContent( fileName ) return content.find( old1 ) != -1 or \ content.find( old2 ) != -1
def _getEvalOrder(self): """ Returns an ordered list with paths to configfiles (in search order). First element: Highest priority (user's home dir.) Last element: Lowest priority (default shipped with application) """ Any.requireIsList(self._addFiles) resultList = [] try: resultList.append(self._cwdFile) except OSError as details: # may be raised by os.getcwd() if there is a problem with the CWD # e.g. NFS problem or directory deleted by another process # # continuing to work in such situation is dangerous, we really should # stop in such case logging.error(details) logging.error('Problem with current working directory detected!') raise SystemExit() resultList.append(self._userFile) resultList.append(self._machineFile) for addFile in self._addFiles: resultList.append(addFile) resultList.append(self._defaultFile) return resultList
def test_addGlobalInstallLog( self ): msgType = 'NEW' message = 'Test message (unittest)' # create log entry logEntry = GlobalInstallLog( ToolBOSSettings.canonicalPath, isFirstInstall=False, msgType=msgType, message=message ) fileName = tempfile.mkstemp( prefix='test-' )[1] logEntry.setFileName( fileName ) logEntry.writeFile() Any.requireIsFileNonEmpty( fileName ) content = FastScript.getFileContent( fileName ) # check result self.assertTrue( content.find( msgType ) > 0, "log file incorrect" ) self.assertTrue( content.find( message ) > 0, "log file incorrect" ) # clean-up FastScript.remove( fileName )
def setContent(self, filePath): """ Allows setting content from original file, in order to evolve an existing pkgInfo.py over time. """ Any.requireIsFileNonEmpty(filePath) self.content = FastScript.getFileContent(filePath)
def _assembleScriptCmd( self, name ): Any.requireIsTextNonEmpty( name ) # When compiling natively, under Linux the *.sh and on Windows the # *.bat needs to be executed. # # But also when cross-compiling we need to execute the script for # the host platform, f.i. a Windows *.bat script won't work on # Linux. # # Hence there is no need to check for the targetPlatform at all, # see TBCORE-1217. if self._hostPlatform.startswith( 'windows' ): filename = '%s.bat' % name cmd = filename else: filename = '%s.sh' % name if Any.getDebugLevel() > 3: cmd = 'bash -x ./%s' % filename else: cmd = './' + filename return filename, cmd
def _execTask( self, name, corefunc ): Any.requireIsTextNonEmpty( name ) Any.requireIsCallable( corefunc ) logging.debug( 'Build System Tools: "%s" step started', name ) status = self._runScript( 'pre-%s' % name ) if status: self._switchToTargetEnv() coreScript = self._assembleScriptCmd( name )[0] if os.path.exists( coreScript ): status = self._runScript( name ) else: status = corefunc() self._switchToHostEnv() if status: status = self._runScript( 'post-%s' % name ) logging.debug( 'Build System Tools: "%s" step finished', name ) return status
def setBuildType( self, buildType ): Any.requireIsTextNonEmpty( buildType ) Any.requireMsg( buildType in ( 'Release', 'Debug' ), 'invalid build type' ) self._buildType = buildType
def addPath( self, path ): Any.requireIsTextNonEmpty( path ) filePath = os.path.join( path, self._settingsFile ) logging.debug( 'registering add. config file: %s', filePath ) self._addPaths.append( filePath )
def convertStr(s): """ Converts a string of Python's 'str' type to: Py2: unicode Py3: str (no need to do anything) """ Any.requireIsInstance(s, str) if six.PY2: # decode str-object (which may contain UTF-8/16) to Unicode object try: result = s.decode('utf8') except UnicodeDecodeError: logging.warning('UTF-8 conversion error, trying UTF-16') try: result = s.decode('utf16') except UnicodeDecodeError as e: logging.error('conversion error: %s', e) result = e else: # no need to do anything (str-objects are unicode-ready) result = s return result
def delUserConfigOption(varName): """ Removes a certain config option from the user's configfile. """ Any.requireIsTextNonEmpty(varName) # read current settings (if any) config = getUserConfigOptions() # remove setting try: del config[varName] logging.debug('deleted config option: %s', varName) # delete entire file if there are no settings left if config: _setUserConfigOptions(config) else: fileName = getSettingsFile_user() logging.debug('deleting empty configfile') logging.debug('rm %s', fileName) FastScript.remove(fileName) except KeyError: logging.debug('%s: No such user config option', varName)
def getConfigOption(name): cache = getGlobalToolBOSConf() Any.requireIsTextNonEmpty(name) Any.requireIsInstance(cache, ToolBOSConf) return cache.getConfigOption(name)
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 _createWizardPage_chooseTemplateType(self): """ Returns a QWizardPage object which asks for the data source. """ page = QWizardPage() page.setTitle('Select template type') page.setSubTitle('Please choose the type of package to be created.') radios = [] group = QVBoxLayout(page) tmp = filter(self._isVisibleTemplate, PackageCreator.getTemplatesAvailable()) self._templatesAvailable = list(tmp) for template in self._templatesAvailable: logging.debug('available template: %s' % template) text = template.replace('_', ' ') radio = QRadioButton(text) page.registerField(template, radio) radios.append(radio) group.addWidget(radio) Any.requireMsg(len(radios) > 0, "No templates found, likely a bug :-(") radios[0].setChecked(True) return page
def getDepInstallCmd(canonicalPaths): """ Returns the Debian/Ubuntu command-line to install all the listed packages. Example: toAptDepsCmd( [ 'deb://foo', 'deb://bar', 'deb://baz' ] ) 'apt install foo bar baz' If 'canonicalPaths' does not contain any item starting with 'deb://' the function will return None. """ Any.requireIsListNonEmpty(canonicalPaths) expr = re.compile('^deb://(.+)') result = '$ apt install' debFound = False for canonicalPath in canonicalPaths: tmp = expr.match(canonicalPath) if tmp: debFound = True pkgName = tmp.group(1) Any.requireIsTextNonEmpty(pkgName) result = '%s %s' % (result, pkgName) return result if debFound else None
def getCDefinesAsList(targetPlatform, targetName): """ Returns a list with all compiler definitions set for the package using the addDefinitions() directive. If no additional definitions are set, an empty list will be returned. NOTE: CMake supports that compiler definitions may be different for various target platforms, and even per executable and/or library. Therefore you need to specify both of them. A rule of thumb is targetName='<PROJECTNAME>-global'. """ Any.requireIsTextNonEmpty(targetPlatform) Any.requireIsTextNonEmpty(targetName) result = [] regexp = re.compile('-D\s*(.*)') for token in getCDefinesAsString(targetPlatform, targetName).split(): if token.startswith('-D'): tmp = regexp.search(token) item = (tmp.group(1)).strip() result.append(item) return frozenset(result)
def _checkForUpdates(): """ Check if there are any updates for this package. """ from ToolBOSCore.CIA.PatchSystem import PatchSystem logging.debug('checking for updates') oldDebugLevel = Any.getDebugLevel() Any.setDebugLevel(1) patcher = PatchSystem() result = patcher.run(dryRun=True) Any.setDebugLevel(oldDebugLevel) if len(result) > 0: logging.info('') logging.info('\033[7;37m\033[1;31m' + ' ' * 60 + '\033[0m') logging.info( '\033[1;31mupdates are available for this package:\033[0m') for patch in result: logging.info(' - %s', patch[0]) logging.info('') logging.info('') logging.info( '\033[0;31mYou may apply them using "BST.py --upgrade".\033[0m') logging.info('\033[7;37m\033[1;31m' + ' ' * 60 + '\033[0m') logging.info('') else: logging.debug('no need to patch')
def errorParser(errorRoot, details): kindNode = errorRoot.find('kind') descriptionNode = errorRoot.find('xwhat') stackNode = errorRoot.find('stack') Any.requireMsg(kindNode is not None, 'Malformed Valgrind output') Any.requireMsg(descriptionNode is not None, 'Malformed Valgrind output') kind = KIND_MAP[kindNode.text] description = descriptionNode.find('text').text fname = '' lineno = '' # Try to isolate among the stack frames # the last one in our code, to help the # user find the root of the problem. if stackNode is not None: for frame in stackNode.findall('frame'): objNode = frame.find('obj') if objNode is not None: obj = objNode.text stackFrameObjPath = os.path.realpath(obj) if stackFrameObjPath.startswith(details.topLevelDir): fname = frame.find('file').text lineno = frame.find('line').text return Error(kind, description, fname, lineno)
def setColor(self, color): Any.requireIsInstance(color, QColor) palette = self.palette() palette.setColor(QPalette.Base, color) self.setAutoFillBackground(True) self.setPalette(palette)
def enableDeployKey(self, keyID): Any.requireIsIntNotZero(keyID) logging.debug('adding deployKey=%d to project=%s', keyID, self._project.path_with_namespace) self._project.keys.enable(keyID)
def requireOutsideTmpDir(): """ Decorator for isWithinTmpDir() which throws an AssertionError if the result is True. """ Any.requireMsg(not isWithinTmpDir(), 'Klocwork can not be run within %s' % tempfile.gettempdir())
def getConfigOptions(addPaths=None): """ Returns a dict with all config options and their values. The master-list of available config options is defined in etc/ToolBOS.conf (the fallback list shipped with ToolBOS SDK). To search in non-standard locations provide a list 'addPaths'. Its path entries will be searched right after ./ToolBOS.conf. """ allSymbols = {} # do in reverse order (starting from default), and update step-by-step # with the higher-priority settings order = _getEvalOrder(addPaths) order.reverse() for fileName in order: try: fileSymbols = FastScript.execFile(fileName) logging.debug('evaluating %s', fileName) except (AssertionError, IOError, OSError): fileSymbols = {} allSymbols.update(fileSymbols) # remove Python modules, callables etc. from dict result = {} for key, value in allSymbols.items(): if Any.isTextNonEmpty(key) and not Any.isCallable(value): result[key] = value return result
def switchEnvironment(toPlatform): """ Modifies the environment variables to appear as if this was another operating system. This is primary used for cross-compilations. If you would like to later restore the original settings, make sure to call "origEnv = FastScript.getEnv()" before invoking this function. When you are done, you can then reset the whole environment by calling "FastScript.setEnv( origMap )". """ Any.requireIsTextNonEmpty(toPlatform) fromPlatform = Platforms.getHostPlatform() src = fromPlatform.replace('-', '') dst = toPlatform.replace('-', '') funcName = "_switchEnv_%s_to_%s" % (src, dst) if fromPlatform == toPlatform: return try: func = globals()[funcName] except KeyError: msg = "requested platform switch (%s to %s) is not supported" % \ ( fromPlatform, toPlatform ) raise NotImplementedError(msg) func() FastScript.setEnv('MAKEFILE_PLATFORM', toPlatform)
def getConfigOption(varName, addPaths=None): """ This function searches for a variable 'varName' in the ToolBOS configfile(s) named 'ToolBOS.conf'. Such configfiles are searched by priority: 1) within the current working directory 2) entries from additional search-paths if provided 3) within ~/.HRI (user's home directory) 4) within /etc (set by the system administrator) 5) within the ToolBOSCore package itself (default / fallback) To search in non-standard locations provide a list 'addPaths'. Its path entries will be searched right after ./ToolBOS.conf. If none of the files contains the specified variable, a key error will be thrown. """ Any.requireIsTextNonEmpty(varName) for fileName in _getEvalOrder(addPaths): # logging.debug( 'evaluating %s', fileName ) try: result = _getConfigOptionFromFile(varName, fileName) # logging.debug( 'found "%s" in %s', varName, fileName ) return result except (AssertionError, IOError, KeyError, OSError): pass # nowhere found raise KeyError("Config option '%s' is nowhere set." % varName)
def __init__(self, details=None): """ Allows modifying an existing pkgInfo.py file, f.i. add/remove entries. Multiple changes can be applied in a row. The actual re-writing of the file is done using write(). We attempt to modify the package in the current working directory unless another PackageDetector class is provided. """ if details is not None: Any.requireIsInstance(details, PackageDetector) self._details = details else: self._details = PackageDetector() self._filePath = os.path.join(self._details.topLevelDir, 'pkgInfo.py') self._worker = PkgInfoWriter(self._details, sourceTree=True) try: self._content = FastScript.getFileContent(self._filePath) self.checkSyntax() self._data = getPkgInfoContent(dirName=self._details.topLevelDir) except IOError: self._content = self._worker.addLeadIn() except SyntaxError: raise
def randomizeValidityFlags(): """ Randomizes valid-/invalid-flags to be used as C-defines, e.g.: #define FOO_VALID ( 0x998877 ) #define FOO_INVALID ( 0x112233 ) Returns a tuple of two strings containing the hexvalues. """ valid = random.randint(0x00000000, 0xFFFFFFFF) invalid = random.randint(0x00000000, 0xFFFFFFFF) if valid == invalid: valid, invalid = randomizeValidityFlags() # format int as hex-string with padding # (e.g. 0x00000000 so ten chars in total) # # { # Format identifier # 0: # first parameter # # # use "0x" prefix # 0 # fill with zeroes # {1} # to a length of n characters (including 0x), defined by the second parameter # x # hexadecimal number, using lowercase letters for a-f # } # End of format identifier # validStr = "{0:#0{1}x}UL".format(valid, 10) invalidStr = "{0:#0{1}x}UL".format(invalid, 10) Any.requireIsTextNonEmpty(validStr) Any.requireIsTextNonEmpty(invalidStr) return validStr, invalidStr