installers.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import distutils.log
  2. import os
  3. import subprocess
  4. import sys
  5. import tarfile
  6. import zipfile
  7. import panda3d.core as p3d
  8. def create_zip(command, basename, build_dir):
  9. base_dir = command.get_archive_basedir()
  10. with zipfile.ZipFile(basename+'.zip', 'w', compression=zipfile.ZIP_DEFLATED) as zf:
  11. zf.write(build_dir, base_dir)
  12. for dirpath, dirnames, filenames in os.walk(build_dir):
  13. for name in sorted(dirnames):
  14. path = os.path.normpath(os.path.join(dirpath, name))
  15. zf.write(path, path.replace(build_dir, base_dir, 1))
  16. for name in filenames:
  17. path = os.path.normpath(os.path.join(dirpath, name))
  18. if os.path.isfile(path):
  19. zf.write(path, path.replace(build_dir, base_dir, 1))
  20. def create_tarball(command, basename, build_dir, tar_compression):
  21. base_dir = command.get_archive_basedir()
  22. build_cmd = command.get_finalized_command('build_apps')
  23. binary_names = list(build_cmd.console_apps.keys()) + list(build_cmd.gui_apps.keys())
  24. def tarfilter(tarinfo):
  25. if tarinfo.isdir() or os.path.basename(tarinfo.name) in binary_names:
  26. tarinfo.mode = 0o755
  27. else:
  28. tarinfo.mode = 0o644
  29. return tarinfo
  30. with tarfile.open('{}.tar.{}'.format(basename, tar_compression), 'w|{}'.format(tar_compression)) as tf:
  31. tf.add(build_dir, base_dir, filter=tarfilter)
  32. def create_gztar(command, basename, build_dir):
  33. return create_tarball(command, basename, build_dir, 'gz')
  34. def create_bztar(command, basename, build_dir):
  35. return create_tarball(command, basename, build_dir, 'bz2')
  36. def create_xztar(command, basename, build_dir):
  37. return create_tarball(command, basename, build_dir, 'xz')
  38. def create_nsis(command, basename, build_dir):
  39. platform = command.get_current_platform()
  40. if not platform.startswith('win'):
  41. command.announce(
  42. '\tNSIS installer not supported for platform: {}'.format(platform),
  43. distutils.log.ERROR
  44. )
  45. return
  46. try:
  47. subprocess.call(['makensis', '--version'])
  48. except OSError:
  49. command.announce(
  50. '\tCould not find makensis tool that is required to build NSIS installers',
  51. distutils.log.ERROR
  52. )
  53. return
  54. is_64bit = platform == 'win_amd64'
  55. # Get a list of build applications
  56. build_cmd = command.get_finalized_command('build_apps')
  57. apps = build_cmd.gui_apps.copy()
  58. apps.update(build_cmd.console_apps)
  59. apps = [
  60. '{}.exe'.format(i)
  61. for i in apps
  62. ]
  63. shortname = command.distribution.get_name()
  64. # Create the .nsi installer script
  65. nsifile = p3d.Filename(build_cmd.build_base, shortname + ".nsi")
  66. nsifile.unlink()
  67. nsi = open(nsifile.to_os_specific(), "w")
  68. # Some global info
  69. nsi.write('Name "%s"\n' % shortname)
  70. nsi.write('OutFile "%s"\n' % os.path.join(command.dist_dir, basename+'.exe'))
  71. if is_64bit:
  72. nsi.write('InstallDir "$PROGRAMFILES64\\%s"\n' % shortname)
  73. else:
  74. nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % shortname)
  75. nsi.write('SetCompress auto\n')
  76. nsi.write('SetCompressor lzma\n')
  77. nsi.write('ShowInstDetails nevershow\n')
  78. nsi.write('ShowUninstDetails nevershow\n')
  79. nsi.write('InstType "Typical"\n')
  80. # Tell Vista that we require admin rights
  81. nsi.write('RequestExecutionLevel admin\n')
  82. nsi.write('\n')
  83. # TODO offer run and desktop shortcut after we figure out how to deal
  84. # with multiple apps
  85. nsi.write('!include "MUI2.nsh"\n')
  86. nsi.write('!define MUI_ABORTWARNING\n')
  87. nsi.write('\n')
  88. nsi.write('Var StartMenuFolder\n')
  89. nsi.write('!insertmacro MUI_PAGE_WELCOME\n')
  90. # TODO license file
  91. nsi.write('!insertmacro MUI_PAGE_DIRECTORY\n')
  92. nsi.write('!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n')
  93. nsi.write('!insertmacro MUI_PAGE_INSTFILES\n')
  94. nsi.write('!insertmacro MUI_PAGE_FINISH\n')
  95. nsi.write('!insertmacro MUI_UNPAGE_WELCOME\n')
  96. nsi.write('!insertmacro MUI_UNPAGE_CONFIRM\n')
  97. nsi.write('!insertmacro MUI_UNPAGE_INSTFILES\n')
  98. nsi.write('!insertmacro MUI_UNPAGE_FINISH\n')
  99. nsi.write('!insertmacro MUI_LANGUAGE "English"\n')
  100. # This section defines the installer.
  101. nsi.write('Section "" SecCore\n')
  102. nsi.write(' SetOutPath "$INSTDIR"\n')
  103. curdir = ""
  104. nsi_dir = p3d.Filename.fromOsSpecific(build_cmd.build_base)
  105. build_root_dir = p3d.Filename.fromOsSpecific(build_dir)
  106. for root, dirs, files in os.walk(build_dir):
  107. for name in files:
  108. basefile = p3d.Filename.fromOsSpecific(os.path.join(root, name))
  109. file = p3d.Filename(basefile)
  110. file.makeAbsolute()
  111. file.makeRelativeTo(nsi_dir)
  112. outdir = p3d.Filename(basefile)
  113. outdir.makeAbsolute()
  114. outdir.makeRelativeTo(build_root_dir)
  115. outdir = outdir.getDirname().replace('/', '\\')
  116. if curdir != outdir:
  117. nsi.write(' SetOutPath "$INSTDIR\\%s"\n' % outdir)
  118. curdir = outdir
  119. nsi.write(' File "%s"\n' % (file.toOsSpecific()))
  120. nsi.write(' SetOutPath "$INSTDIR"\n')
  121. nsi.write(' WriteUninstaller "$INSTDIR\\Uninstall.exe"\n')
  122. nsi.write(' ; Start menu items\n')
  123. nsi.write(' !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n')
  124. nsi.write(' CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n')
  125. for app in apps:
  126. nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s"\n' % (shortname, app))
  127. nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n')
  128. nsi.write(' !insertmacro MUI_STARTMENU_WRITE_END\n')
  129. nsi.write('SectionEnd\n')
  130. # This section defines the uninstaller.
  131. nsi.write('Section Uninstall\n')
  132. nsi.write(' RMDir /r "$INSTDIR"\n')
  133. nsi.write(' ; Desktop icon\n')
  134. nsi.write(' Delete "$DESKTOP\\%s.lnk"\n' % shortname)
  135. nsi.write(' ; Start menu items\n')
  136. nsi.write(' !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n')
  137. nsi.write(' RMDir /r "$SMPROGRAMS\\$StartMenuFolder"\n')
  138. nsi.write('SectionEnd\n')
  139. nsi.close()
  140. cmd = ['makensis']
  141. for flag in ["V2"]:
  142. cmd.append(
  143. '{}{}'.format('/' if sys.platform.startswith('win') else '-', flag)
  144. )
  145. cmd.append(nsifile.to_os_specific())
  146. subprocess.check_call(cmd)