diff options
m--------- | release/scripts/addons | 0 | ||||
-rw-r--r-- | release/windows/msix/AppxManifest.xml.template | 60 | ||||
-rw-r--r-- | release/windows/msix/Assets/Square150x150Logo.png | bin | 0 -> 8864 bytes | |||
-rw-r--r-- | release/windows/msix/Assets/Square310x310Logo.png | bin | 0 -> 24649 bytes | |||
-rw-r--r-- | release/windows/msix/Assets/Square44x44Logo.png | bin | 0 -> 2098 bytes | |||
-rw-r--r-- | release/windows/msix/Assets/Square71x71Logo.png | bin | 0 -> 4297 bytes | |||
-rw-r--r-- | release/windows/msix/Assets/StoreLogo.png | bin | 0 -> 5265 bytes | |||
-rw-r--r-- | release/windows/msix/Assets/Wide310x150Logo.png | bin | 0 -> 10385 bytes | |||
-rw-r--r-- | release/windows/msix/README.md | 81 | ||||
-rw-r--r-- | release/windows/msix/create_msix_package.py | 135 |
10 files changed, 276 insertions, 0 deletions
diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 1be0b3210d8a3a30e99a853b50703a7ca7e8ac1 +Subproject feca8c5289794a70bdd375be76fc4bc59d83c96 diff --git a/release/windows/msix/AppxManifest.xml.template b/release/windows/msix/AppxManifest.xml.template new file mode 100644 index 00000000000..9289a67efef --- /dev/null +++ b/release/windows/msix/AppxManifest.xml.template @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4" xmlns:uap6="http://schemas.microsoft.com/appx/manifest/uap/windows10/6" xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7" xmlns:uap8="http://schemas.microsoft.com/appx/manifest/uap/windows10/8" xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10" xmlns:mobile="http://schemas.microsoft.com/appx/manifest/mobile/windows10" xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:rescap3="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/3" xmlns:rescap6="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/6" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:com2="http://schemas.microsoft.com/appx/manifest/com/windows10/2" xmlns:com3="http://schemas.microsoft.com/appx/manifest/com/windows10/3" IgnorableNamespaces="uap uap2 uap3 uap4 uap6 uap7 uap8 uap10 mobile iot desktop desktop2 desktop6 rescap rescap3 rescap6 com com2 com3"> + <Identity Name="BlenderFoundation.Blender[PACKAGETYPE]" Publisher="[PUBLISHER]" Version="[VERSION]" ProcessorArchitecture="x64" /> + <Properties> + <DisplayName>Blender[LTSORNOT]</DisplayName> + <PublisherDisplayName>Blender Foundation</PublisherDisplayName> + <Description>Blender [VERSION] is the Free and Open Source 3D creation suite</Description> + <Logo>Assets\StoreLogo.png</Logo> + </Properties> + <Resources> + <Resource Language="en-us" /> + </Resources> + <Dependencies> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.18335.0" /> + </Dependencies> + <Capabilities> + <rescap:Capability Name="runFullTrust" /> + </Capabilities> + <Applications> + <Application Id="BLENDER" Executable="Blender\blender.exe" EntryPoint="Windows.FullTrustApplication"> + <uap:VisualElements + BackgroundColor="transparent" + DisplayName="Blender [VERSION]" + Square150x150Logo="Assets\Square150x150Logo.png" + Square44x44Logo="Assets\Square44x44Logo.png" + Description="Blender is the Free and Open Source 3D creation suite" + > + <uap:DefaultTile + Wide310x150Logo="Assets\Wide310x150Logo.png" + Square310x310Logo="Assets\Square310x310Logo.png" + Square71x71Logo="Assets\Square71x71Logo.png" + ShortName="Blender [VERSION]" + > + <uap:ShowNameOnTiles> + <uap:ShowOn Tile="square150x150Logo"/> <!-- Show app name on the 150x150 tile --> + <uap:ShowOn Tile="wide310x150Logo"/> <!-- …and also on the 310x150 tile --> + <uap:ShowOn Tile="square310x310Logo"/> <!-- …and also on the 310x150 tile --> + </uap:ShowNameOnTiles> + </uap:DefaultTile> + </uap:VisualElements> + <Extensions> + <uap3:Extension Category="windows.fileTypeAssociation"> + <uap3:FileTypeAssociation Name="blend"> + <uap:SupportedFileTypes> + <uap:FileType>.blend</uap:FileType> + </uap:SupportedFileTypes> + <uap2:SupportedVerbs> + <uap3:Verb Id="open" Parameters=""%1"">open</uap3:Verb> + </uap2:SupportedVerbs> + </uap3:FileTypeAssociation> + </uap3:Extension> + <uap3:Extension Category="windows.appExecutionAlias" Executable="Blender\blender.exe" EntryPoint="Windows.FullTrustApplication"> + <uap3:AppExecutionAlias> + <desktop:ExecutionAlias Alias="blender.exe" /> + </uap3:AppExecutionAlias> + </uap3:Extension> + </Extensions> + </Application> + </Applications> +</Package> diff --git a/release/windows/msix/Assets/Square150x150Logo.png b/release/windows/msix/Assets/Square150x150Logo.png Binary files differnew file mode 100644 index 00000000000..7dbbde793ba --- /dev/null +++ b/release/windows/msix/Assets/Square150x150Logo.png diff --git a/release/windows/msix/Assets/Square310x310Logo.png b/release/windows/msix/Assets/Square310x310Logo.png Binary files differnew file mode 100644 index 00000000000..2190415e35b --- /dev/null +++ b/release/windows/msix/Assets/Square310x310Logo.png diff --git a/release/windows/msix/Assets/Square44x44Logo.png b/release/windows/msix/Assets/Square44x44Logo.png Binary files differnew file mode 100644 index 00000000000..7b9ca070558 --- /dev/null +++ b/release/windows/msix/Assets/Square44x44Logo.png diff --git a/release/windows/msix/Assets/Square71x71Logo.png b/release/windows/msix/Assets/Square71x71Logo.png Binary files differnew file mode 100644 index 00000000000..75bd9bb264a --- /dev/null +++ b/release/windows/msix/Assets/Square71x71Logo.png diff --git a/release/windows/msix/Assets/StoreLogo.png b/release/windows/msix/Assets/StoreLogo.png Binary files differnew file mode 100644 index 00000000000..e8a671b7e0f --- /dev/null +++ b/release/windows/msix/Assets/StoreLogo.png diff --git a/release/windows/msix/Assets/Wide310x150Logo.png b/release/windows/msix/Assets/Wide310x150Logo.png Binary files differnew file mode 100644 index 00000000000..59f5736393a --- /dev/null +++ b/release/windows/msix/Assets/Wide310x150Logo.png diff --git a/release/windows/msix/README.md b/release/windows/msix/README.md new file mode 100644 index 00000000000..8967a655e3d --- /dev/null +++ b/release/windows/msix/README.md @@ -0,0 +1,81 @@ +create_msix_package +=================== + +This tool is used to create MSIX packages from a given ZiP archive. The MSIX +package is distributed mainly through the Microsoft Store. It can also be +installed when downloaded from blender.org. For that to work the MSIX package +needs to be signed. + +Requirements +============ + +* MakeAppX - this tool is distributed with Windows 10 SDK +* SignTool - this tool is also distributed with Windows 10 SDK +* Python 3 (3.7 or later tested) - to run the create_msix_package.py script +* requests module - can be installed with `pip install requests` +* PFX file (optional, but strongly recommended) - for signing the resulting MSIX + package. **NOTE:** If the MSIX package is not signed when uploaded to the Microsoft + store the validation and certification process can take up to three full + business day. + +Usage +===== + +On the command-line: +```batch +set VERSION=2.83.4.0 +set URL=https://download.blender.org/release/Blender2.83/blender-2.83.4-windows64.zip +set PUBID=CN=PUBIDHERE +set PFX=X:\path\to\cert.pfx +set PFXPW=pwhere + +python create_msix_package.py --version %VERSION% --url %URL% --publisher %PUBID% --pfx %PFX% --password %PFXPW% +``` + +Result will be a MSIX package with the name `blender-2.83.4-windows64.msix`. +With the above usage it will be signed. If the signing options are left out the +package will not be signed. + +Optional arguments +================== + +In support of testing and developing the manifest and scripts there are a few +optional arguments: + +* `--skipdl` : If a `blender.zip` is available already next to the tool use this + to skip actual downloading of the archive designated by `--url`. The latter + option is still required +* `--overwrite` : When script fails the final clean-up may be incomplete leaving + the `Content` folder with its structure. Specify this argument to automatically + clean up this folder before starting to seed the `Content` folder +* `--leavezip` : When specified leave the `blender.zip` file while cleaning up + all other intermediate files, including the `Content` folder. This is useful + to not have to re-download the same archive from `--url` on each usage + + +What it does +============ + +The tool creates in the directory it lives a subfolder called `Content`. This is +where all necessary files are placed. + +The `Assets` folder is copied to the `Content` folder. + +From the application manifest template a version with necessary parts replaced as +their actual values as specified on the command-line is realized. This manifest controls the packaging of Blender into the MSIX format. + +Next the tool downloads the designated ZIP archive locally as blender.zip. From +this archive the files are extracted into the `Content\Blender` folder, 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.4-windows64\blender.exe` + +Once the extraction is completed the MakeAppX tool is executed with the `Content` +folder as input. The result will be the MSIX package with the name in the form +`blender-X.YY.Z-windows64.msix`. + +If the PFX file and its password are given on the command-line this MSIX package +will be signed. + +All intermediate files and directories will be removed. diff --git a/release/windows/msix/create_msix_package.py b/release/windows/msix/create_msix_package.py new file mode 100644 index 00000000000..69b0a2ef901 --- /dev/null +++ b/release/windows/msix/create_msix_package.py @@ -0,0 +1,135 @@ +#!/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.") |