370 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#
 | 
						|
# Gramps - a GTK+ based genealogy program
 | 
						|
#
 | 
						|
# Copyright (C) 2010       Stephen George
 | 
						|
#
 | 
						|
# This program is free software; you can redistribute it and/or modify
 | 
						|
# it under the terms of the GNU General Public License as published by
 | 
						|
# the Free Software Foundation; either version 2 of the License, or
 | 
						|
# (at your option) any later version.
 | 
						|
#
 | 
						|
# This program is distributed in the hope that it will be useful,
 | 
						|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
# GNU General Public License for more details.
 | 
						|
#
 | 
						|
# You should have received a copy of the GNU General Public License
 | 
						|
# along with this program; if not, write to the Free Software
 | 
						|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
						|
#
 | 
						|
# $Id: $
 | 
						|
import sys
 | 
						|
import os
 | 
						|
import _winreg
 | 
						|
from ctypes.util import find_library
 | 
						|
import getopt
 | 
						|
import string
 | 
						|
 | 
						|
NOT_FOUND_STR ='Not Found'
 | 
						|
#small selection of DLL's to test
 | 
						|
testdlls = ['libgdk-win32-2.0-0.dll', 'libglib-2.0-0.dll', 'libgobject-2.0-0.dll', 'libcairo-2.dll', ]
 | 
						|
 | 
						|
explain_exposed = '''    ***********************************************************
 | 
						|
    * It seems that other installations are exposing GTK DLL's
 | 
						|
    * to the operating system as they are in the environment
 | 
						|
    * path variable BEFORE the runtime directory.
 | 
						|
    * You should reorder the path variable to put your GTK
 | 
						|
    * runtime path before these other installations on the path'''
 | 
						|
 | 
						|
explain_safe = '''    ***************************************************************
 | 
						|
    * While there are other installations of GTK DLL's on the path,
 | 
						|
    * it should be safe as they are on the path AFTER the runtime
 | 
						|
    * directory. '''
 | 
						|
 | 
						|
def RunExeCommand( app, args ):
 | 
						|
    cmd = app + ' ' + args
 | 
						|
    #print("Running: ", cmd)
 | 
						|
    stdin, stdout, stderr = os.popen3( cmd )
 | 
						|
    output = string.strip(stdout.read())
 | 
						|
    #print(output)
 | 
						|
    err = stderr.read()
 | 
						|
    if err:
 | 
						|
        print(err)
 | 
						|
    return output
 | 
						|
 | 
						|
def CheckGtkInReg():
 | 
						|
    global gtkPathInRegistry, gtkVersionInRegistry, dllPathInRegistry, dllPathShort
 | 
						|
    print('\n==== Checking Registry for GTK =====')
 | 
						|
    try:
 | 
						|
        with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\GTK\\2.0') as key:
 | 
						|
            gtkVersionInRegistry = _winreg.QueryValueEx(key, 'Version')[0]
 | 
						|
            gtkPathInRegistry = _winreg.QueryValueEx(key, 'Path')[0]
 | 
						|
            dllPathInRegistry = _winreg.QueryValueEx(key, 'DllPath')[0]
 | 
						|
            print('  Version   :', gtkVersionInRegistry)
 | 
						|
            print('  Path      :', gtkPathInRegistry)
 | 
						|
            print('  DllPath   :', dllPathInRegistry)
 | 
						|
 | 
						|
    except WindowsError as e:
 | 
						|
        print('\n  GTK registry key not found in registry')
 | 
						|
        print('''    ********************************************************************
 | 
						|
    * This might not be an error, but means I don't know the directory to
 | 
						|
    * your preferred GTK installation.
 | 
						|
    *  - try passing in your GTK installation path.\n''')
 | 
						|
        print('-' * 60)
 | 
						|
        print(usage)
 | 
						|
        sys.exit(0)
 | 
						|
 | 
						|
