create_windows_msi.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. # Copyright (c) 2022 UltiMaker
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import argparse # Command line arguments parsing and help.
  4. import os
  5. import shutil
  6. import subprocess
  7. import uuid
  8. from datetime import datetime
  9. from pathlib import Path
  10. from jinja2 import Template
  11. def work_path(filename: Path) -> Path:
  12. if not filename.is_absolute():
  13. return Path(os.getcwd(), filename.parent)
  14. else:
  15. return filename.parent
  16. def generate_wxs(source_path: Path, dist_path: Path, filename: Path, app_name: str):
  17. source_loc = Path(os.getcwd(), source_path)
  18. dist_loc = Path(os.getcwd(), dist_path)
  19. work_loc = work_path(filename)
  20. work_loc.mkdir(parents=True, exist_ok=True)
  21. jinja_template_path = Path(source_loc.joinpath("packaging", "msi", "UltiMaker-Cura.wxs.jinja"))
  22. with open(jinja_template_path, "r") as f:
  23. template = Template(f.read())
  24. wxs_content = template.render(
  25. app_name=f"{app_name}",
  26. main_app="UltiMaker-Cura.exe",
  27. version=os.getenv('CURA_VERSION_FULL'),
  28. version_major=os.environ.get("CURA_VERSION_MAJOR"),
  29. version_minor=os.environ.get("CURA_VERSION_MINOR"),
  30. version_patch=os.environ.get("CURA_VERSION_PATCH"),
  31. company="UltiMaker",
  32. web_site="https://ultimaker.com",
  33. year=datetime.now().year,
  34. upgrade_code=str(uuid.uuid5(uuid.NAMESPACE_DNS, app_name)),
  35. shortcut_uuid=str(uuid.uuid5(uuid.NAMESPACE_DNS, f"Shortcut {app_name}")),
  36. cura_license_file=str(source_loc.joinpath("packaging", "msi", "cura_license.rtf")),
  37. cura_banner_top=str(source_loc.joinpath("packaging", "msi", "banner_top.bmp")),
  38. cura_banner_side=str(source_loc.joinpath("packaging", "msi", "banner_side.bmp")),
  39. cura_icon=str(source_loc.joinpath("packaging", "icons", "Cura.ico")),
  40. )
  41. with open(work_loc.joinpath("UltiMaker-Cura.wxs"), "w") as f:
  42. f.write(wxs_content)
  43. try:
  44. shutil.copy(source_loc.joinpath("packaging", "msi", "CustomizeCuraDlg.wxs"),
  45. work_loc.joinpath("CustomizeCuraDlg.wxs"))
  46. except shutil.SameFileError:
  47. pass
  48. try:
  49. shutil.copy(source_loc.joinpath("packaging", "msi", "ExcludeComponents.xslt"),
  50. work_loc.joinpath("ExcludeComponents.xslt"))
  51. except shutil.SameFileError:
  52. pass
  53. def build(dist_path: Path, filename: str):
  54. dist_loc = Path(os.getcwd(), dist_path)
  55. work_loc = work_path(filename)
  56. wxs_loc = work_loc.joinpath("UltiMaker-Cura.wxs")
  57. heat_loc = work_loc.joinpath("HeatFile.wxs")
  58. exclude_components_loc = work_loc.joinpath("ExcludeComponents.xslt")
  59. manageoldcuradlg_loc = work_loc.joinpath("CustomizeCuraDlg.wxs")
  60. build_loc = work_loc.joinpath("build_msi")
  61. heat_command = ["heat", "dir", f"{dist_loc.as_posix()}\\", "-dr", "APPLICATIONFOLDER", "-cg", "NewFilesGroup",
  62. "-gg", "-g1", "-sf", "-srd", "-var", "var.CuraDir", "-t", f"{exclude_components_loc.as_posix()}",
  63. "-out", f"{heat_loc.as_posix()}"]
  64. subprocess.call(heat_command)
  65. build_command = ["candle", "-arch", "x64", f"-dCuraDir={dist_loc}\\", "-out", f"{build_loc.as_posix()}\\",
  66. f"{wxs_loc.as_posix()}", f"{heat_loc.as_posix()}", f"{manageoldcuradlg_loc.as_posix()}"]
  67. subprocess.call(build_command)
  68. link_command = ["light", f"{build_loc.joinpath(wxs_loc.name).with_suffix('.wixobj')}",
  69. f"{build_loc.joinpath(heat_loc.name).with_suffix('.wixobj')}",
  70. f"{build_loc.joinpath(manageoldcuradlg_loc.name).with_suffix('.wixobj')}", "-ext", "WixUIExtension",
  71. "-out", f"{work_loc.joinpath(filename.name)}"]
  72. subprocess.call(link_command)
  73. if __name__ == "__main__":
  74. parser = argparse.ArgumentParser(description="Create Windows msi installer of Cura.")
  75. parser.add_argument("source_path", type=Path, help="Path to Conan install Cura folder.")
  76. parser.add_argument("dist_path", type=Path, help="Path to Pyinstaller dist folder")
  77. parser.add_argument("filename", type=Path,
  78. help="Filename of the exe (e.g. 'UltiMaker-Cura-5.1.0-beta-Windows-X64.msi')")
  79. parser.add_argument("name", type=str, help="App name (e.g. 'UltiMaker Cura')")
  80. args = parser.parse_args()
  81. generate_wxs(args.source_path, args.dist_path, args.filename, args.name)
  82. build(args.dist_path, args.filename)