def _getInstallStatus(self, package, sitPath): try: installed = ProjectProperties.isInstalled(package, sitPath) except ValueError: installed = False if installed: if package.startswith('sit://'): msg = '%s: exists' % \ os.path.join( sitPath, SIT.strip( package) ) else: msg = '%s: installed on this machine' % \ package.replace( 'deb://', '' ) else: if package.startswith('sit://'): msg = '%s: no such file or directory' % \ os.path.join( sitPath, SIT.strip( package ) ) else: msg = '%s: not installed on this machine' % \ package.replace( 'deb://', '' ) return installed, msg
def _removeBrokenSymlinks(sitRootPkgList, sitProxyPkgList, sitRoot, sitProxy, dryRun): """ If 'dryRun' is True, it won't actually do anything to your proxy. Returns the number of broken links that have been removed (or that would have been removed, in case of dry run). """ requireIsProxyDir(sitProxy) logging.info('searching for broken symlinks...') brokenLinks = _findBrokenLinks(sitProxy) for path in brokenLinks: if dryRun: logging.info('-- DRY RUN -- found broken symlink %s', path) else: if path.endswith('.py'): logging.info('deleting %s', path) else: logging.info('package was uninstalled: %s', SIT.strip(path)) os.remove(path) return len(brokenLinks)
def _createCellWidget(self, package): Any.requireMsg( Any.isInstance( package, BSTPackage.BSTPackage ) or \ Any.isInstance( package, DebianPackage ), 'unexpected datatype: %s' % type(package) ) Any.requireIsTextNonEmpty(package.url) cell = QTreeWidgetItem([package.url]) inSystem = self._model.isInstalled_locally inProxy = self._model.isInstalled_proxySIT inGlobal = self._model.isInstalled_globalSIT ProjectProperties.requireIsCanonicalPath(SIT.strip(package.url)) if package.url.startswith('sit://'): if self._hasProxy: self._setCellColorCode(cell, 1, inProxy(package.url)) else: self._setCellColorCode(cell, 1, None) self._setCellColorCode(cell, 2, inGlobal(package.url)) self._setCellColorCode(cell, 3, None) else: self._setCellColorCode(cell, 1, None) self._setCellColorCode(cell, 2, None) self._setCellColorCode(cell, 3, inSystem(package.url)) return cell
def getBuildDependencies(project, recursive=False): """ For now this simply calls getBuildDependenciesFromPkgInfo(), ignoring the case that the pkgInfo.py might not be present. Note: Unlike getDependencies(), the result of this function is a flat (non-nested) list. """ from ToolBOSCore.Storage.PkgInfo import getPkgInfoContent Any.requireIsTextNonEmpty(project) try: resultList = getPkgInfoContent(project)['buildDepends'] except (AssertionError, IOError, KeyError): resultList = [] if recursive: depList = getDependencies(project, recursive=True) depList = FastScript.flattenList(depList) for dep in depList: if dep.startswith('sit://'): try: buildDepList = getPkgInfoContent( SIT.strip(dep))['buildDepends'] except (AssertionError, IOError, KeyError): buildDepList = [] if buildDepList: resultList.append(buildDepList) resultList = FastScript.reduceList(resultList) return resultList
def getBuildRequirements(projectURL, recursive=False, cache=None, ignoreErrors=False): """ Returns a list of packages that are necessary to build the specified package. 'projectURL' must be a canonical path starting with the "sit://" prefix. If recursive=False, the list will contain the pure untreated strings stored in the pkgInfo.py file. There is no preprocessing done on its semantics. In recursive mode, we need to follow those paths and need to resolve 'sit://' etc. """ Any.requireIsTextNonEmpty(projectURL) Any.requireMsg( projectURL.startswith( 'sit://' ) == True, "'project' parameter needs to start with sit:// " + \ "'(you passed: %s)" % projectURL ) # query dependencies of package, don't forget to add package itself resultList = [] # projectURL ] project = SIT.strip(projectURL) if not isinstance(cache, dict): cache = {} try: # first look-up the cache depList = cache[projectURL] #logging.debug( 'CACHE HIT: %s' % projectURL ) except KeyError: # if not found read from filesystem #logging.debug( 'CACHE MISS: %s' % projectURL ) tmpList = getDependencies( project, systemPackages=False ) + \ getBuildDependencies( project ) depList = FastScript.reduceList(tmpList) # store the direct dependencies into the cache map cache.update({projectURL: depList}) for dep in depList: resultList.append(dep) if recursive == True and not dep.startswith('deb://'): subDepList = getBuildRequirements(dep, recursive, cache, ignoreErrors) for subDep in subDepList: if subDep not in resultList: resultList.append(subDep) return resultList
def registerNormalPackages(sitPath, dryRun=False): """ Searches the SIT for RTMaps packages and invokes registerHondaPackage() for each of them. """ Any.requireIsDir(sitPath) Any.requireIsBool(dryRun) sitProxyPath = SIT.getPath() ProxyDir.requireIsProxyDir(sitProxyPath) searchBaseDir = os.path.join(sitPath, 'Modules', 'RTMaps') # Any.requireIsTextNonEmpty( searchBaseDir ) # dir. might not exist Any.requireIsTextNonEmpty(searchBaseDir) indexBaseDir = getIndexBaseDir(sitProxyPath) # Any.requireIsDir( indexBaseDir ) # dir. might not exist Any.requireIsTextNonEmpty(indexBaseDir) logging.debug('SIT path: %s', sitPath) logging.debug('search basedir: %s', searchBaseDir) logging.debug('index basedir: %s', indexBaseDir) # find *.pck files logging.debug('scanning %s...', searchBaseDir) pckPaths = FastScript.findFiles(searchBaseDir, ext='.pck') Any.requireIsList(pckPaths) logging.debug('found HORP files:') logging.debug(pckPaths) # process each *.pck file (tokenize path and create symlink) for pckPath in pckPaths: # the *.pck file is located on the 3rd subdirectory level relative # to the installRoot, so compute the installRoot based on this tokens = pckPath.split(os.path.sep) installRoot = os.path.sep.join(tokens[:-3]) package = SIT.strip(installRoot) Any.requireIsDir(installRoot) Any.requireIsTextNonEmpty(package) try: registerNormalPackage(package, sitProxyPath, indexBaseDir, dryRun) except ValueError as e: logging.error(e)
def toCanonicalPath(string): """ Takes a string and attempts to shrink it to a canonical path, removing any leading SIT prefix or trailing slash. '/hri/sit/latest/DevelopmentTools/ToolBOSCore/3.0/' --> 'DevelopmentTools/ToolBOSCore/3.0' """ Any.requireIsTextNonEmpty(string) canonicalPath = SIT.strip(string) # remove trailing slashes (occurs if user provides a string with trailing slashes) while canonicalPath.endswith('/'): canonicalPath = canonicalPath[0:-1] return canonicalPath
def _removeEmptyCategories(sitRootPkgList, sitProxyPkgList, sitRoot, sitProxy, dryRun): """ If 'dryRun' is True, it won't actually do anything to your proxy. Returns the number of empty directories (unused SIT categories, packages without any version) that have been removed (or that would have been removed, in case of dry run). All parameters except 'sitProxy' path will be ignored and only kept for compatibility. """ requireIsProxyDir(sitProxy) candidates = set() whitelist = (os.path.join(sitProxy, 'Modules', 'Index'), ) for root, dirs, files in os.walk(sitProxy, followlinks=False): for entry in dirs: candidate = os.path.join(root, entry) if candidate not in whitelist: candidates.add(candidate) # path must not contain anything like a version string expr = re.compile('/\d+\.\d+') noMatch = lambda p: not (expr.search(p)) candidates = filter(noMatch, candidates) # only keep really empty directories isEmptyDir = lambda p: os.listdir(p) == [] emptyDirs = list(filter(isEmptyDir, candidates)) emptyDirs.sort() for path in emptyDirs: if dryRun: logging.info('-- DRY RUN -- found empty dir. %s' % path) else: logging.info('rmdir %s' % SIT.strip(path)) os.rmdir(path) return len(emptyDirs)
'servers may require additional steps before connecting, such ' + \ 'as setting up "authorized keys" or SSH agents.' argman = ArgsManagerV2.ArgsManager(desc) argman.addArgument('-u', '--user', help='account name to use for SVN server') argman.addArgument('package', help='absolute or canonical package path') argman.addExample('%(prog)s Libraries/MasterClock/1.6') argman.addExample('%(prog)s -v -u monthy Libraries/MasterClock/1.6') argman.addExample('%(prog)s ${SIT}/Libraries/MasterClock/1.6') args = vars(argman.run()) package = SIT.strip(args['package']) # strip-off the SIT part if provided userName = args['user'] #---------------------------------------------------------------------------- # Main program #---------------------------------------------------------------------------- # When using shell tab-completion on SIT paths for the canonical path, # a trailing slash might be added. Remove this before proceeding. if package.endswith('/'): package = package[:-1] logging.debug('package truncated to: %s', package) try: ProjectProperties.requireIsCanonicalPath(package)
def source(package): """ Python equivalent of "source BashSrc" from SIT, in order to setup PATH, LD_LIBRARY_PATH,... within the Python process. @anchor ProcessEnv_source """ ProjectProperties.requireIsCanonicalPath(package) sourced = FastScript.getEnv('TOOLBOSCORE_SOURCED') Any.requireMsg(sourced, '$TOOLBOSCORE_SOURCED must not be empty') # avoid double-sourcing if package in sourced: return True ProjectProperties.requireIsInstalled(package) logging.debug('source %s/pkgInfo.py', package) sourced = '%s %s' % (package, sourced) FastScript.setEnv('TOOLBOSCORE_SOURCED', sourced) # load pkgInfo.py (if exists) try: content = getPkgInfoContent(project=package) except AssertionError: return True # no such file, this is OK except (IOError, OSError) as details: logging.error(details) return False # setup environment of this package try: envVars = content['envVars'] except KeyError: envVars = [] # no such setting, this is OK sitPath = SIT.getPath() for name, value in envVars: # replace known placeholdes value = value.replace('${INSTALL_ROOT}', os.path.join(sitPath, package)) FastScript.setEnv_withExpansion(name, value) # source dependent packages try: # TODO: eventually extend to sourcing recommended/suggested packages depList = content['depends'] except (AssertionError, KeyError): depList = [] # no such setting, this is OK for dep in depList: if not dep.startswith('deb://'): source(SIT.strip(dep)) # special treatment of PYTHONPATH: # After sourcing add new entries in PYTHONPATH to sys.path _expandSysPath() return True
def getDependencies(project, recursive=False, cache=None, ignoreErrors=False, highlightMissing=True, systemPackages=True, sitPath=None): """ Returns a list containing the direct dependencies of this package. If "recursive=True", they will be followed and the list actually becomes a nested list / tree. If the package does not have any dependencies the list will be empty. 'project' must be specified in canonical form, e.g.: - 'Libraries/Serialize/3.0' - 'sit://Libraries/Serialize/3.0' - 'deb://gcc' If 'recursive=False', the list will contain the pure untreated strings stored in the pkgInfo.py file. There is no preprocessing done on its semantics. In recursive mode, we need to follow those paths and need to resolve 'sit://' etc. The 'cache' map is internally used to avoid processing already treated packages again. You should not specify this parameter when calling this function unless you need to query the dependencies of multiple projects in a list. In such case providing a cache-map will improve performance a lot. If 'systemPackages=False', Non-SIT packages such as *.deb or *.rpm packages will be excluded from the result list. You may speed-up this function by providing 'sitPath' so that it does not need to be queried internally every time. """ from ToolBOSCore.Storage.PkgInfo import getPkgInfoContent if project.find('://') > 0: projectURL = project project = SIT.strip(project) else: projectURL = 'sit://' + project # default protocol resultList = [] if cache is None: cache = {} if not sitPath: sitPath = SIT.getPath() try: # first look-up the cache depList = cache[projectURL] except KeyError: # if not found read from filesystem if projectURL.startswith('sit://'): try: depList = getPkgInfoContent(project)['depends'] except (AssertionError, KeyError): depList = [] else: depList = [] # retrieving *.deb dependencies not implemented # ensure to only use URL-style dependencies for i, dep in enumerate(depList): if isinstance(dep, str): depList[i] = dep.replace('${HRI_GLOBAL_ROOT}/', 'sit://') # store the direct dependencies into the cache map cache[projectURL] = depList for dep in depList: if isinstance(dep, str): if systemPackages == False and not dep.startswith('sit://'): continue resultList.append(dep) if recursive: # 2012-10-09 reactivated this check for isInstalled() == False, # needed by ListDependencies.py + ExportWizard.py try: if not isInstalled(dep, sitPath): if highlightMissing: resultList.append([missingPkgMsg]) if not ignoreErrors: msg = '%s depends on %s which is not installed' \ % ( project, dep ) raise RuntimeError(msg) except ValueError: raise ValueError('invalid dependency "%s" in package %s' % (dep, project)) subDepList = getDependencies(dep, recursive, cache, ignoreErrors, highlightMissing, systemPackages, sitPath) if len(subDepList) > 0: resultList.append(subDepList) else: raise TypeError('dependency entry is not of type "str"') return resultList