def WorkOutShortDosPath():
 | 
						|
    global dllPathShort
 | 
						|
    print('\n==== Use win32Api to query short path name for GTK =====')
 | 
						|
    try:
 | 
						|
        import win32api
 | 
						|
        dllPathShort =  win32api.GetShortPathName(dllPathInRegistry)
 | 
						|
        print('  DllPath8.3:', dllPathShort)
 | 
						|
    except ImportError:
 | 
						|
        print('  **Cant query short path name, Win32Api not installed')
 | 
						|
        print('    install from http://python.net/crew/mhammond/win32/')
 | 
						|
        print('    if you want this function to work')
 | 
						|
 | 
						|
def FindLibsWithCtypes():
 | 
						|
    # use ctypes to check where windows finds it's DLL's
 | 
						|
    print('\n==== Use ctypes to find dlls ====')
 | 
						|
    other_paths = []
 | 
						|
    for dll in testdlls:
 | 
						|
        dllpathvalid = False
 | 
						|
        cpath = find_library(dll)
 | 
						|
        if cpath:
 | 
						|
        #print(cpath)
 | 
						|
            if cpath == os.path.join(dllPathInRegistry, dll) \
 | 
						|
            or cpath == os.path.join(dllPathShort, dll):
 | 
						|
                dllpathvalid = True
 | 
						|
 | 
						|
            if not dllpathvalid:
 | 
						|
                pp = os.path.dirname(cpath)
 | 
						|
                if pp not in other_paths:
 | 
						|
                    other_paths.append(pp)
 | 
						|
        else:
 | 
						|
            print("  ERROR:... ctypes failed to find %s" % dll)
 | 
						|
    if other_paths:
 | 
						|
        for pth in other_paths:
 | 
						|
            print("  ERROR: ctypes loaded some gtk dll's from %s" % pth)
 | 
						|
    else:
 | 
						|
        print("  OK ... ctypes found dll's in %s" % os.path.dirname(cpath))
 | 
						|
 | 
						|
def ScanDependencyFileForErrors(fname):
 | 
						|
    fin = open(fname, 'r')
 | 
						|
    lines = fin.readlines()
 | 
						|
    fin.close()
 | 
						|
    sysroot = os.environ["SystemRoot"]
 | 
						|
    capture = False
 | 
						|
    runtimedlls = {}
 | 
						|
    for line in lines:
 | 
						|
        if line.startswith("       Module"): # work out were paths end
 | 
						|
            pthend_idx = line.find("File Time Stamp")
 | 
						|
        acceptablePaths = [ dllPathShort.lower(),
 | 
						|
                            dllPathInRegistry.lower(),
 | 
						|
                            os.path.join(sysroot, 'system32').lower()
 | 
						|
                          ]
 | 
						|
        if line.startswith('-----  ------------'):
 | 
						|
            capture = True
 | 
						|
        if capture and line.startswith('['):
 | 
						|
            filename = line[5:pthend_idx].strip()
 | 
						|
            dirname = os.path.dirname(filename).strip()
 | 
						|
            parts = line[pthend_idx:].split()
 | 
						|
            OK = False
 | 
						|
            if dirname.startswith(os.path.join(sysroot, 'winsxs').lower()) \
 | 
						|
            or dirname.startswith(os.path.join(sys.prefix, 'lib\site-packages\gtk-2.0').lower()):
 | 
						|
                OK = True
 | 
						|
 | 
						|
            for pth in acceptablePaths:
 | 
						|
                if dirname == pth.lower():
 | 
						|
                    OK = True
 | 
						|
 | 
						|
            if 'MSVCR90.DLL' in filename:
 | 
						|
                if parts[0] == 'Error':
 | 
						|
                    runtimedlls[filename] = "Error dll not found"
 | 
						|
                else:
 | 
						|
                    runtimedlls[filename] = parts[16]
 | 
						|
 | 
						|
            if OK == False:
 | 
						|
                if parts[0] == 'Error':
 | 
						|
                    print("    %s \tError dll not found" %( filename))
 | 
						|
                else:
 | 
						|
                    print("    ERROR: %s \tVersion %s" %( filename, parts[16]))
 | 
						|
    for rtdll in runtimedlls:
 | 
						|
        if runtimedlls[rtdll].startswith("Error"):
 | 
						|
            print('\n    ERROR: MS runtime %s not found'%rtdll)
 | 
						|
        else:
 | 
						|
            print('\n    MS runtime Version %s loaded from' % runtimedlls[rtdll])
 | 
						|
            print("    %s" %rtdll)
 | 
						|
    print()
 | 
						|
 | 
						|
