nsiswriter.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import re
  2. import sys
  3. PY2 = sys.version_info[0] == 2
  4. class NSISFileWriter(object):
  5. """Write an .nsi script file by filling in a template.
  6. """
  7. def __init__(self, template_file, definitions=None):
  8. """Instantiate an NSISFileWriter
  9. :param str template_file: Path to the .nsi template
  10. :param dict definitions: Mapping of name to value (values will be quoted)
  11. """
  12. self.template_file = template_file
  13. self.definitions = definitions or {}
  14. self.files = []
  15. self.directories = []
  16. self.template_fields = {
  17. ';INSTALL_FILES': self.files_install,
  18. ';INSTALL_DIRECTORIES': self.dirs_install,
  19. ';UNINSTALL_FILES': self.files_uninstall,
  20. ';UNINSTALL_DIRECTORIES': self.dirs_uninstall,
  21. }
  22. if PY2:
  23. self.template_fields.update({
  24. ';PYLAUNCHER_INSTALL': self.pylauncher_install,
  25. ';PYLAUNCHER_HELP': self.pylauncher_help})
  26. def write(self, target):
  27. """Fill out the template and write the result to 'target'.
  28. :param str target: Path to the file to be written
  29. """
  30. with open(target, 'w') as fout, open(self.template_file) as fin:
  31. self.write_definitions(fout)
  32. for line in fin:
  33. fout.write(line)
  34. l = line.strip()
  35. if l in self.template_fields:
  36. indent = re.match('\s*', line).group(0)
  37. for fillline in self.template_fields[l]():
  38. fout.write(indent+fillline+'\n')
  39. def write_definitions(self, f):
  40. """Write definition lines at the start of the file.
  41. :param f: A text-mode writable file handle
  42. """
  43. for name, value in self.definitions.items():
  44. f.write('!define {} "{}"\n'.format(name, value))
  45. # Template fillers
  46. # ----------------
  47. # These return an iterable of lines to fill after a given template field
  48. def files_install(self):
  49. for file in self.files:
  50. yield 'File "{}"'.format(file)
  51. def dirs_install(self):
  52. for dir in self.directories:
  53. yield 'SetOutPath "$INSTDIR\{}"'.format(dir)
  54. yield 'File /r "{}\*.*"'.format(dir)
  55. yield 'SetOutPath "$INSTDIR"'
  56. def files_uninstall(self):
  57. for file in self.files:
  58. yield 'Delete "$INSTDIR\{}"'.format(file)
  59. def dirs_uninstall(self):
  60. for dir in self.directories:
  61. yield 'RMDir /r "$INSTDIR\{}"'.format(dir)
  62. def pylauncher_install(self):
  63. return ["Section \"PyLauncher\" sec_pylauncher",
  64. " File \"launchwin${ARCH_TAG}.msi\"",
  65. " ExecWait 'msiexec /i \"$INSTDIR\launchwin${ARCH_TAG}.msi\" /qb ALLUSERS=1'",
  66. " Delete $INSTDIR\launchwin${ARCH_TAG}.msi",
  67. "SectionEnd",
  68. ]
  69. def pylauncher_help(self):
  70. return ["StrCmp $0 ${sec_pylauncher} 0 +2",
  71. "SendMessage $R0 ${WM_SETTEXT} 0 \"STR:The Python launcher. \\",
  72. " This is required for ${PRODUCT_NAME} to run.\"",
  73. ]