diff --git a/setup.py b/setup.py index 38301d2098..2f0f55eab2 100644 --- a/setup.py +++ b/setup.py @@ -21,232 +21,6 @@ import ez_setup ez_setup.use_setuptools() from setuptools import setup, find_packages -################################# py2exe ####################################### -py2exe_options = {} -if sys.argv[1] == 'py2exe': - py2exe_dir = 'c:\libprs500' - fonts = ['src/libprs500/ebooks/lrf/fonts/prs500'] - try: - import py2exe, glob - console = [ - {'script' : 'src/libprs500/devices/prs500/cli/main.py', 'dest_base':'prs500'}, - {'script' : 'src/libprs500/ebooks/lrf/html/convert_from.py', 'dest_base':'html2lrf'}, - {'script' : 'src/libprs500/ebooks/lrf/txt/convert_from.py', 'dest_base':'txt2lrf'}, - {'script' : 'src/libprs500/ebooks/lrf/meta.py', 'dest_base':'lrf-meta'}, - {'script' : 'src/libprs500/ebooks/metadata/rtf.py', 'dest_base':'rtf-meta'}, - ] - windows = [{'script' : 'src/libprs500/gui/main.py', 'dest_base':'prs500-gui', - 'icon_resources':[(1,'icons/library.ico')]}] - excludes = ["Tkconstants", "Tkinter", "tcl", "_imagingtk", - "ImageTk", "FixTk", 'pydoc'] - options = { 'py2exe' : {'includes' : ['sip', 'pkg_resources'], - 'dist_dir' : py2exe_dir, - 'packages' : ['PIL'], - 'excludes' : excludes}} - py2exe_options = {'console' : console, 'windows' : windows, - 'options' : options} - - dest_dir = py2exe_dir + '\\fonts\\' - if os.path.exists(dest_dir): - shutil.rmtree(dest_dir, True) - from distutils.filelist import FileList - fl = FileList() - fl.include_pattern('^src.*\.ttf$', is_regex=True) - fl.findall() - - for file in fl.files: - dir = dest_dir + os.path.basename(os.path.dirname(file)) - if not os.path.exists(dir): - os.makedirs(dir) - shutil.copy(file, dir) - except ImportError: - print >>sys.stderr, 'Failed to import py2exe' - sys.exit(1) - installer = \ -r''' -SetCompressor lzma -ShowInstDetails show -ShowUnInstDetails show - -;------------------------------------------------------------------------------------------------------ -;Include Modern UI - !include "AddToPath.nsh" - !include "XPUI.nsh" - !define XPUI_SKIN "Windows XP" - -;------------------------------------------------------------------------------------------------------ -;Variables -Var STARTMENU_FOLDER -Var MUI_TEMP - -!define PRODUCT_NAME "libprs500" -!define XPUI_BRANDINGTEXT "${PRODUCT_NAME} created by Kovid Goyal" -!define PRODUCT_VERSION "'''+VERSION+r'''" -!define WEBSITE "https://libprs500.kovidgoyal.net" -!define DEVCON "C:\devcon\i386\devcon.exe" -!define PY2EXE_DIR "C:\libprs500" -!define LIBUSB_DIR "C:\libusb-prs500" -!define LIBUNRAR_DIR "C:\Program Files\UnrarDLL" - -;------------------------------------------------------------------------------------------------------ -;General - - ;Name and file - Name "${PRODUCT_NAME}" - OutFile "dist\${PRODUCT_NAME}-${PRODUCT_VERSION}.exe" - - ;Default installation folder - InstallDir "$PROGRAMFILES\${PRODUCT_NAME}" - - ;Get installation folder from registry if available - InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" "" - - ;Vista redirects $SMPROGRAMS to all users without this - RequestExecutionLevel admin - -;------------------------------------------------------------------------------------------------------ -;Interface Settings - - !define MUI_HEADERIMAGE - !define MUI_HEADERIMAGE_BITMAP "icons\library.ico" - !define MUI_ABORTWARNING - -;------------------------------------------------------------------------------------------------------ -;Pages - - !insertmacro MUI_PAGE_WELCOME - !insertmacro MUI_PAGE_LICENSE "LICENSE" - !insertmacro MUI_PAGE_COMPONENTS - !insertmacro MUI_PAGE_DIRECTORY - ;Start Menu Folder Page Configuration - !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" - !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${PRODUCT_NAME}" - !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" - - !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER - !insertmacro MUI_PAGE_INSTFILES - - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_UNPAGE_FINISH -;------------------------------------------------------------------------------------------------------ -;Languages - - !insertmacro MUI_LANGUAGE "English" -;------------------------------------------------------------------------------------------------------ -;Installer Sections - -Function .onInit - ; Prevent multiple instances of the installer from running - System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${PRODUCT_NAME}-setup") i .r1 ?e' - Pop $R0 - - StrCmp $R0 0 +3 - MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." - Abort - -FunctionEnd - - -Section "libprs500" Seclibprs500 - - SetOutPath "$INSTDIR" - - ;ADD YOUR OWN FILES HERE... - File /r "${PY2EXE_DIR}\*" - - SetOutPath "$INSTDIR\driver" - File "${LIBUSB_DIR}\*.dll" - File "${LIBUSB_DIR}\*.sys" - File "${LIBUSB_DIR}\*.cat" - File "${LIBUSB_DIR}\*.inf" - File "${DEVCON}" - - SetOutPath "$SYSDIR" - File "${LIBUSB_DIR}\libusb0.dll" - File "${LIBUNRAR_DIR}\unrar.dll" - DetailPrint " " - - DetailPrint "Installing USB driver for prs500..." - ExecWait '"$INSTDIR\driver\devcon.exe" install "$INSTDIR\driver\prs500.inf" "USB\VID_054C&PID_029B"' $0 - DetailPrint "devcon returned exit code $0" - IfErrors 0 +2 - MessageBox MB_OK "Failed to install USB driver. devcon exit code: $0" - DetailPrint " " - - - ;Store installation folder - WriteRegStr HKCU "Software\${PRODUCT_NAME}" "" $INSTDIR - - ;Create uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "DisplayName" "${PRODUCT_NAME} -- E-book management software" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ - "UninstallString" "$INSTDIR\Uninstall.exe" - - SetOutPath "$INSTDIR" - !insertmacro MUI_STARTMENU_WRITE_BEGIN Application - - ;Create shortcuts - WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${WEBSITE}" - CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\libprs500.lnk" "$INSTDIR\prs500-gui.exe" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" - CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\prs500-gui.exe" - - !insertmacro MUI_STARTMENU_WRITE_END - - ;Add the installation directory to PATH for the commandline tools - Push "$INSTDIR" - Call AddToPath - -SectionEnd -;------------------------------------------------------------------------------------------------------ -;Descriptions - - ;Language strings - LangString DESC_Seclibprs500 ${LANG_ENGLISH} "The GUI and command-line tools for working with ebooks" - - ;Assign language strings to sections - !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${Seclibprs500} $(DESC_Seclibprs500) - !insertmacro MUI_FUNCTION_DESCRIPTION_END -;------------------------------------------------------------------------------------------------------ -;Uninstaller Section - -Section "Uninstall" - ;ADD YOUR OWN FILES HERE... - RMDir /r "$INSTDIR" - !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP - RMDir /r "$SMPROGRAMS\$MUI_TEMP" - ;Delete empty start menu parent diretories - StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" - - startMenuDeleteLoop: - ClearErrors - RMDir $MUI_TEMP - GetFullPathName $MUI_TEMP "$MUI_TEMP\.." - - IfErrors startMenuDeleteLoopDone - - StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop - startMenuDeleteLoopDone: - Delete "$DESKTOP\${PRODUCT_NAME}.lnk" - - DeleteRegKey /ifempty HKCU "Software\${PRODUCT_NAME}" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" - ; Remove installation directory from PATH - Push "$INSTDIR" - Call un.RemoveFromPath - -SectionEnd -''' - f = open('installer.nsi', 'w').write(installer) - -################################################################################ - if sys.hexversion < 0x2050000: print >> sys.stderr, "You must use python >= 2.5 Try invoking this script as python2.5 setup.py." @@ -281,7 +55,7 @@ setup( 'txt2lrf = libprs500.ebooks.lrf.txt.convert_from:main', \ 'html2lrf = libprs500.ebooks.lrf.html.convert_from:main',\ ], - 'gui_scripts' : [ 'prs500-gui = libprs500.gui.main:main'] + 'gui_scripts' : [ 'libprs500 = libprs500.gui.main:main'] }, zip_safe = True, description = @@ -320,8 +94,7 @@ setup( 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Hardware :: Hardware Drivers' - ], - **py2exe_options + ] ) if '--uninstall' in ' '.join(sys.argv[1:]): diff --git a/src/libprs500/__init__.py b/src/libprs500/__init__.py index 01e4bc8f6f..aac4ded34a 100644 --- a/src/libprs500/__init__.py +++ b/src/libprs500/__init__.py @@ -16,6 +16,7 @@ __version__ = "0.3.47" __docformat__ = "epytext" __author__ = "Kovid Goyal " +__appname__ = 'libprs500' import sys iswindows = 'win32' in sys.platform.lower() diff --git a/windows_installer.py b/windows_installer.py new file mode 100644 index 0000000000..c1630fb7c7 --- /dev/null +++ b/windows_installer.py @@ -0,0 +1,303 @@ +''' Create a windows installer ''' +import sys, re, os, shutil, subprocess +sys.path.append('src') +sys.argv[1:2] = ['py2exe'] +if '--verbose' not in ' '.join(sys.argv): + sys.argv.append('--quiet') #py2exe produces too much output by default +from distutils.core import setup +from distutils.filelist import FileList +import py2exe, glob +from py2exe.build_exe import py2exe as build_exe +from libprs500 import __version__ as VERSION +from libprs500 import __appname__ as APPNAME + +class NSISInstaller(object): + TEMPLATE = r''' +SetCompressor lzma +ShowInstDetails show +ShowUnInstDetails show + +;------------------------------------------------------------------------------------------------------ +;Include Modern UI + !include "AddToPath.nsh" + !include "XPUI.nsh" + !define XPUI_SKIN "Windows XP" + +;------------------------------------------------------------------------------------------------------ +;Variables +Var STARTMENU_FOLDER +Var MUI_TEMP + +!define PRODUCT_NAME "%(name)s" +!define XPUI_BRANDINGTEXT "${PRODUCT_NAME} created by Kovid Goyal" +!define PRODUCT_VERSION "%(version)s" +!define WEBSITE "https://libprs500.kovidgoyal.net" +!define DEVCON "C:\devcon\i386\devcon.exe" +!define PY2EXE_DIR "%(py2exe_dir)s" +!define LIBUSB_DIR "C:\libusb-prs500" +!define LIBUNRAR_DIR "C:\Program Files\UnrarDLL" + +;------------------------------------------------------------------------------------------------------ +;General + + ;Name and file + Name "${PRODUCT_NAME}" + OutFile "%(outpath)s\${PRODUCT_NAME}-${PRODUCT_VERSION}.exe" + + ;Default installation folder + InstallDir "$PROGRAMFILES\${PRODUCT_NAME}" + + ;Get installation folder from registry if available + InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" "" + + ;Vista redirects $SMPROGRAMS to all users without this + RequestExecutionLevel admin + +;------------------------------------------------------------------------------------------------------ +;Interface Settings + + !define MUI_HEADERIMAGE + !define MUI_HEADERIMAGE_BITMAP "icons\library.ico" + !define MUI_ABORTWARNING + +;------------------------------------------------------------------------------------------------------ +;Pages + + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "${PY2EXE_DIR}\LICENSE" + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${PRODUCT_NAME}" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + !insertmacro MUI_PAGE_INSTFILES + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH +;------------------------------------------------------------------------------------------------------ +;Languages + + !insertmacro MUI_LANGUAGE "English" +;------------------------------------------------------------------------------------------------------ +;Installer Sections + +Function .onInit + ; Prevent multiple instances of the installer from running + System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${PRODUCT_NAME}-setup") i .r1 ?e' + Pop $R0 + + StrCmp $R0 0 +3 + MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." + Abort + +FunctionEnd + + +Section "libprs500" Seclibprs500 + + SetOutPath "$INSTDIR" + + ;ADD YOUR OWN FILES HERE... + File /r "${PY2EXE_DIR}\*" + + SetOutPath "$INSTDIR\driver" + File "${LIBUSB_DIR}\*.dll" + File "${LIBUSB_DIR}\*.sys" + File "${LIBUSB_DIR}\*.cat" + File "${LIBUSB_DIR}\*.inf" + File "${DEVCON}" + + SetOutPath "$SYSDIR" + File "${LIBUSB_DIR}\libusb0.dll" + File "${LIBUNRAR_DIR}\unrar.dll" + DetailPrint " " + + DetailPrint "Installing USB driver for prs500..." + ExecWait '"$INSTDIR\driver\devcon.exe" install "$INSTDIR\driver\prs500.inf" "USB\VID_054C&PID_029B"' $0 + DetailPrint "devcon returned exit code $0" + IfErrors 0 +2 + MessageBox MB_OK "Failed to install USB driver. devcon exit code: $0" + DetailPrint " " + + + ;Store installation folder + WriteRegStr HKCU "Software\${PRODUCT_NAME}" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ + "DisplayName" "${PRODUCT_NAME} -- E-book management software" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ + "UninstallString" "$INSTDIR\Uninstall.exe" + + SetOutPath "$INSTDIR" + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${WEBSITE}" + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\libprs500.lnk" "$INSTDIR\${PRODUCT_NAME}.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\prs500-gui.exe" + + !insertmacro MUI_STARTMENU_WRITE_END + + ;Add the installation directory to PATH for the commandline tools + Push "$INSTDIR" + Call AddToPath + +SectionEnd +;------------------------------------------------------------------------------------------------------ +;Descriptions + + ;Language strings + LangString DESC_Seclibprs500 ${LANG_ENGLISH} "The GUI and command-line tools for working with ebooks" + + ;Assign language strings to sections + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Seclibprs500} $(DESC_Seclibprs500) + !insertmacro MUI_FUNCTION_DESCRIPTION_END +;------------------------------------------------------------------------------------------------------ +;Uninstaller Section + +Section "Uninstall" + ;ADD YOUR OWN FILES HERE... + RMDir /r "$INSTDIR" + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + RMDir /r "$SMPROGRAMS\$MUI_TEMP" + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + startMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors startMenuDeleteLoopDone + + StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop + startMenuDeleteLoopDone: + Delete "$DESKTOP\${PRODUCT_NAME}.lnk" + + DeleteRegKey /ifempty HKCU "Software\${PRODUCT_NAME}" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" + ; Remove installation directory from PATH + Push "$INSTDIR" + Call un.RemoveFromPath + +SectionEnd + ''' + def __init__(self, name, py2exe_dir, output_dir): + self.installer = self.__class__.TEMPLATE % dict(name=name, py2exe_dir=py2exe_dir, + version=VERSION, + outpath=os.path.abspath(output_dir)) + + def build(self): + f = open('installer.nsi', 'w') + path = f.name + f.write(self.installer) + f.close() + try: + subprocess.check_call('"C:\Program Files\NSIS\makensis.exe" /V2 ' + path, shell=True) + except: + print path + else: + os.remove(path) + + +class BuildInstaller(build_exe): + manifest_resource_id = 0 + MANIFEST_TEMPLATE = ''' + + + + Ebook management application + + + + + + + + + +''' + def run(self): + build_exe.run(self) + qtsvgdll = None + for other in self.other_depends: + if 'qtsvg4.dll' in other.lower(): + qtsvgdll = other + break + shutil.copyfile('LICENSE', os.path.join(self.dist_dir, 'LICENSE')) + print + if qtsvgdll: + print 'Adding', qtsvgdll + shutil.copyfile(qtsvgdll, os.path.join(self.dist_dir, os.path.basename(qtsvgdll))) + qtxmldll = os.path.join(os.path.dirname(qtsvgdll), 'QtXml4.dll') + print 'Adding', qtxmldll + shutil.copyfile(qtxmldll, + os.path.join(self.dist_dir, os.path.basename(qtxmldll))) + print 'Copying fonts' + dest_dir = os.path.join(self.dist_dir, 'fonts') + if os.path.exists(dest_dir): + shutil.rmtree(dest_dir, True) + + fl = FileList() + fl.include_pattern('^src.*\.ttf$', is_regex=True) + fl.findall() + for file in fl.files: + dir = os.path.join(dest_dir, os.path.basename(os.path.dirname(file))) + if not os.path.exists(dir): + os.makedirs(dir) + print file + shutil.copy(file, dir) + print + print 'Building Installer' + installer = NSISInstaller(APPNAME, self.dist_dir, 'dist') + installer.build() + + @classmethod + def manifest(cls, prog): + cls.manifest_resource_id += 1 + return (24, cls.manifest_resource_id, + cls.MANIFEST_TEMPLATE % dict(prog=prog, version=VERSION+'.0')) + +setup( + cmdclass = {'py2exe': BuildInstaller}, + windows = [{'script' : 'src/libprs500/gui/main.py', + 'dest_base' : APPNAME, + 'icon_resources' : [(1, 'icons/library.ico')], + 'other_resources' : [BuildInstaller.manifest(APPNAME)], + },], + console = [ + {'script' : 'src/libprs500/devices/prs500/cli/main.py', 'dest_base':'prs500'}, + {'script' : 'src/libprs500/ebooks/lrf/html/convert_from.py', 'dest_base':'html2lrf'}, + {'script' : 'src/libprs500/ebooks/lrf/txt/convert_from.py', 'dest_base':'txt2lrf'}, + {'script' : 'src/libprs500/ebooks/lrf/meta.py', 'dest_base':'lrf-meta'}, + {'script' : 'src/libprs500/ebooks/metadata/rtf.py', 'dest_base':'rtf-meta'}, + ], + options = { 'py2exe' : {'compressed': 1, + 'optimize' : 2, + 'dist_dir' : r'build\py2exe', + 'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg'], + 'packages' : ['PIL'], + 'excludes' : ["Tkconstants", "Tkinter", "tcl", + "_imagingtk", "ImageTk", "FixTk", + 'pydoc'], + }, + }, + + ) +