def CheckWithDependencyWalker():
 | 
						|
    print('\n==== Checking with Dependency Walker ====')
 | 
						|
    print('      Please be patient takes some time')
 | 
						|
    exe = os.path.join(scriptpath, 'depends.exe')
 | 
						|
    fout = os.path.join(scriptpath, 'depres.txt')
 | 
						|
    f2check = [
 | 
						|
                os.path.join(sys.prefix, 'Lib/site-packages/gtk-2.0/gtk/_Gtk.pyd' ),
 | 
						|
                os.path.join(sys.prefix, 'Lib/site-packages/gtk-2.0/gobject/_GObject.pyd' ),
 | 
						|
                os.path.join(sys.prefix, 'Lib/site-packages/gtk-2.0/pangocairo.pyd' ),
 | 
						|
                ]
 | 
						|
    if os.path.isfile( exe ):
 | 
						|
        for ftest in f2check:
 | 
						|
            if os.path.isfile( ftest ):
 | 
						|
                #delete the output file before running command
 | 
						|
                try:
 | 
						|
                    os.remove(fout)
 | 
						|
                except WindowsError as e:
 | 
						|
                    pass
 | 
						|
                print('  Testing file %s' % ftest)
 | 
						|
                out = RunExeCommand(exe, '/c /f1 /ot "%s" "%s"' % (fout, ftest) )
 | 
						|
                if os.path.isfile(fout):
 | 
						|
                    ScanDependencyFileForErrors(fout)
 | 
						|
            else:
 | 
						|
                print("  ERROR: file %d does not exist", ftest)
 | 
						|
    else:
 | 
						|
        print('  Cannot check with dependency walker, not installed in local directory')
 | 
						|
        print('  get dependency walker from http://www.dependencywalker.com/')
 | 
						|
        print('  and unzip into this directory for it to work.')
 | 
						|
 | 
						|
def CheckPathForOtherGtkInstalls():
 | 
						|
    print('\n====Checking environment path for other gtk installations====')
 | 
						|
    ePath = os.environ['path']
 | 
						|
    dirs = ePath.split(';')
 | 
						|
    gtkpth_idx = 9999
 | 
						|
    other_paths = []
 | 
						|
    explain_level = 0
 | 
						|
    for i, d in enumerate(dirs):
 | 
						|
        #print('==%s==' %d)
 | 
						|
        if d == gtkPathInRegistry or d == dllPathInRegistry\
 | 
						|
        or d == dllPathShort:
 | 
						|
            gtkpth_idx = i
 | 
						|
            continue
 | 
						|
        for fname in testdlls:
 | 
						|
            f = os.path.join(d, fname)
 | 
						|
            if os.path.isfile( f ):
 | 
						|
                #print('   Found Erronous gtk DLL %s' % f)
 | 
						|
                if d not in other_paths:
 | 
						|
                    other_paths.append(d)
 | 
						|
                    if i < gtkpth_idx: # path appears BEFORE runtime path
 | 
						|
                        print('  ERROR: %s should not appear before runtime path' % d)
 | 
						|
                        explain_level = 2
 | 
						|
                    else:
 | 
						|
                        print('  FOUND: %s, Probably OK as appears AFTER runtime path' % d)
 | 
						|
                        if explain_level <= 1:
 | 
						|
                            explain_level = 1
 | 
						|
    if gtkpth_idx == 9999:
 | 
						|
        print('\n  ERROR: Runtime directory not on enviroment path')
 | 
						|
        print("         ** Runtime needs to be on path to load DLL's from\n")
 | 
						|
    if explain_level == 2:
 | 
						|
        print(explain_exposed)
 | 
						|
    elif explain_level == 1:
 | 
						|
        print(explain_safe)
 | 
						|
    if len(other_paths) == 0:
 | 
						|
        print('  No other gtk installatons found\n')
 | 
						|
 | 
						|
