diff options
Diffstat (limited to 'release/windows/msix/create_msix_package.py')
-rw-r--r-- | release/windows/msix/create_msix_package.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/release/windows/msix/create_msix_package.py b/release/windows/msix/create_msix_package.py new file mode 100644 index 00000000000..dda09a10d4b --- /dev/null +++ b/release/windows/msix/create_msix_package.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +import argparse +import os +import pathlib +import requests +import shutil +import subprocess +import zipfile + +parser = argparse.ArgumentParser() +parser.add_argument( + "--version", + required=True, + help="Version string in the form of 2.83.3.0", +) +parser.add_argument( + "--url", + required=True, + help="Location of the release ZIP archive to download", +) +parser.add_argument( + "--publisher", + required=True, + help="A string in the form of 'CN=PUBLISHER'", +) +parser.add_argument( + "--pfx", + required=False, + help="Absolute path to the PFX file used for signing the resulting MSIX package", +) +parser.add_argument( + "--password", + required=False, + default="blender", + help="Password for the PFX file", +) +parser.add_argument( + "--lts", + required=False, + help="If set this MSIX is for an LTS release", + action='store_const', + const=1, +) +parser.add_argument( + "--skipdl", + required=False, + help="If set skip downloading of the specified URL as blender.zip. The tool assumes blender.zip exists", + action='store_const', + const=1, +) +parser.add_argument( + "--leavezip", + required=False, + help="If set don't clean up the downloaded blender.zip", + action='store_const', + const=1, +) +parser.add_argument( + "--overwrite", + required=False, + help="If set remove Content folder if it already exists", + action='store_const', + const=1, +) +args = parser.parse_args() + + +def execute_command(cmd: list, name: str, errcode: int): + """ + Execute given command in cmd. Output is captured. If an error + occurs name is used to print ERROR message, along with stderr and + stdout of the process if either was captured. + """ + cmd_process = subprocess.run(cmd, capture_output=True, encoding="UTF-8") + if cmd_process.returncode != 0: + print(f"ERROR: {name} failed.") + if cmd_process.stdout: + print(cmd_process.stdout) + if cmd_process.stderr: + print(cmd_process.stderr) + exit(errcode) + + +LTSORNOT = "" +PACKAGETYPE = "" +if args.lts: + versionparts = args.version.split(".") + LTSORNOT = f" {versionparts[0]}.{versionparts[1]} LTS" + PACKAGETYPE = f"{versionparts[0]}.{versionparts[1]}LTS" + +blender_package_msix = pathlib.Path(".", f"blender-{args.version}-windows64.msix").absolute() +content_folder = pathlib.Path(".", "Content") +content_blender_folder = pathlib.Path(content_folder, "Blender").absolute() +content_assets_folder = pathlib.Path(content_folder, "Assets") +assets_original_folder = pathlib.Path(".", "Assets") + +local_blender_zip = pathlib.Path(".", "blender.zip") + +if args.pfx: + pfx_path = pathlib.Path(args.pfx) + if not pfx_path.exists(): + print("ERROR: PFX file not found. Please ensure you give the correct path to the PFX file on the command-line.") + exit(1) + print(f"Creating MSIX package with signing using PFX file at {pfx_path}") +else: + pfx_path = None + print("Creating MSIX package without signing.") + +msix_command = ["makeappx", + "pack", + "/h", "SHA256", + "/d", f"{content_folder.absolute()}", + "/p", f"{blender_package_msix}" + ] +if pfx_path: + sign_command = ["signtool", + "sign", + "/fd", "sha256", + "/a", "/f", f"{pfx_path.absolute()}", + "/p", f"{args.password}", + f"{blender_package_msix}" + ] + +if args.overwrite: + if content_folder.joinpath("Assets").exists(): + shutil.rmtree(content_folder) +content_folder.mkdir(exist_ok=True) +shutil.copytree(assets_original_folder, content_assets_folder) + +manifest_text = pathlib.Path("AppxManifest.xml.template").read_text() +manifest_text = manifest_text.replace("[VERSION]", args.version) +manifest_text = manifest_text.replace("[PUBLISHER]", args.publisher) +manifest_text = manifest_text.replace("[LTSORNOT]", LTSORNOT) +manifest_text = manifest_text.replace("[PACKAGETYPE]", PACKAGETYPE) +pathlib.Path(content_folder, "AppxManifest.xml").write_text(manifest_text) + +if not args.skipdl: + print(f"Downloading blender archive {args.url} to {local_blender_zip}...") + + with open(local_blender_zip, "wb") as download_zip: + response = requests.get(args.url) + download_zip.write(response.content) + + print("... download complete.") +else: + print("Skipping download") + +print(f"Extracting files from ZIP to {content_blender_folder}...") + +# Extract the files from the ZIP archive, but skip the leading part of paths +# in the ZIP. We want to write the files to the content_blender_folder where +# blender.exe ends up as ./Content/Blender/blender.exe, and not +# ./Content/Blender/blender-2.83.3-windows64/blender.exe +with zipfile.ZipFile(local_blender_zip, "r") as blender_zip: + for entry in blender_zip.infolist(): + if entry.is_dir(): + continue + entry_location = pathlib.Path(entry.filename) + target_location = content_blender_folder.joinpath(*entry_location.parts[1:]) + pathlib.Path(target_location.parent).mkdir(parents=True, exist_ok=True) + extracted_entry = blender_zip.read(entry) + target_location.write_bytes(extracted_entry) + +print("... extraction complete.") + + +print(f"Creating MSIX package using command: {' '.join(msix_command)}") + +# Remove MSIX file if it already exists. Otherwise the MakeAppX tool +# will hang. +if blender_package_msix.exists(): + os.remove(blender_package_msix) +execute_command(msix_command, "MakeAppX", 2) + +if args.pfx: + print(f"Signing MSIX package using command: {' '.join(sign_command)}") + execute_command(sign_command, "SignTool", 3) + +if not args.leavezip: + os.remove(local_blender_zip) +shutil.rmtree(content_folder) + +print("Done.") |