From 6846befb2145afb7ca8fe24478ff812dc04584de Mon Sep 17 00:00:00 2001 From: Stephen George Date: Fri, 7 May 2010 11:03:48 +0000 Subject: [PATCH] Windows: Provide ability to patch a release version installer Windows: Generate a locale dependent launcher svn: r15347 --- windows/builder/build_GrampsWin32.py | 53 +++++++++- windows/builder/gramps2.nsi | 21 +++- windows/builder/make_launcher.py | 149 +++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 windows/builder/make_launcher.py diff --git a/windows/builder/build_GrampsWin32.py b/windows/builder/build_GrampsWin32.py index 59c76442b..942ccab76 100644 --- a/windows/builder/build_GrampsWin32.py +++ b/windows/builder/build_GrampsWin32.py @@ -478,6 +478,35 @@ class buildbase(gobject.GObject): log.debug( 'Version (%s)' % (vers) ) return vers + def copyPatchTreeToDest(self, src, dst): + '''Patch a tarball build with alternate files as required. + At this stage do not allow new directories to be made or + new files to be added, just replace existing files. + ''' + log.info('Patching: now in %s', src) + names = os.listdir(src) + #os.makedirs(dst) - not creating new dir + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if os.path.isfile(srcname) and os.path.isfile(dstname): + log.info('Overwriting %s -> %s' % (srcname, dstname)) + shutil.copyfile(srcname, dstname) + elif os.path.isdir(srcname) and os.path.isdir(dstname): + self.copyPatchTreeToDest(srcname, dstname) + else: + log.error('UNDEFINED: %s -> %s' % (srcname, dstname)) + except (IOError, os.error), why: + errors.append((srcname, dstname, str(why))) + # catch the Error from the recursive copytree so that we can + # continue with other files + except Error, err: + errors.extend(err.args[0]) + if errors: + raise Error(errors) + def buildGRAMPS( base, out_dir, bTarball): bo = buildbase() @@ -509,6 +538,8 @@ def buildGRAMPS( base, out_dir, bTarball): bo.generateConstPy( ) bo.copyExtraFilesToBuildDir(base) + if bPatchBuild: + bo.copyPatchTreeToDest( patch_dir, bo.build_root ) if bBuildAll: bo.processPO( ) if bo.bBuildInstaller: @@ -536,6 +567,12 @@ Options: --nsis_only Build NSIS only (does not Clean & Build All) -t --tarball Build release version from Tarball. -mDIR, --msgdir=DIR Directory to msgfmt.exe + -pDIR, --patch=DIR Specify a directory to patch files into the build. + only valid for a tarball build. + This directory will allow you to patch the release after expanding + from tarball and before creating installer. + (n.b. each file to be replaced needs to be specified with full path + to exactly mimic the paths in the expanded tarball) ''' # TODO: nsis_dir option - a path to nsismake (for occasions script cannot work it out) # TODO: svn_dir option - a path to svn (for occasions script cannot work it out) @@ -547,10 +584,11 @@ Options: bBuildInstaller = True bTarball = False msg_dir = "" - + bPatchBuild = False + patch_dir = "" try: - opts, args = getopt.getopt(sys.argv[1:], "ho:tm:", - ["help", "out=", "nsis_only", "tarball", "msgdir="]) + opts, args = getopt.getopt(sys.argv[1:], "ho:tm:p:", + ["help", "out=", "nsis_only", "tarball", "msgdir=", "patch="]) for o, a in opts: if o in ("-h", "--help"): @@ -569,12 +607,21 @@ Options: msg_dir = a else: raise getopt.GetoptError, '\nERROR: msgfmt dir does not exist' + if o in ("-p", "--patch"): + if os.path.isdir( a ): + patch_dir = a + bPatchBuild = True + else: + raise getopt.GetoptError, '\nERROR: Patch directory does not exist' if args: #got args use first one as base dir repository_path = path.normpath(args[0]) else: # no base dir passed in, work out one from current working dir repository_path = path.normpath("%s/../.." % os.getcwd() ) + if bPatchBuild and not bTarball: + log.warning("Cannot specify patch for SVN build, resetting patch option") + patch_dir = None # raise getopt.GetoptError, '\nERROR: No base directory specified' if len(args) > 1: diff --git a/windows/builder/gramps2.nsi b/windows/builder/gramps2.nsi index f256c05be..474f592be 100644 --- a/windows/builder/gramps2.nsi +++ b/windows/builder/gramps2.nsi @@ -377,6 +377,16 @@ Function TestDependancies ; MessageBox MB_OK "python: $PythonVerText $\ngtk++: $GTKVerText $\npygtk: $pyGTKVerText$\ngobject: $GObjectVerText$\ncario: $CairoVerText" FunctionEnd +Function WriteGrampsLauncher + SetOutPath $TEMP + + File make_launcher.py + nsExec::ExecToStack '"$PythonExe" $TEMP\make_launcher.py' + Pop $0 # return value/error/timeout + Pop $1 # printed text, up to ${NSIS_MAX_STRLEN} +FunctionEnd + + LangString PAGE_TITLE ${LANG_ENGLISH} "Summary of GRAMP's Dependencies" LangString PAGE_SUBTITLE ${LANG_ENGLISH} "" Var Dialog @@ -405,9 +415,9 @@ Function DependenciesPageFunction !insertmacro MUI_HEADER_TEXT $(PAGE_TITLE) $(PAGE_SUBTITLE) nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog - ${If} $Dialog == error - Abort - ${EndIf} + ${If} $Dialog == error + Abort + ${EndIf} SetOutPath $TEMP @@ -561,6 +571,7 @@ Section "MainSection" SEC01 File /r ${GRAMPS_BUILD_PATH}\*.* WriteRegStr HKLM "SOFTWARE\${PRODUCT_NAME}" "" "$INSTDIR" WriteRegStr HKLM "SOFTWARE\${PRODUCT_NAME}" "version" ${PRODUCT_VERSION} + Call WriteGrampsLauncher SectionEnd @@ -674,8 +685,12 @@ Section -AdditionalIcons SetOutPath $INSTDIR WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" + + IfFileExists '$INSTDIR\gramps_locale.cmd' 0 NoLocaleFile # $3 should contain the path to python, .. then pass gramps.py as an argument #CreateShortCut link.lnk target.file [parameters [icon.file [icon_index_number [start_options[keyboard_shortcut [description]]]]]] + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} (locale) ${PRODUCT_VERSION}.lnk" CMD "/C $\"$INSTDIR\gramps_locale.cmd$\"" "$INSTDIR\images\ped24.ico" "0" "" "" "GRAMPS" + NoLocaleFile: CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} ${PRODUCT_VERSION}.lnk" "$3" "$\"$INSTDIR\gramps.py$\"" "$INSTDIR\images\ped24.ico" "0" "" "" "GRAMPS" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" diff --git a/windows/builder/make_launcher.py b/windows/builder/make_launcher.py new file mode 100644 index 000000000..c9d13eaea --- /dev/null +++ b/windows/builder/make_launcher.py @@ -0,0 +1,149 @@ +# SetLanguage.py +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# $Id: $ +import locale +import _winreg +import sys +import os + +import logging +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(name)-10s %(levelname)-8s %(message)s', + datefmt='%H:%M', + filename= 'c:/launcher.log', #path.join(out_dir,'build.log'), + filemode='w') +#create a Handler for the console +console = logging.StreamHandler() +console.setLevel(logging.INFO) +#Set a simle format for console +formatter = logging.Formatter('%(levelname)-8s %(message)s') +console.setFormatter(formatter) +#add the console handler to the root handler +log = logging.getLogger('BuildApp') +log.addHandler(console) + + +langLookup = { + 'ar' : 'Arabic', + 'bg' : 'Bulgarian', + 'ca' : 'Catalan', + 'cs' : 'Czech', + 'da' : 'Danish ', + 'de' : 'German', + 'en' : 'English', + 'eo' : '', + 'es' : 'Spanish', + 'fi' : 'Finnish', + 'fr' : 'French', + 'he' : 'Hebrew', + 'hr' : 'Croatian', + 'hu' : 'Hungarian', + 'it' : 'Italian', + 'lt' : 'Lithuanian', + 'mk' : 'Macedonian', + 'nb' : '', + 'nl' : 'Dutch', + 'nn' : '', + 'pl' : 'Polish', + 'pt_BR' : 'Portuguese (Brazil)', + 'ro' : 'Romanian', + 'ru' : 'Russian', + 'sk' : 'Slovak', + 'sl' : 'Slovenian', + 'sq' : 'Albanian', + 'sr' : 'Serbian', + 'sv' : 'Swedish', + 'tr' : 'Turkish', + 'zh_CN' : 'Chinese (PRC)', + } + +def GetGtkPath(): + log.debug('GetGtkPath()') + dllPathInRegistry = None + try: + with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\GTK\\2.0') as key: + dllPathInRegistry = _winreg.QueryValueEx(key, 'DllPath')[0] + # check a few key files exist at this location + gtkfiles = ['libgdk-win32-2.0-0.dll', 'libglib-2.0-0.dll', 'libgobject-2.0-0.dll', 'libcairo-2.dll'] + for file in gtkfiles: + if not os.path.isfile(os.path.join(dllPathInRegistry, file)): + dllPathInRegistry = None # one of the files not present, so assume path is wrong + break + except WindowsError, e: + dllPathInRegistry = None + log.debug(' DLLPATH=%s'%dllPathInRegistry) + return dllPathInRegistry + +def GetGrampsPath(): + GrampsPathInRegistry = None + try: + with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\GRAMPS') as key: + GrampsPathInRegistry = _winreg.QueryValue(key, '') + # check a few key files exist at this location + except WindowsError, e: + GrampsPathInRegistry = None + + log.debug(' GRAMPSPATH=%s'%GrampsPathInRegistry) + return GrampsPathInRegistry + +def GetLanguageFromLocale(): + lang = ' ' + try: + lang = os.environ["LANG"] + lang = lang.split('.')[0] + except: + # if LANG is not set + lang = locale.getlocale()[0] + if not lang: + # if lang is empty/None + lang = locale.getdefaultlocale()[0] + return lang + +def writeLauncher(language, langcode, runtimepath, grampspath): + lines = [] + lines.append('\n@rem Command file to set %s language for Gramps \n' % language) + lines.append('SET LANG=$LANG$ \nSET LANGUAGE=$LANG$\n'.replace("$LANG$", langcode) ) + if runtimepath: + path = '\npath="%s";%%PATH%%' % runtimepath + else: + path = "\n@rem path=PATH_TO_YOUR_GTK_RUNTIME;%%PATH%%\n" + lines.append(path) + lines.append('\n@rem start Gramps') + lines.append('\n"%s" "%s"\n' % (os.path.join(sys.prefix, 'pythonw.exe') , os.path.join(grampspath, 'gramps.py' ) )) + fout = open( os.path.join(grampspath, 'gramps_locale.cmd'), 'w') + fout.writelines(lines) + fout.close() + for line in lines: + print line + +gtkpath = GetGtkPath() +grampspath = GetGrampsPath() +lang = GetLanguageFromLocale() +if lang: + try: + lang_text = langLookup[lang.split('_', 1)[0]] + except KeyError, e: + try: + lang_text = langLookup[lang] + except KeyError, e: + lang_text = "Unknown" + + writeLauncher(lang_text, "%s.UTF8"%lang, gtkpath, grampspath)