From 335748cd57461507c383ee795a7cdba5e18ffe7c Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 16 May 2025 16:57:14 +0100 Subject: [PATCH] Adopt pymsbuild-msix for building --- .github/workflows/build.yml | 2 +- _make_helper.py | 20 ++++++----- _msbuild.py | 8 +++-- ci/release.yml | 2 +- make-msi.py | 6 ++-- make-msix.py | 69 +++++++++---------------------------- make.py | 27 +++++++++++---- 7 files changed, 59 insertions(+), 75 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7412d78..8c7ad84 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,7 +56,7 @@ jobs: sys.exit(0 if sys.version_info[:5] == (3, 14, 0, 'beta', 1) else 1)" - name: Install build dependencies - run: python -m pip install "pymsbuild>=1.2.0b1" + run: python -m pip install "pymsbuild>=1.2.2b1" "pymsbuild-msix>=0.1.0a1" - name: 'Install test runner' run: python -m pip install pytest pytest-cov diff --git a/_make_helper.py b/_make_helper.py index ee27ba9..356633d 100644 --- a/_make_helper.py +++ b/_make_helper.py @@ -86,11 +86,10 @@ def get_dirs(): if not _layout: _layout = _temp / "layout" os.environ["PYMSBUILD_LAYOUT_DIR"] = str(_layout) - out = _layout / "python-manager" return dict( root=root, - out=out, + out=_layout, src=src, dist=dist, build=build, @@ -98,10 +97,10 @@ def get_dirs(): ) -def get_msix_version(dirs): +def get_msix_version(manifest): from io import StringIO from xml.etree import ElementTree as ET - appx = (dirs["out"] / "appxmanifest.xml").read_text("utf-8") + appx = Path(manifest).read_text("utf-8") NS = dict(e for _, e in ET.iterparse(StringIO(appx), events=("start-ns",))) for k, v in NS.items(): ET.register_namespace(k, v) @@ -110,10 +109,15 @@ def get_msix_version(dirs): return identity.attrib['Version'] -def get_output_name(dirs): - with open(dirs["out"] / "version.txt", "r", encoding="utf-8") as f: - version = f.read().strip() - return f"python-manager-{version}" +def get_output_name(layout): + with open(layout / "__state.txt", "r") as f: + for line in f: + if line == "# BEGIN FILES": + break + key, sep, value = line.partition("=") + if sep and key == "msix_name": + return value.rpartition(".")[0] + return "python-manager" copyfile = shutil.copyfile diff --git a/_msbuild.py b/_msbuild.py index 387a6cd..370be29 100644 --- a/_msbuild.py +++ b/_msbuild.py @@ -1,6 +1,7 @@ import os from pymsbuild import * from pymsbuild.dllpack import * +from pymsbuild_msix import AppxManifest, AppInstaller, ResourcesXml DLL_NAME = "python314" @@ -15,7 +16,7 @@ def can_embed(tag): METADATA = { "Metadata-Version": "2.2", - "Name": "manage", + "Name": "python-manager", "Version": "0.1a0", "Author": "Python Software Foundation", "Author-email": "steve.dower@python.org", @@ -179,8 +180,8 @@ def pyshellext(ext='.exe', **props): PACKAGE = Package('python-manager', PyprojectTomlFile('pyproject.toml'), # MSIX manifest - File('src/pymanager/appxmanifest.xml'), - File('src/pymanager/pymanager.appinstaller'), + AppxManifest('src/pymanager/appxmanifest.xml'), + AppInstaller('src/pymanager/pymanager.appinstaller'), Package( 'MSIX.AppInstaller.Data', File('src/pymanager/MSIXAppInstallerData.xml'), @@ -208,6 +209,7 @@ def pyshellext(ext='.exe', **props): ), # Directory for MSIX resources + ResourcesXml('src/pymanager/resources.xml'), Package( '_resources', File('src/pymanager/_resources/*.png'), diff --git a/ci/release.yml b/ci/release.yml index 4c3bdf8..b6f37d9 100644 --- a/ci/release.yml +++ b/ci/release.yml @@ -93,7 +93,7 @@ stages: workingDirectory: $(Build.BinariesDirectory) - powershell: | - python -m pip install "pymsbuild>=1.2.0b1" + python -m pip install "pymsbuild>=1.2.2b1" "pymsbuild-msix>=0.1.0a1" displayName: 'Install build dependencies' - ${{ if eq(parameters.PreTest, 'true') }}: diff --git a/make-msi.py b/make-msi.py index 1072a26..3003586 100644 --- a/make-msi.py +++ b/make-msi.py @@ -12,13 +12,13 @@ DIRS = get_dirs() BUILD = DIRS["build"] TEMP = DIRS["temp"] -LAYOUT = DIRS["out"] +LAYOUT = DIRS["out"] / "python-manager" SRC = DIRS["src"] DIST = DIRS["dist"] # Calculate output names (must be after building) -NAME = get_output_name(DIRS) -VERSION = get_msix_version(DIRS) +NAME = get_output_name(DIRS["out"]) +VERSION = get_msix_version(LAYOUT / "appxmanifest.xml") # Package into MSI pydllname = [p.stem for p in (LAYOUT / "runtime").glob("python*.dll")][0] diff --git a/make-msix.py b/make-msix.py index cc07fdc..12a979a 100644 --- a/make-msix.py +++ b/make-msix.py @@ -9,23 +9,11 @@ copyfile, copytree, get_dirs, - get_msix_version, get_output_name, - get_sdk_bins, rmtree, unlink, ) -SDK_BINS = get_sdk_bins() - -MAKEAPPX = SDK_BINS / "makeappx.exe" -MAKEPRI = SDK_BINS / "makepri.exe" - -for tool in [MAKEAPPX, MAKEPRI]: - if not tool.is_file(): - print("Unable to locate Windows Kit tool", tool.name, file=sys.stderr) - sys.exit(3) - DIRS = get_dirs() BUILD = DIRS["build"] TEMP = DIRS["temp"] @@ -35,51 +23,25 @@ DIST = DIRS["dist"] # Calculate output names (must be after building) -NAME = get_output_name(DIRS) -VERSION = get_msix_version(DIRS) -DIST_MSIX = DIST / f"{NAME}.msix" -DIST_STORE_MSIX = DIST / f"{NAME}-store.msix" -DIST_APPXSYM = DIST / f"{NAME}-store.appxsym" -DIST_MSIXUPLOAD = DIST / f"{NAME}-store.msixupload" +DIST_MSIX = DIST / get_output_name(LAYOUT) +DIST_STORE_MSIX = DIST_MSIX.with_name(f"{DIST_MSIX.stem}-store.msix") +DIST_APPXSYM = DIST_STORE_MSIX.with_suffix(".appxsym") +DIST_MSIXUPLOAD = DIST_STORE_MSIX.with_suffix(".msixupload") unlink(DIST_MSIX, DIST_STORE_MSIX, DIST_APPXSYM, DIST_MSIXUPLOAD) -# Generate resources info in LAYOUT -if not (LAYOUT / "_resources.pri").is_file(): - run([MAKEPRI, "new", "/o", - "/pr", LAYOUT, - "/cf", SRC / "pymanager/resources.xml", - "/of", LAYOUT / "_resources.pri", - "/mf", "appx"]) - -# Clean up non-shipping files from LAYOUT -preserved = [ - *LAYOUT.glob("pyshellext*.dll"), -] - -for f in preserved: - print("Preserving", f, "as", TEMP / f.name) - copyfile(f, TEMP / f.name) - -unlink( - *LAYOUT.rglob("*.pdb"), - *LAYOUT.rglob("*.pyc"), - *LAYOUT.rglob("__pycache__"), - *preserved, -) - # Package into DIST -run([MAKEAPPX, "pack", "/o", "/d", LAYOUT, "/p", DIST_MSIX]) +run([sys.executable, "-m", "pymsbuild", "pack", "-v"]) print("Copying appinstaller file to", DIST) -copyfile(LAYOUT / "pymanager.appinstaller", DIST / "pymanager.appinstaller") +copyfile(LAYOUT / "python-manager/pymanager.appinstaller", DIST / "pymanager.appinstaller") if os.getenv("PYMANAGER_APPX_STORE_PUBLISHER"): # Clone and update layout for Store build rmtree(LAYOUT2) copytree(LAYOUT, LAYOUT2) - unlink(*LAYOUT2.glob("*.appinstaller")) + unlink(*LAYOUT2.glob("python-manager/*.appinstaller")) def patch_appx(source): from xml.etree import ElementTree as ET @@ -116,9 +78,16 @@ def patch_appx(source): with open(source, "wb") as f: xml.write(f, "utf-8") - patch_appx(LAYOUT2 / "appxmanifest.xml") + patch_appx(LAYOUT2 / "python-manager/appxmanifest.xml") - run([MAKEAPPX, "pack", "/o", "/d", LAYOUT2, "/p", DIST_STORE_MSIX]) + run( + [sys.executable, "-m", "pymsbuild", "pack", "-v"], + env={ + **os.environ, + "PYMSBUILD_LAYOUT_DIR": str(LAYOUT2), + "PYMSBUILD_MSIX_NAME": DIST_STORE_MSIX.name, + } + ) # Pack symbols print("Packing symbols to", DIST_APPXSYM) @@ -131,9 +100,3 @@ def patch_appx(source): with zipfile.ZipFile(DIST_MSIXUPLOAD, "w") as zf: zf.write(DIST_STORE_MSIX, arcname=DIST_STORE_MSIX.name) zf.write(DIST_APPXSYM, arcname=DIST_APPXSYM.name) - - -for f in preserved: - print("Restoring", f, "from", TEMP / f.name) - copyfile(TEMP / f.name, f) - unlink(TEMP / f.name) diff --git a/make.py b/make.py index 1da9cc2..cf06db2 100644 --- a/make.py +++ b/make.py @@ -1,6 +1,7 @@ import os import subprocess import sys +from pathlib import PurePath from subprocess import check_call as run from _make_helper import get_dirs, rmtree, unlink @@ -38,13 +39,27 @@ pass # Run main build - this fills in BUILD and LAYOUT -run([sys.executable, "-m", "pymsbuild", "wheel"], +run([sys.executable, "-m", "pymsbuild", "msix"], cwd=DIRS["root"], env={**os.environ, "BUILD_SOURCEBRANCH": ref}) # Bundle current latest release -run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", TEMP / "bundle", "default"]) -(LAYOUT / "bundled").mkdir(parents=True, exist_ok=True) -(TEMP / "bundle" / "index.json").rename(LAYOUT / "bundled" / "fallback-index.json") -for f in (TEMP / "bundle").iterdir(): - f.rename(LAYOUT / "bundled" / f.name) +run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", LAYOUT / "bundled", "default"]) +(LAYOUT / "bundled" / "index.json").rename(LAYOUT / "bundled" / "fallback-index.json") + +# Update package state for when we pack +new_lines = [] +state_txt = LAYOUT.parent / "__state.txt" +for line in state_txt.read_text("utf-8").splitlines(): + if not line or "=" in line or line.startswith("#"): + new_lines.append(line) + continue + # Exclude the in-proc shell extension from the MSIX + if PurePath(line).match("pyshellext*.dll"): + continue + new_lines.append(line) +# Include the bundled files in the MSIX +for f in LAYOUT.rglob(r"bundled\*"): + new_lines.append(str(f.relative_to(state_txt.parent))) + +state_txt.write_text("\n".join(new_lines), encoding="utf-8") pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy