diff --git a/bin/InstallDB.py b/bin/InstallDB.py index 0457105e6..2a07c42af 100644 --- a/bin/InstallDB.py +++ b/bin/InstallDB.py @@ -1,453 +1,394 @@ -import os -import utils -import portage -import emergePlatform -import sqlite3 -import threading - -__blockme = threading.local() - -def isDBEnabled(): - """ this function returns whether sqlite database should be used """ - if not os.getenv("EMERGE_ENABLE_SQLITEDB"): - return True - return utils.envAsBool("EMERGE_ENABLE_SQLITEDB") - -def blocking(fn): - """ Block parallel access to sqlite """ - def block(*args, **kw): - if hasattr(__blockme, "blocked"): # Already blocked - return fn(*args, **kw) - try: - with utils.LockFile(utils.LockFileName("SQLITE")): - __blockme.blocked = True - ret = fn(*args, **kw) - finally: - delattr(__blockme, "blocked"); - return ret - - return block - -class InstallPackage: - """ InstallPackage finalizes an installation. - - If you call addInstalled or remInstalled an InstallPackage object is returned which - you can use to handle file information with the InstallDB. For installation use code - similar to this one: - - # get an InstallPackage object p - p = InstallDB.installdb.addInstalled( "cat", "pac", "ver", "prefix" ) - # add files ( including the hash ) - p.addFiles( [ ( "file1", "hash1" ), ( "file2", "hash2" ), ( "file3", "hash3" ) ] ) - if failed: - # in case we somehow need to go back - p.revert() - else: - # finalize the installation - p.install() - - Deinstallation works similar: - p = InstallDB.installdb.remInstalled( "cat", "pac", "ver", "prefix" ) - # get the files ( including the hash ) - f = p.getFiles() - # f now contains [ ( "file1", "hash1" ), ( "file2", "hash2" ), ( "file3", "hash3" ) ] - if failed: - # in case we somehow need to go back - p.revert() - else: - # finalize the uninstall - p.uninstall() - """ - - def __init__( self, cursor, packageId ): - self.cursor = cursor - self.packageId = packageId - self.fileDict = dict() - - def addFiles( self, fileDict ): - """ appends files to the list of files to be installed """ - self.fileDict.update( fileDict ) - - @blocking - def getFiles( self ): - """ get a list of files that will be uninstalled """ - cmd = '''SELECT filename, fileHash FROM fileList WHERE packageId=?;''' - utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) - self.cursor.execute(cmd, (self.packageId,)) - return self.cursor.fetchall() - - @blocking - def revert( self ): - """ revert all changes made to the database, use with care """ - self.cursor.connection.rollback() - - @blocking - def uninstall( self ): - """ really uninstall that package """ - cmd = '''DELETE FROM fileList WHERE packageId=?;''' - utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) - self.cursor.execute(cmd, (self.packageId,)) - cmd = '''DELETE FROM packageList WHERE packageId=?;''' - utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) - self.cursor.execute(cmd, (self.packageId,)) - self.cursor.connection.commit() - - @blocking - def install( self ): - """ marking the package & package file list installed """ - fileNumber = len( self.fileDict ) - # keys() and values will stay in the same order if no changes are done in between calls - # structure of each tuple: - # fileId | packageId == package Id | filenames | file hashes - dataList = list(zip( [ None ] * fileNumber, [ self.packageId ] * fileNumber, list(self.fileDict.keys()), list(self.fileDict.values()) )) - - cmd = '''INSERT INTO fileList VALUES (?, ?, ?, ?)''' - utils.debug( "executing sqlcmd '%s' %s times" % ( cmd, len( self.fileDict ) ), 1 ) - self.cursor.executemany( cmd, dataList ) - - # at last, commit all the changes so that they are committed only after everything is written to the - # database - self.cursor.connection.commit() - - -class InstallDB: - """ a database object which provides the methods for adding and removing a package and - checking its installation status. - In case the database doesn't exist if the constructor is called, a new database is constructed - """ - - def __init__( self, filename = os.path.join( utils.etcDir(), 'install.db' ) ): - self.dbfilename = filename - if not os.path.exists( filename ): - if not os.path.exists( utils.etcDir() ): - os.makedirs( utils.etcDir() ) - utils.debug( "database does not exist yet: creating database & importing old data" ) - self._prepareDatabase() - else: - utils.debug( "found database", 1 ) - self.connection = sqlite3.connect( self.dbfilename ) - - @blocking - def getLastId( self ): - """ returns the last id from a table, which is essentially the """ - cmd = '''SELECT max(packageId) FROM packageList;''' - - cursor = self.connection.cursor() - cursor.execute( cmd ) - lastId = cursor.fetchall()[0] - return lastId[0] - - def __constructWhereStmt( self, _dict ): - params = [] - parametersUsed = False - stmt = "" -# if not prefix == '' or not category == '' or not package == '': -# cmd += ''' WHERE''' -# - for key in list(_dict.keys()): - if not _dict[ key ] == None: - if parametersUsed: - stmt += ''' AND''' - stmt += ''' %s=?''' % key - params.append( _dict[ key ] ) - parametersUsed = True - if not stmt == "": - stmt = ''' WHERE''' + stmt - - return stmt, params - - @blocking - def isInstalled( self, category, package, version=None, prefix=None ): - """ returns whether a package is installed. If version and prefix are empty, all versions - and prefixes will be checked. """ - cmd = '''SELECT * FROM packageList''' - # TODO: what is the difference between prefix=None and prefix=''? Both happens. Document. - stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'version': version } ) - cmd += stmt - cmd += ''';''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - - cursor = self.connection.cursor() - cursor.execute( cmd, tuple( params ) ) - isPackageInstalled = len( cursor.fetchall() ) > 0 - if isPackageInstalled: - utils.debug( """The package %s/%s has been installed in prefix '%s' with - version '%s'.""" % ( category, package, prefix, version ), 1 ) - else: - utils.debug( """Couldn't find a trace that the package %s/%s has been installed in - prefix '%s' with version '%s'""" % ( category, package, prefix, version ), 1 ) - cursor.close() - return isPackageInstalled - - def findInstalled( self, category, package, prefix=None ): - """ get the version of a package that is installed """ - f = self.getInstalled( category, package, prefix ) - if len(f) == 1: - return f[ 0 ][2] - else: - return None - - @blocking - def getInstalled( self, category=None, package=None, prefix=None ): - """ returns a list of the installed packages, which can be restricted by adding - package, category and prefix. - """ - cmd = '''SELECT category, packageName, version, prefix FROM packageList''' - stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package } ) - cmd += stmt - cmd += ''';''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - - cursor = self.connection.cursor() - cursor.execute( cmd, tuple( params ) ) - values = cursor.fetchall() - cursor.close() - return values - - @blocking - def getDistinctInstalled( self, category=None, package=None, prefix=None ): - """ returns a list of the installed packages, which can be restricted by adding - package, category and prefix. - """ - cmd = '''SELECT DISTINCT category, packageName, version FROM packageList''' - stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package } ) - cmd += stmt - cmd += ''';''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - - cursor = self.connection.cursor() - cursor.execute( cmd, tuple( params ) ) - values = cursor.fetchall() - cursor.close() - return values - - @blocking - def getPackageIds( self, category=None, package=None, version=None, prefix=None ): - """ returns a list of the ids of the packages, which can be restricted by adding - package, category and prefix. - """ - cmd = '''SELECT packageId FROM packageList''' - stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'version': version } ) - cmd += stmt - cmd += ''';''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - - cursor = self.connection.cursor() - cursor.execute( cmd, tuple( params ) ) - values = [] - for row in cursor: - values.append( row[0] ) - return values - - @blocking - def addInstalled( self, category, package, version, prefix=None, ignoreInstalled=False ): - """ adds an installed package """ - cursor = self.connection.cursor() - if self.isInstalled( category, package, version, prefix ) and not ignoreInstalled: - raise Exception( 'package %s/%s-%s already installed (prefix %s)' % ( category, package, version, prefix ) ) - - params = [ None, prefix, category, package, version ] - cmd = '''INSERT INTO packageList VALUES (?, ?, ?, ?, ?)''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - cursor.execute( cmd, tuple( params ) ) - return InstallPackage( cursor, self.getLastId() ) - - @blocking - def remInstalled( self, category, package, version, prefix=None ): - """ removes an installed package """ - cmd = '''DELETE FROM packageList''' - stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'version': version } ) - cmd += stmt - cmd += ''';''' - utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) - - cursor = self.connection.cursor() - return [ InstallPackage( cursor, pId ) for pId in self.getPackageIds( category, package, version, prefix ) ] - - @blocking - def _prepareDatabase( self ): - """ prepare a new database and add the required table layout """ - self.connection = sqlite3.connect( self.dbfilename ) - cursor = self.connection.cursor() - - # first, create the required tables - cursor.execute( '''CREATE TABLE packageList (packageId INTEGER PRIMARY KEY AUTOINCREMENT, - prefix TEXT, category TEXT, packageName TEXT, version TEXT)''' ) - cursor.execute( '''CREATE TABLE fileList (fileId INTEGER PRIMARY KEY AUTOINCREMENT, - packageId INTEGER, filename TEXT, fileHash TEXT)''' ) - self.connection.commit() - - self.importExistingDatabase() - - def importExistingDatabase( self ): - """ imports from the previous installation database system """ - for category, package, version in portage.PortageInstance.getInstallables(): - # FIXME: we need to adapt this to use prefixes as well - utils.debug( "importing package %s/%s-%s ..." % ( category, package, version ) ) - if self.isPkgInstalled( category, package, version ): - utils.debug( 'adding installed package %s/%s-%s' % ( category, package, version ), 1 ) - packageObject = self.addInstalled( category, package, version, "" ) - packageObject.addFiles( utils.getFileListFromManifest( os.getenv( "KDEROOT" ), package ) ) - packageObject.install() - if emergePlatform.isCrossCompilingEnabled(): - targetObject = self.addInstalled( category, package, version, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) - targetObject.addFiles( utils.getFileListFromManifest( os.path.join( os.getenv( "KDEROOT" ), - os.getenv( "EMERGE_TARGET_PLATFORM" ) ), package ) ) - targetObject.install() - # check PackageBase.mergeDestinationDir() for further things regarding the import from other prefixes - - - - - def isPkgInstalled( self, category, package, version, buildType='' ): - # TODO: we have self.isPkgInstalled (formerly self._isInstalled) and self.isInstalled. Clarify names. - """ check if a package with a certain category, package and version is installed (used for import) """ - - # find in old style database - path = utils.etcDir() - fileName = os.path.join( path, 'installed' ) - if not os.path.isfile( fileName ): - return False - - with open( fileName, "rb" ) as f: - for line in f.read().splitlines(): - ( _category, _packageVersion ) = line.split( "/" ) - ( _package, _version ) = utils.packageSplit(_packageVersion) - if category != '' and version != '' and category == _category and package == _package \ - and version == _version: - return True - elif category == '' and version == '' and package == _package: - return True - - # find in release mode database - if buildType != '': - fileName = os.path.join( path,'installed-' + buildType ) - if os.path.isfile( fileName ): - with open( fileName, "rb" ) as f: - for line in f.read().splitlines(): - ( _category, _packageVersion ) = line.split( "/" ) - ( _package, _version ) = utils.packageSplit( _packageVersion ) - if category != '' and version != '' and category == _category and package == _package and version == _version: - return True - elif category == '' and version == '' and package == _package: - return True - return False - -# get a global object -if isDBEnabled(): - installdb = InstallDB() - -# an additional function from portage.py -def printInstalled(): - """get all the packages that are already installed""" - host = target = portage.alwaysTrue - if emergePlatform.isCrossCompilingEnabled(): - host = portage.isHostBuildEnabled - target = portage.isTargetBuildEnabled - portage.printCategoriesPackagesAndVersions( installdb.getDistinctInstalled(), portage.alwaysTrue, host, target ) - - -def main(): - """ Testing the class""" - - # add two databases - tempdbpath1 = os.path.join( os.getenv("KDEROOT"), "tmp", "temp1.db" ) - tempdbpath2 = os.path.join( os.getenv("KDEROOT"), "tmp", "temp2.db" ) - - if not os.path.exists( os.path.join( os.getenv( "KDEROOT" ), "tmp" ) ): - os.makedirs( os.path.join( os.getenv( "KDEROOT" ), "tmp" ) ) - - if os.path.exists( tempdbpath1 ): - os.remove( tempdbpath1 ) - if os.path.exists( tempdbpath2 ): - os.remove( tempdbpath2 ) - - db_temp = InstallDB( tempdbpath1 ) - db = InstallDB( tempdbpath2 ) - - utils.debug( 'testing installation database' ) - - utils.debug( 'testing if package win32libs-sources/dbus-src with version 1.4.0 is installed: %s' % - db.isPkgInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ) ) - - # in case the package is still installed, remove it first silently - if db.isInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ): - packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ) - # really commit uninstall - for package in packageList: - package.uninstall() - utils.debug_line() - - utils.new_line() - # add a package - utils.debug( 'installing package win32libs-sources/dbus-src-1.4.0 (release)' ) - package = db.addInstalled( 'win32libs-sources', 'dbus-src', '1.4.0', 'release' ) - package.addFiles( dict().fromkeys( [ 'test', 'test1', 'test2' ], 'empty hash' ) ) - # now really commit the package - package.install() - - # add another package in a different prefix - utils.debug( 'installing package win32libs-sources/dbus-src-1.4.0 (debug)' ) - package = db.addInstalled( 'win32libs-sources', 'dbus-src', '1.4.0', 'debug' ) - package.addFiles( dict().fromkeys( [ 'test', 'test1', 'test2' ], 'empty hash' ) ) - # now really commit the package - package.install() - utils.debug_line() - - utils.new_line() - utils.debug( 'checking installed packages' ) - utils.debug( 'get installed package (release): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) - utils.debug( 'get installed package (debug): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) - - utils.new_line() - utils.debug( 'now trying to remove package & revert it again later' ) - # remove the package again - packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ) - for pac in packageList: - for line in pac.getFiles(): # pylint: disable=W0612 - # we could remove the file here - # print line - pass - utils.debug_line() - - utils.new_line() - utils.debug( 'checking installed packages' ) - utils.debug( 'get installed package (release): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) - utils.debug( 'get installed package (debug): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) - utils.debug_line() - - utils.new_line() - utils.debug( 'reverting removal' ) - # now instead of completing the removal, revert it - for pac in packageList: - pac.revert() - - utils.debug( 'checking installed packages' ) - utils.debug( 'get installed package (release): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) - utils.debug( 'get installed package (debug): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) - utils.debug_line() - - db.getInstalled() - db.getInstalled( category='win32libs-sources', prefix='debug' ) - db.getInstalled( package='dbus-src' ) - - utils.new_line() - utils.debug( 'now really remove the package' ) - packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0') - for pac in packageList: - utils.debug( 'removing %s files' % len( pac.getFiles() ) ) - pac.uninstall() - - utils.debug( 'get installed package (release): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) - utils.debug( 'get installed package (debug): %s' % db.getInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) - utils.debug_line() - - # test the import from the old style (manifest based) databases - utils.new_line() - db_temp.importExistingDatabase() - print("getInstalled:", db_temp.getInstalled()) - print("findInstalled:", portage.findInstalled( 'win32libs-sources', 'dbus-src' )) - print("getFileListFromManifest:", len( utils.getFileListFromManifest( os.getenv( "KDEROOT" ), 'dbus-src' ) )) - -if __name__ == '__main__': - main() +import os +import utils +import portage +import emergePlatform +import sqlite3 +import threading + +__blockme = threading.local() + +def isDBEnabled(): + """ this function returns whether sqlite database should be used """ + if not os.getenv("EMERGE_ENABLE_SQLITEDB"): + return True + return utils.envAsBool("EMERGE_ENABLE_SQLITEDB") + +def blocking(fn): + """ Block parallel access to sqlite """ + def block(*args, **kw): + if hasattr(__blockme, "blocked"): # Already blocked + return fn(*args, **kw) + try: + with utils.LockFile(utils.LockFileName("SQLITE")): + __blockme.blocked = True + ret = fn(*args, **kw) + finally: + delattr(__blockme, "blocked"); + return ret + + return block + +class InstallPackage: + """ InstallPackage finalizes an installation. + + If you call addInstalled or remInstalled an InstallPackage object is returned which + you can use to handle file information with the InstallDB. For installation use code + similar to this one: + + # get an InstallPackage object p + p = InstallDB.installdb.addInstalled( "cat", "pac", "ver", "prefix" ) + # add files ( including the hash ) + p.addFiles( [ ( "file1", "hash1" ), ( "file2", "hash2" ), ( "file3", "hash3" ) ] ) + if failed: + # in case we somehow need to go back + p.revert() + else: + # finalize the installation + p.install() + + Deinstallation works similar: + p = InstallDB.installdb.remInstalled( "cat", "pac", "ver", "prefix" ) + # get the files ( including the hash ) + f = p.getFiles() + # f now contains [ ( "file1", "hash1" ), ( "file2", "hash2" ), ( "file3", "hash3" ) ] + if failed: + # in case we somehow need to go back + p.revert() + else: + # finalize the uninstall + p.uninstall() + """ + + def __init__( self, cursor, packageId ): + self.cursor = cursor + self.packageId = packageId + self.fileDict = dict() + + def addFiles( self, fileDict ): + """ appends files to the list of files to be installed """ + self.fileDict.update( fileDict ) + + @blocking + def getFiles( self ): + """ get a list of files that will be uninstalled """ + cmd = '''SELECT filename, fileHash FROM fileList WHERE packageId=?;''' + utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) + self.cursor.execute(cmd, (self.packageId,)) + return self.cursor.fetchall() + + @blocking + def revert( self ): + """ revert all changes made to the database, use with care """ + self.cursor.connection.rollback() + + @blocking + def uninstall( self ): + """ really uninstall that package """ + cmd = '''DELETE FROM fileList WHERE packageId=?;''' + utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) + self.cursor.execute(cmd, (self.packageId,)) + cmd = '''DELETE FROM packageList WHERE packageId=?;''' + utils.debug( "executing sqlcmd '%s' with parameter %s" % ( cmd, str( self.packageId ) ), 1 ) + self.cursor.execute(cmd, (self.packageId,)) + self.cursor.connection.commit() + + @blocking + def install( self ): + """ marking the package & package file list installed """ + fileNumber = len( self.fileDict ) + # keys() and values will stay in the same order if no changes are done in between calls + # structure of each tuple: + # fileId | packageId == package Id | filenames | file hashes + dataList = list(zip( [ None ] * fileNumber, [ self.packageId ] * fileNumber, list(self.fileDict.keys()), list(self.fileDict.values()) )) + + cmd = '''INSERT INTO fileList VALUES (?, ?, ?, ?)''' + utils.debug( "executing sqlcmd '%s' %s times" % ( cmd, len( self.fileDict ) ), 1 ) + self.cursor.executemany( cmd, dataList ) + + # at last, commit all the changes so that they are committed only after everything is written to the + # database + self.cursor.connection.commit() + + +class InstallDB: + """ a database object which provides the methods for adding and removing a package and + checking its installation status. + In case the database doesn't exist if the constructor is called, a new database is constructed + """ + + def __init__( self, filename = os.path.join( utils.etcDir(), 'install.db' ) ): + self.dbfilename = filename + if not os.path.exists( filename ): + if not os.path.exists( utils.etcDir() ): + os.makedirs( utils.etcDir() ) + utils.debug( "database does not exist yet: creating database & importing old data" ) + self._prepareDatabase() + else: + utils.debug( "found database", 1 ) + self.connection = sqlite3.connect( self.dbfilename ) + + @blocking + def getLastId( self ): + """ returns the last id from a table, which is essentially the """ + cmd = '''SELECT max(packageId) FROM packageList;''' + + cursor = self.connection.cursor() + cursor.execute( cmd ) + lastId = cursor.fetchall()[0] + return lastId[0] + + def __constructWhereStmt( self, _dict ): + params = [] + parametersUsed = False + stmt = "" +# if not prefix == '' or not category == '' or not package == '': +# cmd += ''' WHERE''' +# + for key in list(_dict.keys()): + if not _dict[ key ] == None: + if parametersUsed: + stmt += ''' AND''' + stmt += ''' %s=?''' % key + params.append( _dict[ key ] ) + parametersUsed = True + if not stmt == "": + stmt = ''' WHERE''' + stmt + + return stmt, params + + @blocking + def isInstalled( self, category, package, target=None, portage_revision=None, prefix=None ): + """ returns whether a package is installed. If version and prefix are empty, all versions + and prefixes will be checked. """ + cmd = '''SELECT * FROM packageList''' + # TODO: what is the difference between prefix=None and prefix=''? Both happens. Document. + stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'target': target } ) + cmd += stmt + cmd += ''';''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + + cursor = self.connection.cursor() + cursor.execute( cmd, tuple( params ) ) + isPackageInstalled = len( cursor.fetchall() ) > 0 + if isPackageInstalled: + utils.debug( """The package %s/%s has been installed in prefix '%s' with + version '%s'.""" % ( category, package, prefix, target ), 1 ) + else: + utils.debug( """Couldn't find a trace that the package %s/%s has been installed in + prefix '%s' with version '%s'""" % ( category, package, prefix, target ), 1 ) + cursor.close() + return isPackageInstalled + + def findInstalledVersion( self, category, package, prefix=None ): + """ get the version of a package that is installed """ + f = self.getListInstalled( category, package, prefix=prefix ) + if len(f) == 1: + return f[ 0 ][2] + else: + return None + + @blocking + def getListInstalled( self, category=None, package=None, prefix=None ): + """ returns a list of the installed packages, which can be restricted by adding + package, category and prefix. + """ + cmd = '''SELECT category, packageName, target, prefix, portage_revision FROM packageList''' + stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package } ) + cmd += stmt + cmd += ''';''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + + cursor = self.connection.cursor() + cursor.execute( cmd, tuple( params ) ) + values = cursor.fetchall() + cursor.close() + return values + + @blocking + def getDistinctListInstalled( self, category=None, package=None, prefix=None ): + """ returns a list of the installed packages, which can be restricted by adding + package, category and prefix. + """ + cmd = '''SELECT DISTINCT category, packageName, target FROM packageList''' + stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package } ) + cmd += stmt + cmd += ''';''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + + cursor = self.connection.cursor() + cursor.execute( cmd, tuple( params ) ) + values = cursor.fetchall() + cursor.close() + return values + + @blocking + def getPackageIds( self, category=None, package=None, target=None, prefix=None ): + """ returns a list of the ids of the packages, which can be restricted by adding + package, category and prefix. + """ + cmd = '''SELECT packageId FROM packageList''' + stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'target': target } ) + cmd += stmt + cmd += ''';''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + + cursor = self.connection.cursor() + cursor.execute( cmd, tuple( params ) ) + values = [] + for row in cursor: + values.append( row[0] ) + return values + + @blocking + def addInstalled( self, category, package, target, portage_revision=0, isDefaultTarget=True, prefix=None, ignoreInstalled=False ): + """ adds an installed package """ + cursor = self.connection.cursor() + if self.isInstalled( category, package, target, prefix=prefix ) and not ignoreInstalled: + raise Exception( 'package %s/%s already installed (prefix %s)' % ( category, package, prefix ) ) + + params = [ None, prefix, category, package, target, isDefaultTarget, portage_revision ] + cmd = '''INSERT INTO packageList VALUES (?, ?, ?, ?, ?, ?, ?)''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + cursor.execute( cmd, tuple( params ) ) + return InstallPackage( cursor, self.getLastId() ) + + @blocking + def remInstalled( self, category, package, target, prefix=None ): + """ removes an installed package """ + cmd = '''DELETE FROM packageList''' + stmt, params = self.__constructWhereStmt( { 'prefix': prefix, 'category': category, 'packageName': package, 'target': target } ) + cmd += stmt + cmd += ''';''' + utils.debug( "executing sqlcmd '%s' with parameters: %s" % ( cmd, tuple( params ) ), 1 ) + + cursor = self.connection.cursor() + return [ InstallPackage( cursor, pId ) for pId in self.getPackageIds( category, package, target, prefix ) ] + + @blocking + def _prepareDatabase( self ): + """ prepare a new database and add the required table layout """ + self.connection = sqlite3.connect( self.dbfilename ) + cursor = self.connection.cursor() + + # first, create the required tables + cursor.execute( '''CREATE TABLE packageList (packageId INTEGER PRIMARY KEY AUTOINCREMENT, + prefix TEXT, category TEXT, packageName TEXT, target TEXT, isDefaultTarget TEXT, portage_revision TEXT)''' ) + cursor.execute( '''CREATE TABLE fileList (fileId INTEGER PRIMARY KEY AUTOINCREMENT, + packageId INTEGER, filename TEXT, fileHash TEXT)''' ) + self.connection.commit() + +# get a global object +if isDBEnabled(): + installdb = InstallDB() + +# an additional function from portage.py +def printInstalled(): + """get all the packages that are already installed""" + host = target = portage.alwaysTrue + if emergePlatform.isCrossCompilingEnabled(): + host = portage.isHostBuildEnabled + target = portage.isTargetBuildEnabled + portage.printCategoriesPackagesAndVersions( installdb.getDistinctListInstalled(), portage.alwaysTrue, host, target ) + + +def main(): + """ Testing the class""" + + # add two databases + tempdbpath1 = os.path.join( os.getenv("KDEROOT"), "tmp", "temp1.db" ) + tempdbpath2 = os.path.join( os.getenv("KDEROOT"), "tmp", "temp2.db" ) + + if not os.path.exists( os.path.join( os.getenv( "KDEROOT" ), "tmp" ) ): + os.makedirs( os.path.join( os.getenv( "KDEROOT" ), "tmp" ) ) + + if os.path.exists( tempdbpath1 ): + os.remove( tempdbpath1 ) + if os.path.exists( tempdbpath2 ): + os.remove( tempdbpath2 ) + + db_temp = InstallDB( tempdbpath1 ) + db = InstallDB( tempdbpath2 ) + + utils.debug( 'testing installation database' ) + + # in case the package is still installed, remove it first silently + if db.isInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ): + packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ) + # really commit uninstall + for package in packageList: + package.uninstall() + utils.debug_line() + + utils.new_line() + # add a package + utils.debug( 'installing package win32libs-sources/dbus-src-1.4.0 (release)' ) + package = db.addInstalled( 'win32libs-sources', 'dbus-src', '1.4.0', 'release' ) + package.addFiles( dict().fromkeys( [ 'test', 'test1', 'test2' ], 'empty hash' ) ) + # now really commit the package + package.install() + + # add another package in a different prefix + utils.debug( 'installing package win32libs-sources/dbus-src-1.4.0 (debug)' ) + package = db.addInstalled( 'win32libs-sources', 'dbus-src', '1.4.0', 'debug' ) + package.addFiles( dict().fromkeys( [ 'test', 'test1', 'test2' ], 'empty hash' ) ) + # now really commit the package + package.install() + utils.debug_line() + + utils.new_line() + utils.debug( 'checking installed packages' ) + utils.debug( 'get installed package (release): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) + utils.debug( 'get installed package (debug): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) + + utils.new_line() + utils.debug( 'now trying to remove package & revert it again later' ) + # remove the package again + packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0' ) + for pac in packageList: + for line in pac.getFiles(): # pylint: disable=W0612 + # we could remove the file here + # print line + pass + utils.debug_line() + + utils.new_line() + utils.debug( 'checking installed packages' ) + utils.debug( 'get installed package (release): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) + utils.debug( 'get installed package (debug): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) + utils.debug_line() + + utils.new_line() + utils.debug( 'reverting removal' ) + # now instead of completing the removal, revert it + for pac in packageList: + pac.revert() + + utils.debug( 'checking installed packages' ) + utils.debug( 'get installed package (release): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) + utils.debug( 'get installed package (debug): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) + utils.debug_line() + + db.getListInstalled() + db.getListInstalled( category='win32libs-sources', prefix='debug' ) + db.getListInstalled( package='dbus-src' ) + + utils.new_line() + utils.debug( 'now really remove the package' ) + packageList = db.remInstalled( 'win32libs-sources', 'dbus-src', '1.4.0') + for pac in packageList: + utils.debug( 'removing %s files' % len( pac.getFiles() ) ) + pac.uninstall() + + utils.debug( 'get installed package (release): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'release' ) ) + utils.debug( 'get installed package (debug): %s' % db.getListInstalled( 'win32libs-sources', 'dbus-src', 'debug' ) ) + utils.debug_line() + + # test the import from the old style (manifest based) databases + utils.new_line() + db_temp.importExistingDatabase() + print("getListInstalled:", db_temp.getListInstalled()) + print("findInstalled:", portage.findInstalled( 'win32libs-sources', 'dbus-src' )) + print("getFileListFromManifest:", len( utils.getFileListFromManifest( os.getenv( "KDEROOT" ), 'dbus-src' ) )) + +if __name__ == '__main__': + main() diff --git a/bin/Package/PackageBase.py b/bin/Package/PackageBase.py index 999f5f111..ba2f1f953 100644 --- a/bin/Package/PackageBase.py +++ b/bin/Package/PackageBase.py @@ -1,301 +1,279 @@ -# -# copyright (c) 2009 Ralf Habacker -# - -from EmergeBase import * -from InstallDB import * -from compiler import * - -class PackageBase (EmergeBase): - """ - provides a generic interface for packages and implements the basic stuff for all - packages - """ - - # uses the following instance variables - # todo: place in related ...Base - - #rootdir -> EmergeBase - #package -> PackageBase - #force -> PackageBase - #category -> PackageBase - #version -> PackageBase - #packagedir -> PackageBase - #imagedir -> PackageBase - - def __init__(self): - utils.debug("PackageBase.__init__ called", 2) - EmergeBase.__init__(self) - self.setBuildTarget() - self.forceCreateManifestFiles = False - - def _installedDBPrefix(self, buildType=None): - postfix = '' - if buildType == None: - buildType = self.buildType() - if self.useBuildTypeRelatedMergeRoot: - if buildType == 'Debug': - postfix = 'debug' - elif buildType == 'Release': - postfix = 'release' - elif buildType == 'RelWithDebInfo': - postfix = 'relwithdebinfo' - return postfix - - def qmerge( self ): - """mergeing the imagedirectory into the filesystem""" - self.manifest() - ## \todo is this the optimal place for creating the post install scripts ? - # create post install scripts - for pkgtype in ['bin', 'lib', 'doc', 'src']: - script = os.path.join( self.packageDir(), "post-install-%s.cmd" ) % pkgtype - scriptName = "post-install-%s-%s-%s.cmd" % ( self.package, self.version, pkgtype ) - # are there any cases there installDir should be honored ? - destscript = os.path.join( self.imageDir(), "manifest", scriptName ) - if not os.path.exists( os.path.join( self.imageDir(), "manifest" ) ): - utils.createDir( os.path.join( self.imageDir(), "manifest" ) ) - if os.path.exists( script ): - utils.copyFile( script, destscript ) - ignoreInstalled = False - if isDBEnabled(): - if self.isTargetBuild(): - if installdb.isInstalled( category=None, package=self.package, prefix=os.getenv( "EMERGE_TARGET_PLATFORM" ) ): - ignoreInstalled = True - self.unmerge() - else: - prefixPath = self._installedDBPrefix( self.buildType() ) - if installdb.isInstalled( category=None, package=self.package, prefix=prefixPath ): - ignoreInstalled = True - self.unmerge() - else: - if portage.isInstalled( '', self.package, '', self.buildType() ): - ignoreInstalled = True - self.unmerge() - - - - utils.debug("qmerge package to %s" % self.mergeDestinationDir(), 2) - utils.mergeImageDirToRootDir( self.mergeSourceDir(), self.mergeDestinationDir() ,utils.envAsBool("EMERGE_USE_SYMLINKS")) - - # run post-install scripts - if not utils.envAsBool("EMERGE_NO_POST_INSTALL"): - for pkgtype in ['bin', 'lib', 'doc', 'src']: - scriptName = "post-install-%s-%s-%s.cmd" % ( self.package, self.version, pkgtype ) - script = os.path.join( self.rootdir, "manifest", scriptName ) - if os.path.exists( script ): - cmd = "cd /D %s && %s" % ( self.rootdir, script ) - if not utils.system(cmd): - utils.warning("%s failed!" % cmd ) - else: - utils.debug("running of post-install scripts disabled!", 0) - - # add package to installed database -> is this not the task of the manifest files ? - - # only packages using a specific merge destination path are shared between build types - if self.useBuildTypeRelatedMergeRoot and self.subinfo.options.merge.ignoreBuildType \ - and self.subinfo.options.merge.destinationPath != None: - for prefix in [ "Release", "RelWithDebInfo", "Debug" ]: - if isDBEnabled(): - package = installdb.addInstalled( self.category, self.package, self.version, self._installedDBPrefix( prefix ), ignoreInstalled ) - package.addFiles( utils.getFileListFromManifest( self._installedDBPrefix( prefix ), self.package ) ) - package.install() - else: - portage.addInstalled( self.category, self.package, self.version, self._installedDBPrefix( prefix ) ) - else: - if isDBEnabled(): - if emergePlatform.isCrossCompilingEnabled(): - if self.isTargetBuild(): - package = installdb.addInstalled( self.category, self.package, self.version, - os.getenv( "EMERGE_TARGET_PLATFORM" ), ignoreInstalled ) - else: - package = installdb.addInstalled( self.category, self.package, self.version, self._installedDBPrefix() ) - package.addFiles( utils.getFileListFromDirectory( self.mergeSourceDir() ) ) - package.install() - else: - package = installdb.addInstalled( self.category, self.package, self.version, self._installedDBPrefix(), ignoreInstalled ) - package.addFiles( utils.getFileListFromDirectory( self.mergeSourceDir() ) ) - package.install() - else: - portage.addInstalled( self.category, self.package, self.version, self._installedDBPrefix() ) - - return True - - def unmerge( self ): - """unmergeing the files from the filesystem""" - utils.debug( "Packagebase unmerge called", 2 ) - - ## \todo mergeDestinationDir() reads the real used merge dir from the - ## package definition, which fails if this is changed - ## a better solution will be to save the merge sub dir into - ## /etc/portage/installed and to read from it on unmerge - utils.debug( "unmerge package from %s" % self.mergeDestinationDir(), 2 ) - if isDBEnabled(): - if self.useBuildTypeRelatedMergeRoot and self.subinfo.options.merge.ignoreBuildType \ - and self.subinfo.options.merge.destinationPath != None: - for prefix in [ "Release", "RelWithDebInfo", "Debug" ]: - packageList = installdb.remInstalled( self.category, self.package, self.version, self._installedDBPrefix( prefix ) ) - for package in packageList: - fileList = package.getFiles() - utils.unmergeFileList( self.mergeDestinationDir(), fileList, self.forced ) - package.uninstall() - else: - if self.isTargetBuild(): - packageList = installdb.remInstalled( self.category, self.package, self.version, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) - else: - packageList = installdb.remInstalled( self.category, self.package, self.version, self._installedDBPrefix() ) - for package in packageList: - fileList = package.getFiles() - utils.unmergeFileList( self.mergeDestinationDir(), fileList, self.forced ) - package.uninstall() - else: - if not utils.unmerge( self.mergeDestinationDir(), self.package, self.forced ) and not emergePlatform.isCrossCompilingEnabled(): - # compatibility code: uninstall subclass based package - utils.unmerge( self.rootdir, self.package, self.forced ) - portage.remInstalled( self.category, self.package, self.version, '') - - # only packages using a specific merge destination path are shared between build types - if self.useBuildTypeRelatedMergeRoot and self.subinfo.options.merge.ignoreBuildType \ - and self.subinfo.options.merge.destinationPath != None: - portage.remInstalled( self.category, self.package, self.version, self._installedDBPrefix( "Release" ) ) - portage.remInstalled( self.category, self.package, self.version, self._installedDBPrefix( "RelWithDebInfo" ) ) - portage.remInstalled( self.category, self.package, self.version, self._installedDBPrefix( "Debug" ) ) - else: - portage.remInstalled( self.category, self.package, self.version, self._installedDBPrefix() ) - return True - - def cleanImage( self ): - """cleanup before install to imagedir""" - if self.buildSystemType == 'binary': - utils.debug("skipped cleaning image dir because we use binary build system", 1) - return True - if ( os.path.exists( self.imageDir() ) ): - utils.debug( "cleaning image dir: %s" % self.imageDir(), 1 ) - utils.cleanDirectory( self.imageDir() ) - os.rmdir(self.imageDir()) - return True - - def cleanBuild( self ): - """cleanup currently used build dir""" - if os.path.exists( self.buildDir() ): - utils.cleanDirectory( self.buildDir() ) - utils.debug( "cleaning build dir: %s" % self.buildDir(), 1 ) - - return True - - def manifest( self ): - """installer compatibility: make the manifest files that make up the installers - install database""" - - utils.debug("base manifest called", 2) - # important - remove all old manifests to not pollute merge root manifest dir with old packaging info - utils.cleanManifestDir( self.mergeSourceDir() ) - # For qmerging the manifests files could go into merge destination - # For packaging they have to stay in image dir - # -> the common denominator is to create manifests in image dir - # qmerge needs creating of manifests and packaging too, there is not need why they are - # created in the qmerge step *and* the package step - # -> merge them into the install step of the build system classes - ## @todo move all createManifestFiles() calls into install() method of the Buildsystem classes - utils.createManifestFiles( self.mergeSourceDir(), self.mergeSourceDir(), self.category, self.package, self.version ) - return True - - def stripLibs( self, pkgName ): - """strip debugging informations from shared libraries - mingw only!!! """ - return self.strip(pkgName + ".dll" ) - - def strip( self , fileName ): - """strip debugging informations from shared libraries and executables - mingw only!!! """ - if self.subinfo.options.package.disableStriping or not isMinGW(): - utils.debug("Skiping stipping of " + fileName ,2 ) - return True - basepath = os.path.join( self.installDir() ) - filepath = os.path.join( basepath, "bin", fileName ) - - cmd = "strip -s " + filepath - utils.debug(cmd,2) - os.system( cmd ) - return True - - def createImportLibs( self, pkgName ): - """create the import libraries for the other compiler(if ANSI-C libs)""" - basepath = os.path.join( self.installDir() ) - utils.createImportLibs( pkgName, basepath ) - - def getAction(self, cmd = None ): - if not cmd: - command = sys.argv[ 1 ] - options = None -# print sys.argv - if ( len( sys.argv ) > 2 ): - options = sys.argv[ 2: ] - else: - command = cmd - options = None - # \todo options are not passed through by emerge.py fix it - return [command, options] - - def execute( self, cmd=None ): - """called to run the derived class - this will be executed from the package if the package is started on its own - it shouldn't be called if the package is imported as a python module""" - - utils.debug( "EmergeBase.execute called. args: %s" % sys.argv, 2 ) - command, _ = self.getAction(cmd) - - #if self.createCombinedPackage: - # oldBuildType = os.environ["EMERGE_BUILDTYPE"] - # os.environ["EMERGE_BUILDTYPE"] = "Release" - # self.runAction(command) - # os.environ["EMERGE_BUILDTYPE"] = "Debug" - # self.runAction(command) - # os.environ["EMERGE_BUILDTYPE"] = oldBuildType - #else: - if self.subinfo.options.disableReleaseBuild and self.buildType() == "Release" \ - or self.subinfo.options.disableDebugBuild and self.buildType() == "Debug": - print("target ignored for this build type") - return False - - if emergePlatform.isCrossCompilingEnabled() and self.isHostBuild() and self.subinfo.disableHostBuild \ - and not command == "fetch" and not command == "unpack": - utils.debug( "host build disabled, skipping host build", 1 ) - return True - - if emergePlatform.isCrossCompilingEnabled() and self.isTargetBuild() and self.subinfo.disableTargetBuild \ - and not command == "fetch" and not command == "unpack": - utils.debug( "target build disabled, skipping target build", 1 ) - return True - - self.runAction(command) - return True - - def runAction( self, command ): - """ \todo TODO: rename the internal functions into the form cmdFetch, cmdCheckDigest etc - then we get by without this dict: - ok = getattr(self, 'cmd' + command.capitalize()() - next we could """ - functions = {"fetch": "fetch", - "cleanimage": "cleanImage", - "cleanbuild": "cleanBuild", - "unpack": "unpack", - "compile": "compile", - "configure": "configure", - "make": "make", - "install": "install", - "test": "unittest", - "qmerge": "qmerge", - "unmerge": "unmerge", - "manifest": "manifest", - "package": "createPackage", - "createpatch": "createPatch", - "geturls": "getUrls", - "printrev": "sourceVersion", - "checkdigest": "checkDigest", - "dumpdeps": "dumpDependencies"} - if command in functions: - ok = getattr(self, functions[command])() - else: - ok = utils.error( "command %s not understood" % command ) - - if ( not ok ): - utils.die( "command %s failed" % command ) - return True +# +# copyright (c) 2009 Ralf Habacker +# + +from EmergeBase import * +from InstallDB import * +from compiler import * + +class PackageBase (EmergeBase): + """ + provides a generic interface for packages and implements the basic stuff for all + packages + """ + + # uses the following instance variables + # todo: place in related ...Base + + #rootdir -> EmergeBase + #package -> PackageBase + #force -> PackageBase + #category -> PackageBase + #version -> PackageBase + #packagedir -> PackageBase + #imagedir -> PackageBase + + def __init__(self): + utils.debug("PackageBase.__init__ called", 2) + EmergeBase.__init__(self) + self.setBuildTarget() + self.forceCreateManifestFiles = False + + def _installedDBPrefix(self, buildType=None): + postfix = None + if buildType == None: + buildType = self.buildType() + if self.useBuildTypeRelatedMergeRoot: + if buildType == 'Debug': + postfix = 'debug' + elif buildType == 'Release': + postfix = 'release' + elif buildType == 'RelWithDebInfo': + postfix = 'relwithdebinfo' + return postfix + + def qmerge( self ): + """mergeing the imagedirectory into the filesystem""" + self.manifest() + ## \todo is this the optimal place for creating the post install scripts ? + # create post install scripts + for pkgtype in ['bin', 'lib', 'doc', 'src']: + script = os.path.join( self.packageDir(), "post-install-%s.cmd" ) % pkgtype + scriptName = "post-install-%s-%s-%s.cmd" % ( self.package, self.version, pkgtype ) + # are there any cases there installDir should be honored ? + destscript = os.path.join( self.imageDir(), "manifest", scriptName ) + if not os.path.exists( os.path.join( self.imageDir(), "manifest" ) ): + utils.createDir( os.path.join( self.imageDir(), "manifest" ) ) + if os.path.exists( script ): + utils.copyFile( script, destscript ) + ignoreInstalled = False + if isDBEnabled(): + if self.isTargetBuild(): + if installdb.isInstalled( category=None, package=self.package, prefix=os.getenv( "EMERGE_TARGET_PLATFORM" ) ): + ignoreInstalled = True + self.unmerge() + else: + prefixPath = self._installedDBPrefix( self.buildType() ) + if installdb.isInstalled( category=None, package=self.package, prefix=prefixPath ): + ignoreInstalled = True + self.unmerge() + else: + if portage.isInstalled( '', self.package, '', self.buildType() ): + ignoreInstalled = True + self.unmerge() + + utils.debug("qmerge package to %s" % self.mergeDestinationDir(), 2) + utils.mergeImageDirToRootDir( self.mergeSourceDir(), self.mergeDestinationDir() ,utils.envAsBool("EMERGE_USE_SYMLINKS")) + + # run post-install scripts + if not utils.envAsBool("EMERGE_NO_POST_INSTALL"): + for pkgtype in ['bin', 'lib', 'doc', 'src']: + scriptName = "post-install-%s-%s-%s.cmd" % ( self.package, self.version, pkgtype ) + script = os.path.join( self.rootdir, "manifest", scriptName ) + if os.path.exists( script ): + cmd = "cd /D %s && %s" % ( self.rootdir, script ) + if not utils.system(cmd): + utils.warning("%s failed!" % cmd ) + else: + utils.debug("running of post-install scripts disabled!", 0) + + # add package to installed database -> is this not the task of the manifest files ? + + # only packages using a specific merge destination path are shared between build types + if self.useBuildTypeRelatedMergeRoot and self.subinfo.options.merge.ignoreBuildType \ + and self.subinfo.options.merge.destinationPath != None: + for prefix in [ "Release", "RelWithDebInfo", "Debug" ]: + package = installdb.addInstalled( self.category, self.package, self.buildTarget, self._installedDBPrefix( prefix ), ignoreInstalled ) + package.addFiles( utils.getFileListFromManifest( self._installedDBPrefix( prefix ), self.package ) ) + package.install() + else: + if emergePlatform.isCrossCompilingEnabled(): + if self.isTargetBuild(): + package = installdb.addInstalled( self.category, self.package, self.buildTarget, + os.getenv( "EMERGE_TARGET_PLATFORM" ), ignoreInstalled ) + else: + package = installdb.addInstalled( self.category, self.package, self.buildTarget, self._installedDBPrefix() ) + package.addFiles( utils.getFileListFromDirectory( self.mergeSourceDir() ) ) + package.install() + else: + package = installdb.addInstalled( self.category, self.package, self.buildTarget, self._installedDBPrefix(), ignoreInstalled ) + package.addFiles( utils.getFileListFromDirectory( self.mergeSourceDir() ) ) + package.install() + + return True + + def unmerge( self ): + """unmergeing the files from the filesystem""" + utils.debug( "Packagebase unmerge called", 2 ) + + ## \todo mergeDestinationDir() reads the real used merge dir from the + ## package definition, which fails if this is changed + ## a better solution will be to save the merge sub dir into + ## /etc/portage/installed and to read from it on unmerge + utils.debug( "unmerge package from %s" % self.mergeDestinationDir(), 2 ) + if self.useBuildTypeRelatedMergeRoot and self.subinfo.options.merge.ignoreBuildType \ + and self.subinfo.options.merge.destinationPath != None: + for prefix in [ "Release", "RelWithDebInfo", "Debug" ]: + packageList = installdb.remInstalled( self.category, self.package, self.buildTarget, self._installedDBPrefix( prefix ) ) + for package in packageList: + fileList = package.getFiles() + utils.unmergeFileList( self.mergeDestinationDir(), fileList, self.forced ) + package.uninstall() + else: + if self.isTargetBuild(): + packageList = installdb.remInstalled( self.category, self.package, self.buildTarget, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) + else: + packageList = installdb.remInstalled( self.category, self.package, self.buildTarget, self._installedDBPrefix() ) + for package in packageList: + fileList = package.getFiles() + utils.unmergeFileList( self.mergeDestinationDir(), fileList, self.forced ) + package.uninstall() + + return True + + def cleanImage( self ): + """cleanup before install to imagedir""" + if self.buildSystemType == 'binary': + utils.debug("skipped cleaning image dir because we use binary build system", 1) + return True + if ( os.path.exists( self.imageDir() ) ): + utils.debug( "cleaning image dir: %s" % self.imageDir(), 1 ) + utils.cleanDirectory( self.imageDir() ) + os.rmdir(self.imageDir()) + return True + + def cleanBuild( self ): + """cleanup currently used build dir""" + if os.path.exists( self.buildDir() ): + utils.cleanDirectory( self.buildDir() ) + utils.debug( "cleaning build dir: %s" % self.buildDir(), 1 ) + + return True + + def manifest( self ): + """installer compatibility: make the manifest files that make up the installers + install database""" + + utils.debug("base manifest called", 2) + # important - remove all old manifests to not pollute merge root manifest dir with old packaging info + utils.cleanManifestDir( self.mergeSourceDir() ) + # For qmerging the manifests files could go into merge destination + # For packaging they have to stay in image dir + # -> the common denominator is to create manifests in image dir + # qmerge needs creating of manifests and packaging too, there is not need why they are + # created in the qmerge step *and* the package step + # -> merge them into the install step of the build system classes + ## @todo move all createManifestFiles() calls into install() method of the Buildsystem classes + utils.createManifestFiles( self.mergeSourceDir(), self.mergeSourceDir(), self.category, self.package, self.buildTarget ) + return True + + def stripLibs( self, pkgName ): + """strip debugging informations from shared libraries - mingw only!!! """ + return self.strip(pkgName + ".dll" ) + + def strip( self , fileName ): + """strip debugging informations from shared libraries and executables - mingw only!!! """ + if self.subinfo.options.package.disableStriping or not isMinGW(): + utils.debug("Skiping stipping of " + fileName ,2 ) + return True + basepath = os.path.join( self.installDir() ) + filepath = os.path.join( basepath, "bin", fileName ) + + cmd = "strip -s " + filepath + utils.debug(cmd,2) + os.system( cmd ) + return True + + def createImportLibs( self, pkgName ): + """create the import libraries for the other compiler(if ANSI-C libs)""" + basepath = os.path.join( self.installDir() ) + utils.createImportLibs( pkgName, basepath ) + + def getAction(self, cmd = None ): + if not cmd: + command = sys.argv[ 1 ] + options = None +# print sys.argv + if ( len( sys.argv ) > 2 ): + options = sys.argv[ 2: ] + else: + command = cmd + options = None + # \todo options are not passed through by emerge.py fix it + return [command, options] + + def execute( self, cmd=None ): + """called to run the derived class + this will be executed from the package if the package is started on its own + it shouldn't be called if the package is imported as a python module""" + + utils.debug( "EmergeBase.execute called. args: %s" % sys.argv, 2 ) + command, _ = self.getAction(cmd) + + #if self.createCombinedPackage: + # oldBuildType = os.environ["EMERGE_BUILDTYPE"] + # os.environ["EMERGE_BUILDTYPE"] = "Release" + # self.runAction(command) + # os.environ["EMERGE_BUILDTYPE"] = "Debug" + # self.runAction(command) + # os.environ["EMERGE_BUILDTYPE"] = oldBuildType + #else: + if self.subinfo.options.disableReleaseBuild and self.buildType() == "Release" \ + or self.subinfo.options.disableDebugBuild and self.buildType() == "Debug": + print("target ignored for this build type") + return False + + if emergePlatform.isCrossCompilingEnabled() and self.isHostBuild() and self.subinfo.disableHostBuild \ + and not command == "fetch" and not command == "unpack": + utils.debug( "host build disabled, skipping host build", 1 ) + return True + + if emergePlatform.isCrossCompilingEnabled() and self.isTargetBuild() and self.subinfo.disableTargetBuild \ + and not command == "fetch" and not command == "unpack": + utils.debug( "target build disabled, skipping target build", 1 ) + return True + + self.runAction(command) + return True + + def runAction( self, command ): + """ \todo TODO: rename the internal functions into the form cmdFetch, cmdCheckDigest etc + then we get by without this dict: + ok = getattr(self, 'cmd' + command.capitalize()() + next we could """ + functions = {"fetch": "fetch", + "cleanimage": "cleanImage", + "cleanbuild": "cleanBuild", + "unpack": "unpack", + "compile": "compile", + "configure": "configure", + "make": "make", + "install": "install", + "test": "unittest", + "qmerge": "qmerge", + "unmerge": "unmerge", + "manifest": "manifest", + "package": "createPackage", + "createpatch": "createPatch", + "geturls": "getUrls", + "printrev": "sourceVersion", + "checkdigest": "checkDigest", + "dumpdeps": "dumpDependencies"} + if command in functions: + ok = getattr(self, functions[command])() + else: + ok = utils.error( "command %s not understood" % command ) + + if ( not ok ): + utils.die( "command %s failed" % command ) + return True diff --git a/bin/emerge.py b/bin/emerge.py index 33c4cbe10..f57e80a02 100644 --- a/bin/emerge.py +++ b/bin/emerge.py @@ -1,646 +1,647 @@ -# -*- coding: utf-8 -*- -# this will emerge some programs... - -# copyright: -# Holger Schroeder -# Patrick Spendrin - -import sys - -# The minimum python version for emerge please edit here -# if you add code that changes this requirement -MIN_PY_VERSION = (3, 0, 0) - -if sys.version_info[0:3] < MIN_PY_VERSION: - print ("Error: Python too old!") - print ("Emerge needs at least Python Version %s.%s.%s" % MIN_PY_VERSION ) - print ("Please install it and adapt your kdesettings.bat") - exit(1) - -import os -import utils -import portage -import emergePlatform -import portageSearch -import shutil -from InstallDB import * -import sched -import time -import datetime -import threading - - -def usage(): - print(""" -Usage: - emerge [[ command and flags ] [ singletarget ] - [ command and flags ] [ singletarget ] - ... ] - - where singletarget can be of the form: - category - package - category/package - -Emerge is a tool for building KDE-related software under Windows. emerge -automates it, looks for the dependencies and fetches them automatically. -Some options should be used with extreme caution since they will -make your kde installation unusable in 999 out of 1000 cases. - -Commands (no packagename needed - will be ignored when given): - ---print-installed This will show a list of all packages that - are installed currently. It queries both - databases (etc\portage\installed) and the - manifest directory - it prints out only those - packages that are contained within - --print-installable ---print-installable This will give you a list of packages that can - be installed. Currently you don't need to - enter the category and package: only the - package will be enough. ---update-all this option tries to update all installed - packages that contain one or multiple svn - targets. This is equivalent to running all - those packages with the flag --update. - -Commands (must have a packagename): - ---print-targets This will print all the different targets one package - can contain: different releases might have different - tags that are build as targets of a package. As an - example: You could build the latest amarok sources with - the target 'svnHEAD' the previous '1.80' release would - be contained as target '1.80'. ---print-revision This will print the revision that the source repository - of this package currently has or nothing if there is no - repository. ---fetch retrieve package sources (also checkout sources from - svn or git). ---unpack unpack package sources and make up the build directory. ---compile compile the sources: this includes - configure'ing/cmake'ing and running [mingw32-|n|]make. ---configure configure the sources (support is package specific) ---make run [mingw32-|n|]make (support is package specific) ---install This will run [mingw32-|n|]make install into the image - directory of each package. ---manifest This step creates the files contained in the manifest - dir. ---qmerge This will merge the image directory into the KDEROOT ---test This will run the unittests if they are present ---package This step will create a package out of the image - directory instead of merge'ing the image directory into - the KDEROOT (Requires the packager to be installed - already.) ---full-package This will create packages instead of installing stuff - to KDEROOT ---install-deps This will fetch and install all required dependencies - for the specified package ---unmerge this uninstalls a package from KDEROOT - it requires a - working manifest directory. unmerge only delete - unmodified files by default. You may use the -f or - --force option to let unmerge delete all files - unconditional. ---cleanallbuilds Clean complete build directory. ---cleanbuild Clean build directory for the specified package. This - cleans also all the image directories of all targets of - the specified package. ---checkdigest Check digest for the specified package. If no digest is - available calculate and print digests. ---cleanimage Clean image directory for the specified package and - target. ---createpatch Create source patch file for the specific package based - on the original archive file or checkout revision of - the used software revision control system. ---disable-buildhost This disables the building for the host. ---disable-buildtarget This disables the building for the target. - -Flags: - ---buildtype=[BUILDTYPE] This will override the build type set by the - environment option EMERGE_BUILDTYPE . - Please set it to one out of Release, Debug, - RelWithDebInfo, MinSizeRel ---target=[TARGET] This will override the build of the default - target. The default Target is marked with a - star in the printout of --print-targets ---options= Set emerge property from string . - An example for is "cmake.openIDE=1"; - see options.py for more informations. ---patchlevel=[PATCHLEVEL] This will add a patch level when used together - with --package ---log-dir=[LOG_DIR] This will log the build output to a logfile in - LOG_DIR for each package. Logging information - is appended to existing logs. - --i ignore install: using this option will install a package over an - existing install. This can be useful if you want to check some - new code and your last build isn't that old. --p ---probe probing: emerge will only look which files it has to build - according to the list of installed files and according to the - dependencies of the package. --q quiet: there should be no output - The verbose level should be 0 --t test: if used on an KDE target it will override the environment - variable and build the target with -DKDE_BUILD_TESTS=ON --v verbose: increases the verbose level of emerge. Default is 1. - verbose level 1 contains some notes from emerge, all output of - cmake, make and other programs that are used. verbose level 2 - adds an option VERBOSE=1 to make and emerge is more verbose - highest level is verbose level 3. --z if packages from version control system sources are installed, - it marks them as out of date and rebuilds them (tags are not - marked as out of date). --sz similar to -z, only that it acts only on the last package, and - works as normal on the rest. ---noclean this option will try to use an existing build directory. Please - handle this option with care - it will possibly break if the - directory isn't existing. ---nocopy this option is deprecated. In older releases emerge would have - copied everything from the SVN source tree to a source directory - under %KDEROOT%\\tmp - currently nocopy is applied by default if - EMERGE_NOCOPY is not set to "False". Be aware that setting - EMERGE_NOCOPY to "False" might slow down the build process, - irritate you and increase the disk space roughly by the size of - SVN source tree. ---offline do not try to connect to the internet: KDE packages will try to - use an existing source tree and other packages would try to use - existing packages in the download directory. If that doesn't - work, the build will fail. ---update this option is the same as '-i --noclean'. It will update a single - package that is already installed. ---cleanup Clean your portage directory, to prevent emerge errors, removes - empty directories and *.pyc files - -Internal options or options that aren't fully implemented yet: -PLEASE DO NOT USE! ---version-dir ---version-package - -More information see the README or http://windows.kde.org/. -Send feedback to . - -""") - -@utils.log -def doExec( category, package, version, action, opts ): - utils.startTimer("%s for %s" % ( action,package),1) - utils.debug( "emerge doExec called. action: %s opts: %s" % (action, opts), 2 ) - fileName = portage.getFilename( category, package, version ) - opts_string = ( "%s " * len( opts ) ) % tuple( opts ) - commandstring = "python %s %s %s" % ( fileName, action, opts_string ) - - utils.debug( "file: " + fileName, 1 ) - try: - #Switched to import the packages only, because otherwise degugging is very hard, if it troubles switch back - #makes touble for xcompile -> changed back - if not utils.system( commandstring ): - utils.die( "running %s" % commandstring ) - #mod = portage.__import__( fileName ) - #mod.Package().execute(action) - except OSError: - utils.stopTimer("%s for %s" % ( action,package)) - return False - utils.stopTimer("%s for %s" % ( action,package)) - return True - -def updateTitle(startTime,title): - while(len(utils._TIMERS)>0): - delta = datetime.datetime.now() - startTime - utils.setTitle("Emerge %s %s" %(title , delta)) - time.sleep(1) - -def handlePackage( category, package, version, buildAction, opts ): - utils.debug( "emerge handlePackage called: %s %s %s %s" % (category, package, version, buildAction), 2 ) - success = True - - if continueFlag: - actionList = ['fetch', 'unpack', 'configure', 'make', 'cleanimage', 'install', 'manifest', 'qmerge'] - - found = None - for action in actionList: - if not found and action != buildAction: - continue - found = True - success = success and doExec( category, package, version, action, opts ) - elif ( buildAction == "all" or buildAction == "full-package" ): - os.putenv( "EMERGE_BUILD_STEP", "" ) - success = doExec( category, package, version, "fetch", opts ) - success = success and doExec( category, package, version, "unpack", opts ) - if emergePlatform.isCrossCompilingEnabled(): - if not disableHostBuild: - os.putenv( "EMERGE_BUILD_STEP", "host" ) - success = success and doExec( category, package, version, "compile", opts ) - success = success and doExec( category, package, version, "cleanimage", opts ) - success = success and doExec( category, package, version, "install", opts ) - if ( buildAction == "all" ): - success = success and doExec( category, package, version, "manifest", opts ) - if ( buildAction == "all" ): - success = success and doExec( category, package, version, "qmerge", opts ) - if( buildAction == "full-package" ): - success = success and doExec( category, package, version, "package", opts ) - if disableTargetBuild: - return success - os.putenv( "EMERGE_BUILD_STEP", "target" ) - - success = success and doExec( category, package, version, "compile", opts ) - success = success and doExec( category, package, version, "cleanimage", opts ) - success = success and doExec( category, package, version, "install", opts ) - if ( buildAction == "all" ): - success = success and doExec( category, package, version, "manifest", opts ) - if ( buildAction == "all" ): - success = success and doExec( category, package, version, "qmerge", opts ) - if( buildAction == "full-package" ): - success = success and doExec( category, package, version, "package", opts ) - - elif ( buildAction in [ "fetch", "unpack", "preconfigure", "configure", "compile", "make", "qmerge", "checkdigest", "dumpdeps", - "package", "manifest", "unmerge", "test", "cleanimage", "cleanbuild", "createpatch", "geturls", - "printrev"] and category and package and version ): - os.putenv( "EMERGE_BUILD_STEP", "" ) - success = True - if emergePlatform.isCrossCompilingEnabled(): - if not disableHostBuild: - os.putenv( "EMERGE_BUILD_STEP", "host" ) - success = doExec( category, package, version, buildAction, opts ) - if disableTargetBuild: - return success - os.putenv( "EMERGE_BUILD_STEP", "target" ) - success = success and doExec( category, package, version, buildAction, opts ) - elif ( buildAction == "install" ): - os.putenv( "EMERGE_BUILD_STEP", "" ) - success = True - if emergePlatform.isCrossCompilingEnabled(): - if not disableHostBuild: - os.putenv( "EMERGE_BUILD_STEP", "host" ) - success = doExec( category, package, version, "cleanimage", opts ) - success = success and doExec( category, package, version, "install", opts ) - if disableTargetBuild: - return success - os.putenv( "EMERGE_BUILD_STEP", "target" ) - success = success and doExec( category, package, version, "cleanimage", opts ) - success = success and doExec( category, package, version, "install", opts ) - elif ( buildAction == "version-dir" ): - print("%s-%s" % ( package, version )) - success = True - elif ( buildAction == "version-package" ): - print("%s-%s-%s" % ( package, os.getenv( "KDECOMPILER" ), version )) - success = True - elif ( buildAction == "print-installable" ): - portage.printInstallables() - success = True - elif ( buildAction == "print-installed" ): - if isDBEnabled(): - printInstalled() - else: - portage.printInstalled() - success = True - elif ( buildAction == "print-targets" ): - portage.printTargets( category, package, version ) - success = True - elif ( buildAction == "install-deps" ): - success = True - else: - success = utils.error( "could not understand this buildAction: %s" % buildAction ) - - return success - -# -# "main" action starts here -# - -# TODO: all the rest should go into main(). But here I am not -# sure - maybe some of those variables are actually MEANT to -# be used in other modules. Put this back for now - -# but as a temporary solution rename variables to mainXXX -# where it is safe so there are less redefinitions in inner scopes - -utils.startTimer("Emerge") -tittleThread = threading.Thread(target=updateTitle,args = (datetime.datetime.now()," ".join(sys.argv[:]),)) -tittleThread.setDaemon(True) -tittleThread.start() - - -mainBuildAction = "all" -packageName = None -doPretend = False -outDateVCS = False -outDatePackage = False -stayQuiet = False -disableHostBuild = False -disableTargetBuild = False -ignoreInstalled = False -updateAll = False -continueFlag = False - -if len( sys.argv ) < 2: - usage() - utils.die("") - -environ = dict() # TODO: why do we need this at all? -environ["EMERGE_TRACE"] = os.getenv( "EMERGE_TRACE" ) -environ["EMERGE_BUILDTESTS"] = os.getenv( "EMERGE_BUILDTESTS" ) -environ["EMERGE_OFFLINE"] = os.getenv( "EMERGE_OFFLINE" ) -environ["EMERGE_FORCED"] = os.getenv( "EMERGE_FORCED" ) -environ["EMERGE_VERSION"] = os.getenv( "EMERGE_VERSION" ) -environ["EMERGE_BUILDTYPE"] = os.getenv( "EMERGE_BUILDTYPE" ) -environ["EMERGE_TARGET"] = os.getenv( "EMERGE_TARGET" ) -environ["EMERGE_PKGPATCHLVL"] = os.getenv( "EMERGE_PKGPATCHLVL" ) -environ["EMERGE_LOG_DIR"] = os.getenv( "EMERGE_LOG_DIR" ) - -if environ['EMERGE_TRACE'] == None or not environ['EMERGE_TRACE'].isdigit(): - trace = 0 - os.environ["EMERGE_TRACE"] = str( trace ) -else: - trace = int( environ[ "EMERGE_TRACE" ] ) - -mainOpts = list() - -executableName = sys.argv.pop( 0 ) -nextArguments = sys.argv[:] - -for i in sys.argv: - nextArguments.pop(0) - if ( i == "-p" or i == "--probe" ): - doPretend = True - elif ( i.startswith("--options=") ): - # @todo how to add -o option - options = i.replace( "--options=", "" ) - if "EMERGE_OPTIONS" in os.environ: - os.environ["EMERGE_OPTIONS"] += " %s" % options - else: - os.environ["EMERGE_OPTIONS"] = options - elif ( i == "-z" ): - outDateVCS = True - elif ( i == "-sz" ): - outDatePackage = True - elif ( i == "-q" ): - stayQuiet = True - elif ( i == "-t" ): - os.environ["EMERGE_BUILDTESTS"] = "True" - elif i == "-c" or i == "--continue": - continueFlag = True - elif ( i == "--offline" ): - mainOpts.append( "--offline" ) - os.environ["EMERGE_OFFLINE"] = "True" - elif ( i == "-f" or i == "--force" ): - os.environ["EMERGE_FORCED"] = "True" - elif ( i.startswith( "--buildtype=" ) ): - os.environ["EMERGE_BUILDTYPE"] = i.replace( "--buildtype=", "" ) - elif ( i.startswith( "--target=" ) ): - os.environ["EMERGE_TARGET"] = i.replace( "--target=", "" ) - elif ( i.startswith( "--patchlevel=" ) ): - os.environ["EMERGE_PKGPATCHLVL"] = i.replace( "--patchlevel=", "" ) - elif ( i.startswith( "--log-dir=" ) ): - os.environ["EMERGE_LOG_DIR"] = i.replace( "--log-dir=", "" ) - elif ( i == "-v" ): - utils.Verbose.increase() - elif ( i == "--trace" ): - trace = trace + 1 - os.environ["EMERGE_TRACE"] = str( trace ) - elif ( i == "--nocopy" ): - os.environ["EMERGE_NOCOPY"] = str( True ) - elif ( i == "--noclean" ): - os.environ["EMERGE_NOCLEAN"] = str( True ) - elif ( i == "--clean" ): - os.environ["EMERGE_NOCLEAN"] = str( False ) - elif ( i in [ "--version-dir", "--version-package", "--print-installable", - "--print-installed", "--print-targets" ] ): - mainBuildAction = i[2:] - stayQuiet = True - if i in [ "--print-installable", "--print-installed" ]: - break - elif ( i == "-i" ): - ignoreInstalled = True - elif ( i == "--update" ): - ignoreInstalled = True - os.environ["EMERGE_NOCLEAN"] = str( True ) - elif ( i == "--update-all" ): - ignoreInstalled = True - os.environ["EMERGE_NOCLEAN"] = str( True ) - updateAll = True - elif ( i == "--install-deps" ): - ignoreInstalled = True - mainBuildAction = "install-deps" - elif ( i in [ "--fetch", "--unpack", "--preconfigure", "--configure", "--compile", "--make", - "--install", "--qmerge", "--manifest", "--package", "--unmerge", "--test", "--checkdigest", "--dumpdeps", - "--full-package", "--cleanimage", "--cleanbuild", "--createpatch", "--geturls"] ): - mainBuildAction = i[2:] - elif ( i == "--print-revision" ): - mainBuildAction = "printrev" - elif ( i == "--disable-buildhost" ): - disableHostBuild = True - elif ( i == "--disable-buildtarget" ): - disableTargetBuild = True - elif( i == "--cleanup" ): - utils.debug("Starting to clean emerge" ) - utils.system("cd %s && git clean -f -x -e *.py -e *.diff -e *.ba\\t -e *.cmd -e *.reg" % os.path.join(os.getenv("KDEROOT"),"emerge") ) - exit(0) - elif( i == "--cleanup-dry" ): - utils.debug("Starting to clean emerge" ) - utils.system("cd %s && git clean --dry-run -x -e *.py -e *.diff -e *.ba\\t -e *.cmd -e *.reg" % os.path.join(os.getenv("KDEROOT"),"emerge") ) - exit(0) - elif i == "--cleanallbuilds": - # clean complete build directory - utils.cleanDirectory(os.path.join( os.getenv("KDEROOT"), "build")) - exit(0) - elif ( i == "--search" ): - package = nextArguments.pop(0) - category = "" - if not package.find("/") == -1: - (category,package) = package.split("/") - portageSearch.printSearch(category, package) - exit(0) - elif ( i.startswith( "-" ) ): - usage() - exit ( 1 ) - else: - packageName = i - break - -if stayQuiet == True: - utils.setVerbose(0) - -# get KDEROOT from env -KDEROOT = os.getenv( "KDEROOT" ) -utils.debug( "buildAction: %s" % mainBuildAction ) -utils.debug( "doPretend: %s" % doPretend, 1 ) -utils.debug( "packageName: %s" % packageName ) -utils.debug( "buildType: %s" % os.getenv( "EMERGE_BUILDTYPE" ) ) -utils.debug( "buildTests: %s" % utils.envAsBool( "EMERGE_BUILDTESTS" ) ) -utils.debug( "verbose: %d" % utils.verbose(), 1 ) -utils.debug( "trace: %s" % os.getenv( "EMERGE_TRACE" ), 1 ) -utils.debug( "KDEROOT: %s\n" % KDEROOT, 1 ) -utils.debug_line() - -def unset_var( varname ): - if not os.getenv( varname ) == None: - print() - utils.warning( "%s found as environment variable. you cannot override emerge"\ - " with this - unsetting %s locally" % ( varname, varname ) ) - os.environ[ varname ] = "" - -unset_var( "CMAKE_INCLUDE_PATH" ) -unset_var( "CMAKE_LIBRARY_PATH" ) -unset_var( "CMAKE_FIND_PREFIX" ) -unset_var( "CMAKE_INSTALL_PREFIX" ) - -# adding emerge/bin to find base.py and gnuwin32.py etc. -os.environ["PYTHONPATH"] = os.getenv( "PYTHONPATH", "" ) + os.pathsep + \ - os.path.join( os.getcwd(), os.path.dirname( executableName ) ) -sys.path.append( os.path.join( os.getcwd(), os.path.dirname( executableName ) ) ) - -_deplist = [] -deplist = [] -packageList = [] -categoryList = [] - - -buildType = os.getenv("EMERGE_BUILDTYPE") -if "EMERGE_DEFAULTCATEGORY" in os.environ: - defaultCategory = os.environ["EMERGE_DEFAULTCATEGORY"] -else: - defaultCategory = "kde" - -if updateAll: - installedPackages = portage.PortageInstance.getInstallables() - if portage.PortageInstance.isCategory( packageName ): - utils.debug( "Updating installed packages from category " + packageName, 1 ) - else: - utils.debug( "Updating all installed packages", 1 ) - packageList = [] - for mainCategory, mainPackage, mainVersion in installedPackages: - if portage.PortageInstance.isCategory( packageName ) and ( mainCategory != packageName ): - continue - if portage.isInstalled( mainCategory, mainPackage, mainVersion, buildType ) \ - and portage.isPackageUpdateable( mainCategory, mainPackage, mainVersion ): - categoryList.append( mainCategory ) - packageList.append( mainPackage ) - utils.debug( "Will update packages: " + str (packageList), 1 ) -elif packageName: - packageList, categoryList = portage.getPackagesCategories(packageName) - -for entry in packageList: - utils.debug( "%s" % entry, 1 ) -utils.debug_line( 1 ) - -for mainCategory, entry in zip (categoryList, packageList): - _deplist = portage.solveDependencies( mainCategory, entry, "", _deplist ) - -deplist = [p.ident() for p in _deplist] - -for item in range( len( deplist ) ): - if deplist[ item ][ 0 ] in categoryList and deplist[ item ][ 1 ] in packageList: - deplist[ item ].append( ignoreInstalled ) - else: - deplist[ item ].append( False ) - - utils.debug( "dependency: %s" % deplist[ item ], 1 ) - -#for item in deplist: -# cat = item[ 0 ] -# pac = item[ 1 ] -# ver = item[ 2 ] - -# if portage.isInstalled( cat, pac, ver, buildType) and updateAll and not portage.isPackageUpdateable( cat, pac, ver ): -# print "remove:", cat, pac, ver -# deplist.remove( item ) - -if mainBuildAction == "install-deps": - # the first dependency is the package itself - ignore it - # TODO: why are we our own dependency? - del deplist[ 0 ] - -deplist.reverse() - -# package[0] -> category -# package[1] -> package -# package[2] -> version - -if ( mainBuildAction != "all" and mainBuildAction != "install-deps" ): - # if a buildAction is given, then do not try to build dependencies - # and do the action although the package might already be installed. - # This is still a bit problematic since packageName might not be a valid - # package - - if packageName and len( deplist ) >= 1: - mainCategory, mainPackage, mainVersion, tag, ignoreInstalled = deplist[ -1 ] - else: - mainCategory, mainPackage, mainVersion = None, None, None - - if not handlePackage( mainCategory, mainPackage, mainVersion, mainBuildAction, mainOpts ): - utils.notify("Emerge %s failed" % mainBuildAction, "%s of %s/%s-%s failed" % ( mainBuildAction,mainCategory, mainPackage, mainVersion),mainBuildAction) - exit(1) - utils.notify("Emerge %s finished"% mainBuildAction, "%s of %s/%s-%s finished" % ( mainBuildAction,mainCategory, mainPackage, mainVersion),mainBuildAction) - -else: - for mainCategory, mainPackage, mainVersion, defaultTarget, ignoreInstalled in deplist: - target = "" - targetList = [] - isLastPackage = [mainCategory, mainPackage, mainVersion, defaultTarget, ignoreInstalled] == deplist[-1] - if outDateVCS or (outDatePackage and isLastPackage): - target = os.getenv( "EMERGE_TARGET" ) - if not target or target not in list(portage.PortageInstance.getAllTargets( mainCategory, mainPackage, mainVersion ).keys()): - # if no target or a wrong one is defined, simply set the default target here - target = defaultTarget - targetList = portage.PortageInstance.getUpdatableVCSTargets( mainCategory, mainPackage, mainVersion ) - if isDBEnabled(): - if emergePlatform.isCrossCompilingEnabled(): - hostEnabled = portage.isHostBuildEnabled( mainCategory, mainPackage, mainVersion ) - targetEnabled = portage.isTargetBuildEnabled( mainCategory, mainPackage, mainVersion ) - hostInstalled = installdb.isInstalled( mainCategory, mainPackage, mainVersion, "" ) - targetInstalled = installdb.isInstalled( mainCategory, mainPackage, mainVersion, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) - isInstalled = ( not hostEnabled or hostInstalled ) and ( not targetEnabled or targetInstalled ) - else: - isInstalled = installdb.isInstalled( mainCategory, mainPackage, mainVersion, "" ) - else: - isInstalled = portage.isInstalled( mainCategory, mainPackage, mainVersion, buildType ) - if ( isInstalled and not ignoreInstalled ) and not ( - isInstalled and (outDateVCS or (outDatePackage and isLastPackage) ) and target in targetList ): - if utils.verbose() > 1 and mainPackage == packageName: - utils.warning( "already installed %s/%s-%s" % ( mainCategory, mainPackage, mainVersion ) ) - elif utils.verbose() > 2 and not mainPackage == packageName: - utils.warning( "already installed %s/%s-%s" % ( mainCategory, mainPackage, mainVersion ) ) - else: - # in case we only want to see which packages are still to be build, simply return the package name - if ( doPretend ): - if utils.verbose() > 0: - msg = " " - if emergePlatform.isCrossCompilingEnabled(): - if isDBEnabled(): - hostEnabled = portage.isHostBuildEnabled( mainCategory, mainPackage, mainVersion ) - targetEnabled = portage.isTargetBuildEnabled( mainCategory, mainPackage, mainVersion ) - hostInstalled = installdb.isInstalled( mainCategory, mainPackage, mainVersion, "" ) - targetInstalled = installdb.isInstalled( mainCategory, mainPackage, mainVersion, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) - msg += portage.getHostAndTarget( hostEnabled and not hostInstalled, targetEnabled and not targetInstalled ) - else: - msg = "" - utils.warning( "pretending %s/%s-%s%s" % ( mainCategory, mainPackage, mainVersion, msg ) ) - else: - mainAction = mainBuildAction - if mainBuildAction == "install-deps": - mainAction = "all" - - if not handlePackage( mainCategory, mainPackage, mainVersion, mainAction, mainOpts ): - utils.error( "fatal error: package %s/%s-%s %s failed" % \ - ( mainCategory, mainPackage, mainVersion, mainBuildAction ) ) - utils.notify("Emerge build failed", "Build of %s/%s-%s failed" % ( mainCategory, mainPackage, mainVersion),mainAction) - exit( 1 ) - utils.notify("Emerge build finished", "Build of %s/%s-%s finished" % ( mainCategory, mainPackage, mainVersion),mainAction) - -utils.new_line() -if len( nextArguments ) > 0: - command = "\"" + sys.executable + "\" -u " + executableName + " " + " ".join( nextArguments ) - - #for element in environ.keys(): - # if environ[ element ]: - # os.environ[ element ] = environ[ element ] - # elif element == "EMERGE_VERBOSE": - # os.environ[ element ] = "1" - # else: - # os.environ[ element ] = "" - if not utils.system(command): - utils.die( "cannot execute next commands cmd: %s" % command ) - -utils.stopTimer("Emerge") - +# -*- coding: utf-8 -*- +# this will emerge some programs... + +# copyright: +# Holger Schroeder +# Patrick Spendrin + +import sys + +# The minimum python version for emerge please edit here +# if you add code that changes this requirement +MIN_PY_VERSION = (3, 0, 0) + +if sys.version_info[0:3] < MIN_PY_VERSION: + print ("Error: Python too old!") + print ("Emerge needs at least Python Version %s.%s.%s" % MIN_PY_VERSION ) + print ("Please install it and adapt your kdesettings.bat") + exit(1) + +import os +import utils +import portage +import emergePlatform +import portageSearch +import shutil +from InstallDB import * +import sched +import time +import datetime +import threading + + +def usage(): + print(""" +Usage: + emerge [[ command and flags ] [ singletarget ] + [ command and flags ] [ singletarget ] + ... ] + + where singletarget can be of the form: + category + package + category/package + +Emerge is a tool for building KDE-related software under Windows. emerge +automates it, looks for the dependencies and fetches them automatically. +Some options should be used with extreme caution since they will +make your kde installation unusable in 999 out of 1000 cases. + +Commands (no packagename needed - will be ignored when given): + +--print-installed This will show a list of all packages that + are installed currently. It queries both + databases (etc\portage\installed) and the + manifest directory - it prints out only those + packages that are contained within + --print-installable +--print-installable This will give you a list of packages that can + be installed. Currently you don't need to + enter the category and package: only the + package will be enough. +--update-all this option tries to update all installed + packages that contain one or multiple svn + targets. This is equivalent to running all + those packages with the flag --update. + +Commands (must have a packagename): + +--print-targets This will print all the different targets one package + can contain: different releases might have different + tags that are build as targets of a package. As an + example: You could build the latest amarok sources with + the target 'svnHEAD' the previous '1.80' release would + be contained as target '1.80'. +--print-revision This will print the revision that the source repository + of this package currently has or nothing if there is no + repository. +--fetch retrieve package sources (also checkout sources from + svn or git). +--unpack unpack package sources and make up the build directory. +--compile compile the sources: this includes + configure'ing/cmake'ing and running [mingw32-|n|]make. +--configure configure the sources (support is package specific) +--make run [mingw32-|n|]make (support is package specific) +--install This will run [mingw32-|n|]make install into the image + directory of each package. +--manifest This step creates the files contained in the manifest + dir. +--qmerge This will merge the image directory into the KDEROOT +--test This will run the unittests if they are present +--package This step will create a package out of the image + directory instead of merge'ing the image directory into + the KDEROOT (Requires the packager to be installed + already.) +--full-package This will create packages instead of installing stuff + to KDEROOT +--install-deps This will fetch and install all required dependencies + for the specified package +--unmerge this uninstalls a package from KDEROOT - it requires a + working manifest directory. unmerge only delete + unmodified files by default. You may use the -f or + --force option to let unmerge delete all files + unconditional. +--cleanallbuilds Clean complete build directory. +--cleanbuild Clean build directory for the specified package. This + cleans also all the image directories of all targets of + the specified package. +--checkdigest Check digest for the specified package. If no digest is + available calculate and print digests. +--cleanimage Clean image directory for the specified package and + target. +--createpatch Create source patch file for the specific package based + on the original archive file or checkout revision of + the used software revision control system. +--disable-buildhost This disables the building for the host. +--disable-buildtarget This disables the building for the target. + +Flags: + +--buildtype=[BUILDTYPE] This will override the build type set by the + environment option EMERGE_BUILDTYPE . + Please set it to one out of Release, Debug, + RelWithDebInfo, MinSizeRel +--target=[TARGET] This will override the build of the default + target. The default Target is marked with a + star in the printout of --print-targets +--options= Set emerge property from string . + An example for is "cmake.openIDE=1"; + see options.py for more informations. +--patchlevel=[PATCHLEVEL] This will add a patch level when used together + with --package +--log-dir=[LOG_DIR] This will log the build output to a logfile in + LOG_DIR for each package. Logging information + is appended to existing logs. + +-i ignore install: using this option will install a package over an + existing install. This can be useful if you want to check some + new code and your last build isn't that old. +-p +--probe probing: emerge will only look which files it has to build + according to the list of installed files and according to the + dependencies of the package. +-q quiet: there should be no output - The verbose level should be 0 +-t test: if used on an KDE target it will override the environment + variable and build the target with -DKDE_BUILD_TESTS=ON +-v verbose: increases the verbose level of emerge. Default is 1. + verbose level 1 contains some notes from emerge, all output of + cmake, make and other programs that are used. verbose level 2 + adds an option VERBOSE=1 to make and emerge is more verbose + highest level is verbose level 3. +-z if packages from version control system sources are installed, + it marks them as out of date and rebuilds them (tags are not + marked as out of date). +-sz similar to -z, only that it acts only on the last package, and + works as normal on the rest. +--noclean this option will try to use an existing build directory. Please + handle this option with care - it will possibly break if the + directory isn't existing. +--nocopy this option is deprecated. In older releases emerge would have + copied everything from the SVN source tree to a source directory + under %KDEROOT%\\tmp - currently nocopy is applied by default if + EMERGE_NOCOPY is not set to "False". Be aware that setting + EMERGE_NOCOPY to "False" might slow down the build process, + irritate you and increase the disk space roughly by the size of + SVN source tree. +--offline do not try to connect to the internet: KDE packages will try to + use an existing source tree and other packages would try to use + existing packages in the download directory. If that doesn't + work, the build will fail. +--update this option is the same as '-i --noclean'. It will update a single + package that is already installed. +--cleanup Clean your portage directory, to prevent emerge errors, removes + empty directories and *.pyc files + +Internal options or options that aren't fully implemented yet: +PLEASE DO NOT USE! +--version-dir +--version-package + +More information see the README or http://windows.kde.org/. +Send feedback to . + +""") + +@utils.log +def doExec( category, package, action, opts ): + utils.startTimer("%s for %s" % ( action,package),1) + utils.debug( "emerge doExec called. action: %s opts: %s" % (action, opts), 2 ) + fileName = portage.getFilename( category, package ) + opts_string = ( "%s " * len( opts ) ) % tuple( opts ) + commandstring = "python %s %s %s" % ( fileName, action, opts_string ) + + utils.debug( "file: " + fileName, 1 ) + try: + #Switched to import the packages only, because otherwise degugging is very hard, if it troubles switch back + #makes touble for xcompile -> changed back + if not utils.system( commandstring ): + utils.die( "running %s" % commandstring ) + #mod = portage.__import__( fileName ) + #mod.Package().execute(action) + except OSError: + utils.stopTimer("%s for %s" % ( action,package)) + return False + utils.stopTimer("%s for %s" % ( action,package)) + return True + +def updateTitle(startTime,title): + while(len(utils._TIMERS)>0): + delta = datetime.datetime.now() - startTime + utils.setTitle("Emerge %s %s" %(title , delta)) + time.sleep(1) + +def handlePackage( category, package, buildAction, opts ): + utils.debug( "emerge handlePackage called: %s %s %s" % (category, package, buildAction), 2 ) + success = True + + if continueFlag: + actionList = ['fetch', 'unpack', 'configure', 'make', 'cleanimage', 'install', 'manifest', 'qmerge'] + + found = None + for action in actionList: + if not found and action != buildAction: + continue + found = True + success = success and doExec( category, package, action, opts ) + elif ( buildAction == "all" or buildAction == "full-package" ): + os.putenv( "EMERGE_BUILD_STEP", "" ) + success = doExec( category, package, "fetch", opts ) + success = success and doExec( category, package, "unpack", opts ) + if emergePlatform.isCrossCompilingEnabled(): + if not disableHostBuild: + os.putenv( "EMERGE_BUILD_STEP", "host" ) + success = success and doExec( category, package, "compile", opts ) + success = success and doExec( category, package, "cleanimage", opts ) + success = success and doExec( category, package, "install", opts ) + if ( buildAction == "all" ): + success = success and doExec( category, package, "manifest", opts ) + if ( buildAction == "all" ): + success = success and doExec( category, package, "qmerge", opts ) + if( buildAction == "full-package" ): + success = success and doExec( category, package, "package", opts ) + if disableTargetBuild: + return success + os.putenv( "EMERGE_BUILD_STEP", "target" ) + + success = success and doExec( category, package, "compile", opts ) + success = success and doExec( category, package, "cleanimage", opts ) + success = success and doExec( category, package, "install", opts ) + if ( buildAction == "all" ): + success = success and doExec( category, package, "manifest", opts ) + if ( buildAction == "all" ): + success = success and doExec( category, package, "qmerge", opts ) + if( buildAction == "full-package" ): + success = success and doExec( category, package, "package", opts ) + + elif ( buildAction in [ "fetch", "unpack", "preconfigure", "configure", "compile", "make", "qmerge", "checkdigest", "dumpdeps", + "package", "manifest", "unmerge", "test", "cleanimage", "cleanbuild", "createpatch", "geturls", + "printrev"] and category and package ): + os.putenv( "EMERGE_BUILD_STEP", "" ) + success = True + if emergePlatform.isCrossCompilingEnabled(): + if not disableHostBuild: + os.putenv( "EMERGE_BUILD_STEP", "host" ) + success = doExec( category, package, buildAction, opts ) + if disableTargetBuild: + return success + os.putenv( "EMERGE_BUILD_STEP", "target" ) + success = success and doExec( category, package, buildAction, opts ) + elif ( buildAction == "install" ): + os.putenv( "EMERGE_BUILD_STEP", "" ) + success = True + if emergePlatform.isCrossCompilingEnabled(): + if not disableHostBuild: + os.putenv( "EMERGE_BUILD_STEP", "host" ) + success = doExec( category, package, "cleanimage", opts ) + success = success and doExec( category, package, "install", opts ) + if disableTargetBuild: + return success + os.putenv( "EMERGE_BUILD_STEP", "target" ) + success = success and doExec( category, package, "cleanimage", opts ) + success = success and doExec( category, package, "install", opts ) + elif ( buildAction == "version-dir" ): + print("%s" % ( package )) + success = True + elif ( buildAction == "version-package" ): + print("%s-%s" % ( package, os.getenv( "KDECOMPILER" ) )) + success = True + elif ( buildAction == "print-installable" ): + portage.printInstallables() + success = True + elif ( buildAction == "print-installed" ): + if isDBEnabled(): + printInstalled() + else: + portage.printInstalled() + success = True + elif ( buildAction == "print-targets" ): + portage.printTargets( category, package ) + success = True + elif ( buildAction == "install-deps" ): + success = True + else: + success = utils.error( "could not understand this buildAction: %s" % buildAction ) + + return success + +# +# "main" action starts here +# + +# TODO: all the rest should go into main(). But here I am not +# sure - maybe some of those variables are actually MEANT to +# be used in other modules. Put this back for now + +# but as a temporary solution rename variables to mainXXX +# where it is safe so there are less redefinitions in inner scopes + +utils.startTimer("Emerge") +tittleThread = threading.Thread(target=updateTitle,args = (datetime.datetime.now()," ".join(sys.argv[:]),)) +tittleThread.setDaemon(True) +tittleThread.start() + + +mainBuildAction = "all" +packageName = None +doPretend = False +outDateVCS = False +outDatePackage = False +stayQuiet = False +disableHostBuild = False +disableTargetBuild = False +ignoreInstalled = False +updateAll = False +continueFlag = False + +if len( sys.argv ) < 2: + usage() + utils.die("") + +environ = dict() # TODO: why do we need this at all? +environ["EMERGE_TRACE"] = os.getenv( "EMERGE_TRACE" ) +environ["EMERGE_BUILDTESTS"] = os.getenv( "EMERGE_BUILDTESTS" ) +environ["EMERGE_OFFLINE"] = os.getenv( "EMERGE_OFFLINE" ) +environ["EMERGE_FORCED"] = os.getenv( "EMERGE_FORCED" ) +environ["EMERGE_VERSION"] = os.getenv( "EMERGE_VERSION" ) +environ["EMERGE_BUILDTYPE"] = os.getenv( "EMERGE_BUILDTYPE" ) +environ["EMERGE_TARGET"] = os.getenv( "EMERGE_TARGET" ) +environ["EMERGE_PKGPATCHLVL"] = os.getenv( "EMERGE_PKGPATCHLVL" ) +environ["EMERGE_LOG_DIR"] = os.getenv( "EMERGE_LOG_DIR" ) + +if environ['EMERGE_TRACE'] == None or not environ['EMERGE_TRACE'].isdigit(): + trace = 0 + os.environ["EMERGE_TRACE"] = str( trace ) +else: + trace = int( environ[ "EMERGE_TRACE" ] ) + +mainOpts = list() + +executableName = sys.argv.pop( 0 ) +nextArguments = sys.argv[:] + +for i in sys.argv: + nextArguments.pop(0) + if ( i == "-p" or i == "--probe" ): + doPretend = True + elif ( i.startswith("--options=") ): + # @todo how to add -o option + options = i.replace( "--options=", "" ) + if "EMERGE_OPTIONS" in os.environ: + os.environ["EMERGE_OPTIONS"] += " %s" % options + else: + os.environ["EMERGE_OPTIONS"] = options + elif ( i == "-z" ): + outDateVCS = True + elif ( i == "-sz" ): + outDatePackage = True + elif ( i == "-q" ): + stayQuiet = True + elif ( i == "-t" ): + os.environ["EMERGE_BUILDTESTS"] = "True" + elif i == "-c" or i == "--continue": + continueFlag = True + elif ( i == "--offline" ): + mainOpts.append( "--offline" ) + os.environ["EMERGE_OFFLINE"] = "True" + elif ( i == "-f" or i == "--force" ): + os.environ["EMERGE_FORCED"] = "True" + elif ( i.startswith( "--buildtype=" ) ): + os.environ["EMERGE_BUILDTYPE"] = i.replace( "--buildtype=", "" ) + elif ( i.startswith( "--target=" ) ): + os.environ["EMERGE_TARGET"] = i.replace( "--target=", "" ) + elif ( i.startswith( "--patchlevel=" ) ): + os.environ["EMERGE_PKGPATCHLVL"] = i.replace( "--patchlevel=", "" ) + elif ( i.startswith( "--log-dir=" ) ): + os.environ["EMERGE_LOG_DIR"] = i.replace( "--log-dir=", "" ) + elif ( i == "-v" ): + utils.Verbose.increase() + elif ( i == "--trace" ): + trace = trace + 1 + os.environ["EMERGE_TRACE"] = str( trace ) + elif ( i == "--nocopy" ): + os.environ["EMERGE_NOCOPY"] = str( True ) + elif ( i == "--noclean" ): + os.environ["EMERGE_NOCLEAN"] = str( True ) + elif ( i == "--clean" ): + os.environ["EMERGE_NOCLEAN"] = str( False ) + elif ( i in [ "--version-dir", "--version-package", "--print-installable", + "--print-installed", "--print-targets" ] ): + mainBuildAction = i[2:] + stayQuiet = True + if i in [ "--print-installable", "--print-installed" ]: + break + elif ( i == "-i" ): + ignoreInstalled = True + elif ( i == "--update" ): + ignoreInstalled = True + os.environ["EMERGE_NOCLEAN"] = str( True ) + elif ( i == "--update-all" ): + ignoreInstalled = True + os.environ["EMERGE_NOCLEAN"] = str( True ) + updateAll = True + elif ( i == "--install-deps" ): + ignoreInstalled = True + mainBuildAction = "install-deps" + elif ( i in [ "--fetch", "--unpack", "--preconfigure", "--configure", "--compile", "--make", + "--install", "--qmerge", "--manifest", "--package", "--unmerge", "--test", "--checkdigest", "--dumpdeps", + "--full-package", "--cleanimage", "--cleanbuild", "--createpatch", "--geturls"] ): + mainBuildAction = i[2:] + elif ( i == "--print-revision" ): + mainBuildAction = "printrev" + elif ( i == "--disable-buildhost" ): + disableHostBuild = True + elif ( i == "--disable-buildtarget" ): + disableTargetBuild = True + elif( i == "--cleanup" ): + utils.debug("Starting to clean emerge" ) + utils.system("cd %s && git clean -f -x -e *.py -e *.diff -e *.ba\\t -e *.cmd -e *.reg" % os.path.join(os.getenv("KDEROOT"),"emerge") ) + exit(0) + elif( i == "--cleanup-dry" ): + utils.debug("Starting to clean emerge" ) + utils.system("cd %s && git clean --dry-run -x -e *.py -e *.diff -e *.ba\\t -e *.cmd -e *.reg" % os.path.join(os.getenv("KDEROOT"),"emerge") ) + exit(0) + elif i == "--cleanallbuilds": + # clean complete build directory + utils.cleanDirectory(os.path.join( os.getenv("KDEROOT"), "build")) + exit(0) + elif ( i == "--search" ): + package = nextArguments.pop(0) + category = "" + if not package.find("/") == -1: + (category,package) = package.split("/") + portageSearch.printSearch(category, package) + exit(0) + elif ( i.startswith( "-" ) ): + usage() + exit ( 1 ) + else: + packageName = i + break + +if stayQuiet == True: + utils.setVerbose(0) + +# get KDEROOT from env +KDEROOT = os.getenv( "KDEROOT" ) +utils.debug( "buildAction: %s" % mainBuildAction ) +utils.debug( "doPretend: %s" % doPretend, 1 ) +utils.debug( "packageName: %s" % packageName ) +utils.debug( "buildType: %s" % os.getenv( "EMERGE_BUILDTYPE" ) ) +utils.debug( "buildTests: %s" % utils.envAsBool( "EMERGE_BUILDTESTS" ) ) +utils.debug( "verbose: %d" % utils.verbose(), 1 ) +utils.debug( "trace: %s" % os.getenv( "EMERGE_TRACE" ), 1 ) +utils.debug( "KDEROOT: %s\n" % KDEROOT, 1 ) +utils.debug_line() + +def unset_var( varname ): + if not os.getenv( varname ) == None: + print() + utils.warning( "%s found as environment variable. you cannot override emerge"\ + " with this - unsetting %s locally" % ( varname, varname ) ) + os.environ[ varname ] = "" + +unset_var( "CMAKE_INCLUDE_PATH" ) +unset_var( "CMAKE_LIBRARY_PATH" ) +unset_var( "CMAKE_FIND_PREFIX" ) +unset_var( "CMAKE_INSTALL_PREFIX" ) + +# adding emerge/bin to find base.py and gnuwin32.py etc. +os.environ["PYTHONPATH"] = os.getenv( "PYTHONPATH", "" ) + os.pathsep + \ + os.path.join( os.getcwd(), os.path.dirname( executableName ) ) +sys.path.append( os.path.join( os.getcwd(), os.path.dirname( executableName ) ) ) + +_deplist = [] +deplist = [] +packageList = [] +categoryList = [] + + +buildType = os.getenv("EMERGE_BUILDTYPE") +if "EMERGE_DEFAULTCATEGORY" in os.environ: + defaultCategory = os.environ["EMERGE_DEFAULTCATEGORY"] +else: + defaultCategory = "kde" + +if updateAll: + installedPackages = portage.PortageInstance.getInstallables() + if portage.PortageInstance.isCategory( packageName ): + utils.debug( "Updating installed packages from category " + packageName, 1 ) + else: + utils.debug( "Updating all installed packages", 1 ) + packageList = [] + for mainCategory, mainPackage, _dummy in installedPackages: + if portage.PortageInstance.isCategory( packageName ) and ( mainCategory != packageName ): + continue +# FIXME: +# if portage.isInstalled( mainCategory, mainPackage, mainVersion, buildType ) \ +# and portage.isPackageUpdateable( mainCategory, mainPackage, mainVersion ): +# categoryList.append( mainCategory ) +# packageList.append( mainPackage ) + utils.debug( "Will update packages: " + str (packageList), 1 ) +elif packageName: + packageList, categoryList = portage.getPackagesCategories(packageName) + +for entry in packageList: + utils.debug( "%s" % entry, 1 ) +utils.debug_line( 1 ) + +for mainCategory, entry in zip (categoryList, packageList): + _deplist = portage.solveDependencies( mainCategory, entry, _deplist ) + +deplist = [p.ident() for p in _deplist] + +for item in range( len( deplist ) ): + if deplist[ item ][ 0 ] in categoryList and deplist[ item ][ 1 ] in packageList: + deplist[ item ].append( ignoreInstalled ) + else: + deplist[ item ].append( False ) + + utils.debug( "dependency: %s" % deplist[ item ], 1 ) + +#for item in deplist: +# cat = item[ 0 ] +# pac = item[ 1 ] +# ver = item[ 2 ] + +# if portage.isInstalled( cat, pac, ver, buildType) and updateAll and not portage.isPackageUpdateable( cat, pac, ver ): +# print "remove:", cat, pac, ver +# deplist.remove( item ) + +if mainBuildAction == "install-deps": + # the first dependency is the package itself - ignore it + # TODO: why are we our own dependency? + del deplist[ 0 ] + +deplist.reverse() + +# package[0] -> category +# package[1] -> package +# package[2] -> version + +if ( mainBuildAction != "all" and mainBuildAction != "install-deps" ): + # if a buildAction is given, then do not try to build dependencies + # and do the action although the package might already be installed. + # This is still a bit problematic since packageName might not be a valid + # package + + if packageName and len( deplist ) >= 1: + mainCategory, mainPackage, tag, ignoreInstalled = deplist[ -1 ] + else: + mainCategory, mainPackage = None, None + + if not handlePackage( mainCategory, mainPackage, mainBuildAction, mainOpts ): + utils.notify("Emerge %s failed" % mainBuildAction, "%s of %s/%s failed" % ( mainBuildAction, mainCategory, mainPackage ), mainBuildAction) + exit(1) + utils.notify("Emerge %s finished"% mainBuildAction, "%s of %s/%s finished" % ( mainBuildAction, mainCategory, mainPackage ), mainBuildAction) + +else: + for mainCategory, mainPackage, defaultTarget, ignoreInstalled in deplist: + target = "" + targetList = [] + isLastPackage = [mainCategory, mainPackage, defaultTarget, ignoreInstalled] == deplist[-1] + if outDateVCS or (outDatePackage and isLastPackage): + target = os.getenv( "EMERGE_TARGET" ) + if not target or target not in list(portage.PortageInstance.getAllTargets( mainCategory, mainPackage ).keys()): + # if no target or a wrong one is defined, simply set the default target here + target = defaultTarget + targetList = portage.PortageInstance.getUpdatableVCSTargets( mainCategory, mainPackage ) + if isDBEnabled(): + if emergePlatform.isCrossCompilingEnabled(): + hostEnabled = portage.isHostBuildEnabled( mainCategory, mainPackage ) + targetEnabled = portage.isTargetBuildEnabled( mainCategory, mainPackage ) + hostInstalled = installdb.isInstalled( mainCategory, mainPackage ) + targetInstalled = installdb.isInstalled( mainCategory, mainPackage, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) + isInstalled = ( not hostEnabled or hostInstalled ) and ( not targetEnabled or targetInstalled ) + else: + isInstalled = installdb.isInstalled( mainCategory, mainPackage, prefix=None ) + else: + isInstalled = portage.isInstalled( mainCategory, mainPackage, buildType ) + if ( isInstalled and not ignoreInstalled ) and not ( + isInstalled and (outDateVCS or (outDatePackage and isLastPackage) ) and target in targetList ): + if utils.verbose() > 1 and mainPackage == packageName: + utils.warning( "already installed %s/%s" % ( mainCategory, mainPackage ) ) + elif utils.verbose() > 2 and not mainPackage == packageName: + utils.warning( "already installed %s/%s" % ( mainCategory, mainPackage ) ) + else: + # in case we only want to see which packages are still to be build, simply return the package name + if ( doPretend ): + if utils.verbose() > 0: + msg = " " + if emergePlatform.isCrossCompilingEnabled(): + if isDBEnabled(): + hostEnabled = portage.isHostBuildEnabled( mainCategory, mainPackage ) + targetEnabled = portage.isTargetBuildEnabled( mainCategory, mainPackage ) + hostInstalled = installdb.isInstalled( mainCategory, mainPackage, prefix=None ) + targetInstalled = installdb.isInstalled( mainCategory, mainPackage, os.getenv( "EMERGE_TARGET_PLATFORM" ) ) + msg += portage.getHostAndTarget( hostEnabled and not hostInstalled, targetEnabled and not targetInstalled ) + else: + msg = "" + utils.warning( "pretending %s/%s%s" % ( mainCategory, mainPackage, msg ) ) + else: + mainAction = mainBuildAction + if mainBuildAction == "install-deps": + mainAction = "all" + + if not handlePackage( mainCategory, mainPackage, mainAction, mainOpts ): + utils.error( "fatal error: package %s/%s %s failed" % \ + ( mainCategory, mainPackage, mainBuildAction ) ) + utils.notify("Emerge build failed", "Build of %s/%s failed" % ( mainCategory, mainPackage ), mainAction) + exit( 1 ) + utils.notify("Emerge build finished", "Build of %s/%s finished" % ( mainCategory, mainPackage ), mainAction) + +utils.new_line() +if len( nextArguments ) > 0: + command = "\"" + sys.executable + "\" -u " + executableName + " " + " ".join( nextArguments ) + + #for element in environ.keys(): + # if environ[ element ]: + # os.environ[ element ] = environ[ element ] + # elif element == "EMERGE_VERBOSE": + # os.environ[ element ] = "1" + # else: + # os.environ[ element ] = "" + if not utils.system(command): + utils.die( "cannot execute next commands cmd: %s" % command ) + +utils.stopTimer("Emerge") + diff --git a/bin/portage.py b/bin/portage.py index 1176abfc3..00d19cfce 100644 --- a/bin/portage.py +++ b/bin/portage.py @@ -1,869 +1,750 @@ -## @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, version ): - self.category = category - self.name = name - self.version = version - self.runtimeChildren = [] - self.buildChildren = [] - self.__readChildren() - - def __eq__( self, other ): - return self.category == other.category and self.name == other.name and self.version == other.version - - def __ne__( self, other ): - return self.category != other.category or self.name != other.name or self.version != other.version - - def ident( self ): - return [ self.category, self.name, self.version, PortageInstance.getDefaultTarget( self.category, self.name, self.version ) ] - - def __readChildren( self ): - runtimeDependencies, buildDependencies = readChildren( self.category, self.name, self.version ) - 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 ) - version = PortageInstance.getNewestVersion( category, package ) - if not line in list(packageDict.keys()): - p = DependencyPackage( category, package, version ) - utils.debug( "adding package p %s/%s-%s" % ( category, package, version ), 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, version ): - """ return absolute filename for a given category, package and version """ - return os.path.join( getDirname( category, package ), "%s-%s.py" % ( package, version ) ) - -def getCategoryPackageVersion( path ): - utils.debug( "getCategoryPackageVersion: %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 ) - 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? - -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] - - version = self.getNewestVersion( category, package ) - fileName = getFilename( category, package, version ) - module = __import__( fileName ) - p = module.Package() - p.setup(fileName, category, package, version, buildtarget) - return p - - def getDefaultTarget( self, category, package, version ): - """ returns the default package of a specified package """ - utils.debug( "importing file %s" % getFilename( category, package, version ), 1 ) - if not ( category and package and version ): - return dict() - mod = __import__( getFilename( category, package, version ) ) - if hasattr( mod, 'subinfo' ): - return mod.subinfo().defaultTarget - else: - return None - - def getMetaData( self, category, package, version ): - """ returns all targets of a specified package """ - utils.debug( "importing file %s" % getFilename( category, package, version ), 1 ) - if not ( category and package and version ): - return dict() - mod = __import__( getFilename( category, package, version ) ) - 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, version ): - """ returns all targets of a specified package """ - utils.debug( "importing file %s" % getFilename( category, package, version ), 1 ) - if not ( category and package and version ): - return dict() - mod = __import__( getFilename( category, package, version ) ) - 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, version ): - """ returns all version control system targets of a specified package, - excluding those which do contain tags """ - utils.debug( "importing file %s" % getFilename( category, package, version ), 1 ) - mod = __import__( getFilename( category, package, version ) ) - 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, version ): - """ check if the targets are tags or not """ - targetDict = PortageInstance.getAllVCSTargets( category, package, version ) - 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 - - 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' ): - version = script.replace('.py', '').replace(package + '-', '') - instList.append([category, package, version]) - 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, version, buildtype=''): # pylint: disable=W0613 - """ this function tries to guess which target got used by looking at the different image directories """ - target = PortageInstance.getDefaultTarget( category, package, version ) - buildroot = os.path.join( ROOTDIR, "build", category, "%s-%s" % ( package, version ) ) - - 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, version, runtimeOnly=False ): - """returns the dependencies of this package as list of strings: - category/package""" - if not os.path.isfile( getFilename( category, package, version ) ): - utils.die( "package name %s/%s-%s unknown" % ( category, package, version ) ) - - package, subpackage = getSubPackage( category, package ) - if subpackage: - utils.debug( "solving package %s/%s/%s-%s %s" % ( category, subpackage, package, version, getFilename( category, package, version ) ), 2 ) - else: - utils.debug( "solving package %s/%s-%s %s" % ( category, package, version, getFilename( category, package, version ) ), 2 ) - subpackage = package - - deps = [] - for pkg in subpackage: - mod = __import__( getFilename( category, subpackage, version ) ) - 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( "/" ) - version = PortageInstance.getNewestVersion( category, package ) - deps.append( [ category, package, version, depDict[ line ] ] ) - - return deps - -def solveDependencies( category, package, version, 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 ] - version = PortageInstance.getNewestVersion( category, package ) - 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 ) - if ( version == "" ): - version = PortageInstance.getNewestVersion( category, package ) - utils.debug( "found package with newest version %s" % version, 2 ) - - pac = DependencyPackage( category, package, version ) - depList = pac.getDependencies( depList, dep_type=dep_type ) - - depList.reverse() - return depList - -def printTargets( category, package, version ): - targetsDict = PortageInstance.getAllTargets( category, package, version ) - defaultTarget = PortageInstance.getDefaultTarget( category, package, version ) - 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, version ): - identFileName = getFilename( category, package, version ) - if not os.path.isfile( identFileName ): - utils.die( "package name %s/%s-%s unknown" % ( category, package, version ) ) - - # 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 %s" % ( category, subpackage, package, version, getFilename( category, package, version ) ), 2 ) - else: - utils.debug( "solving package %s/%s-%s %s" % ( category, package, version, getFilename( category, package, version ) ), 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, version ) ) - 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, version ): - """ returns whether this package's target build is enabled. This will only work if - isCrossCompilingEnabled() == True """ - - if emergePlatform.isCrossCompilingEnabled(): - mod = __import__( getFilename( category, package, version ) ) - 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, version ): - utils.debug( "importing file %s" % getFilename( category, package, version ), 2 ) - mod = __import__( getFilename( category, package, version ) ) - 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, version in lines: - if emergePlatform.isCrossCompilingEnabled(): - msg = getHostAndTarget( hostEnabled( category, package, version ), targetEnabled( category, package, version ) ) - else: - msg = "" - if condition( category, package, version ): - printLine( category, package, version, 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 isInstalled( category, package, version, buildtype='' ): - """ deprecated, use InstallDB.installdb.isInstalled() instead """ - utils.debug( "isInstalled(%s, %s, %s, %s)" % (category, package, version, buildtype), 2 ) - # find in old style database - path = utils.etcDir() - fileName = os.path.join(path,'installed') - found = False - if os.path.isfile( fileName ): - with open( fileName, "rt" ) as f: - for line in f.read().splitlines(): - if not line: continue # Ignore empty lines - (_category, _packageVersion) = line.split( "/" ) - (_package, _version) = utils.packageSplit(_packageVersion) - if category != '' and version != '' and category == _category and package == _package and version == _version: - found = True - break - elif category == '' and version == '' and package == _package: - found = True - break - utils.debug("...%s found in main database" % (' ' if found else ' not'), 2 ) - if found: - return True - - # find in release mode database - if buildtype != '': - fileName = os.path.join(path,'installed-' + buildtype ) - if os.path.isfile( fileName ): - with open( fileName, "rt" ) as f: - for line in f.read().splitlines(): - if not line or line == "": - continue - (_category, _packageVersion) = line.split( "/" ) - (_package, _version) = utils.packageSplit(_packageVersion) - if category != '' and version != '' and category == _category and package == _package and version == _version: - found = True - break - elif category == '' and version == '' and package == _package: - found = True - break - utils.debug( "...%s found in %s database" % ( (' ' if found else ' not'), buildtype), 2 ) - if found: - return True - - # try to detect packages from the installer - binary = utils.checkManifestFile( os.path.join( os.getenv( "KDEROOT" ), "manifest", - package + "-" + version + "-bin.ver"), category, package, version ) - lib = utils.checkManifestFile( os.path.join( os.getenv( "KDEROOT" ), "manifest", - package + "-" + version + "-lib.ver"), category, package, version ) - found = found or binary or lib - - if not utils.envAsBool("EMERGE_VERSIONING", default=True) or utils.isSourceOnly(): - # check for any installation except data packages - if not os.path.exists(os.path.join( os.getenv( "KDEROOT" ), "manifest" ) ): - return False - if package.endswith( "-src" ): - package = package[:-4] - for filename in os.listdir( os.path.join( os.getenv( "KDEROOT" ), "manifest" ) ): - if filename.startswith( package ) and not \ - filename.startswith( package + "-data" ): - return True - return False - -def findInstalled( category, package): - """ deprecated, use InstallDB.installdb.findInstalled() instead """ - fileName = os.path.join(utils.etcDir(), "installed" ) - if ( not os.path.isfile( fileName ) ): - return None - - ret = None - regexStr = "^%s/%s-(.*)$" % ( category, re.escape(package) ) - regex = re.compile( regexStr ) - with open( fileName, "rt" ) as f: - for line in f.read().splitlines(): - match = regex.match( line ) - if match: - utils.debug( "found: " + match.group(1), 2 ) - ret = match.group(1) - return ret - -def addInstalled( category, package, version, buildtype='' ): - """ deprecated, use InstallDB.installdb.addInstalled() instead """ - utils.debug( "addInstalled called", 2 ) - # write a line to etc/portage/installed, - # that contains category/package-version - path = os.path.join(utils.etcDir() ) - if ( not os.path.isdir( path ) ): - os.makedirs( path ) - if buildtype != '': - fileName = 'installed-' + buildtype - else: - fileName = 'installed' - utils.debug("installing package %s - %s into %s" % (package, version, fileName), 2) - if( os.path.isfile( os.path.join( path, fileName ) ) ): - with open( os.path.join( path, fileName ), "rt" ) as f: - for line in f: - if line.startswith( "%s/%s-%s" % ( category, package, version) ): - utils.warning( "version already installed" ) - return - elif line.startswith( "%s/%s-" % ( category, package ) ): - utils.die( "Already installed, this should not happen" ) - with open( os.path.join( path, fileName ), "at" ) as f: - f.write( "%s/%s-%s\r\n" % ( category, package, version ) ) - -def remInstalled( category, package, version, buildtype='' ): - """ deprecated, use InstallDB.installdb.remInstalled() instead """ - utils.debug( "remInstalled called", 2 ) - if buildtype != '': - fileName = 'installed-' + buildtype - else: - fileName = 'installed' - utils.debug("removing package %s - %s from %s" % (package, version, fileName), 2) - dbFileName = os.path.join(utils.etcDir(), fileName ) - tmpdbfile = os.path.join(utils.etcDir(), "TMPinstalled" ) - found = False - if os.path.exists( dbFileName ): - with open( dbFileName, "rt" ) as dbFile: - with open( tmpdbfile, "wt" ) as tfile: - for line in dbFile: - ## \todo the category should not be part of the search string - ## because otherwise it is not possible to unmerge package using - ## the same name but living in different categories - if not line.startswith("%s/%s" % ( category, package ) ): - tfile.write( line ) - else: - found = True - os.remove( dbFileName ) - os.rename( tmpdbfile, dbFileName ) - return found - -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 - - +## @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 """ + 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 ) + 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 ) + 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 ) + 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? + +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 + + diff --git a/bin/portageSearch.py b/bin/portageSearch.py index 87cd6da31..86998b21f 100644 --- a/bin/portageSearch.py +++ b/bin/portageSearch.py @@ -1,43 +1,43 @@ import portage import re import utils import InstallDB def printSearch(search_category, search_package,maxDist = 3): installable = portage.PortageInstance.getInstallables() similar = [] match = None package_re = re.compile(".*%s.*" % search_package) for category,package,version in installable: if search_category == "" or search_category == category: levDist = utils.levenshtein(search_package,package) if levDist == 0 : match = ((levDist,category,package,version)) break; elif package_re.match(package): similar.append((levDist-maxDist,category,package,version)) elif levDist <= maxDist: similar.append((levDist,category,package,version)) if match == None: print("Package %s not found, similar packages are:" % search_package) similar.sort() else: print("Package %s found:" % search_package) similar = [match] for levDist,category,package,version in similar: utils.debug((category,package,version,levDist),1) meta = portage.PortageInstance.getMetaData( category, package, version ) description = "" if "shortDescription" in meta: description = meta["shortDescription"] homepage = "" if "homepage" in meta: homepage = meta["homepage"] #print(levDist) print("%s/%s" % (category,package)) print("\t Homepage: %s" % homepage) print("\t Description: %s" % description) print("\t Latest version: %s" % version) - print("\t Installed version: %s" % InstallDB.installdb.findInstalled(category,package)) + print("\t Installed version: %s" % InstallDB.installdb.findInstalledVersion(category,package)) \ No newline at end of file diff --git a/portage/win32libs-sources/dbus-src/dbus-src.py b/portage/win32libs-sources/dbus-src/dbus-src.py new file mode 100644 index 000000000..0aaa35cfe --- /dev/null +++ b/portage/win32libs-sources/dbus-src/dbus-src.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +import utils +import os +import info +import emergePlatform +import compiler + +class subinfo(info.infoclass): + def setTargets( self ): + svnurl = "https://windbus.svn.sourceforge.net/svnroot/windbus/" + self.svnTargets['1.2.4'] = svnurl + 'tags/1.2.4' + self.targetInstSrc['1.2.4'] = 'tags/1.2.4' + self.targetConfigurePath['1.2.4'] = 'cmake' + + self.svnTargets['svnHEAD'] = svnurl + 'trunk' + self.targetConfigurePath['svnHEAD'] = 'cmake' + + # dbus-1.3.1.tar.gz is missing the cmake sub dir and because + # emerge is not able yet to apply more than one patch we the + # 1.3.1 snapshot took for now + #self.targets['1.3.1'] = 'http://dbus.freedesktop.org/releases/dbus/dbus-1.3.1.tar.gz' + #self.targetDigests['1.3.1'] = '83c27e15ba79d4a84a10b123ff382233cc77773b' + self.targets['1.3.1'] = 'http://cgit.freedesktop.org/dbus/dbus/snapshot/dbus-1.3.1.tar.bz2' + self.targetDigests['1.3.1'] = 'e8fa74ad6f2294bdf7d22aed25896d8943287c32' + self.targetInstSrc['1.3.1'] = 'dbus-1.3.1' + self.targetConfigurePath['1.3.1'] = 'cmake' + + self.targets['1.4.0'] = 'http://cgit.freedesktop.org/dbus/dbus/snapshot/dbus-1.4.0.tar.bz2' + self.targetDigests['1.4.0'] = '3983d9a1456e5772fa4cb5e2818ed015b2f6131b' + self.targetInstSrc['1.4.0'] = 'dbus-1.4.0' + self.targetConfigurePath['1.4.0'] = 'cmake' + + self.targets['1.4.1'] = 'http://dbus.freedesktop.org/releases/dbus/dbus-1.4.1.tar.gz' + self.targetDigests['1.4.1'] = '112279ff58305027294fe0eb5bee600f68cf0b50' + self.targetInstSrc['1.4.1'] = 'dbus-1.4.1' + self.targetConfigurePath['1.4.1'] = 'cmake' + + for ver in ['1.4.6', '1.4.8', '1.4.10', '1.4.12', '1.4.14']: + self.svnTargets[ver] = 'git://anongit.freedesktop.org/git/dbus/dbus||dbus-' + ver + self.targetSrcSuffix[ver] = 'git' + self.targetConfigurePath[ver] = 'cmake' + + self.targets['1.4.16'] = 'http://dbus.freedesktop.org/releases/dbus/dbus-1.4.16.tar.gz' + self.targetDigests['1.4.16'] = 'd6e6538cfc1ed71992f6786a6da55d815d995b5b' + self.targetInstSrc['1.4.16'] = 'dbus-1.4.16' + self.targetConfigurePath['1.4.16'] = 'cmake' + + self.svnTargets['gitHEAD'] = 'git://anongit.freedesktop.org/git/dbus/dbus' + self.targetSrcSuffix['gitHEAD'] = 'git' + self.targetConfigurePath['gitHEAD'] = 'cmake' + + + if emergePlatform.isCrossCompilingEnabled(): + self.patchToApply['1.4.0'] = [('dbus-1.4.0.diff', 1), + ('0001-tentative-workaround-for-the-random-hangs-on-windows.patch', 1), + ('no-auth.diff', 1), + ('msvc2010-has-errnoh.diff', 1), + ('live-lock-fix.diff', 1), + ('wince-splashscreen.diff', 1) + ] + self.patchToApply['1.4.1'] = [('no-auth.diff', 1), + ('msvc2010-has-errnoh.diff', 1), + ] + else: + self.patchToApply['1.4.0'] = [('dbus-1.4.0.diff', 1), + ('0001-tentative-workaround-for-the-random-hangs-on-windows.patch', 1), + ('msvc2010-has-errnoh.diff', 1), + ('live-lock-fix.diff', 1) + ] + self.patchToApply['1.4.1'] = [('msvc2010-has-errnoh.diff', 1), + ('live-lock-fix.diff', 1), + ('replace_path_with_current_installdir.diff', 1) + ] + self.patchToApply['1.4.6'] = [('live-lock-fix.diff', 1), + ('0001-Do-not-use-ELEMENT_TYPE-which-is-reserved.patch', 1), + ('16e6236b8310d41d0f21923bb87fa4cf148919d0.patch', 1) + ] + self.patchToApply['1.4.10'] = [('workaround-for-inline-keyword-in-msvc10.patch', 1), + ('16e6236b8310d41d0f21923bb87fa4cf148919d0.patch', 1) + ] + + self.shortDescription = "Freedesktop message bus system (daemon and clients)" + if emergePlatform.isCrossCompilingEnabled(): + self.defaultTarget = '1.4.0' + else: + self.defaultTarget = '1.4.16' + + def setDependencies( self ): + self.buildDependencies['virtual/base'] = 'default' + self.dependencies['win32libs-bin/expat'] = 'default' + +from Package.CMakePackageBase import * + +class Package(CMakePackageBase): + def __init__( self, **args ): + self.subinfo = subinfo() + CMakePackageBase.__init__( self ) + self.subinfo.options.package.packageName = 'dbus' + self.subinfo.options.make.slnBaseName = 'dbus' + self.subinfo.options.configure.defines = ( + "-DDBUS_BUILD_TESTS=OFF " + "-DDBUS_ENABLE_XML_DOCS=OFF " + "-DDBUS_USE_EXPAT=ON " + "-DDBUS_REPLACE_LOCAL_DIR=ON ") + + if (self.buildType == "Release"): + self.subinfo.options.configure.defines += ( + "-DDBUS_ENABLE_VERBOSE_MODE=OFF " + "-DDBUS_DISABLE_ASSERTS=ON ") + + if emergePlatform.isCrossCompilingEnabled(): + self.subinfo.options.configure.defines += ( + "-DDBUS_SESSION_BUS_DEFAULT_ADDRESS:" + "STRING=tcp:host=localhost,port=12434 ") + else: + # for 1.4.1 and greater switch to official + # supported scopes -> autolaunch:scope=*install-path + self.subinfo.options.configure.defines += ( + "-DDBUS_SESSION_BUS_DEFAULT_ADDRESS:" + "STRING=autolaunch:scope=install-path ") + # kde uses debugger output, so dbus should do too + # not sure if this works for wince too, so limited to win32 + self.subinfo.options.configure.defines += ( + "-DDBUS_USE_OUTPUT_DEBUG_STRING=ON ") + + def unpack(self): + if not CMakePackageBase.unpack(self): + return False + if compiler.isMinGW32(): + if self.buildTarget in ['1.2.1', '1.2.3', '1.2.4', 'svnHEAD']: + utils.copyFile( os.path.join(self.packageDir(), "wspiapi.h"), + os.path.join(self.buildDir(), "wspiapi.h") ) + return True + + +if __name__ == '__main__': + Package().execute()