create_appimage.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  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. from jinja2 import Template
  5. import os # Finding installation directory.
  6. import os.path # Finding files.
  7. import shutil # Copying files.
  8. import stat # For setting file permissions.
  9. import subprocess # For calling system commands.
  10. def build_appimage(dist_path, version, appimage_filename):
  11. """
  12. Creates an AppImage file from the build artefacts created so far.
  13. """
  14. copy_metadata_files(dist_path, version)
  15. try:
  16. os.remove(os.path.join(dist_path, appimage_filename)) # Ensure any old file is removed, if it exists.
  17. except FileNotFoundError:
  18. pass # If it didn't exist, that's even better.
  19. generate_appimage(dist_path, appimage_filename)
  20. sign_appimage(dist_path, appimage_filename)
  21. def copy_metadata_files(dist_path, version):
  22. """
  23. Copy metadata files for the metadata of the AppImage.
  24. """
  25. copied_files = {
  26. os.path.join("..", "icons", "cura-icon_256x256.png"): "cura-icon.png",
  27. "cura.appdata.xml": "cura.appdata.xml",
  28. "AppRun": "AppRun"
  29. }
  30. packaging_dir = os.path.dirname(__file__)
  31. for source, dest in copied_files.items():
  32. print("Copying", os.path.join(packaging_dir, source), "to", os.path.join(dist_path, dest))
  33. shutil.copyfile(os.path.join(packaging_dir, source), os.path.join(dist_path, dest))
  34. # Ensure that AppRun has the proper permissions: 755 (user reads, writes and executes, group reads and executes, world reads and executes).
  35. print("Changing permissions for AppRun")
  36. os.chmod(os.path.join(dist_path, "AppRun"), stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
  37. # Provision the Desktop file with the correct version number.
  38. template_path = os.path.join(packaging_dir, "cura.desktop.jinja")
  39. desktop_path = os.path.join(dist_path, "cura.desktop")
  40. print("Provisioning desktop file from", template_path, "to", desktop_path)
  41. with open(template_path, "r") as f:
  42. desktop_file = Template(f.read())
  43. with open(desktop_path, "w") as f:
  44. f.write(desktop_file.render(cura_version = version))
  45. def generate_appimage(dist_path, appimage_filename):
  46. appimage_path = os.path.join(dist_path, "..", appimage_filename)
  47. appimagetool = os.getenv("APPIMAGETOOL_LOCATION", "appimagetool")
  48. command = [appimagetool, "--appimage-extract-and-run", f"{dist_path}/", appimage_path]
  49. result = subprocess.call(command)
  50. if result != 0:
  51. raise RuntimeError(f"The AppImageTool command returned non-zero: {result}")
  52. def sign_appimage(dist_path, appimage_filename):
  53. appimage_path = os.path.join(dist_path, "..", appimage_filename)
  54. command = ["gpg", "--yes", "--armor", "--detach-sig", appimage_path]
  55. result = subprocess.call(command)
  56. if result != 0:
  57. raise RuntimeError(f"The GPG command returned non-zero: {result}")
  58. if __name__ == "__main__":
  59. parser = argparse.ArgumentParser(description = "Create AppImages of Cura.")
  60. parser.add_argument("dist_path", type=str, help="Path to where PyInstaller installed the distribution of Cura.")
  61. parser.add_argument("version", type=str, help="Full version number of Cura (e.g. '5.1.0-beta')")
  62. parser.add_argument("filename", type = str, help = "Filename of the AppImage (e.g. 'UltiMaker-Cura-5.1.0-beta-Linux-X64.AppImage')")
  63. args = parser.parse_args()
  64. build_appimage(args.dist_path, args.version, args.filename)