From 22c3bbdbb3ff8667cad8f3d7fa3ae605109107a0 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Thu, 21 Aug 2008 21:34:44 -0700 Subject: [PATCH] Initial Windows installer packaging based on py2exe Inno Setup example. --- setup.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 942a3ef..58f3090 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,18 @@ +import os import sys from glob import glob from distutils.core import setup, Distribution try: import py2exe + from py2exe.build_exe import py2exe except ImportError: pass +VERSION = "1.5.0" + + def files( path ): if sys.platform.startswith( "win" ): path = path.replace( "/", "\\" ) @@ -24,26 +29,165 @@ class Luminotes( Distribution ): self.service = [] self.isapi = [] self.console = [ "luminotes.py" ] - self.zipfile = "luminotes.zip" + self.zipfile = "lib\luminotes.zip" Distribution.__init__( self, attrs ) +manifest_template = ''' + + + +%(prog)s Program + + + + + + +''' + +RT_MANIFEST = 24 + +luminotes = dict( + script = "luminotes.py", + other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="Luminotes"))], + dest_base = r"prog\luminotes") + +class InnoScript: + def __init__(self, + name, + lib_dir, + dist_dir, + windows_exe_files = [], + lib_files = [], + version = "1.0"): + self.lib_dir = lib_dir + self.dist_dir = dist_dir + if not self.dist_dir[-1] in "\\/": + self.dist_dir += "\\" + self.name = name + self.version = version + self.windows_exe_files = [self.chop(p) for p in windows_exe_files] + self.lib_files = [self.chop(p) for p in lib_files] + + def chop(self, pathname): + assert pathname.startswith(self.dist_dir) + return pathname[len(self.dist_dir):] + + def create(self, pathname="dist\\luminotes.iss"): + self.pathname = pathname + ofi = self.file = open(pathname, "w") + print >> ofi, "; WARNING: This script has been created by py2exe. Changes to this script" + print >> ofi, "; will be overwritten the next time py2exe is run!" + print >> ofi, r"[Setup]" + print >> ofi, r"AppName=%s" % self.name + print >> ofi, r"AppVerName=%s %s" % (self.name, self.version) + print >> ofi, r"DefaultDirName={pf}\%s" % self.name + print >> ofi, r"DefaultGroupName=%s" % self.name + print >> ofi + + print >> ofi, r"[Files]" + for path in self.windows_exe_files + self.lib_files: + print >> ofi, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)) + print >> ofi + + print >> ofi, r"[Icons]" + for path in self.windows_exe_files: + print >> ofi, r'Name: "{group}\%s"; Filename: "{app}\%s"' % \ + (self.name, path) + print >> ofi, 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name + + def compile(self): + try: + import ctypes + except ImportError: + try: + import win32api + except ImportError: + import os + os.startfile(self.pathname) + else: + print "Ok, using win32api." + win32api.ShellExecute(0, "compile", + self.pathname, + None, + None, + 0) + else: + print "Cool, you have ctypes installed." + res = ctypes.windll.shell32.ShellExecuteA(0, "compile", + self.pathname, + None, + None, + 0) + if res < 32: + raise RuntimeError, "ShellExecute failed, error %d" % res + + + +class Build_installer(py2exe): + # This class first builds the exe file(s), then creates a Windows installer. + # You need InnoSetup for it. + def run(self): + # TODO: run initdb.py -l to generate a luminotes.db + + # First, let py2exe do it's work. + py2exe.run(self) + + lib_dir = self.lib_dir + dist_dir = self.dist_dir + + # create the Installer, using the files py2exe has created. + script = InnoScript("Luminotes", + lib_dir, + dist_dir, + self.console_exe_files, + self.lib_files, + version = VERSION) + print "*** creating the inno setup script***" + script.create() + print "*** compiling the inno setup script***" + script.compile() + # Note: By default the final setup.exe will be in an Output subdirectory. + + setup( + name = "Luminotes", + version = VERSION, + author = "Dan Helfman", + author_email = "support@luminotes.com", + url = "http://luminotes.com", + description = "personal wiki notebook", distclass = Luminotes, + cmdclass = { "py2exe": Build_installer }, # override default py2exe class data_files = [ ( "", [ "luminotes.db", ] ), ( "static/css", files( "static/css/*.*" ) ), - ( "static/html", files( "static/css/html/*.*" ) ), + ( "static/html", files( "static/html/*.*" ) ), ( "static/images", files( "static/images/*.*" ) ), ( "static/images/toolbar", files( "static/images/toolbar/*.*" ) ), ( "static/images/toolbar/small", files( "static/images/toolbar/small/*.*" ) ), ( "static/js", files( "static/js/*.*" ) ), - ( "files", [] ), + ( "files", files( "files/.empty" ) ), ], options = dict( py2exe = dict( packages = "cherrypy.filters", includes = "email.header", + compressed = 1, + optimize = 2, ) ), )