1
0

nsiswriter.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import itertools
  2. import operator
  3. import ntpath
  4. import re
  5. import sys
  6. PY2 = sys.version_info[0] == 2
  7. class NSISFileWriter(object):
  8. """Write an .nsi script file by filling in a template.
  9. """
  10. def __init__(self, template_file, installerbuilder, definitions=None):
  11. """Instantiate an NSISFileWriter
  12. :param str template_file: Path to the .nsi template
  13. :param dict definitions: Mapping of name to value (values will be quoted)
  14. """
  15. self.template_file = template_file
  16. self.installerbuilder = installerbuilder
  17. self.definitions = definitions or {}
  18. self.template_fields = {
  19. ';INSTALL_FILES': self.files_install,
  20. ';INSTALL_DIRECTORIES': self.dirs_install,
  21. ';INSTALL_SHORTCUTS': self.shortcuts_install,
  22. ';UNINSTALL_FILES': self.files_uninstall,
  23. ';UNINSTALL_DIRECTORIES': self.dirs_uninstall,
  24. ';UNINSTALL_SHORTCUTS': self.shortcuts_uninstall,
  25. }
  26. if installerbuilder.py_version < '3.3':
  27. self.template_fields.update({
  28. ';PYLAUNCHER_INSTALL': self.pylauncher_install,
  29. ';PYLAUNCHER_HELP': self.pylauncher_help})
  30. def write(self, target):
  31. """Fill out the template and write the result to 'target'.
  32. :param str target: Path to the file to be written
  33. """
  34. with open(target, 'w') as fout, open(self.template_file) as fin:
  35. self.write_definitions(fout)
  36. for line in fin:
  37. fout.write(line)
  38. l = line.strip()
  39. if l in self.template_fields:
  40. indent = re.match('\s*', line).group(0)
  41. for fillline in self.template_fields[l]():
  42. fout.write(indent+fillline+'\n')
  43. def write_definitions(self, f):
  44. """Write definition lines at the start of the file.
  45. :param f: A text-mode writable file handle
  46. """
  47. for name, value in self.definitions.items():
  48. f.write('!define {} "{}"\n'.format(name, value))
  49. # Template fillers
  50. # ----------------
  51. # These return an iterable of lines to fill after a given template field
  52. def files_install(self):
  53. for destination, group in itertools.groupby(
  54. self.installerbuilder.install_files, operator.itemgetter(1)):
  55. yield 'SetOutPath "{}"'.format(destination)
  56. for file, _ in group:
  57. yield 'File "{}"'.format(file)
  58. yield 'SetOutPath "$INSTDIR"'
  59. def dirs_install(self):
  60. for dir, destination in self.installerbuilder.install_dirs:
  61. yield 'SetOutPath "{}"'.format(ntpath.join(destination, dir))
  62. yield 'File /r "{}\*.*"'.format(dir)
  63. yield 'SetOutPath "$INSTDIR"'
  64. def shortcuts_install(self):
  65. shortcuts = self.installerbuilder.shortcuts
  66. # The output path becomes the working directory for shortcuts.
  67. yield 'SetOutPath "%HOMEDRIVE%\\%HOMEPATH%"'
  68. if len(shortcuts) == 1:
  69. scname, sc = next(iter(shortcuts.items()))
  70. yield 'CreateShortCut "$SMPROGRAMS\{}.lnk" "{}" \'"$INSTDIR\{}"\' \\'.format(\
  71. scname, ('py' if sc['console'] else 'pyw'), sc['script'])
  72. yield ' "$INSTDIR\{}"'.format(sc['icon'])
  73. yield 'SetOutPath "$INSTDIR"'
  74. return
  75. # Multiple shortcuts - make a folder
  76. yield 'CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"'
  77. for scname, sc in shortcuts.items():
  78. yield 'CreateShortCut "$SMPROGRAMS\${{PRODUCT_NAME}}\{}.lnk" "{}" \\'.format(\
  79. scname, sc['target'])
  80. yield ' \'{}\' "$INSTDIR\{}"'.format(sc['parameters'], sc['icon'])
  81. yield 'SetOutPath "$INSTDIR"'
  82. def files_uninstall(self):
  83. for file, destination in self.installerbuilder.install_files:
  84. yield 'Delete "{}"'.format(ntpath.join(destination, file))
  85. def dirs_uninstall(self):
  86. for dir, destination in self.installerbuilder.install_dirs:
  87. yield 'RMDir /r "{}"'.format(ntpath.join(destination, dir))
  88. def shortcuts_uninstall(self):
  89. shortcuts = self.installerbuilder.shortcuts
  90. if len(shortcuts) == 1:
  91. scname = next(iter(shortcuts))
  92. yield 'Delete "$SMPROGRAMS\{}.lnk"'.format(scname)
  93. else:
  94. yield 'RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"'
  95. def pylauncher_install(self):
  96. return ["Section \"PyLauncher\" sec_pylauncher",
  97. " File \"launchwin${ARCH_TAG}.msi\"",
  98. " ExecWait 'msiexec /i \"$INSTDIR\launchwin${ARCH_TAG}.msi\" /qb ALLUSERS=1'",
  99. " Delete $INSTDIR\launchwin${ARCH_TAG}.msi",
  100. "SectionEnd",
  101. ]
  102. def pylauncher_help(self):
  103. return ["StrCmp $0 ${sec_pylauncher} 0 +2",
  104. "SendMessage $R0 ${WM_SETTEXT} 0 \"STR:The Python launcher. \\",
  105. " This is required for ${PRODUCT_NAME} to run.\"",
  106. ]