diff --git a/bin/EmergeBase.py b/bin/EmergeBase.py index 30ccd3798..6c908f9e9 100644 --- a/bin/EmergeBase.py +++ b/bin/EmergeBase.py @@ -1,378 +1,378 @@ # # copyright (c) 2009 Ralf Habacker # import utils import portage import os import sys import datetime import emergePlatform from ctypes import * import compiler ## @todo complete a release and binary merge dir below rootdir # 1. enable build type related otDmerge install settings # 2a. use different install databases for debug and release # 3. binary packages which are build type independent should be # marked in both databases or should have a separate install database # question: How to detect reliable this case ? ROOTDIR = os.getenv( "KDEROOT" ) COMPILER = os.getenv( "KDECOMPILER" ) DOWNLOADDIR = os.getenv( "DOWNLOADDIR" ) if ( DOWNLOADDIR == None ): DOWNLOADDIR = os.path.join( ROOTDIR, "distfiles" ) KDESVNDIR = os.getenv( "KDESVNDIR" ) if ( KDESVNDIR == None ): KDESVNDIR = os.path.join( DOWNLOADDIR, "svn-src", "kde" ) KDESVNSERVER = os.getenv( "KDESVNSERVER" ) if ( KDESVNSERVER == None ): KDESVNSERVER = "svn://anonsvn.kde.org" KDESVNUSERNAME = os.getenv( "KDESVNUSERNAME" ) # ok, we have the following dirs: # ROOTDIR: the root where all this is below # DOWNLOADDIR: the dir under rootdir, where the downloaded files are put into # WORKDIR: the directory, under which the files are unpacked and compiled. # here rootdir/tmp/packagename/work # IMAGEDIR: the directory, under which the compiled files are installed. # here rootdir/tmp/packagename/image class EmergeBase(object): """base class for emerge system - holds attributes and methods required by base classes""" def __init__( self, **args): """args really should be documented, see self.argv0 below""" # TODO: some __init__ of subclasses need to already have been # called here. That is really the wrong way round. object.__init__(self) utils.debug( "EmergeBase.__init__ called", 2 ) if not hasattr(self, 'subinfo'): # see the TODO above. This helps pylint understand the code, otherwise # it generates tons of error messages. self.subinfo = None if not hasattr(self, 'buildSystemType'): self.buildSystemType = None # if implicit build time dependency is wanted, depend on internal packages # for this class and all of its ancestor classes if utils.envAsBool('EMERGE_ENABLE_IMPLICID_BUILDTIME_DEPENDENCIES'): for cls in type(self).mro(): className = cls.__name__ packageName = 'internal/%s' % className if os.path.exists(os.path.join(ROOTDIR, 'emerge', 'portage', 'internal', className, '%s-internal.py' % className)): if self.subinfo and not packageName in self.subinfo.buildDependencies: self.subinfo.buildDependencies[packageName] = 'default' if hasattr(self,'alreadyCalled'): return self.alreadyCalled = True self.buildTarget = None if "args" in list(args.keys()) and "argv0" in list(args["args"].keys()): self.argv0 = args["args"]["argv0"] else: self.argv0 = sys.argv[ 0 ] self.versioned = False self.CustomDefines = "" self.createCombinedPackage = False ## specifies if a build type related root directory should be used self.useBuildTypeRelatedMergeRoot = False if utils.envAsBool("EMERGE_MERGE_ROOT_WITH_BUILD_TYPE"): self.useBuildTypeRelatedMergeRoot = True self.isoDateToday = str( datetime.date.today() ).replace('-', '') self.noFetch = utils.envAsBool( "EMERGE_OFFLINE" ) self.noCopy = utils.envAsBool( "EMERGE_NOCOPY") self.noFast = utils.envAsBool( "EMERGE_NOFAST", default=True ) self.noClean = utils.envAsBool( "EMERGE_NOCLEAN" ) self.forced = utils.envAsBool( "EMERGE_FORCED" ) self.buildTests = utils.envAsBool( "EMERGE_BUILDTESTS" ) if COMPILER == "msvc2005": self.__compiler = "msvc2005" elif COMPILER == "msvc2008": self.__compiler = "msvc2008" elif COMPILER == "msvc2010": self.__compiler = "msvc2010" elif COMPILER == "msvc2011": self.__compiler = "msvc2011" elif COMPILER == "mingw": self.__compiler = "mingw" elif COMPILER == "mingw4": self.__compiler = "mingw4" else: print("emerge error: KDECOMPILER: '%s' not understood" % COMPILER, file=sys.stderr) exit( 1 ) self.rootdir = ROOTDIR if self.subinfo: self.setup() def __adjustPath(self, directory): """return adjusted path""" if not self.subinfo.options.useShortPathes: return directory path = c_char_p(directory) length = windll.kernel32.GetShortPathNameA(path, 0, 0) if length == 0: return directory buf = create_string_buffer('\000' * (length + 1)) windll.kernel32.GetShortPathNameA(path, byref(buf), length+1) # ignore function result... if utils.verbose() > 0: print("converting " + directory + " to " + buf.value) return buf.value def buildType(self): """return currently selected build type""" Type = os.getenv( "EMERGE_BUILDTYPE" ) if ( not Type == None ): buildType = Type else: buildType = None return buildType def compiler(self): """return currently selected compiler""" return self.__compiler def isTargetBuild(self): if not emergePlatform.isCrossCompilingEnabled(): return False else: return os.getenv( "EMERGE_BUILD_STEP" ) == "target" def isHostBuild(self): if not emergePlatform.isCrossCompilingEnabled(): return True else: return os.getenv( "EMERGE_BUILD_STEP" ) == "host" def buildPlatform(self): """return the cross-compiling target platform""" if self.isTargetBuild(): return os.getenv( "EMERGE_TARGET_PLATFORM" ) else: return "WIN32" def buildArchitecture(self): """return the target CPU architecture""" if self.isTargetBuild(): return os.getenv( "EMERGE_TARGET_ARCHITECTURE" ) else: return os.getenv( "EMERGE_ARCHITECTURE" ) def workDirPattern(self): """return base directory name for package related work directory""" directory = "" if self.subinfo.options.useCompilerType == True: directory += "%s-" % COMPILER if self.isTargetBuild(): directory += "%s-" % self.buildPlatform() if self.subinfo.options.cmake.useIDE or self.subinfo.options.cmake.openIDE: directory += "ide-" if self.subinfo.options.useBuildType == False: directory += "%s" % (self.buildTarget) elif( self.buildType() == None ): directory += "%s-%s" % ("default", self.buildTarget) else: directory += "%s-%s" % (self.buildType(), self.buildTarget) return directory def imageDirPattern(self): """return base directory name for package related image directory""" directory = "image" # we assume that binary packages are for all compiler and targets ## \todo add image directory support for using binary packages for a specific compiler and build type if self.buildSystemType == 'binary': return directory if self.subinfo.options.useCompilerType == True: directory += '-' + COMPILER if self.isTargetBuild(): directory += "-%s" % self.buildPlatform() if self.subinfo.options.useBuildType == True: directory += '-' + self.buildType() directory += '-' + self.buildTarget return directory def downloadDir(self): """ location of directory where fetched files are stored """ return self.__adjustPath(DOWNLOADDIR) def sourceDir(self, dummyIndex=0): utils.abstract() def packageDir(self): """ add documentation """ return self.__adjustPath( portage.getDirname( self.category, self.package ) ) def buildRoot(self): """return absolute path to the root directory of the currently active package""" buildroot = os.path.join( ROOTDIR, "build", self.category, self.PV ) return self.__adjustPath(buildroot) def workDir(self): """return absolute path to the 'work' subdirectory of the currently active package""" _workDir = os.path.join( self.buildRoot(), "work" ) return self.__adjustPath(_workDir) def buildDir(self): utils.debug("EmergeBase.buildDir() called", 2) self.setBuildTarget() builddir = os.path.join(self.workDir(), self.workDirPattern()) if self.subinfo.options.unpack.unpackIntoBuildDir and self.subinfo.hasTargetSourcePath(): builddir = os.path.join(builddir, self.subinfo.targetSourcePath()) utils.debug("package builddir is: %s" % builddir, 2) return self.__adjustPath(builddir) def imageDir(self): """return absolute path to the install root directory of the currently active package """ imageDir = os.path.join( self.buildRoot(), self.imageDirPattern() ) return self.__adjustPath(imageDir) def installDir(self): """return absolute path to the install directory of the currently active package. This path may point to a subdir of imageDir() in case @ref info.targetInstallPath is used """ if self.subinfo.hasInstallPath(): installDir = os.path.join( self.imageDir(), self.subinfo.installPath()) elif self.subinfo.options.install.installPath: installDir = os.path.join(self.imageDir(), self.subinfo.options.install.installPath) else: installDir = self.imageDir() return self.__adjustPath(installDir) def mergeSourceDir(self): """return absolute path to the merge source directory of the currently active package. This path may point to a subdir of imageDir() in case @ref info.targetInstallPath for a specific target or @ref self.subinfo.options.merge.sourcePath is used """ if self.subinfo.hasMergeSourcePath(): directory = os.path.join( self.imageDir(), self.subinfo.mergeSourcePath() ) elif not self.subinfo.options.merge.sourcePath == None: directory = os.path.join( self.imageDir(), self.subinfo.options.merge.sourcePath ) else: directory = self.imageDir() return self.__adjustPath(directory) def mergeDestinationDir(self): """return absolute path to the merge destination directory of the currently active package. This path may point to a subdir of rootdir in case @ref info.targetMergePath for a specific build target or @ref self.subinfo.options.merge.destinationPath is used """ if self.subinfo.hasMergePath(): directory = os.path.join( ROOTDIR, self.subinfo.mergePath() ) elif self.isTargetBuild(): directory = os.path.join(ROOTDIR, self.buildPlatform()) elif not self.subinfo.options.merge.destinationPath == None: directory = os.path.join( ROOTDIR, self.subinfo.options.merge.destinationPath ) elif not self.useBuildTypeRelatedMergeRoot or self.subinfo.options.merge.ignoreBuildType: directory = ROOTDIR elif self.buildType() == 'Debug': directory = os.path.join(ROOTDIR,'debug') elif self.buildType() == 'Release': directory = os.path.join(ROOTDIR,'release') elif self.buildType() == 'RelWithDebInfo': directory = os.path.join(ROOTDIR,'relwithdebinfo') else: directory = ROOTDIR return self.__adjustPath(directory) def packageDestinationDir( self, withBuildType=True ): """return absolute path to the directory where binary packages are placed into. Default is to optionally append build type subdirectory""" utils.debug( "EmergeBase.packageDestinationDir called", 2 ) dstpath = os.getenv( "EMERGE_PKGDSTDIR" ) if not dstpath: dstpath = os.path.join( self.rootdir, "tmp" ) if withBuildType: if utils.envAsBool( "EMERGE_MERGE_ROOT_WITH_BUILD_TYPE" ): dstpath = os.path.join( dstpath, self.buildType()) if not os.path.exists(dstpath): utils.createDir(dstpath) return dstpath def setBuildTarget( self, target = None): utils.debug( "EmergeBase.setBuildTarget called", 2 ) self.subinfo.setBuildTarget(target) ## \todo replace self.buildTarget by self.buildTarget() self.buildTarget = self.subinfo.buildTarget if hasattr(self,'source'): # pylint: disable=E1101 # this class never defines self.source, that happens only # in MultiSource. self.source.buildTarget = self.subinfo.buildTarget def setup( self, fileName=None, category=None, package=None, version=None, buildTarget=None): if fileName == None: self.PV, _ = os.path.splitext( os.path.basename( self.argv0 ) ) - self.category, self.package, self.version = portage.getCategoryPackageVersion( self.argv0 ) + self.category, self.package = portage.getCategoryPackage( self.argv0 ) else: self.category = category self.package = package self.version = version self.PV, _ = os.path.splitext( os.path.basename( fileName) ) self.setBuildTarget(buildTarget) if hasattr(self,'source'): # pylint: disable=E1101 # this class never defines self.source, that happens only # in MultiSource. self.source.setup( fileName, category, package, version, buildTarget) def enterBuildDir(self): utils.debug( "EmergeBase.enterBuildDir called", 2 ) if ( not os.path.exists( self.buildDir() ) ): os.makedirs( self.buildDir() ) if utils.verbose() > 0: print("creating: %s" % self.buildDir()) os.chdir( self.buildDir() ) if utils.verbose() > 0: print("entering: %s" % self.buildDir()) def enterSourceDir(self): if ( not os.path.exists( self.sourceDir() ) ): return False utils.warning("entering the source directory!") os.chdir( self.sourceDir() ) if utils.verbose() > 0: print("entering: %s" % self.sourceDir()) def system( self, command, errorMessage="", debuglevel=1, **kw): """convencience function for running system commands. This method prints a debug message and then runs a system command. If the system command returns with errors the method prints an error message and exits if @ref self.subinfo.options.exitOnErrors is true""" utils.debug( str(command), debuglevel ) if utils.system( command, **kw): return True if self.subinfo.options.exitOnErrors: utils.die( "while running %s cmd: %s" % (errorMessage, str(command)) ) else: utils.warning( "while running %s cmd: %s" % (errorMessage, str(command)) ) return False def proxySettings(self): host = os.getenv('EMERGE_PROXY_HOST') port = os.getenv('EMERGE_PROXY_PORT') username = os.getenv('EMERGE_PROXY_USERNAME') password = os.getenv('EMERGE_PROXY_PASSWORD') return [host, port, username, password] diff --git a/bin/Source/MultiSource.py b/bin/Source/MultiSource.py index 8110052d7..07808ec2f 100644 --- a/bin/Source/MultiSource.py +++ b/bin/Source/MultiSource.py @@ -1,83 +1,81 @@ # # copyright (c) 2009 Ralf Habacker # import utils from Source.SourceFactory import * class MultiSource(object): """ provides multi source type api """ def __init__(self): object.__init__(self) utils.trace( "MultiSource __init__", 2 ) # pylint: disable=E1101 # multiple inheritance: MultiSource is never the only # superclass, others define self.source, self.subinfo etc. # TODO: This code should mostly be in the class defining self.source etc. self.source = SourceFactory(self.subinfo) self.source.localFileNames = self.localFileNames.__get__(self, MultiSource) self.source.category = self.category self.source.package = self.package - self.source.version = self.version - self.source.PV = self.PV def localFileNames( self ): utils.trace( "MultiSource localFileNames", 2 ) if self.subinfo.archiveName() == "": return self.source.localFileNamesBase() return (self.subinfo.archiveName(),) def fetch( self, repopath = None ): utils.trace( "MultiSource fetch", 2 ) return self.source.fetch( repopath ) def checkDigest(self): utils.trace( "MultiSource checkDigest", 2 ) return self.source.checkDigest() def unpack(self): utils.trace( "MultiSource unpack", 2 ) # pylint: disable=E1101 # multiple inheritance: MultiSource is never the only # superclass, others define self.buildSystemType. self.source.buildSystemType = self.buildSystemType return self.source.unpack() def checkoutDir(self): utils.trace( "MultiSource checkoutDir", 2 ) return self.source.checkoutDir() def sourceDir(self): utils.trace( "MultiSource sourceDir", 2 ) return self.source.sourceDir() def repositoryUrl(self, index=0): utils.trace( "MultiSource repositoryUrl", 2 ) return self.source.repositoryUrl(index) def repositoryUrlCount(self): utils.trace( "MultiSource repositoryUrlCount", 2 ) return self.source.repositoryUrlCount() def applyPatches(self): utils.trace( "MultiSource applyPatches", 2 ) return self.source.applyPatches() def applyPatch(self): raise Exception('MultiSource.applyPatch is deprecated. ' 'it calls self.source.applyPatch without arguments which must fail') # utils.trace( "MultiSource applyPatch", 2 ) # return self.source.applyPatch() def createPatch(self): utils.trace( "MultiSource createPatch", 2 ) return self.source.createPatch() def getUrls(self): utils.trace( "MultiSource getUrls", 2 ) return self.source.getUrls() def sourceVersion(self): utils.trace( "MultiSource sourceVersion", 2 ) return self.source.sourceVersion() diff --git a/bin/portage.py b/bin/portage.py index 00d19cfce..1163ce406 100644 --- a/bin/portage.py +++ b/bin/portage.py @@ -1,750 +1,746 @@ ## @package portage # @brief contains portage tree related functions # @note this file should replace all other related portage related files import utils import builtins import imp import os import re import sys import portage_versions import emergePlatform import copy internalCategory = 'internal' ROOTDIR = os.getenv( "KDEROOT" ) modDict = dict() packageDict = dict() def __import__( module ): # pylint: disable=W0622 utils.debug( "module to import: %s" % module, 2 ) if not os.path.isfile( module ): try: return builtins.__import__( module ) except ImportError as e: utils.warning( 'import failed for module %s: %s' % (module, str(e)) ) return None else: sys.path.append( os.path.dirname( module ) ) modulename = os.path.basename( module ).replace('.py', '') suff_index = None for suff in imp.get_suffixes(): if suff[0] == ".py": suff_index = suff break if suff_index is None: utils.die("no .py suffix found") with open( module ) as fileHdl: try: return imp.load_module( modulename.replace('.', '_'), fileHdl, module, suff_index ) except ImportError as e: utils.warning( 'import failed for file %s: %s' % (module, e) ) return None class DependencyPackage: """ This class wraps each package and constructs the dependency tree original code is from dependencies.py, integration will come later... """ def __init__( self, category, name, target=None ): self.category = category self.name = name self.target = target self.runtimeChildren = [] self.buildChildren = [] self.__readChildren() def __eq__( self, other ): return self.category == other.category and self.name == other.name and self.target == other.target def __ne__( self, other ): return self.category != other.category or self.name != other.name or self.target != other.target def ident( self ): return [ self.category, self.name, PortageInstance.getDefaultTarget( self.category, self.name ) ] def __readChildren( self ): runtimeDependencies, buildDependencies = readChildren( self.category, self.name ) self.runtimeChildren = self.__readDependenciesForChildren( list(runtimeDependencies.keys()) ) self.buildChildren = self.__readDependenciesForChildren( list(buildDependencies.keys()) ) def __readDependenciesForChildren( self, deps ): children = [] if deps: for line in deps: ( category, package ) = line.split( "/" ) if emergePlatform.isCrossCompilingEnabled() or utils.isSourceOnly(): sp = PortageInstance.getCorrespondingSourcePackage( package ) if sp: # we found such a package and we're allowed to replace it category = sp[ 0 ] package = sp[ 1 ] line = "%s/%s" % ( category, package ) utils.debug( "category: %s, name: %s" % ( category, package ), 1 ) if not line in list(packageDict.keys()): p = DependencyPackage( category, package ) utils.debug( "adding package p %s/%s" % ( category, package ), 1 ) packageDict[ line ] = p else: p = packageDict[ line ] children.append( p ) return children def getDependencies( self, depList=None, dep_type="both" ): """ returns all dependencies """ if depList is None: depList = [] if dep_type == "runtime": children = self.runtimeChildren elif dep_type == "buildtime": children = self.buildChildren else: children = self.runtimeChildren + self.buildChildren for p in children: if not p in depList: p.getDependencies( depList, dep_type ) #if self.category != internalCategory: if not self in depList: depList.append( self ) return depList def buildType(): """return currently selected build type""" return os.getenv( "EMERGE_BUILDTYPE" ) def rootDirectories(): # this function should return all currently set portage directories if os.getenv( "EMERGE_PORTAGE_ROOT" ): rootDirs = os.getenv( "EMERGE_PORTAGE_ROOT" ).split( ";" ) else: rootDirs = [] if len( rootDirs ) == 0: rootDirs = [ os.path.join( os.getenv( "KDEROOT" ), "emerge", "portage" ) ] return rootDirs def rootDir(): # this function should return the portage directory, either the first set # via the environment, or the default one # keep this function for compat reasons return rootDirectories()[0] def rootDirForCategory( category ): # this function should return the portage directory where it finds the # first occurance of a category or the default value for i in rootDirectories(): if category and os.path.exists( os.path.join( i, category ) ): return i # as a fall back return the default even if it might be wrong return os.path.join( os.getenv( "KDEROOT" ), "emerge", "portage" ) def rootDirForPackage( category, package ): # this function should return the portage directory where it finds the # first occurance of a package or the default value package, subpackage = getSubPackage( category, package ) if category and package: if subpackage: for i in rootDirectories(): if os.path.exists( os.path.join( i, category, package, subpackage ) ): return i else: for i in rootDirectories(): if os.path.exists( os.path.join( i, category, package ) ): return i # as a fall back return the default even if it might be wrong return os.path.join( os.getenv( "KDEROOT" ), "emerge", "portage" ) def getDirname( category, package ): """ return absolute pathname for a given category and package """ _package, _subpackage = getSubPackage( category, package ) if category and _package: if _subpackage: return os.path.join( rootDirForPackage( category, package ), category, _package, _subpackage ) else: return os.path.join( rootDirForPackage( category, package ), category, package ) else: return "" def getFilename( category, package ): - """ return absolute filename for a given category, package and version """ + """ return absolute filename for a given category, package """ originalFileName = os.path.join( getDirname( category, package ), "%s.py" % package ) utils.debug( "originalFileName: %s (%s, %s)" % ( originalFileName, category, package ), 1 ) if os.path.isfile( originalFileName ): return os.path.join( getDirname( category, package ), "%s.py" % package ) else: - utils.debug( "originalFileName not found, trying backup solution:", 1 ) + utils.warning( "fallback to version number for %s" % package ) fileList = os.listdir( getDirname( category, package ) ) - utils.debug("fileList: %s" % fileList) for f in fileList: utils.debug( "filename: %s" % f, 1 ) if f.endswith( ".py" ) and f.startswith( "%s" % package ): utils.debug( "found %s" % f, 1 ) return os.path.join( getDirname( category, package ), "%s" % f ) - if package == "__pycache__": bla return False -def getCategoryPackageVersion( path ): - utils.debug( "getCategoryPackageVersion: %s" % path, 2 ) +def getCategoryPackage( path ): + """ extract the category and package from a given file path """ + utils.debug( "getCategoryPackage %s" % path, 2 ) head, fullFileName = os.path.split( path ) for rd in rootDirectories(): if head.startswith(rd): head = head.replace(rd + os.sep, "") break if len( head.split( os.sep ) ) == 3: - category, _dummy, package = head.split( os.sep ) + category, subcategory, package = head.split( os.sep ) else: head, package = os.path.split( head ) head, category = os.path.split( head ) - - filename = os.path.splitext( fullFileName )[0] - package, version = utils.packageSplit( filename ) - utils.debug( "category: %s, package: %s, version: %s" % ( category, package, version ), 1 ) - return [ category, package, version ] # TODO: why a list and not a tuple? + utils.debug( "category: %s, package: %s" % ( category, package ), 2 ) + return ( category, package ) def VCSDirs(): return [ '.svn', 'CVS', '.hg', '.git' ] class Portage: def __init__( self ): """ """ self.categories = {} self.subpackages = {} self.portages = {} def addPortageDir( self, directory ): """ adds the categories and packages of a portage directory """ if not os.path.exists( directory ): return categoryList = os.listdir( directory ) # remove vcs directories for vcsdir in VCSDirs(): if vcsdir in categoryList: categoryList.remove( vcsdir ) self.portages[ directory ] = [] for category in categoryList: if not os.path.isdir( os.path.join( directory, category ) ): continue self.portages[ directory ].append( category ) packageList = os.listdir( os.path.join( directory, category ) ) # remove vcs directories for vcsdir in VCSDirs(): if vcsdir in packageList: packageList.remove( vcsdir ) if not category in list(self.categories.keys()): self.categories[ category ] = [] for package in packageList: if not os.path.isdir( os.path.join( directory, category, package ) ): continue if not package in self.categories[ category ]: self.categories[ category ].append( package ) subPackageList = os.listdir( os.path.join( directory, category, package ) ) for subPackage in subPackageList: if not os.path.isdir( os.path.join( directory, category, package, subPackage ) ) or subPackage in VCSDirs(): continue if not subPackage in list(self.subpackages.keys()): self.subpackages[ subPackage ] = [] if not subPackage in self.categories[ category ]: self.categories[ category ].append( subPackage ) self.subpackages[ subPackage ].append( category + "/" + package ) def getCategory( self, package ): """ returns the category of this package """ utils.debug( "getCategory: %s" % package, 2 ) for cat in list(self.categories.keys()): if package in self.categories[ cat ]: utils.debug( "found: category %s for package %s" % ( cat, package ), 1 ) return cat return False def isCategory( self, category ): """ returns whether a certain category exists """ return category in list(self.categories.keys()) def isPackage( self, category, package ): """ returns whether a certain package exists within a category """ return package in self.categories[ category ] def isVirtualPackage( self, category, package ): """ check if that package is of VirtualPackageBase """ if not self.isPackage( category, package ): return False version = self.getNewestVersion( category, package ) mod = __import__( getFilename( category, package, version ) ) if hasattr( mod, 'Package' ): for baseClassObject in mod.Package.__bases__: if baseClassObject.__name__ == 'VirtualPackageBase': return True return False def getAllPackages( self, category ): """returns all packages of a category except those that are listed in a file 'dont_build.txt' in the category directory in case the category doesn't exist, nothing is returned""" if self.isCategory( category ): plist = copy.copy(self.categories[ category ]) if os.path.exists( os.path.join( rootDirForCategory( category ), category, "dont_build.txt" ) ): with open( os.path.join( rootDirForCategory( category ), category, "dont_build.txt" ), "r" ) as f: for line in f: try: plist.remove( line.strip() ) except ValueError: utils.warning( "couldn't remove package %s from category %s's package list" % ( line.strip(), category ) ) return plist else: return def getPackageInstance(self, category, package, buildtarget=None): """return instance of class Package from package file""" if emergePlatform.isCrossCompilingEnabled() \ or utils.isSourceOnly(): sp = self.getCorrespondingSourcePackage( package ) if sp: category = sp[0] package = sp[1] fileName = getFilename( category, package ) module = __import__( fileName ) p = module.Package() p.setup(fileName, category, package, buildtarget) return p def getDefaultTarget( self, category, package ): """ returns the default package of a specified package """ utils.debug( "importing file %s" % getFilename( category, package ), 1 ) if not ( category and package ): return dict() mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): return mod.subinfo().defaultTarget else: return None def getMetaData( self, category, package ): """ returns all targets of a specified package """ utils.debug( "importing file %s" % getFilename( category, package ), 1 ) if not ( category and package ): return dict() mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() tmpdict = dict() if not info.categoryName == "": tmpdict['categoryName'] = info.categoryName if not info.shortDescription == "": tmpdict['shortDescription'] = info.shortDescription if not info.description == "": tmpdict['description'] = info.description if not info.homepage == "": tmpdict['homepage'] = info.homepage tmpdict['withCompiler'] = info.options.package.withCompiler utils.debug( tmpdict, 2 ) return tmpdict else: return {'withCompiler': True} def getAllTargets( self, category, package ): """ returns all targets of a specified package """ utils.debug( "importing file %s" % getFilename( category, package ), 1 ) if not ( category and package ): return dict() mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() tagDict = info.svnTargets tagDict.update( info.targets ) utils.debug( tagDict, 2 ) return tagDict else: return dict() def getAllVCSTargets( self, category, package ): """ returns all version control system targets of a specified package, excluding those which do contain tags """ utils.debug( "importing file %s" % getFilename( category, package ), 1 ) mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() tagDict = info.svnTargets for key in tagDict: utils.debug( '%s: %s' % ( key, tagDict[key] ), 2 ) return tagDict else: return dict() def getUpdatableVCSTargets( self, category, package ): """ check if the targets are tags or not """ targetDict = PortageInstance.getAllVCSTargets( category, package ) retList = [] for key in targetDict: url = targetDict[ key ] if url: sourceType = utils.getVCSType( url ) if sourceType == "svn": # for svn, ignore tags if not url.startswith( "tags/" ) and not "/tags/" in url: retList.append( key ) elif sourceType == "git": _, branch, tag = utils.splitVCSUrl( url ) if tag == "" and not branch.endswith("-patched"): retList.append( key ) elif not sourceType == "": # for all other vcs types, simply rebuild everything for now retList.append( key ) return retList # FIXME: not needed anymore! def getNewestVersion( self, category, package ): """ returns the newest version of this category/package """ if( category == None ): utils.die( "Empty category for package '%s'" % package ) if not self.isCategory( category ): utils.die( "could not find category '%s'" % category ) if not self.isPackage( category, package ): utils.die( "could not find package '%s' in category '%s'" % ( package, category ) ) versions = [] for fileName in os.listdir( getDirname( category, package ) ): (shortname, ext) = os.path.splitext( fileName ) if ( ext != ".py" ): continue if ( shortname.startswith( package ) ): versions.append( shortname ) tmpver = "" for ver in versions: if ( tmpver == "" ): tmpver = ver else: ret = portage_versions.pkgcmp(portage_versions.pkgsplit(ver), \ portage_versions.pkgsplit(tmpver)) if ( ret == 1 ): tmpver = ver ret = utils.packageSplit( tmpver ) #print "ret:", ret return ret[ 1 ] def getInstallables( self ): """ get all the packages that are within the portage directory """ instList = list() for category in list(self.categories.keys()): for package in self.categories[ category ]: for script in os.listdir( getDirname( category, package ) ): if script.endswith( '.py' ): # FIXME: check needed if this file really is a portage script instList.append([category, package]) return instList def getCorrespondingSourcePackage( self, package ): category = self.getCategory( package + "-src" ) if category: # we found a corresponding package utils.debug( "replacing package %s with its source package" % ( package ), 1 ) return [ category, package + "-src" ] else: return False def getCorrespondingBinaryPackage( self, package ): if not package.endswith( "-src" ): return [ None, None ] category = self.getCategory( package[ :-4 ] ) if category: # we found a corresponding package utils.debug( "replacing package %s with its binary package" % ( package ), 1 ) return [ category, package[ :-4 ] ] else: return [ None, None ] # when importing this, this static Object should get added PortageInstance = Portage() for _dir in rootDirectories(): PortageInstance.addPortageDir( _dir ) def getSubPackage( category, package ): """ returns package and subpackage names """ """ in case no subpackage could be found, None is returned """ if package in PortageInstance.subpackages: for entry in PortageInstance.subpackages[ package ]: cat, pac = entry.split("/") if cat == category: return pac, package return package, None def findPossibleTargets( category, package, buildtype=''): # pylint: disable=W0613 """ this function tries to guess which target got used by looking at the different image directories """ # FIXME: this won't work due to removal of version utils.die("this isn't working correctly, please implement") target = PortageInstance.getDefaultTarget( category, package ) buildroot = os.path.join( ROOTDIR, "build", category, "%s" % ( package ) ) if not os.path.exists( buildroot ): return target for directory in os.listdir( buildroot ): if os.path.isdir( os.path.join( buildroot, directory ) ): if directory.startswith( "image" ) and directory != "image": particles = directory.split( '-' )[ 1: ] # the first part should be image- anyway if len(particles) == 3: _platform, _buildType, _target = particles elif len(particles) == 4 and emergePlatform.isCrossCompilingEnabled(): _platform, _buildType, _buildArch, _target = particles elif len(particles) >= 4 and not emergePlatform.isCrossCompilingEnabled(): _platform, _buildType = particles[0:2] _target = '-'.join(particles[2:]) else: return target if _platform == os.getenv( "KDECOMPILER" ) and \ _buildType == os.getenv( "EMERGE_BUILDTYPE" ): return _target return target def getPackageInstance(category, package, buildtarget=None): """return instance of class Package from package file""" return PortageInstance.getPackageInstance(category, package, buildtarget) def getDependencies( category, package, runtimeOnly=False ): """returns the dependencies of this package as list of strings: category/package""" if not os.path.isfile( getFilename( category, package ) ): utils.die( "package name %s/%s unknown" % ( category, package ) ) package, subpackage = getSubPackage( category, package ) if subpackage: utils.debug( "solving package %s/%s/%s %s" % ( category, subpackage, package, getFilename( category, package ) ), 2 ) else: utils.debug( "solving package %s/%s-%s %s" % ( category, package, getFilename( category, package ) ), 2 ) subpackage = package deps = [] for pkg in subpackage: mod = __import__( getFilename( category, subpackage ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() depDict = info.hardDependencies depDict.update( info.dependencies ) depDict.update( info.runtimeDependencies ) if not runtimeOnly: depDict.update( info.buildDependencies ) for line in list(depDict.keys()): (category, package) = line.split( "/" ) deps.append( [ category, package, depDict[ line ] ] ) return deps def solveDependencies( category, package, depList, dep_type='both' ): depList.reverse() if emergePlatform.isCrossCompilingEnabled() or utils.isSourceOnly(): sp = PortageInstance.getCorrespondingSourcePackage( package ) if sp: # we found such a package and we're allowed to replace it category = sp[ 0 ] package = sp[ 1 ] utils.debug( "found corresponding source package for %s" % package, 1 ) if ( category == "" ): category = PortageInstance.getCategory( package ) utils.debug( "found package in category %s" % category, 2 ) pac = DependencyPackage( category, package ) depList = pac.getDependencies( depList, dep_type=dep_type ) depList.reverse() return depList def printTargets( category, package ): targetsDict = PortageInstance.getAllTargets( category, package ) defaultTarget = PortageInstance.getDefaultTarget( category, package ) if 'svnHEAD' in targetsDict and not targetsDict['svnHEAD']: del targetsDict['svnHEAD'] targetsDictKeys = list(targetsDict.keys()) targetsDictKeys.sort() for i in targetsDictKeys: if defaultTarget == i: print('*', end=' ') else: print(' ', end=' ') print(i) def readChildren( category, package ): identFileName = getFilename( category, package ) if not os.path.isfile( identFileName ): utils.die( "package name %s/%s unknown" % ( category, package ) ) # if we are an emerge internal package and already in the dictionary, ignore childrens # To avoid possible endless recursion this may be also make sense for all packages if category == internalCategory and identFileName in list(modDict.keys()): return dict(), dict() package, subpackage = getSubPackage( category, package ) if subpackage: utils.debug( "solving package %s/%s/%s %s" % ( category, subpackage, package, getFilename( category, package ) ), 2 ) else: utils.debug( "solving package %s/%s %s" % ( category, package, getFilename( category, package ) ), 2 ) if not identFileName in list(modDict.keys()): mod = __import__( identFileName ) modDict[ identFileName ] = mod else: mod = modDict[ identFileName ] if utils.envAsBool('EMERGE_ENABLE_IMPLICID_BUILDTIME_DEPENDENCIES') and hasattr( mod, 'Package' ): _package = mod.Package() subinfo = _package.subinfo elif hasattr( mod, 'subinfo' ): subinfo = mod.subinfo() else: return dict(), dict() runtimeDependencies = subinfo.runtimeDependencies or dict() buildDependencies = subinfo.buildDependencies or dict() # hardDependencies commonDependencies = subinfo.hardDependencies commonDependencies.update( subinfo.dependencies ) runtimeDependencies.update( commonDependencies ) buildDependencies.update( commonDependencies ) return runtimeDependencies, buildDependencies def isHostBuildEnabled( category, package, version ): """ returns whether this package's host build is enabled. This will only work if isCrossCompilingEnabled() == True """ if emergePlatform.isCrossCompilingEnabled(): mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() return not info.disableHostBuild else: return False else: utils.die( "This function must not be used outside of cross-compiling environments!" ) def isTargetBuildEnabled( category, package ): """ returns whether this package's target build is enabled. This will only work if isCrossCompilingEnabled() == True """ if emergePlatform.isCrossCompilingEnabled(): mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() return not info.disableTargetBuild else: return False else: utils.die( "This function must not be used outside of cross-compiling environments!" ) def isPackageUpdateable( category, package ): utils.debug( "importing file %s" % getFilename( category, package ), 2 ) mod = __import__( getFilename( category, package ) ) if hasattr( mod, 'subinfo' ): info = mod.subinfo() if len( info.svnTargets ) == 1 and not info.svnTargets[ list(info.svnTargets.keys())[0] ]: return False return len( info.svnTargets ) > 0 else: return False def alwaysTrue( *dummyArgs): """we sometimes need a function that always returns True""" return True def getHostAndTarget( hostEnabled, targetEnabled ): """used for messages""" msg = "" if hostEnabled or targetEnabled: msg += "(" if hostEnabled: msg += "H" if hostEnabled and targetEnabled: msg += "/" if targetEnabled: msg += "T" msg += ")" return msg def printCategoriesPackagesAndVersions( lines, condition, hostEnabled=alwaysTrue, targetEnabled=alwaysTrue ): """prints a number of 'lines', each consisting of category, package and version field""" def printLine( cat, pack, ver, hnt="" ): catlen = 25 packlen = 25 print(cat + " " * ( catlen - len( cat ) ) + pack + " " * ( packlen - len( pack ) ) + ver, hnt) printLine( 'Category', 'Package', 'Version' ) printLine( '--------', '-------', '-------' ) for category, package, target in lines: if emergePlatform.isCrossCompilingEnabled(): msg = getHostAndTarget( hostEnabled( category, package, target ), targetEnabled( category, package, target ) ) else: msg = "" if condition( category, package, target ): printLine( category, package, target, msg ) def printInstallables(): """get all the packages that can be installed""" printCategoriesPackagesAndVersions( PortageInstance.getInstallables(), alwaysTrue ) def printInstalled(): """get all the packages that are already installed""" printCategoriesPackagesAndVersions( PortageInstance.getInstallables(), isInstalled ) def getPackagesCategories(packageName, defaultCategory = None): utils.debug( "getPackagesCategories for package name %s" % packageName, 1 ) if defaultCategory is None: if "EMERGE_DEFAULTCATEGORY" in os.environ: defaultCategory = os.environ["EMERGE_DEFAULTCATEGORY"] else: defaultCategory = "kde" packageList, categoryList = [], [] if len( packageName.split( "/" ) ) == 1: if PortageInstance.isCategory( packageName ): utils.debug( "isCategory=True", 2 ) packageList = PortageInstance.getAllPackages( packageName ) categoryList = [ packageName ] * len(packageList) else: utils.debug( "isCategory=False", 2 ) if PortageInstance.isCategory( defaultCategory ) and PortageInstance.isPackage( defaultCategory, packageName ): # prefer the default category packageList = [ packageName ] categoryList = [ defaultCategory ] else: if PortageInstance.getCategory( packageName ): packageList = [ packageName ] categoryList = [ PortageInstance.getCategory( packageName ) ] else: utils.warning( "unknown category or package: %s" % packageName ) elif len( packageName.split( "/" ) ) == 2: [ cat, pac ] = packageName.split( "/" ) if PortageInstance.isCategory( cat ): categoryList = [ cat ] else: utils.warning( "unknown category %s; ignoring package %s" % ( cat, packageName ) ) if len( categoryList ) > 0 and PortageInstance.isPackage( categoryList[0], pac ): packageList = [ pac ] if len( categoryList ) and len( packageList ): utils.debug( "added package %s/%s" % ( categoryList[0], pac ), 2 ) else: utils.debug( "ignoring package %s" % packageName ) else: utils.error( "unknown packageName" ) return packageList, categoryList