nsiswriter.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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.extra_files = []
  15. self.template_fields = {
  16. ';EXTRA_FILES_INSTALL': self.make_extra_files_install,
  17. ';EXTRA_FILES_UNINSTALL': self.make_extra_files_uninstall,
  18. }
  19. if PY2:
  20. self.template_fields.update({
  21. ';PYLAUNCHER_INSTALL': self.make_pylauncher_install,
  22. ';PYLAUNCHER_HELP': self.make_pylauncher_help})
  23. def write_definitions(self, f):
  24. """Write definition lines at the start of the file.
  25. :param f: A text-mode writable file handle
  26. """
  27. for name, value in self.definitions.items():
  28. f.write('!define {} "{}"\n'.format(name, value))
  29. def make_extra_files_install(self):
  30. """Write the commands to install the list of extra files and directories.
  31. :param f: A text-mode writable file handle
  32. :param str indent: Leading space at this point in the file
  33. """
  34. for file, is_dir in self.extra_files:
  35. if is_dir:
  36. yield 'SetOutPath "$INSTDIR\{}"\n'.format(file)
  37. yield 'File /r "{}\*.*"\n'.format(file)
  38. yield 'SetOutPath "$INSTDIR"\n'
  39. else:
  40. yield 'File "{}"\n'.format(file)
  41. def make_extra_files_uninstall(self):
  42. """Write the commands to uninstall the list of extra files and directories.
  43. :param f: A text-mode writable file handle
  44. :param str indent: Leading space at this point in the file
  45. """
  46. for file, is_dir in self.extra_files:
  47. if is_dir:
  48. yield 'RMDir /r "$INSTDIR\{}"\n'.format(file)
  49. else:
  50. yield 'Delete "$INSTDIR\{}"\n'.format(file)
  51. def make_pylauncher_install(self):
  52. return ["Section \"PyLauncher\" sec_pylauncher",
  53. " File \"launchwin${ARCH_TAG}.msi\"",
  54. " ExecWait 'msiexec /i \"$INSTDIR\launchwin${ARCH_TAG}.msi\" /qb ALLUSERS=1'",
  55. " Delete $INSTDIR\launchwin${ARCH_TAG}.msi",
  56. "SectionEnd",
  57. ]
  58. def make_pylauncher_help(self):
  59. return ["StrCmp $0 ${sec_pylauncher} 0 +2",
  60. "SendMessage $R0 ${WM_SETTEXT} 0 \"STR:The Python launcher. \\",
  61. " This is required for ${PRODUCT_NAME} to run.\"",
  62. ]
  63. def write(self, target):
  64. """Fill out the template and write the result to 'target'.
  65. :param str target: Path to the file to be written
  66. """
  67. with open(target, 'w') as fout, open(self.template_file) as fin:
  68. self.write_definitions(fout)
  69. for line in fin:
  70. fout.write(line)
  71. l = line.strip()
  72. if l in self.template_fields:
  73. indent = re.match('\s*', line).group(0)
  74. for fillline in self.template_fields[l]():
  75. fout.write(indent+fillline+'\n')