diff options
Diffstat (limited to 'src/kdedistutils.py')
-rw-r--r-- | src/kdedistutils.py | 2209 |
1 files changed, 2209 insertions, 0 deletions
diff --git a/src/kdedistutils.py b/src/kdedistutils.py new file mode 100644 index 0000000..b6e2458 --- /dev/null +++ b/src/kdedistutils.py @@ -0,0 +1,2209 @@ +#!/usr/bin/python +########################################################################### +# kdedistutils - description # +# ------------------------------ # +# begin : Thu Apr 21 2005 # +# copyright : (C) 2005 by Simon Edwards # +# email : [email protected] # +# # +########################################################################### +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU Library General Public License as # +# published by the Free Software Foundation; either version 2 of the # +# License, or (at your option) any later version. # +# # +########################################################################### + +import distutils.core +from distutils.core import Extension +from distutils.cmd import Command +from distutils.dist import Distribution +from distutils.command.build import build +from distutils.command.install import install +from distutils.command.install_scripts import install_scripts +from distutils.command.install_data import install_data +from distutils.command.install_lib import install_lib +from distutils.util import change_root, convert_path +from distutils.spawn import find_executable,spawn +from distutils import sysconfig +from distutils import log +from distutils import file_util +from distutils import dir_util +from distutils.util import byte_compile +import qtuicompiler +import stat +import os,os.path,imp,glob +import sys +from types import StringType + +INSTALL_LIST = 'install_log.txt' + +########################################################################### +def setup(**arg_dict): + + if 'cmdclass' not in arg_dict: + arg_dict['cmdclass'] = {} + + cmdclass = arg_dict['cmdclass'] + + arg_dict.setdefault('data_files',[]) + + kdecmdclass = {'install' : InstallKDE, + 'install_executable_links' : InstallExecutableLinks, + 'install_application_data' : InstallApplicationDataAndLinks, + 'build_messages' : BuildI18NMessages, + 'install_messages' : InstallI18NMessages, + 'update_messages' : UpdateI18NMessages, + 'checkpyqt' : CheckPyQt, + 'checkpykde' : CheckPyKDE, + 'uninstall' : Uninstall, + 'build' : BuildKDE, + 'build_kcm' : BuildKControlModule, + 'install_kcm' : InstallKControlModule, + 'build_html' : BuildDocbookHTML, + 'install_html' : InstallDocbookHTML, + 'install_lib' : InstallLibWithRoot, + 'build_kioslave' : BuildKioslave, + 'install_kioslave' : InstallKioslave} + + for key in kdecmdclass.iterkeys(): + cmdclass.setdefault(key,kdecmdclass[key]) + + arg_dict.setdefault('distclass',KDEDistribution) + + apply(distutils.core.setup,[],arg_dict) + +########################################################################### +class KDEDistribution(Distribution): + def __init__(self,attrs=None): + self.min_kde_version = None + self.min_qt_version = None + self.kcontrol_modules = None + self.kioslaves = None + self.executable_links = None + self.docbooks = None + self.application_data = None + self.i18n = None + Distribution.__init__(self,attrs) + +########################################################################### +def has_kcms(self): + if self.distribution.kcontrol_modules is None: + return 0 + return len(self.distribution.kcontrol_modules)!=0 + +def has_docbook_html(self): + if self.distribution.docbooks is None: + return 0 + return len(self.distribution.docbooks)!=0 + +def has_messages(self): + if self.distribution.i18n is None: + return 0 + return len(self.distribution.i18n)!=0 + +def has_application_data(self): + if self.distribution.application_data is None: + return 0 + return len(self.distribution.application_data)!=0 + +def has_kioslaves(self): + if self.distribution.kioslaves is None: + return 0 + return len(self.distribution.kioslaves)!=0 + +########################################################################### +# Our slightly extended build command. This also does kcontrol modules. +class BuildKDE(build): + + user_options = build.user_options[:] + user_options.append( ('msgfmt-exe=',None,'Path to the msgfmt executable') ) + user_options.append( ('meinproc-exe=',None,'Path to the meinproc executable') ) + + sub_commands = build.sub_commands[:] + sub_commands.append( ('build_kcm',has_kcms) ) + sub_commands.append( ('build_kioslave',has_kioslaves) ) + sub_commands.append( ('build_html',has_docbook_html) ) + sub_commands.append( ('build_messages',has_messages) ) + + def __init__(self,dist): + build.__init__(self,dist) + self.has_kcms = has_kcms + self.has_kioslaves = has_kioslaves + self.has_docbook_html = has_docbook_html + self.has_messages = has_messages + + def initialize_options(self): + self.msgfmt_exe = None + self.meinproc_exe = None + build.initialize_options(self) + + def finalize_options(self): + build.finalize_options(self) + + if self.msgfmt_exe is None: + # Find msgfmt + canidatepaths = [] + canidatepaths.append( ask_kde_config('--install exe --expandvars').strip() ) + self.msgfmt_exe = FindExeOnPath('msgfmt',canidatepaths) + if self.msgfmt_exe is None: + raise SystemExit, "Unable to find 'msgfmt', needed to build i18n messages." + + if self.meinproc_exe is None: + # Find meinproc + canidatepaths = [] + canidatepaths.append( ask_kde_config('--install exe --expandvars').strip() ) + self.meinproc_exe = FindExeOnPath('meinproc',canidatepaths) + if self.meinproc_exe is None: + raise SystemExit, "Unable to find 'meinproc', needed to generate Docbook HTML documentation." + +########################################################################### +def has_executable_links(self): + if self.distribution.executable_links is None: + return 0 + return len(self.distribution.executable_links)!=0 + +########################################################################### +class InstallKDE(install): + user_options = install.user_options[:] + user_options.append( ('kde-prefix=',None,"KDE installation prefix") ) + user_options.append( ('install-messages=',None,"installation directory for i18n message files") ) + user_options.append( ('install-html=',None,"installation directory for Docbook HTML files") ) + user_options.append( ('install-cmd=',None,"Command to use to install the files") ) + user_options.append( ('install-xdg-apps=',None,"directory for XDG app files") ) + user_options.append( ('install-kcm=',None,"directory for kcm library files") ) + user_options.append( ('install-kioslave',None,"directory for kioslave library files") ) + user_options.append( ('install-protocol',None,"directory for kioslave protocol files") ) + + sub_commands = install.sub_commands[:] + sub_commands.insert(0, ('checkpykde',None) ) + sub_commands.insert(0, ('checkpyqt',None) ) + sub_commands.append( ('install_executable_links',has_executable_links) ) + sub_commands.append( ('install_messages',has_messages) ) + sub_commands.append( ('install_html',has_docbook_html) ) + sub_commands.append( ('install_kcm',has_kcms) ) + sub_commands.append( ('install_kioslave',has_kioslaves) ) + sub_commands.append( ('install_application_data',has_application_data) ) + + def initialize_options(self): + self.kde_prefix = None + self.install_messages = None + self.install_html = None + self.install_cmd = None + self.install_xdg_apps = None + self.install_kcm = None + self.install_kioslave = None + self.install_protocol = None + self.install_application_data = None + install.initialize_options(self) + + def finalize_options(self): + # If no install prefix was provided, then we try to detect the KDE install prefix. + self.user_supplied_kde_prefix = True + + if self.install_scripts is None: + if self.kde_prefix is not None: + self.install_scripts = os.path.join(self.kde_prefix,'bin') + else: + self.announce("Detecting KDE 'bin' directory...") + self.install_scripts = ask_kde_config('--install exe --expandvars').strip() + self.announce(" ...KDE 'bin' directory is %s" % self.install_scripts) + + if self.install_application_data is None: + if self.kde_prefix is not None: + self.install_application_data = os.path.join(self.kde_prefix,'share/apps',self.distribution.metadata.name) + else: + self.announce("Detecting KDE application directory...") + kdeappdir = ask_kde_config('--install data --expandvars').strip() + self.announce(" ...KDE application directory is %s" % self.install_application_data) + self.install_application_data = os.path.join(kdeappdir,self.distribution.metadata.name) + + if self.install_messages is None: + if self.kde_prefix is not None: + self.install_messages = os.path.join(self.kde_prefix,'share/locale') + else: + self.announce("Detecting KDE messages directory...") + self.install_messages = ask_kde_config('--install locale --expandvars').strip() + self.announce(" ...KDE messages directory is %s" % self.install_messages) + + if self.install_html is None: + if self.kde_prefix is not None: + self.install_html = os.path.join(self.kde_prefix,'share/doc/HTML') + else: + self.announce("Detecting KDE HTML directory...") + self.install_html = ask_kde_config('--install html --expandvars').strip() + self.announce(" ...KDE HTML directory is %s" % self.install_html) + + if self.kde_prefix is None: + self.announce("Detecting KDE install prefix...") + self.kde_prefix = ask_kde_config('--prefix').strip() + self.announce(" ...KDE install prefix is %s" % self.kde_prefix) + self.user_supplied_kde_prefix = False + + if self.install_cmd is None: + self.announce("Detecting 'install' command...") + # Ok, time to find the install command. + self.install_cmd = find_executable('install') + if self.install_cmd is None: + raise SystemExit, "Unable to find the 'install' command, needed to install libraries." + self.announce(" ...'install' command is %s" % self.install_cmd) + + if self.install_xdg_apps is None: + self.announce("Detecting XDG apps directory...") + self.install_xdg_apps = ask_kde_config('--install xdgdata-apps --expandvars').strip() + self.announce(" ...XDG apps directory is %s" % self.install_xdg_apps) + + if self.install_kcm is None: + self.announce("Detecting kcm library directory...") + self.install_kcm = os.path.join(ask_kde_config('--install lib --expandvars').strip(),'kde3') + self.announce(" ...kcm library directory is %s" % self.install_kcm) + + if self.install_kioslave is None: + self.announce("Detecting kioslave library directory...") + self.install_kioslave = os.path.join(ask_kde_config('--install lib --expandvars').strip(),'kde3') + self.announce(" ...kioslave library directory is %s" % self.install_kioslave) + + if self.install_protocol is None: + self.announce("Detecting kioslave protocol directory...") + self.install_protocol = ask_kde_config('--install services --expandvars').strip() + self.announce(" ...kioslave protocol directory is %s" % self.install_protocol) + + install.finalize_options(self) + + if self.root is not None: + self.change_roots('application_data','html','messages','xdg_apps','kcm') + + def get_command_name(self): + return 'install' + + def run(self): + global INSTALL_LIST + install.run(self) + + # Write out the uninstall list. + fhandle = open(INSTALL_LIST,'w') + for item in self.get_outputs(): + fhandle.write(item) + fhandle.write('\n') + fhandle.close() + +########################################################################### +class InstallApplicationDataAndLinks(install_data): + def get_command_name(self): + return 'install_application_data' + + def initialize_options(self): + install_data.initialize_options(self) + + self.data_files = self.distribution.application_data + + def finalize_options(self): + self.set_undefined_options('install', + ('install_application_data', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ) + + def run(self): + self.outfiles.extend(self.mkpath(self.install_dir)) + for f in self.data_files: + if type(f) is StringType: + # it's a simple file, so copy it + f = convert_path(f) + if self.warn_dir: + self.warn("setup script did not provide a directory for " + "'%s' -- installing right in '%s'" % + (f, self.install_dir)) + if os.path.isfile(f): + (out, _) = self.copy_file(f, self.install_dir) + self.outfiles.append(out) + elif os.path.isdir(f): + out = self.copy_tree(f,os.path.join(self.install_dir,f)) + self.outfiles.extend(out) + else: + self.warn("Setup script can't find file or directory %s needed for installation." % f) + else: + # it's a tuple with path to install to and a list of files + dir = convert_path(f[0]) + if not os.path.isabs(dir): + dir = change_root(self.install_dir, dir) + elif self.root: + dir = change_root(self.root, dir) + self.outfiles.extend(self.mkpath(dir)) + + if f[1] == []: + # If there are no files listed, the user must be + # trying to create an empty directory, so add the + # directory to the list of output files. + self.outfiles.append(dir) + else: + # Copy files, adding them to the list of output files. + for data in f[1]: + data = convert_path(data) + if os.path.islink(data): + # Transplant the link to the new location without changing + # where it points to. (ie it is _not_ relocated). + dest = os.path.join(dir, os.path.basename(data)) + if os.path.exists(dest): + os.remove(dest) + os.symlink(os.readlink(data),dest) + log.info("moving link %s -> %s" % (data,dest) ) + #os.chmod(dest, os.stat(data)[stat.ST_MODE]) + elif os.path.isdir(data): + out = self.copy_tree(data,dir) + self.outfiles.extend(out) + else: + (out, _) = self.copy_file(data, dir) + self.outfiles.append(out) + + # Compile the .ui files + install_cmd = self.get_finalized_command('install') + prefix = self.install_dir + if prefix[-1] != os.sep: + prefix = prefix + os.sep + self.outfiles.extend(compile_qtdesigner(self.outfiles, force=1, prefix=prefix, base_dir=install_cmd.prefix, dry_run=self.dry_run)) + + # Byte compile the .py files + from distutils.util import byte_compile + byte_compile(self.outfiles, optimize=0, force=1, prefix=prefix, base_dir=install_cmd.prefix, dry_run=self.dry_run) + + # Add the .pyc files to the list of outfiles. + self.outfiles.extend( [item+'c' for item in self.outfiles if item.endswith('.py')] ) + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + +########################################################################### +class InstallExecutableLinks(Command): + description = "Install symlinks" + + user_options = [] + + def initialize_options(self): + self.outfiles = [] + + def finalize_options(self): + pass + + def get_command_name(self): + return 'install_executable_links' + + def run(self): + # FIXME add cmd options? + install_script_cmd = self.get_finalized_command('install_scripts') + install_data_cmd = self.get_finalized_command('install_application_data') + + destination_dir = install_data_cmd.install_dir + + if not os.path.exists(install_script_cmd.install_dir): + self.outfiles.extend(self.mkpath(install_script_cmd.install_dir)) + + if self.distribution.executable_links is not None: + for link in self.distribution.executable_links: + symname = os.path.join(install_script_cmd.install_dir,link[0]) + target = os.path.join(destination_dir,link[1]) + log.info("symlinking %s -> %s", symname, target) + if not self.dry_run: + if os.path.islink(symname): + os.remove(symname) + os.symlink(target,symname) + self.outfiles.append(symname) + + def get_outputs(self): + return self.outfiles or [] + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + +########################################################################### +# Fix the --root option for the install_lib command. +class InstallLibWithRoot(install_lib): + user_options = install_lib.user_options[:] + user_options.append( ('root=',None,"install everything relative to this alternate root directory") ) + + def initialize_options(self): + install_lib.initialize_options(self) + self.root = None + + def finalize_options(self): + own_install_dir = self.install_dir is not None + + install_lib.finalize_options(self) + self.set_undefined_options('install', ('root', 'root')) + + if self.root is not None and own_install_dir: + self.install_dir = change_root(self.root, self.install_dir) + +########################################################################### +class Uninstall(Command): + description = "Remove all installed files" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def get_command_name(self): + return 'uninstall' + + def run(self): + global INSTALL_LIST + + if not os.path.isfile(INSTALL_LIST): + self.announce("Unable to uninstall, can't find the file list %s." % INSTALL_LIST) + return + + # Suck in the file list. + fhandle = open(INSTALL_LIST,'r') + file_list = fhandle.readlines() + fhandle.close() + + # Remove the files first. + for item in file_list: + item = item.strip() + if os.path.isfile(item) or os.path.islink(item): + self.announce("removing '%s'" % item) + if not self.dry_run: + try: + os.remove(item) + except OSError, details: + self.warn("Could not remove file: %s" % details) + elif not os.path.isdir(item): + self.announce("skipping removal of '%s' (does not exist)" % item) + + # Remove the directories. + file_list.sort() + file_list.reverse() + # Starting with the longest paths first. + for item in file_list: + item = item.strip() + if os.path.isdir(item): + self.announce("removing '%s'" % item) + if not self.dry_run: + try: + os.rmdir(item) + except OSError, details: + self.warn("Could not remove directory: %s" % details) + +########################################################################### +class BuildKControlModule(Command): + description = "Build KControl extensions" + + user_options = [('no-kcontrol',None,"Don't build kcontrol extensions"), + ('build-dir=','b', "build directory (where to install from)"), + ('python-dir=',None,'Directory containing the Python installation'), + ('python-inc-dir=',None,'Directory containing C Header files for Python'), + ('kde-inc-dir=',None,'Directory containing C++ header files for KDE'), + ('kde-lib-dir=',None,'Directory containing library files for KDE'), + ('kde-kcm-lib-dir=',None,'Directory for KDE kcm library files'), + ('qt-inc-dir=',None,'Directory containing C++ header files for Qt'), + ('qt-lib-dir=',None,'Directory containing library files for Qt'), + ('sip-dir=','/usr/lib/pyshared/python2.6','Directory containing the sip library files'), + ('clib=',None,'gcc library and path'), + ('pyqt-dir=','/usr/lib/pyshared/python2.6','PyQt module directory'), + ('pykde-dir=',None,'PyKDE module directory'), + ('data-dir=',None,'installation directory for data (script) files')] + + def initialize_options(self): + self.no_kcontrol = 0 + self.build_dir = None + self.python_inc_dir = None + self.python_dir = None + self.kde_inc_dir = None + self.kde_lib_dir = None + self.kde_kcm_lib_dir = None + self.qt_inc_dir = None + self.qt_lib_dir = None + self.sip_dir = "/usr/lib/pyshared/python2.6" + self.clib = None + self.pyqt_dir = "/usr/lib/pyshared/python2.6" + self.pykde_dir = None + self.data_dir = None + + def finalize_options(self): + if self.no_kcontrol==0: + self.set_undefined_options('install', ('build_base', 'build_dir'),('install_application_data','data_dir')) + + install = self.get_finalized_command('install') + self.install_prefix = "/opt/kde3/" + + # KDE inc dir: find it! + if self.kde_inc_dir is None: + canidatepaths = [] + kdedir = os.getenv("KDEDIR") + if kdedir!=None: + canidatepaths.append(os.path.join(kdedir,"include")) + canidatepaths.append(os.path.join(install.prefix,"include")) + canidatepaths.append('/opt/kde3/include') + canidatepaths.append('/opt/kde/include') + self.kde_inc_dir = FindFileInPaths('kapplication.h',canidatepaths) + if self.kde_inc_dir is None: + raise SystemExit, "Failed to find the KDE header file directory." + if FindFileInPaths('kapplication.h',[self.kde_inc_dir]) is None: + raise SystemExit, "Failed to find KDE header files in: %s" % self.kde_inc_dir + self.announce("Using %s for KDE header files" % self.kde_inc_dir) + + # KDE lib dir + #if self.kde_lib_dir is None: + # self.kde_lib_dir = os.path.join(install.prefix,"lib") + self.kde_lib_dir = "/opt/kde3/lib/" + self.announce("Using %s for KDE library files" % self.kde_lib_dir) + + # KDE KCM lib dir + #if self.kde_kcm_lib_dir is None: + # self.kde_kcm_lib_dir = os.path.join(self.kde_lib_dir,"kde3") + self.kde_kcm_lib_dir = "/opt/kde3/lib/kde3/" + if FindFileInPaths('*kcm*.so',[self.kde_kcm_lib_dir]) is None: + raise SystemExit, "Failed to find KDE KCM files in: %s" % self.kde_kcm_lib_dir + self.announce("Using %s for KDE KCM library files" % self.kde_kcm_lib_dir) + + # Qt inc dir + if self.qt_inc_dir is None: + canidatepaths = [] + qtdir = os.getenv("QTDIR") + if qtdir != None: + canidatepaths.append(os.path.join(qtdir,"include")) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) + canidatepaths.append(os.path.join(install.prefix,"include")) + canidatepaths.append("/opt/qt3/include") + canidatepaths.append("/opt/qt/include") + canidatepaths.append("/opt/qt/lib/include") + canidatepaths.append("/opt/qt3/lib/include") + canidatepaths.append("/usr/include/qt3") + self.qt_inc_dir = FindFileInPaths('qstring.h',canidatepaths) + if self.qt_inc_dir is None: + raise SystemExit,"Failed to find the Qt header file directory" + if FindFileInPaths('qstring.h',[self.qt_inc_dir]) is None: + raise SystemExit, "Failed to find Qt header files in: %s" % self.qt_inc_dir + self.announce("Using %s for Qt header files" % self.qt_inc_dir) + + # Qt lib dir + if self.qt_lib_dir is None: + canidatepaths = [] + qtdir = os.getenv("QTDIR") + if qtdir != None: + canidatepaths.append(os.path.join(qtdir,get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,get_libdir_name())) + canidatepaths.append("/opt/qt3/"+get_libdir_name()) + canidatepaths.append("/opt/qt/"+get_libdir_name()) + canidatepaths.append("/opt/qt/lib/"+get_libdir_name()) + canidatepaths.append("/opt/qt3/lib/"+get_libdir_name()) + self.qt_lib_dir = FindFileInPaths('libqt*',canidatepaths) + if self.qt_lib_dir is None: + raise SystemExit, "Failed to find Qt library files" + self.announce("Using %s for Qt library files" % self.qt_lib_dir) + + # Python dir + if self.python_dir is None: + self.python_dir = os.path.split(sysconfig.get_config_var("LIBP"))[0] + self.announce("Using %s for the python directory" % self.python_dir) + + # Python include dir. + if self.python_inc_dir is None: + # Find the Python include directory. + self.python_inc_dir = sysconfig.get_config_var("INCLUDEPY") + self.announce("Using %s for Python header files" % self.python_inc_dir) + + # PyQt dir + if self.pyqt_dir is None: + self.pyqt_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libqtcmodule*",[self.pyqt_dir]) is None) and (FindFileInPaths("qt*",[self.pyqt_dir]) is None): + raise SystemExit, "Failed to find the PyQt directory: %s" % self.pyqt_dir + self.announce("Using %s for PyQt modules" % self.pyqt_dir) + + # PyKDE dir + if self.pykde_dir is None: + self.pykde_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libkdecorecmodule*",[self.pykde_dir]) is None) and (FindFileInPaths("kdecore*",[self.pykde_dir]) is None): + raise SystemExit, "Failed to find the PyKDE directory: %s" % self.pykde_dir + self.announce("Using %s for PyKDE modules" % self.pykde_dir) + + # Sip dir + if self.sip_dir is None: + self.sip_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libsip*", [self.sip_dir]) is None) and (FindFileInPaths("sip*", [self.sip_dir]) is None): + raise SystemExit, "Failed to find libsip files in directory: %s" % self.sip_dir + self.announce("Using %s for libsip files" % self.sip_dir) + + # Find the C library (libgcc, libgcc_s or some other variation). + if self.clib is None: + canidatepaths = ["/usr/"+get_libdir_name(), "/usr/local/"+get_libdir_name() ] + self.clib = FindFileInPaths("libgcc*.so",canidatepaths) + if self.clib!=None: + self.clib = glob.glob(os.path.join(self.clib,'libgcc*.so'))[0] + else: + self.clib = FindFileInPaths("libgcc*.a",canidatepaths) + if self.clib!=None: + self.clib = glob.glob(os.path.join(self.clib,'libgcc*.a'))[0] + if self.clib is None: + raise SystemExit, "Failed to find a suitable libgcc library" + self.announce("Using %s for clib" % self.clib) + + # Make a list of places to look for python .so modules + self.python_sub_dirs = sysconfig.get_config_var("LIBSUBDIRS").split() + base = sysconfig.get_config_var("LIBP") + self.python_sub_dirs = [ os.path.join(base,item) for item in self.python_sub_dirs ] + self.python_sub_dirs.append(base) + + def get_command_name(self): + return 'build_kcm' + + def run(self): + if self.no_kcontrol: + self.announce("Skipping KControl modules") + return + + if not os.path.isdir(self.build_dir): + os.mkdir(self.build_dir) + + for moduletuple in self.distribution.kcontrol_modules: + self.announce("Building KControl module from desktop file %s." % moduletuple[0]) + + # Read the desktop file + factoryfunction = None + libraryname = None + cmodulecategory = None + try: + fhandle = open(moduletuple[0],'r') + for line in fhandle.readlines(): + parts = line.strip().split('=') + try: + if parts[0]=="X-KDE-Library": + libraryname = parts[1] + elif parts[0]=="Exec": + shellcmd = parts[1].split() + modulepath = shellcmd[-1] + if '/' in modulepath: + cmodulecategory = os.path.dirname(modulepath) + else: + cmodulecategory = "" + elif parts[0]=="X-KDE-FactoryName": + factoryfunction = 'create_'+parts[1] + except IndexError: + pass + fhandle.close() + except IOError: + raise SystemExit, "Failed to find kcontrol desktop file: %s" % moduletuple[0] + + # Sanity check. + if factoryfunction is None: + raise SystemExit, "Failed to find factory name (Was there a X-KDE-FactoryName entry in the desktop file?)" + if libraryname is None: + raise SystemExit, "Failed to find library name (Was there a X-KDE-Library entry in the desktop file?)" + if cmodulecategory is None: + raise SystemExit, "Failed to find the kcontrol category name (Was there a Exec entry in the desktop file?)" + + modulename = os.path.basename(moduletuple[1]) + if modulename.endswith('.py'): + modulename = modulename[:-3] + desktopfilename = moduletuple[0] + + stub_cpp_name = 'kcm_'+libraryname+'.cpp' + stub_so_name = 'kcm_'+libraryname+'.so' + stub_la_name = 'kcm_'+libraryname+'.la' + python_version = '%i.%i' % (sys.version_info[0],sys.version_info[1]) + + # Build the 'stub' code. + cppcode = self.cpptemplate % {"moduledir": self.data_dir, + "modulename": modulename, + "factoryfunction": factoryfunction, + "python_version": python_version} + + # Put it on disk. + cppfile = os.path.join(os.path.dirname(moduletuple[0]),stub_cpp_name) + try: + fhandle = open(cppfile,'w') + fhandle.write(cppcode) + fhandle.close() + except IOError: + raise SystemExit, "Could not write the C++ stub: %s" % cppfile + + # Compile the stub library. + cmdlist = ['libtool'] + + # Couldn't get it to pass without this ... + cmdlist.append("--mode=compile") + cmdlist.append("--tag=CXX") + + # Find the compiler flags and options + # CXX is empty on some Systems, let's do it 'the hard way'. + # FIXME :: get CXX from make.conf for Gentoo. + if len(sysconfig.get_config_var("CXX").split()) >= 2: + cmdlist.extend(sysconfig.get_config_var("CXX").split()) + else: + cmdlist.extend(['g++', '-pthread']) + + #cmdlist.extend(sysconfig.get_config_var("CXX").split()) + + # cc_flags + cmdlist.append("-c") + cmdlist.append("-g") + + # The 4 is randomly chosen! + # FIXME :: get CFLAGS from make.conf for Gentoo. + if len(sysconfig.get_config_var("CFLAGS").split()) >=4: + cmdlist.extend(sysconfig.get_config_var("CFLAGS").split()) + else: + # On Gentoo systems, CFLAGS are not in the environment. + raw = os.popen('emerge info 2> /dev/null|grep CFLAGS') + lines = raw.readlines() + if len(lines): + cflags = lines[0].split('"')[1].split() + print "Got CFLAGS from emerge info." + cmdlist.extend(cflags) + else: + # Still no CFLAGS found, use these ... + cmdlist.extend(['-fno-strict-aliasing', '-DNDEBUG', '-g', '-O3', '-Wall', '-Wstrict-prototypes']) + + #sysconfig.get_config_var("CFLAGS").split() + # includes + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEPY")) + cmdlist.append("-I" + self.python_inc_dir) + cmdlist.append("-I" + self.kde_inc_dir) + cmdlist.append("-I" + self.qt_inc_dir) + cmdlist.append("-I.") + # input + cmdlist.append(cppfile) + # output + outputfile = os.path.join(self.build_dir,libraryname+'.lo') + cmdlist.append("-o") + cmdlist.append(outputfile) + spawn(cmdlist) # Execute!!! + print + + # Link the resulting object file to create a shared library. + cmdlist = ['libtool'] + cmdlist.append("--mode=link") + + # Grab the linker command name + cmdlist.append(sysconfig.get_config_var("LDSHARED").split()[0]) + # link_flags + cmdlist.append("-module") + cmdlist.append("-export-dynamic") + # object + cmdlist.append(outputfile) + cmdlist.append("-rpath"); cmdlist.append(self.kde_kcm_lib_dir) + cmdlist.append("-o"); cmdlist.append(os.path.join(self.build_dir,stub_la_name)) + # Link libs + linklist = [] + linklist.append("-lpython%s" % python_version) + linklist.extend(sysconfig.get_config_var("LIBS").split()) + + # FIXME I doubt half of these libraries need to be here. + linklist.append(self.sip_dir+"/sip.so") + # PyQt libs + linklist.append(self.pyqt_dir+"/qt.so") + # PyKDE libs + linklist.append(self.pykde_dir+"/kdecore.so") + linklist.append(self.pykde_dir+"/kdeui.so") + +# linklist.append("-L"+self.sip_dir); linklist.append("-lsip") +# # PyQt libs +# linklist.append("-L"+self.pyqt_dir); linklist.append("-lqtcmodule") +# # PyKDE libs +# linklist.append("-L"+self.pykde_dir); linklist.append("-lkdecorecmodule"); linklist.append("-lkdeuicmodule") + + linklist.append("-L"+self.kde_lib_dir); linklist.append("-L/opt/kde3/lib"); linklist.append("-lkdecore"); linklist.append("-lpythonize") + linklist.append("-L"+self.qt_lib_dir); linklist.append("-lqt-mt") + linklist.append("-lm") + linklist.append("-lstdc++") + linklist.append("-lc") + linklist.append(self.clib) + + linklist.append("-R"); linklist.append(self.python_dir) + linklist.append("-R"); linklist.append(self.qt_lib_dir) + linklist.append("-R"); linklist.append(self.sip_dir) + linklist.append("-R"); linklist.append(self.pyqt_dir) + linklist.append("-R"); linklist.append(self.pykde_dir) + linklist.append("-R"); linklist.append(self.kde_lib_dir) + + cmdlist.extend(linklist) + spawn(cmdlist) # Execute!! + print + + cpptemplate = r""" +/* + * pykcm_launcher.cpp + * + * Launch Control Centre modules written in Python using an embedded Python + * interpreter. + * Based on David Boddie's PyKDE-components. + */ + +// pythonize.h must be included first. +#include <pythonize.h> +#include <kcmodule.h> +#include <kglobal.h> +#include <klocale.h> +#include <klibloader.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> +#include <qstring.h> +#include <sip.h> + +#define MODULE_DIR "%(moduledir)s" +#define EXTRA_MODULE_DIR "/opt/kde3/share/python-support/kde-guidance-kde3" +#define EXTRA_MODULE_DIR_TWO "/opt/kde3/share/python-support/guidance-backends-kde3" +#define EXTRA_MODULE_DIR_THREE "/opt/kde3/share/python-support/kde-guidance-powermanager-kde3" +#define MODULE_NAME "%(modulename)s" +#define FACTORY "%(factoryfunction)s" +#define CPP_FACTORY %(factoryfunction)s +#define LIB_PYTHON "libpython%(python_version)s.so" +#define debug 1 + +static KCModule *report_error(char *msg) { + if (debug) printf ("error: %%s\n", msg); + return NULL; +} + +static KCModule* return_instance( QWidget *parent, const char *name ) { + KCModule* kcmodule; + PyObject *pyKCModuleTuple; + PyObject *pyKCModule; + Pythonize *pyize; // Pythonize object to manage the Python interpreter. + int isErr; + + // Try to determine what py script we're loading. Note that "name" + // typically appears to be NULL. + QString script(MODULE_NAME); + + // Reload libpython, but this time tell the runtime linker to make the + // symbols global and available for later loaded libraries/module. + KLibLoader::self()->globalLibrary(LIB_PYTHON); + + // Start the interpreter. + pyize = initialize(); + if (!pyize) { + return report_error ("***Failed to start interpreter\n"); + } + + // Add the path to the python script to the interpreter search path. + QString path = QString(MODULE_DIR); + if(path == QString::null) { + return report_error ("***Failed to locate script path"); + } + if(!pyize->appendToSysPath (path.latin1 ())) { + return report_error ("***Failed to set sys.path\n"); + } + QString extrapath = QString(EXTRA_MODULE_DIR); + if(!pyize->appendToSysPath (extrapath.latin1 ())) { + return report_error ("***Failed to set extra sys.path\n"); + } + QString extrapath_two = QString(EXTRA_MODULE_DIR_TWO); + if(!pyize->appendToSysPath (extrapath_two.latin1 ())) { + return report_error ("***Failed to set extra 2 sys.path\n"); + } + QString extrapath_three = QString(EXTRA_MODULE_DIR_THREE); + if(!pyize->appendToSysPath (extrapath_three.latin1 ())) { + return report_error ("***Failed to set extra 3 sys.path\n"); + } + + // Load the Python script. + PyObject *pyModule = pyize->importModule ((char *)script.latin1 ()); + if(!pyModule) { + PyErr_Print(); + return report_error ("***failed to import module\n"); + } + + // Inject a helper function + QString bridge = QString("import sip\n" + "import qt\n" + "def kcontrol_bridge_" FACTORY "(parent,name):\n" + " if parent!=0:\n" +#if SIP_VERSION >= 0x040200 + " wparent = sip.wrapinstance(parent,qt.QWidget)\n" +#else + " wparent = sip.wrapinstance(parent,'QWidget')\n" +#endif + " else:\n" + " wparent = None\n" + " inst = " FACTORY "(wparent, name)\n" + " return (inst,sip.unwrapinstance(inst))\n"); + PyRun_String(bridge.latin1(),Py_file_input,PyModule_GetDict(pyModule),PyModule_GetDict(pyModule)); + + // Get the Python module's factory function. + PyObject *kcmFactory = pyize->getNewObjectRef(pyModule, "kcontrol_bridge_" FACTORY); + if(!kcmFactory) { + return report_error ("***failed to find module factory\n"); + } + + // Call the factory function. Set up the args. + PyObject *pyParent = PyLong_FromVoidPtr(parent); + PyObject *pyName = PyString_FromString(MODULE_NAME); + // Using NN here is effect gives our references to the arguement away. + PyObject *args = Py_BuildValue ("NN", pyParent, pyName); + if(pyName && pyParent && args) { + // run the factory function + pyKCModuleTuple = pyize->runFunction(kcmFactory, args); + if(!pyKCModuleTuple) { + PyErr_Print(); + return report_error ("*** runFunction failure\n;"); + } + } else { + return report_error ("***failed to create args\n"); + } + // cleanup a bit + pyize->decref(args); + pyize->decref(kcmFactory); + + // Stop this from getting garbage collected. + Py_INCREF(PyTuple_GET_ITEM(pyKCModuleTuple,0)); + + // convert the KCModule PyObject to a real C++ KCModule *. + isErr = 0; + pyKCModule = PyTuple_GET_ITEM(pyKCModuleTuple,1); + kcmodule = (KCModule *)PyLong_AsVoidPtr(pyKCModule); + if(!kcmodule) { + return report_error ("***failed sip conversion to C++ pointer\n"); + } + pyize->decref(pyKCModuleTuple); + + // PyKDE can't run the module without this - Pythonize + // grabs the lock at initialization and we have to give + // it back before exiting. At this point, we no longer need + // it. + //pyize->releaseLock (); + + // take care of any translation info + KGlobal::locale()->insertCatalogue(script); + + // Return the pointer to our new KCModule + return kcmodule; +} + +extern "C" { + // Factory function that kcontrol will call. + KCModule* CPP_FACTORY(QWidget *parent, const char *name) { + return return_instance(parent, name); + } +} +""" + +########################################################################### +class InstallKControlModule(Command): + description = "Install Kcontrol module files" + + user_options = [ + ('install-dir=', 'd', "base directory for installing kcontrol module files"), + ('install-cmd=', None, "Command to use to install the files"), + ('xdg-apps-dir=',None,"directory for XDG app files"), + ('build-dir=','b', "build directory (where to install from)"), + ('root=', None, "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + boolean_options = ['force', 'skip-build'] + + def initialize_options(self): + self.build_dir = None + self.install_dir = None + self.install_cmd = None + self.xdg_apps_dir = None + self.outfiles = [] + self.root = None + self.force = 0 + self.warn_dir = 1 + self.skip_build = None + + def finalize_options(self): + own_install_dir = self.install_dir is not None + own_xdg_apps_dir = self.xdg_apps_dir is not None + + self.set_undefined_options('install', + ('build_base', 'build_dir'), + ('install_kcm', 'install_dir'), + ('install_xdg_apps','xdg_apps_dir'), + ('root', 'root'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ('install_cmd', 'install_cmd') + ) + + if own_install_dir and self.root is not None: + self.install_dir = change_root(self.root,self.installdir) + if own_xdg_apps_dir and self.root is not None: + self.xdg_apps_dir = change_root(self.root,self.xdg_apps_dir) + + def get_command_name(self): + return 'install_kcm' + + def run(self): + if not self.skip_build: + self.run_command('build_kcm') + + self.announce("Installing Kcontrol module files...") + + for moduletuple in self.distribution.kcontrol_modules: + self.announce("Building KControl module from desktop file %s." % moduletuple[0]) + + # Read the desktop file + libraryname = None + cmodulecategory = None + try: + fhandle = open(moduletuple[0],'r') + for line in fhandle.readlines(): + parts = line.strip().split('=') + try: + if parts[0]=="X-KDE-Library": + libraryname = parts[1] + elif parts[0]=="Exec": + shellcmd = parts[1].split() + modulepath = shellcmd[-1] + if '/' in modulepath: + cmodulecategory = os.path.dirname(modulepath) + else: + cmodulecategory = "" + except IndexError: + pass + fhandle.close() + except IOError: + raise SystemExit, "Failed to find kcontrol desktop file: %s" % moduletuple[0] + + if libraryname is None: + raise SystemExit, "Failed to find library name (Was there a X-KDE-Library entry in the desktop file?)" + if cmodulecategory is None: + raise SystemExit, "Failed to find the kcontrol category name (Was there a Exec entry in the desktop file?)" + + desktopfilename = moduletuple[0] + self.outfiles.extend(self.mkpath(self.xdg_apps_dir)) + desktopfile_dest = os.path.join(self.xdg_apps_dir,os.path.basename(desktopfilename)) + self.copy_file(desktopfilename, desktopfile_dest) + + stub_la_name = 'kcm_'+libraryname+'.la' + + self.outfiles.extend(self.mkpath(self.install_dir)) + + # Install the library. + cmdlist = ['libtool'] + cmdlist.append("--mode=install") + cmdlist.append(self.install_cmd) + cmdlist.append("-c") + cmdlist.append(os.path.join(self.build_dir,stub_la_name)) + cmdlist.append(os.path.join(self.install_dir,stub_la_name)) + spawn(cmdlist) # Execute!! + print + + self.outfiles = [os.path.join(self.install_dir,os.path.basename(file)) for file in glob.glob(os.path.join(self.build_dir,'.libs','kcm_'+libraryname+'*'))] + self.outfiles.append(desktopfile_dest) + + self.announce("Done installing Kcontrol module files.") + + def get_outputs(self): + return self.outfiles or [] + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + +########################################################################### +class BuildDocbookHTML(Command): + description = "Build Docbook HTML documentation" + + user_options = [('meinproc-exe=',None,"Path to the meinproc executable")] + + def initialize_options(self): + self.html_prefix = None + self.meinproc_exe = None + + def finalize_options(self): + self.set_undefined_options('build', ('meinproc_exe', 'meinproc_exe') ) + + def get_command_name(self): + return 'build_docbook' + + def run(self): + for docbook_tuple in self.distribution.docbooks: + input_dir = docbook_tuple[0] + language_code = docbook_tuple[1] + + self.announce("Building Docbook documentation from directory %s." % input_dir) + + indexdoc_file_name = os.path.join(input_dir,'index.docbook') + if not os.path.exists(indexdoc_file_name): + raise SystemExit, "File %s is missing." % indexdoc_file_name + + cwd = os.getcwd() + os.chdir(input_dir) + try: + spawn([self.meinproc_exe,"--check","--cache",'index.cache.bz2', 'index.docbook']) + spawn([self.meinproc_exe, 'index.docbook']) + finally: + os.chdir(cwd) + +########################################################################### +class InstallDocbookHTML(Command): + description = "Install Docbook HTML files" + + user_options = [ + ('install-dir=', 'd',"base directory for installing docbook HTML files"), + ('root=', None, "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + boolean_options = ['force', 'skip-build'] + + def initialize_options(self): + self.install_dir = None + self.outfiles = [] + self.root = None + self.force = 0 + self.warn_dir = 1 + self.skip_build = None + + def finalize_options(self): + own_install_dir = self.install_dir is not None + + self.set_undefined_options('install', + ('install_html', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ) + + if own_install_dir and self.root is not None: + self.install_dir = change_root(self.root,self.installdir) + + def get_command_name(self): + return 'install_html' + + def run(self): + if not self.skip_build: + self.run_command('build_html') + + self.announce("Installing HTML files...") + counter = 0 + for docbook_tuple in self.distribution.docbooks: + input_dir = docbook_tuple[0] + language_code = docbook_tuple[1] + + self.announce("Install Docbook documentation from directory %s." % input_dir) + source_file = os.path.join(input_dir,'index.cache.bz2') + if not os.path.exists(source_file): + raise SystemExit, "File %s is missing." % source_file + + dest_path = os.path.join(self.install_dir, language_code, self.distribution.metadata.name) + self.outfiles.extend(self.mkpath(dest_path)) + dest_file = os.path.join(dest_path,'index.cache.bz2') + + self.copy_file(source_file, dest_file) + self.outfiles.append(dest_file) + counter += 1 + + # Also install any lose HTML files. + for source_file in glob.glob(os.path.join(input_dir,'*.html')): + htmlfile = os.path.basename(source_file) + dest_file = os.path.join(dest_path,htmlfile) + self.copy_file(source_file, dest_file) + self.outfiles.append(dest_file) + counter += 1 + + if len(docbook_tuple)==3: + extra_files = docbook_tuple[2] + for file in extra_files: + source_file = os.path.join(input_dir,file) + dest_file = os.path.join(self.install_dir, language_code, self.distribution.metadata.name,file) + self.copy_file(source_file, dest_file) + self.outfiles.append(dest_file) + counter += 1 + + self.announce("Done installing %i HTML files." % counter) + + def get_outputs(self): + return self.outfiles or [] + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + +########################################################################### +class UpdateI18NMessages(Command): + description = "Extract and update messages for translation" + + user_options = [('xgettext-exe=',None,'Full path to the xgetext executable'),\ + ('kde-pot=',None,'Location of the the KDE pot file'),\ + ('msgmerge-exe=',None,'Full path to the msgmerge executable')] + + def initialize_options(self): + self.xgettext_exe = None + self.msgmerge_exe = None + self.kde_pot = None + + def finalize_options(self): + if self.xgettext_exe is None: + install = self.get_finalized_command('install') + + canidate_paths = [] + if install.user_supplied_kde_prefix: + canidate_paths.append(os.path.join(install.kde_prefix,'bin')) + + self.announce("Detecting xgettext...") + canidate_paths.append(ask_kde_config('--install exe --expandvars').strip()) + self.xgettext_exe = FindExeOnPath('xgettext',canidate_paths) + if self.xgettext_exe is None: + raise SystemExit, "Unable to find 'xgettext'." + self.announce(" ...xgettext found at %s" % self.xgettext_exe) + + if self.msgmerge_exe is None: + install = self.get_finalized_command('install') + + canidate_paths = [] + if install.user_supplied_kde_prefix: + canidate_paths.append(os.path.join(install.kde_prefix,'bin')) + + self.announce("Detecting msgmerge...") + canidate_paths.append(ask_kde_config('--install exe --expandvars').strip()) + self.msgmerge_exe = FindExeOnPath('msgmerge',canidate_paths) + if self.msgmerge_exe is None: + raise SystemExit, "Unable to find 'xgettext'." + self.announce(" ...msgmerge found at %s" % self.msgmerge_exe) + + if self.kde_pot is None: + self.announce("Detecting kde.pot...") + canidatepaths = [] + kdedir = os.getenv("KDEDIR") + if kdedir!=None: + canidatepaths.append(os.path.join(kdedir,"include")) + install = self.get_finalized_command('install') + canidatepaths.append(os.path.join(install.kde_prefix,"include")) + canidatepaths.append('/opt/kde3/include') + canidatepaths.append('/opt/kde/include') + kde_pot_dir = FindFileInPaths('kde.pot',canidatepaths) + + if kde_pot_dir is None: + raise SystemExit, "Failed to find the kde.pot file." + + self.kde_pot = os.path.join(kde_pot_dir,'kde.pot') + self.announce(" ...kde.pot found at %s" % self.kde_pot) + + def get_command_name(self): + return 'update_messages' + + def run(self): + if self.distribution.i18n is None: return + + self.announce("Extracting and merging i18n messages...") + po_dir = self.distribution.i18n[0] + + # FIXME : .rc and .ui files + input_files = [] + + # Compile any UI files + for dir in self.distribution.i18n[1]: + for file in glob.glob(os.path.join(dir,'*.ui')): + qtuicompiler.UpdateUI(file,kde=True) + + # Fetch all of the python files. + for dir in self.distribution.i18n[1]: + input_files.extend(glob.glob(os.path.join(dir,'*.py'))) + + target_pot = os.path.join(po_dir,self.distribution.metadata.name+".pot") + + cmd = [self.xgettext_exe, '-o', target_pot, '-ki18n', '-ktr2i18n', \ + '-kI18N_NOOP', '-ktranslate', '-kaliasLocale','-x',self.kde_pot] + cmd.extend(input_files) + spawn(cmd) + + for po_file in glob.glob(os.path.join(po_dir,'*.po')): + temp_po = po_file + '.temp' + cmd = [self.msgmerge_exe,'-q','-o',temp_po,po_file,target_pot] + spawn(cmd) + os.rename(temp_po,po_file) + + self.announce("Finished with i18n messages.") + +########################################################################### +class BuildI18NMessages(Command): + description = "Build i18n messages" + + user_options = [('msgfmt-exe=',None,'Path to the msgfmt executable')] + + def initialize_options(self): + self.msgfmt_exe = None + + def finalize_options(self): + self.set_undefined_options('build', ('msgfmt_exe', 'msgfmt_exe')) + + def get_command_name(self): + return 'build_messages' + + def run(self): + if self.distribution.i18n is None: return + + self.announce("Building i18n messages...") + po_dir = self.distribution.i18n[0] + + i = 0 + for po_file in [file for file in os.listdir(po_dir) if file.endswith('.po')]: + source = os.path.join(po_dir,po_file) + target = source[:-3]+'.gmo' + cmd = [self.msgfmt_exe,'-o',target, source] + spawn(cmd) + i += 1 + self.announce("Done building %i i18n messages." % i) + +########################################################################### +class InstallI18NMessages(Command): + description = "Install messages" + + user_options = [ + ('install-dir=', 'd',"base directory for installing message files (default: installation base dir)"), + ('root=', None, "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + + boolean_options = ['force', 'skip-build'] + + def initialize_options(self): + self.install_dir = None + self.outfiles = [] + self.root = None + self.force = 0 + self.warn_dir = 1 + self.skip_build = None + + def finalize_options(self): + own_install_dir = self.install_dir is not None + + self.set_undefined_options('install', + ('install_messages', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ) + + if own_install_dir and self.root is not None: + self.install_dir = change_root(self.root,self.installdir) + + def get_command_name(self): + return 'install_messages' + + def run(self): + if not self.skip_build: + self.run_command('build_messages') + + self.announce("Installing i18n messages...") + po_dir = self.distribution.i18n[0] + + counter = 0 + for po_file in os.listdir(po_dir): + if po_file.endswith('.po'): + source_file = os.path.join(po_dir,po_file[:-3]) + '.gmo' + + # Setup installation of the translation file. + dest_path = os.path.join(self.install_dir, po_file[:-3],'LC_MESSAGES') + self.outfiles.extend(self.mkpath(dest_path)) + dest_file = os.path.join(dest_path, self.distribution.metadata.name+'.mo') + + self.copy_file(source_file, dest_file) + self.outfiles.append(dest_file) + counter += 1 + self.announce("Done installing %i i18n messages." % counter) + + def get_outputs(self): + return self.outfiles + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + + +########################################################################### +class BuildKioslave(Command): + description = "Build Kioslaves" + + user_options = [('no-kioslave',None,"Don't build kioslaves"), + ('build-dir=','b', "build directory (where to install from)"), + ('python-dir=',None,'Directory containing the Python installation'), + ('python-inc-dir=',None,'Directory containing C Header files for Python'), + ('kde-inc-dir=',None,'Directory containing C++ header files for KDE'), + ('kde-lib-dir=',None,'Directory containing library files for KDE'), + ('kde-kioslave-lib-dir=',None,'Directory for KDE kioslave library files'), + ('kde-protocol-dir=',None,'Directory for KDE kioslave protocol files'), + ('qt-inc-dir=',None,'Directory containing C++ header files for Qt'), + ('qt-lib-dir=',None,'Directory containing library files for Qt'), + ('sip-dir=','/usr/lib/pyshared/python2.6','Directory containing the sip library files'), + ('clib=',None,'gcc library and path'), + ('pyqt-dir=','/usr/lib/pyshared/python2.6','PyQt module directory'), + ('pykde-dir=',None,'PyKDE module directory'), + ('data-dir=',None,'installation directory for data (script) files')] + + def initialize_options(self): + self.no_kioslave = 0 + self.build_dir = None + self.python_inc_dir = None + self.python_dir = None + self.kde_inc_dir = None + self.kde_lib_dir = None + self.kde_kioslave_lib_dir = None + self.kde_protocol_dir = None + self.qt_inc_dir = None + self.qt_lib_dir = None + self.sip_dir = "/usr/lib/pyshared/python2.6" + self.clib = None + self.pyqt_dir = "/usr/lib/pyshared/python2.6" + self.pykde_dir = None + self.data_dir = None + + def finalize_options(self): + if self.no_kioslave==0: + self.set_undefined_options('install', ('build_base', 'build_dir'),('install_application_data','data_dir')) + + install = self.get_finalized_command('install') + self.install_prefix = "/opt/kde3/" + + # KDE inc dir: find it! + if self.kde_inc_dir is None: + canidatepaths = [] + kdedir = os.getenv("KDEDIR") + if kdedir!=None: + canidatepaths.append(os.path.join(kdedir,"include")) + canidatepaths.append(os.path.join(install.prefix,"include")) + canidatepaths.append('/opt/kde3/include') + canidatepaths.append('/opt/kde/include') + self.kde_inc_dir = FindFileInPaths('kapplication.h',canidatepaths) + if self.kde_inc_dir is None: + raise SystemExit, "Failed to find the KDE header file directory." + if FindFileInPaths('kapplication.h',[self.kde_inc_dir]) is None: + raise SystemExit, "Failed to find KDE header files in: %s" % self.kde_inc_dir + self.announce("Using %s for KDE header files" % self.kde_inc_dir) + + # KDE lib dir + #if self.kde_lib_dir is None: + # self.kde_lib_dir = os.path.join(install.prefix,"lib") + self.kde_lib_dir = "/opt/kde3/lib/" + self.announce("Using %s for KDE library files" % self.kde_lib_dir) + + # KDE kioslave lib dir + #if self.kde_kioslave_lib_dir is None: + # self.kde_kioslave_lib_dir = os.path.join(self.kde_lib_dir,"kde3") + self.kde_kioslave_lib_dir = "/opt/kde3/lib/kde3/" + if FindFileInPaths('kio_*.so',[self.kde_kioslave_lib_dir]) is None: + raise SystemExit, "Failed to find KDE Kioslave library files in: %s" % self.kde_kioslave_lib_dir + self.announce("Using %s for KDE Kioslave library files" % self.kde_kioslave_lib_dir) + + # Qt inc dir + if self.qt_inc_dir is None: + canidatepaths = [] + qtdir = os.getenv("QTDIR") + if qtdir != None: + canidatepaths.append(os.path.join(qtdir,"include")) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/include")) + canidatepaths.append(os.path.join(install.prefix,"include")) + canidatepaths.append("/opt/qt3/include") + canidatepaths.append("/opt/qt/include") + canidatepaths.append("/opt/qt/lib/include") + canidatepaths.append("/opt/qt3/lib/include") + self.qt_inc_dir = FindFileInPaths('qstring.h',canidatepaths) + if self.qt_inc_dir is None: + raise SystemExit,"Failed to find the Qt header file directory" + if FindFileInPaths('qstring.h',[self.qt_inc_dir]) is None: + raise SystemExit, "Failed to find Qt header files in: %s" % self.qt_inc_dir + self.announce("Using %s for Qt header files" % self.qt_inc_dir) + + # Qt lib dir + if self.qt_lib_dir is None: + canidatepaths = [] + qtdir = os.getenv("QTDIR") + if qtdir != None: + canidatepaths.append(os.path.join(qtdir,get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,"lib/qt3/"+get_libdir_name())) + canidatepaths.append(os.path.join(install.prefix,get_libdir_name())) + canidatepaths.append("/opt/qt3/"+get_libdir_name()) + canidatepaths.append("/opt/qt/"+get_libdir_name()) + canidatepaths.append("/opt/qt/lib/"+get_libdir_name()) + canidatepaths.append("/opt/qt3/lib/"+get_libdir_name()) + self.qt_lib_dir = FindFileInPaths('libqt*',canidatepaths) + if self.qt_lib_dir is None: + raise SystemExit, "Failed to find Qt library files" + self.announce("Using %s for Qt library files" % self.qt_lib_dir) + + # Python dir + if self.python_dir is None: + self.python_dir = os.path.split(sysconfig.get_config_var("LIBP"))[0] + self.announce("Using %s for the python directory" % self.python_dir) + + # Python include dir. + if self.python_inc_dir is None: + # Find the Python include directory. + self.python_inc_dir = sysconfig.get_config_var("INCLUDEPY") + self.announce("Using %s for Python header files" % self.python_inc_dir) + + # PyQt dir + if self.pyqt_dir is None: + self.pyqt_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libqtcmodule*",[self.pyqt_dir]) is None) and (FindFileInPaths("qt*",[self.pyqt_dir]) is None): + raise SystemExit, "Failed to find the PyQt directory: %s" % self.pyqt_dir + self.announce("Using %s for PyQt modules" % self.pyqt_dir) + + # PyKDE dir + if self.pykde_dir is None: + self.pykde_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libkdecorecmodule*",[self.pykde_dir]) is None) and (FindFileInPaths("kdecore*",[self.pykde_dir]) is None): + raise SystemExit, "Failed to find the PyKDE directory: %s" % self.pykde_dir + self.announce("Using %s for PyKDE modules" % self.pykde_dir) + + # Sip dir + if self.sip_dir is None: + self.sip_dir = sysconfig.get_python_lib() + if (FindFileInPaths("libsip*", [self.sip_dir]) is None) and (FindFileInPaths("sip*", [self.sip_dir]) is None): + raise SystemExit, "Failed to find libsip files in directory: %s" % self.sip_dir + self.announce("Using %s for libsip files" % self.sip_dir) + + # Find the C library (libgcc, libgcc_s or some other variation). + if self.clib is None: + canidatepaths = ["/usr/"+get_libdir_name(), "/usr/local/"+get_libdir_name() ] + self.clib = FindFileInPaths("libgcc*.so",canidatepaths) + if self.clib!=None: + self.clib = glob.glob(os.path.join(self.clib,'libgcc*.so'))[0] + else: + self.clib = FindFileInPaths("libgcc*.a",canidatepaths) + if self.clib!=None: + self.clib = glob.glob(os.path.join(self.clib,'libgcc*.a'))[0] + if self.clib is None: + raise SystemExit, "Failed to find a suitable libgcc library" + self.announce("Using %s for clib" % self.clib) + + # Make a list of places to look for python .so modules + self.python_sub_dirs = sysconfig.get_config_var("LIBSUBDIRS").split() + base = sysconfig.get_config_var("LIBP") + self.python_sub_dirs = [ os.path.join(base,item) for item in self.python_sub_dirs ] + self.python_sub_dirs.append(base) + + def get_command_name(self): + return 'build_kioslave' + + def run(self): + if self.no_kioslave: + self.announce("Skipping KIO Slaves") + return + + if not os.path.isdir(self.build_dir): + os.mkdir(self.build_dir) + + for moduletuple in self.distribution.kioslaves: + self.announce("Building KIO Slave from protocol file %s." % moduletuple[0]) + + protocolfilename = moduletuple[0] + + # Read the protocol file + libraryname = None + try: + fhandle = open(protocolfilename,'r') + for line in fhandle.readlines(): + parts = line.strip().split('=') + try: + if parts[0]=="exec": + libraryname = parts[1] + except IndexError: + pass + fhandle.close() + except IOError: + raise SystemExit, "Failed to find kioslave protocol file: %s" % moduletuple[0] + + # Sanity check. + if libraryname is None: + raise SystemExit, "Failed to find library name (Was there a exec entry in the protocol file?)" + + modulename = os.path.basename(moduletuple[1]) + if modulename.endswith('.py'): + modulename = modulename[:-3] + + stub_cpp_name = libraryname+'.cpp' + stub_so_name = libraryname+'.so' + stub_la_name = libraryname+'.la' + python_version = '%i.%i' % (sys.version_info[0],sys.version_info[1]) + + # Build the 'stub' code. + cppcode = self.cpptemplate % {"moduledir": self.data_dir, + "modulename": modulename, + "python_version": python_version} + + # Put it on disk. + cppfile = os.path.join(os.path.dirname(moduletuple[0]),stub_cpp_name) + try: + fhandle = open(cppfile,'w') + fhandle.write(cppcode) + fhandle.close() + except IOError: + raise SystemExit, "Could not write the C++ stub: %s" % cppfile + + # Compile the stub library. + cmdlist = ['libtool'] + + # Couldn't get it to pass without this ... + cmdlist.append("--mode=compile") + cmdlist.append("--tag=CXX") + + # Find the compiler flags and options + # CXX is empty on some Systems, let's do it 'the hard way'. + # FIXME :: get CXX from make.conf for Gentoo. + if len(sysconfig.get_config_var("CXX").split()) >= 2: + cmdlist.extend(sysconfig.get_config_var("CXX").split()) + else: + cmdlist.extend(['g++', '-pthread']) + + #cmdlist.extend(sysconfig.get_config_var("CXX").split()) + + # cc_flags + cmdlist.append("-c") + cmdlist.append("-g") + + # The 4 is randomly chosen! + # FIXME :: get CFLAGS from make.conf for Gentoo. + if len(sysconfig.get_config_var("CFLAGS").split()) >=4: + cmdlist.extend(sysconfig.get_config_var("CFLAGS").split()) + else: + # On Gentoo systems, CFLAGS are not in the environment. + raw = os.popen('emerge info 2> /dev/null|grep CFLAGS') + lines = raw.readlines() + if len(lines): + cflags = lines[0].split('"')[1].split() + print "Got CFLAGS from emerge info." + cmdlist.extend(cflags) + else: + # Still no CFLAGS found, use these ... + cmdlist.extend(['-fno-strict-aliasing', '-DNDEBUG', '-g', '-O3', '-Wall', '-Wstrict-prototypes']) + + #sysconfig.get_config_var("CFLAGS").split() + # includes + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEDIR")) + cmdlist.append("-I" + sysconfig.get_config_var("INCLUDEPY")) + cmdlist.append("-I" + self.python_inc_dir) + cmdlist.append("-I" + self.kde_inc_dir) + cmdlist.append("-I" + self.qt_inc_dir) + cmdlist.append("-I.") + # input + cmdlist.append(cppfile) + # output + outputfile = os.path.join(self.build_dir,libraryname+'.lo') + cmdlist.append("-o") + cmdlist.append(outputfile) + spawn(cmdlist) # Execute!!! + print + + # Link the resulting object file to create a shared library. + cmdlist = ['libtool'] + cmdlist.append("--mode=link") + + # Grab the linker command name + cmdlist.append(sysconfig.get_config_var("LDSHARED").split()[0]) + # link_flags + cmdlist.append("-module") + cmdlist.append("-export-dynamic") + # object + cmdlist.append(outputfile) + cmdlist.append("-rpath"); cmdlist.append(self.kde_kioslave_lib_dir) + cmdlist.append("-o"); cmdlist.append(os.path.join(self.build_dir,stub_la_name)) + # Link libs + linklist = [] + linklist.append("-lpython%s" % python_version) + linklist.extend(sysconfig.get_config_var("LIBS").split()) + + # FIXME I doubt half of these libraries need to be here. + linklist.append(self.sip_dir+"/sip.so") + # PyQt libs + linklist.append(self.pyqt_dir+"/qt.so") + # PyKDE libs + linklist.append(self.pykde_dir+"/kdecore.so") + +# linklist.append("-L"+self.sip_dir); linklist.append("-lsip") +# # PyQt libs +# linklist.append("-L"+self.pyqt_dir); linklist.append("-lqtcmodule") +# # PyKDE libs +# linklist.append("-L"+self.pykde_dir); linklist.append("-lkdecorecmodule"); linklist.append("-lkdeuicmodule") + + linklist.append("-L"+self.kde_lib_dir); linklist.append("-L/opt/kde3/lib"); linklist.append("-lkdecore"); linklist.append("-lpythonize") + linklist.append("-L"+self.qt_lib_dir); linklist.append("-lqt-mt") + linklist.append("-lm") + linklist.append("-lstdc++") + linklist.append("-lc") + linklist.append(self.clib) + + linklist.append("-R"); linklist.append(self.python_dir) + linklist.append("-R"); linklist.append(self.qt_lib_dir) + linklist.append("-R"); linklist.append(self.sip_dir) + linklist.append("-R"); linklist.append(self.pyqt_dir) + linklist.append("-R"); linklist.append(self.pykde_dir) + linklist.append("-R"); linklist.append(self.kde_lib_dir) + + cmdlist.extend(linklist) + spawn(cmdlist) # Execute!! + print + + cpptemplate = r""" +/* + * Launch Control Centre modules written in Python using an embedded Python + * interpreter. + * Based on David Boddie's PyKDE-components. + */ + +#include <stdio.h> +#include <Python.h> +#include <kinstance.h> +#define MODULE_DIR "%(moduledir)s" +#define MODULE_NAME "%(modulename)s" +#define FACTORY "SlaveFactory" + +const char modname[] = MODULE_NAME; +#define MAIN_METHOD "dispatchLoop" + +FILE *d = NULL; + +PyObject* call_function(PyObject *callable, PyObject *args) { + PyObject *result, *pArgs; + + if (callable == NULL) { + printf(MODULE_NAME " kioslave error: callable == NULL in call_function\n"); + return NULL; + } + + if (PyCallable_Check(callable)) { + if(args == NULL) { + pArgs = PyTuple_New(0); + } else { + pArgs = args; + } + result = PyObject_CallObject(callable, pArgs); + + /* If the arguments were created is this function then decrease + their reference count. */ + if(args == NULL) { + Py_XDECREF(pArgs); + /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */ + } + + if(result == NULL) { + PyErr_Print(); + PyErr_Clear(); + } + } + + return result; +} + +extern "C" { + int kdemain( int argc, char **argv) { + PyObject *pModule, *pName, *pDict; + KInstance slave(MODULE_NAME); + + Py_SetProgramName(argv[0]); + Py_Initialize(); + //PyEval_InitThreads(); + PySys_SetArgv(1, argv); + + PyRun_SimpleString("import sys\n"); + PyRun_SimpleString("sys.path.append('"MODULE_DIR"')\n"); + + pName = PyString_FromString(modname); + pModule = PyImport_Import(pName); + + Py_XDECREF(pName); + + if(pModule == NULL) { + printf(MODULE_NAME " kioslave error: pModule == NULL\n"); + return 1; + } else { + PyObject *pClass, *pMethod, *pArgs, *pArg1, *pArg2, *pInstance; + int i; + + pDict = PyModule_GetDict(pModule); + /* pDict is a borrowed reference */ + + pClass = PyDict_GetItemString(pDict, FACTORY); + + if(pClass == NULL) { + printf(MODULE_NAME " kioslave error: pClass == NULL\n"); + return 1; + } else { + pArgs = PyTuple_New(2); + + pArg1 = PyString_FromString(argv[2]); + pArg2 = PyString_FromString(argv[3]); + + PyTuple_SetItem(pArgs, 0, pArg1); + PyTuple_SetItem(pArgs, 1, pArg2); + + call_function(pClass, pArgs); + + /* Some time later... */ + Py_XDECREF(pClass); + Py_XDECREF(pArgs); + } + + Py_XDECREF(pModule); + } + + Py_Finalize(); + return 0; + } +} +""" +########################################################################### +class InstallKioslave(Command): + description = "Install Kioslave files" + + user_options = [ + ('install-dir=', 'd', "base directory for installing kioslave module files"), + ('install-cmd=', None, "Command to use to install the files"), + ('install-protocol-dir=',None,"directory for kioslave protocol files"), + ('build-dir=','b', "build directory (where to install from)"), + ('root=', None, "install everything relative to this alternate root directory"), + ('force', 'f', "force installation (overwrite existing files)"), + ('skip-build', None, "skip the build steps"), + ] + boolean_options = ['force', 'skip-build'] + + def initialize_options(self): + self.build_dir = None + self.install_dir = None + self.install_cmd = None + self.install_protocol_dir = None + self.outfiles = [] + self.root = None + self.force = 0 + self.warn_dir = 1 + self.skip_build = None + + def finalize_options(self): + own_install_dir = self.install_dir is not None + own_install_protocol_dir = self.install_protocol_dir is not None + + self.set_undefined_options('install', + ('build_base', 'build_dir'), + ('install_kioslave', 'install_dir'), + ('root', 'root'), + ('force', 'force'), + ('skip_build', 'skip_build'), + ('install_cmd', 'install_cmd'), + ('install_protocol','install_protocol_dir') + ) + + if own_install_dir and self.root is not None: + self.install_dir = change_root(self.root,self.installdir) + + if own_install_protocol_dir and self.root is not None: + self.install_protocol_dir = change_root(self.root,self.install_protocol_dir) + + def get_command_name(self): + return 'install_kioslave' + + def run(self): + if not self.skip_build: + self.run_command('build_kioslave') + + self.announce("Installing Kioslave files...") + + for moduletuple in self.distribution.kioslaves: + self.announce("Building Kioslave module from protocol file %s." % moduletuple[0]) + + protocolfilename = moduletuple[0] + + # Read the protocol file + libraryname = None + try: + fhandle = open(protocolfilename,'r') + for line in fhandle.readlines(): + parts = line.strip().split('=') + try: + if parts[0]=="exec": + libraryname = parts[1] + except IndexError: + pass + fhandle.close() + except IOError: + raise SystemExit, "Failed to find kioslave protocol file: %s" % moduletuple[0] + + if libraryname is None: + raise SystemExit, "Failed to find library name (Was there a exec entry in the protocol file?)" + + self.outfiles.extend(self.mkpath(self.install_protocol_dir)) + protocolfile_dest = os.path.join(self.install_protocol_dir,os.path.basename(protocolfilename)) + self.copy_file(protocolfilename, protocolfile_dest) + + stub_la_name = libraryname+'.la' + + self.outfiles.extend(self.mkpath(self.install_dir)) + + # Install the library. + cmdlist = ['libtool'] + cmdlist.append("--mode=install") + cmdlist.append(self.install_cmd) + cmdlist.append("-c") + cmdlist.append(os.path.join(self.build_dir,stub_la_name)) + cmdlist.append(os.path.join(self.install_dir,stub_la_name)) + spawn(cmdlist) # Execute!! + print + + self.outfiles = [os.path.join(self.install_dir,os.path.basename(file)) for file in glob.glob(os.path.join(self.build_dir,'.libs',libraryname+'*'))] + self.outfiles.append(protocolfile_dest) + + self.announce("Done installing Kioslave files.") + + def get_outputs(self): + return self.outfiles or [] + + def mkpath(self, name, mode=0777): + return dir_util.mkpath(name, mode, dry_run=self.dry_run) + +########################################################################### +class CheckPyQt(Command): + description = "Checks for the presence of a working PyQt installation" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + self.min_qt_version = self.distribution.min_qt_version + + def run(self): + if self.min_qt_version!=None: + qtver,kdever = get_qt_kde_versions() + if compare_versions(self.min_qt_version,qtver)==1: + raise SystemExit, "Your Qt version is too old. Version %s or higher is required, found %s." % (self.min_qt_version,qtver) + self.announce("Found Qt version %s." % qtver) + try: + self.announce("Checking for a working PyQt...") + import qt + self.announce(" ...PyQt is working") + except: + raise SystemExit, "Couldn't import Qt! Please make sure that PyQt is installed and working." + + def get_outputs(self): return [] + +########################################################################### +class CheckPyKDE(Command): + description = "Checks for the presence of a working PyKDE installation" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + self.min_kde_version = self.distribution.min_kde_version + + def run(self): + if self.min_kde_version!=None: + qtver,kdever = get_qt_kde_versions() + if compare_versions(self.min_kde_version,kdever)==1: + raise SystemExit, "Your KDE version is too old. Version %s or higher is required, found %s." % (self.min_kde_version,kdever) + self.announce("Found KDE version %s." % kdever) + self.announce("Checking for a working PyKDE...") + + # Try to import modules one by one. + for k_module in ('dcop', 'kdecore', 'kdeui', 'kio', 'kfile', 'kparts', 'khtml', 'kspell'): + self.announce(k_module) + try: + exec('import ' + k_module) + except: + raise SystemExit, "Error: Couldn't find module '" + k_module + "'. \n" + \ + "Couldn't import KDE! Please make sure that PyKDE is installed and working.\n" + \ + "PyKDE is available here: http://www.riverbankcomputing.co.uk/pykde/index.php" + self.announce(" ...PyKDE is working") + + def get_outputs(self): return [] + +########################################################################### +def FindFileInPaths2(globpattern,canidatepaths): + if canidatepaths is None or len(canidatepaths)==0: + return (None,None) + + # Look for the globpattern on the path. + for path in canidatepaths: + if path!=None: + files = glob.glob(os.path.join(path, globpattern)) + if len(files)!=0: + return (path,os.path.basename(files[0])) + + # Continue searching with a breadth first search. + dirs = [] + for path in canidatepaths: + # Examine any directories on this path. + dirlist = glob.glob(os.path.join(path, "*")) + for item in dirlist: + if os.path.isdir(item): + # Examine each subdirectory. + dirs.append(item) + # Examine all subdirectories. + return FindFileInPaths2(globpattern, dirs) + +########################################################################### +def FindFileInPaths(globpattern,canidatepaths): + x,y = FindFileInPaths2(globpattern,canidatepaths) + return x + +########################################################################### +# FIXME replace this with spawn.find_executable(). +def FindExeOnPath(exe_name,high_prio_dirs=None,low_prio_dirs=None): + candiate_paths = [] + + if high_prio_dirs is not None: + candiate_paths.extend(high_prio_dirs) + + path_var = os.getenv("PATH") + candiate_paths.extend(path_var.split(':')) + + if low_prio_dirs is not None: + candiate_paths.extend(low_prio_dirs) + + for dir in candiate_paths: + if dir is not None: + candiate = os.path.join(dir,exe_name) + if os.path.isfile(candiate): + if os.access(candiate,os.X_OK): + return candiate + return None + +########################################################################### + +def ask_kde_config(question): + # Look for the kde-config program + kdeconfig = find_executable("kde-config", os.environ['PATH'] + os.pathsep + \ + os.pathsep.join(['/bin','/usr/bin','/opt/kde3/bin','/opt/kde/bin','/usr/local/bin'])) + if kdeconfig!=None: + # Ask the kde-config program for the + fhandle = os.popen(kdeconfig+' ' + question,'r') + result = fhandle.read() + fhandle.close() + return result + else: + return None + +########################################################################### +# Convert for example, "3.1.1a" => [3,1,1,'a'] +# +def split_version_name(name): + result = [] + accu = '' + type = 0 + for c in name: + if type==0: + if c.isdigit(): + type = 1 + else: + type = 2 + accu += c + elif c=='.': + if type==1: + result.append(int(accu)) + else: + result.append(accu) + accu = '' + type = 0 + elif type==1: + # Digits + if c.isdigit(): + accu += c + else: + result.append(int(accu)) + type = 2 + accu = c + else: + if c.isdigit(): + result.append(accu) + type = 1 + accu = c + else: + accu += c + if accu!='': + result.append(accu) + return result + +########################################################################### +# +# Returns: +# -1 if a < b +# 0 if a and b are equal +# 1 if a > b +def compare_versions(a,b): + aparts = split_version_name(a) + bparts = split_version_name(b) + if len(aparts)>len(bparts): + compmax = len(aparts) + else: + compmax = len(bparts) + i = 0 + for i in range(compmax): + abit = 0 + if i<len(aparts): + abit = aparts[i] + bit = 0 + if i<len(bparts): + bbit = bparts[i] + if isinstance(abit,str) and not isinstance(bbit,str): + return 1 + elif not isinstance(abit,str) and isinstance(bbit,str): + return -1 + else: + if abit>bbit: + return 1 + elif abit<bbit: + return -1 + return 0 + +########################################################################### +def get_qt_kde_versions(): + versioninfo = ask_kde_config('--version') + qtver = None + kdever = None + if versioninfo!=None: + for line in versioninfo.splitlines(): + if line.startswith("Qt: "): + qtver = line[4:] + elif line.startswith("KDE: "): + kdever = line[5:] + return qtver,kdever + +########################################################################### +def compile_qtdesigner(ui_files, + force=0, + prefix=None, base_dir=None, + verbose=1, dry_run=0): + """Compile a collection of QT Designer UI files to .py + + If 'dry_run' is true, doesn't actually do anything that would + affect the filesystem. + """ + generated_files = [] + for file in ui_files: + if not file.endswith(".ui"): + continue + + # Terminology from the py_compile module: + # cfile - byte-compiled file + # dfile - purported source filename (same as 'file' by default) + if base_dir: + file = os.path.join(base_dir ,file) + + pyfile = file[:-3] + '.py' + uifile = file + + pyfile_base = os.path.basename(pyfile) + if force or newer(uifile, pyfile): + log.info("compiling Qt-Designer UI %s to %s", file, pyfile_base) + if not dry_run: + qtuicompiler.CompileUI(uifile, pyfile) + generated_files.append(pyfile) + else: + log.debug("skipping Qt-Designer compilation of %s to %s", + file, pyfile_base) + return generated_files + +########################################################################### +def get_libdir_name(): + #if os.uname()[4] in ['x86_64','mips64','ppc64','sparc64','s390x']: + # return 'lib64' + #else: + return 'lib' |