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 _getInheritedProjects(self): # This is a legacy combination of the real (not build-)dependencies # and recommendations. They all will get sourced to be in the PATH. # # Note that Non-SIT-dependencies (e.g. "deb://binutils") get # filtered out. from ToolBOSCore.Storage.SIT import strip tmpList = FastScript.reduceList(self.dependencies + self.recommendations) tmpList = filter(lambda s: not s.startswith('deb://'), tmpList) self.inheritedProjects = list(map(lambda s: strip(s), tmpList))
def run( self, dryRun=False ): """ Performs all patching routines, if dryRun=True all operations are fake (your project won't be altered). """ available = self.getPatchesAvailable() descrLen = 0 applied = [] # determine the longest description to compute number of dashes for patch in available: descrLen = max( len(patch[0]), descrLen ) descrLen = max( len(patch[2]), descrLen ) logging.info( descrLen * '-' ) for patch in available: logging.info( 'EXECUTING PATCH: %s' % patch[0] ) result = patch[1]( dryRun ) if result: Any.requireIsList( result ) fileList = FastScript.reduceList( result ) fileList.sort() for item in fileList: logging.info( 'patching %s' % item ) logging.info( patch[2] ) applied.append( patch ) else: logging.info( 'no need to patch' ) logging.info( descrLen * '-' ) logging.info( '' ) return applied
def areAllDependenciesInstalled(project, dependencyList=None): """ Checks and returns a boolean if all dependencies of a project are present in the SIT. It will also return 'False' if the dependencies could not be queried at all or if there are some errors. So receiving a 'True' status is quite reliable. 'project' must be in canonical form, e.g. 'Libraries/Serialize/3.0'. If 'dependencyList' (an optionally nested list of dependencies) is specified it will be used as a cache instead of querying the dependency tree from the slower filesystem. If such 'dependencyList' is provided but is an empty list then always 'True' will be returned. """ Any.requireIsTextNonEmpty(project) #Any.requireIsList( dependencyList ) if (isinstance(dependencyList, list)) and len(dependencyList) == 0: return True if not dependencyList: try: dependencyList = getDependencies(project, True) except RuntimeError: # e.g. unable to retrieve dependencies return False urlList = FastScript.reduceList(FastScript.flattenList(dependencyList)) for url in urlList: try: if not isInstalled(url): return False except ValueError as details: logging.error(details) raise ValueError('unable to check install status of %s' % project) return True
def addPackage( self, canonicalPath, recursive, filterFunc ): """ Runs 'filterFunc' on the specified package. Does the same for all dependent packages if 'recursive=True'. """ Any.requireIsTextNonEmpty( canonicalPath ) Any.requireIsBool( recursive ) Any.requireIsCallable( filterFunc ) canonicalPath = strip( canonicalPath ) installRoot = self.sitPath + os.sep + canonicalPath if canonicalPath in self.pkgList: # avoid duplicates return if canonicalPath.startswith( 'deb://' ): # ignore Debian packages return if self._showProgress: logging.info( 'processing %s', canonicalPath ) if os.path.exists( installRoot + os.sep + 'SkipLibIndex' ): logging.debug( '%s: SkipLibIndex found' % canonicalPath ) else: filterFunc( self, canonicalPath ) if recursive: deps = getDependencies( project = canonicalPath, recursive = True, cache = self._depCache, systemPackages = False, sitPath = getPath() ) shortDepList = FastScript.reduceList( deps ) for package in shortDepList: if package not in self.pkgList: self.addPackage( package, False, filterFunc )
def addPackageList( self, pkgList, recursive, filterFunc ): """ Like addPackage(), but for a list of packages. pkgList = ( 'Basics/Any/2.2', 'Basics/Time/1.1' ) LibIndex.createFromList( pkgList, 'MyLibIndex' ) """ Any.requireIsList( pkgList ) Any.requireIsCallable( filterFunc ) pkgFileDependecies = [] for pkg in pkgList: deps = getDependencies( project = pkg, recursive = True, cache = self._depCache, systemPackages = False, sitPath = getPath() ) shortDeps = FastScript.reduceList( deps ) for shortDep in shortDeps: path = splitPath( pkg ) Any.requireIsTuple( path ) dependency = splitPath( shortDep ) Any.requireIsTuple( dependency ) mod = strip( path[ 1 ] ) lib = strip( dependency[ 1 ] ) vers = strip( dependency[ 2 ] ) pkgFileDependecies.append( ( mod, lib, vers ) ) conflictDeps = [] #returns the list of conflicting dependencies, if empty there are no conflicts for deps in pkgFileDependecies: mod = deps[ 0 ] lib = deps[ 1 ] vers = deps[ 2 ] #we build the list where the lib library appears in other versions listDep = [ x for x in pkgFileDependecies if x[ 1 ] == lib and not x[ 2 ] == vers ] for dep in listDep: module = dep[ 0 ] lib = dep[ 1 ] version = dep[ 2 ] #check for duplicates if not ( module, mod, lib, version, vers ) in conflictDeps: conflictDeps.append( ( mod, module, lib, vers, version ) ) textError = 'ERROR:\n' text = '{} {} used by {} \n is in conflict with \n{} {} used by {}\n\n' for dep in conflictDeps: mod1 = dep[ 0 ] # first module mod2 = dep[ 1 ] # second module lib = dep[ 2 ] # library vers1 = dep[ 3 ] # first version vers2 = dep[ 4 ] # second version textError = textError + text.format( lib, vers1, mod1, lib, vers2, mod2 ) Any.requireMsg( not conflictDeps, '\n %s' % textError ) for pkg in pkgList: self.addPackage( pkg, recursive, filterFunc )