# ==== report what python thinks it's using =====
 | 
						|
MIN_PYTHON_VER   = (2,5,1)
 | 
						|
UNTESTED_PYTHON_VER = (3,0,0)
 | 
						|
 | 
						|
MIN_GTK_VER      = (2,10,11)
 | 
						|
UNTESTED_GTK_VER = (2,16,7)
 | 
						|
 | 
						|
MIN_PYGTK_VER    = (2,10,6)
 | 
						|
UNTESTED_PYGTK_VER    = (2,12,2)
 | 
						|
 | 
						|
MIN_GOBJECT_VER  = (2,12,3)
 | 
						|
UNTESTED_GOBJECT_VER  = (2,14,3)
 | 
						|
 | 
						|
MIN_CAIRO_VER    = (1,2,6)
 | 
						|
UNTESTED_CAIRO_VER    = (1,4,13)
 | 
						|
 | 
						|
def PrintFailedImport(appl, minVersion, result):
 | 
						|
    print(appl,)
 | 
						|
    print('version %d.%d.%d or above.....\t' % minVersion ,)
 | 
						|
    print(result)
 | 
						|
 | 
						|
def PrintVersionResult(appl, minVersion, actualVersion, untestedVersion):
 | 
						|
    print(appl,)
 | 
						|
    print('version %d.%d.%d or above.....\t' % minVersion ,)
 | 
						|
    print('found %d.%d.%d' % actualVersion ,)
 | 
						|
    if minVersion <= actualVersion < untestedVersion:
 | 
						|
        print('...OK')
 | 
						|
    elif  actualVersion >= untestedVersion:
 | 
						|
        print('...UNTESTED VERSION')
 | 
						|
    else:
 | 
						|
        print('...FAILED')
 | 
						|
 | 
						|
