Personal wiki notebook (not under development)

setup.py 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #!/usr/bin/python
  2. import os
  3. import os.path
  4. import sys
  5. from glob import glob
  6. from distutils.core import setup, Distribution
  7. from config.Version import VERSION
  8. def files( path, excludes = None ):
  9. if excludes is None:
  10. excludes = []
  11. if sys.platform.startswith( "win" ):
  12. path = path.replace( "/", "\\" )
  13. files_in_path = glob( path )
  14. for exclude in excludes:
  15. if sys.platform.startswith( "win" ):
  16. exclude = exclude.replace( "/", "\\" )
  17. for file_to_exclude in glob( exclude ):
  18. try:
  19. files_in_path.remove( file_to_exclude )
  20. except ValueError:
  21. pass
  22. return files_in_path
  23. class Luminotes( Distribution ):
  24. def __init__( self, attrs ):
  25. self.ctypes_com_server = []
  26. self.com_server = []
  27. self.services = []
  28. self.windows = [ dict(
  29. script = "luminotes.py",
  30. icon_resources = [ ( 0, "static\\images\\luminotes.ico" ) ],
  31. ) ]
  32. self.console = []
  33. self.service = []
  34. self.isapi = []
  35. self.zipfile = "lib\luminotes.zip"
  36. Distribution.__init__( self, attrs )
  37. manifest_template = '''
  38. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  39. <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  40. <assemblyIdentity
  41. version="5.0.0.0"
  42. processorArchitecture="x86"
  43. name="%(prog)s"
  44. type="win32"
  45. />
  46. <description>%(prog)s Program</description>
  47. <dependency>
  48. <dependentAssembly>
  49. <assemblyIdentity
  50. type="win32"
  51. name="Microsoft.Windows.Common-Controls"
  52. version="6.0.0.0"
  53. processorArchitecture="X86"
  54. publicKeyToken="6595b64144ccf1df"
  55. language="*"
  56. />
  57. </dependentAssembly>
  58. </dependency>
  59. </assembly>
  60. '''
  61. RT_MANIFEST = 24
  62. luminotes = dict(
  63. script = "luminotes.py",
  64. other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="Luminotes"))],
  65. dest_base = r"prog\luminotes")
  66. class InnoScript:
  67. def __init__(self,
  68. name,
  69. lib_dir,
  70. dist_dir,
  71. windows_exe_files = [],
  72. lib_files = [],
  73. version = "1.0"):
  74. self.lib_dir = lib_dir
  75. self.dist_dir = dist_dir
  76. if not self.dist_dir[-1] in "\\/":
  77. self.dist_dir += "\\"
  78. self.name = name
  79. self.version = version
  80. self.windows_exe_files = [self.chop(p) for p in windows_exe_files]
  81. self.lib_files = [self.chop(p) for p in lib_files]
  82. def chop(self, pathname):
  83. assert pathname.startswith(self.dist_dir)
  84. return pathname[len(self.dist_dir):]
  85. def create(self, pathname="dist\\luminotes.iss"):
  86. self.pathname = pathname
  87. ofi = self.file = open(pathname, "w")
  88. print >> ofi, "; WARNING: This script has been created by py2exe. Changes to this script"
  89. print >> ofi, "; will be overwritten the next time py2exe is run!"
  90. print >> ofi, r"[Setup]"
  91. print >> ofi, r"AppName=%s" % self.name
  92. print >> ofi, r"AppVerName=%s %s" % (self.name, self.version)
  93. print >> ofi, r"DefaultDirName={pf}\%s" % self.name
  94. print >> ofi, r"DisableProgramGroupPage=yes"
  95. print >> ofi, r"SetupIconFile=static\images\luminotes.ico"
  96. print >> ofi, r"WizardImageFile=static\images\installer.bmp"
  97. print >> ofi, r"WizardSmallImageFile=static\images\installer_small.bmp"
  98. print >> ofi
  99. print >> ofi, r"[Files]"
  100. for path in self.windows_exe_files + self.lib_files:
  101. if path.endswith( "README.txt" ):
  102. extra = " isreadme"
  103. elif path.endswith( "luminotes.exe" ):
  104. extra = "; BeforeInstall: stop_exe()"
  105. else:
  106. extra = ""
  107. print >> ofi, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion%s' % (path, os.path.dirname(path), extra)
  108. print >> ofi
  109. print >> ofi, r"[Icons]"
  110. for path in self.windows_exe_files:
  111. print >> ofi, r'Name: "{commonprograms}\%s"; Filename: "{app}\%s"' % \
  112. (self.name, path)
  113. print >> ofi
  114. print >> ofi, r"[UninstallDelete]"
  115. print >> ofi, r'Type: files; Name: "{app}\luminotes.log"'
  116. print >> ofi, r'Type: files; Name: "{app}\luminotes_error.log"'
  117. print >> ofi
  118. print >> ofi, r"[UninstallRun]"
  119. print >> ofi, r'Filename: "{app}\luminotes.exe"; Parameters: "-k"; RunOnceId: LuminotesShutdown'
  120. print >> ofi
  121. print >> ofi, r"[Code]"
  122. print >> ofi, r"procedure stop_exe();"
  123. print >> ofi, r"var"
  124. print >> ofi, r" result_code: Integer;"
  125. print >> ofi, r"begin"
  126. print >> ofi, r" Exec( ExpandConstant('{app}\luminotes.exe'), '-k', '', SW_SHOW, ewWaitUntilTerminated, result_code)"
  127. print >> ofi, r"end;"
  128. def compile(self):
  129. import os
  130. if os.environ.get( "CYGWIN" ):
  131. print "Running in Cygwin, so skipping compile"
  132. return
  133. try:
  134. import ctypes
  135. except ImportError:
  136. try:
  137. import win32api
  138. except ImportError:
  139. import os
  140. os.startfile(self.pathname)
  141. else:
  142. print "Ok, using win32api."
  143. win32api.ShellExecute(0, "compile",
  144. self.pathname,
  145. None,
  146. None,
  147. 0)
  148. else:
  149. print "Cool, you have ctypes installed."
  150. res = ctypes.windll.shell32.ShellExecuteA(0, "compile",
  151. self.pathname,
  152. None,
  153. None,
  154. 0)
  155. if res < 32:
  156. raise RuntimeError, "ShellExecute failed, error %d" % res
  157. try:
  158. import py2exe
  159. from py2exe.build_exe import py2exe
  160. class Build_installer( py2exe ):
  161. # This class first builds the exe file(s), then creates a Windows installer.
  162. # You need InnoSetup for it.
  163. def run( self ):
  164. # generate an initial database file
  165. try:
  166. os.remove( "luminotes.db" )
  167. except OSError:
  168. pass
  169. from tools import initdb
  170. initdb.main( ( "-l", ) )
  171. # copy the README and COPYING files to have ".txt" extensions and Windows newlines
  172. self.copy_doc( "README" )
  173. self.copy_doc( "COPYING" )
  174. # First, let py2exe do it's work.
  175. py2exe.run(self)
  176. lib_dir = self.lib_dir
  177. dist_dir = self.dist_dir
  178. # create the Installer, using the files py2exe has created.
  179. script = InnoScript("Luminotes",
  180. lib_dir,
  181. dist_dir,
  182. self.windows_exe_files,
  183. self.lib_files,
  184. version = VERSION)
  185. print "*** creating the inno setup script***"
  186. script.create()
  187. print "*** compiling the inno setup script***"
  188. script.compile()
  189. # Note: By default the final setup.exe will be in an Output subdirectory.
  190. @staticmethod
  191. def copy_doc( path ):
  192. out = file( "%s.txt" % path, "w" )
  193. for line in file( path ).readlines():
  194. line = line.rstrip( "\r\n" )
  195. out.write( "%s\r\n" % line )
  196. out.close()
  197. except ImportError:
  198. class Build_installer:
  199. pass
  200. if "py2exe" in sys.argv[ 1: ]:
  201. txt_extension = ".txt"
  202. else:
  203. txt_extension = ""
  204. data_files = [
  205. ( "", [ "README%s" % txt_extension, ] ),
  206. ( "", [ "COPYING%s" % txt_extension, ] ),
  207. ( "", [ "luminotes.db", ] ),
  208. ( "", [ "tools/usb_luminotes.bat" ] ),
  209. ( "static/css", files( "static/css/*.*" ) ),
  210. ( "static/html", files( "static/html/*.*" ) ),
  211. ( "static/images", files( "static/images/*.*", excludes = [
  212. "static/images/*.xcf",
  213. "static/images/*screenshot*",
  214. "static/images/*tour*",
  215. "static/images/*index_card*",
  216. "static/images/*thumb*",
  217. "static/images/dan.png",
  218. ] ) ),
  219. ( "static/images/toolbar", files( "static/images/toolbar/*.*", excludes = [ "static/images/toolbar/*.xcf" ] ) ),
  220. ( "static/images/toolbar/small", files( "static/images/toolbar/small/*.*", excludes = [ "static/images/toolbar/small/*.xcf" ] ) ),
  221. ( "static/themes/default/images/toolbar", files( "static/themes/default/images/toolbar/*.*", excludes = [ "static/themes/default/images/toolbar/*.xcf" ] ) ),
  222. ( "static/themes/default/images/toolbar/small", files( "static/themes/default/images/toolbar/small/*.*", excludes = [ "static/themes/default/images/toolbar/small/*.xcf" ] ) ),
  223. ( "static/js", files( "static/js/*.*" ) ),
  224. ( "static/js", files( "static/js/*_LICENSE" ) ),
  225. ( "model/delta", files( "model/delta/*.sqlite" ) ),
  226. ]
  227. package_data = { ".": sum( [ pair[ 1 ] for pair in data_files ], [] ) }
  228. setup(
  229. name = "Luminotes",
  230. version = VERSION,
  231. author = "Dan Helfman",
  232. author_email = "support@luminotes.com",
  233. url = "http://luminotes.com",
  234. description = "personal wiki notebook",
  235. distclass = Luminotes,
  236. cmdclass = { "py2exe": Build_installer }, # override default py2exe class
  237. scripts = [ "luminotes.py" ],
  238. packages = [ ".", "config", "controller", "model", "tools", "view" ],
  239. package_dir = { ".": "." },
  240. data_files = data_files, # for py2exe
  241. package_data = package_data, # for everything else
  242. options = dict(
  243. py2exe = dict(
  244. packages = "cherrypy.filters",
  245. includes = "email.header,simplejson,plugins.*",
  246. compressed = 1,
  247. optimize = 2,
  248. )
  249. ),
  250. )