def Import_pyGtkIntoPython():
 | 
						|
    print('\n==== Test import into python ====')
 | 
						|
    #py_str = 'found %d.%d.%d' %  sys.version_info[:3]
 | 
						|
    PrintVersionResult('  Python ', MIN_PYTHON_VER, sys.version_info[:3], UNTESTED_PYTHON_VER)
 | 
						|
 | 
						|
    # Test the GTK version
 | 
						|
    try:
 | 
						|
        import gtk
 | 
						|
 | 
						|
        PrintVersionResult('  GTK+   ', MIN_GTK_VER, Gtk.gtk_version, UNTESTED_GTK_VER )
 | 
						|
 | 
						|
        #test the pyGTK version (which is in the gtk namespace)
 | 
						|
        PrintVersionResult('  pyGTK  ', MIN_PYGTK_VER, Gtk.pygtk_version, UNTESTED_PYGTK_VER )
 | 
						|
 | 
						|
    except ImportError:
 | 
						|
        PrintFailedImport('  GTK+   ', MIN_GTK_VER, NOT_FOUND_STR)
 | 
						|
        PrintFailedImport('  pyGTK  ', MIN_PYGTK_VER, 'Cannot test, ...GTK+ missing')
 | 
						|
 | 
						|
 | 
						|
    #test the gobject version
 | 
						|
    try:
 | 
						|
        import gobject
 | 
						|
        PrintVersionResult('  gobject', MIN_GOBJECT_VER, GObject.pygobject_version, UNTESTED_GOBJECT_VER) 
 | 
						|
 | 
						|
    except ImportError:
 | 
						|
        PrintFailedImport('  gobject', MIN_GOBJECT_VER, NOT_FOUND_STR)
 | 
						|
 | 
						|
 | 
						|
    #test the cairo version
 | 
						|
    try:
 | 
						|
        import cairo
 | 
						|
        PrintVersionResult('  cairo  ', MIN_CAIRO_VER, cairo.version_info, UNTESTED_CAIRO_VER )
 | 
						|
 | 
						|
    except ImportError:
 | 
						|
        PrintFailedImport('  cairo  ', MIN_CAIRO_VER, NOT_FOUND_STR)
 | 
						|
 | 
						|
    #test for glade
 | 
						|
    print('\n==== See if libglade installed ====')
 | 
						|
 | 
						|
    try:
 | 
						|
        import Gtk.glade
 | 
						|
        print('  Glade   tesing import of libglade .......\tOK\n')
 | 
						|
    except ImportError as e:
 | 
						|
        print('  Glade   importError: %s\n' % e)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    usage = '''Check for common problems in GTK/pyGTK installation.
 | 
						|
Usage:
 | 
						|
    python %s [options] [gtkPath]
 | 
						|
 | 
						|
Arguments:
 | 
						|
    gtkPath                    Path to your GTK installation directory (not the bin dir)
 | 
						|
 | 
						|
Options:
 | 
						|
    None
 | 
						|
    ''' %(os.path.basename(__file__) )
 | 
						|
 | 
						|
    gtkPath = None
 | 
						|
    gtkPathInRegistry = NOT_FOUND_STR
 | 
						|
    gtkVersionInRegistry = NOT_FOUND_STR
 | 
						|
    dllPathInRegistry = NOT_FOUND_STR
 | 
						|
    dllPathShort = 'NoShortPath'
 | 
						|
    scriptpath = os.path.dirname(sys.argv[0])
 | 
						|
    try:
 | 
						|
        opts, args = getopt.getopt(sys.argv[1:], "",
 | 
						|
                                  [])
 | 
						|
 | 
						|
        for o, a in opts:
 | 
						|
            if o in ("-h", "--help"):
 | 
						|
                print(usage)
 | 
						|
                sys.exit(0)
 | 
						|
 | 
						|
        if len(args) > 1:
 | 
						|
            raise getopt.GetoptError('\nERROR: Too many arguments')
 | 
						|
        for arg in args:
 | 
						|
            if os.path.isdir(arg):
 | 
						|
                gtkPath = arg
 | 
						|
            else:
 | 
						|
                raise getopt.GetoptError('\nERROR: Not a valid GTK path %s' % arg)
 | 
						|
 | 
						|
    except getopt.GetoptError as msg:
 | 
						|
        print(msg)
 | 
						|
        print('\n %s' % usage)
 | 
						|
        sys.exit(2)
 | 
						|
 | 
						|
    import platform
 | 
						|
    winver = platform.win32_ver()
 | 
						|
    if len(winver) == 4:
 | 
						|
        print('''\n==== platform.win32_ver() reports ====
 | 
						|
  Operating System: %s
 | 
						|
  Version         : %s
 | 
						|
  Service Pack    : %s
 | 
						|
  OS type         : %s''' %  winver)
 | 
						|
    else:
 | 
						|
        print(winver)
 | 
						|
 | 
						|
    if gtkPath:
 | 
						|
        gtkPathInRegistry = gtkPath
 | 
						|
        dllPathInRegistry = os.path.join(gtkPath, 'bin')
 | 
						|
        print('  Using %s as GTK install path' % gtkPathInRegistry)
 | 
						|
        print('  Using %s as GTK dll path' % dllPathInRegistry)
 | 
						|
    else:
 | 
						|
        CheckGtkInReg()
 | 
						|
 | 
						|
    WorkOutShortDosPath()
 | 
						|
    FindLibsWithCtypes()
 | 
						|
    CheckPathForOtherGtkInstalls()
 | 
						|
    Import_pyGtkIntoPython()
 | 
						|
 | 
						|
    CheckWithDependencyWalker()
 | 
						|
 |