Skip to content

Commit 335748c

Browse files
committed
Adopt pymsbuild-msix for building
1 parent ffcd936 commit 335748c

File tree

7 files changed

+59
-75
lines changed

7 files changed

+59
-75
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
sys.exit(0 if sys.version_info[:5] == (3, 14, 0, 'beta', 1) else 1)"
5757
5858
- name: Install build dependencies
59-
run: python -m pip install "pymsbuild>=1.2.0b1"
59+
run: python -m pip install "pymsbuild>=1.2.2b1" "pymsbuild-msix>=0.1.0a1"
6060

6161
- name: 'Install test runner'
6262
run: python -m pip install pytest pytest-cov

_make_helper.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,21 @@ def get_dirs():
8686
if not _layout:
8787
_layout = _temp / "layout"
8888
os.environ["PYMSBUILD_LAYOUT_DIR"] = str(_layout)
89-
out = _layout / "python-manager"
9089

9190
return dict(
9291
root=root,
93-
out=out,
92+
out=_layout,
9493
src=src,
9594
dist=dist,
9695
build=build,
9796
temp=temp,
9897
)
9998

10099

101-
def get_msix_version(dirs):
100+
def get_msix_version(manifest):
102101
from io import StringIO
103102
from xml.etree import ElementTree as ET
104-
appx = (dirs["out"] / "appxmanifest.xml").read_text("utf-8")
103+
appx = Path(manifest).read_text("utf-8")
105104
NS = dict(e for _, e in ET.iterparse(StringIO(appx), events=("start-ns",)))
106105
for k, v in NS.items():
107106
ET.register_namespace(k, v)
@@ -110,10 +109,15 @@ def get_msix_version(dirs):
110109
return identity.attrib['Version']
111110

112111

113-
def get_output_name(dirs):
114-
with open(dirs["out"] / "version.txt", "r", encoding="utf-8") as f:
115-
version = f.read().strip()
116-
return f"python-manager-{version}"
112+
def get_output_name(layout):
113+
with open(layout / "__state.txt", "r") as f:
114+
for line in f:
115+
if line == "# BEGIN FILES":
116+
break
117+
key, sep, value = line.partition("=")
118+
if sep and key == "msix_name":
119+
return value.rpartition(".")[0]
120+
return "python-manager"
117121

118122

119123
copyfile = shutil.copyfile

_msbuild.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from pymsbuild import *
33
from pymsbuild.dllpack import *
4+
from pymsbuild_msix import AppxManifest, AppInstaller, ResourcesXml
45

56

67
DLL_NAME = "python314"
@@ -15,7 +16,7 @@ def can_embed(tag):
1516

1617
METADATA = {
1718
"Metadata-Version": "2.2",
18-
"Name": "manage",
19+
"Name": "python-manager",
1920
"Version": "0.1a0",
2021
"Author": "Python Software Foundation",
2122
"Author-email": "[email protected]",
@@ -179,8 +180,8 @@ def pyshellext(ext='.exe', **props):
179180
PACKAGE = Package('python-manager',
180181
PyprojectTomlFile('pyproject.toml'),
181182
# MSIX manifest
182-
File('src/pymanager/appxmanifest.xml'),
183-
File('src/pymanager/pymanager.appinstaller'),
183+
AppxManifest('src/pymanager/appxmanifest.xml'),
184+
AppInstaller('src/pymanager/pymanager.appinstaller'),
184185
Package(
185186
'MSIX.AppInstaller.Data',
186187
File('src/pymanager/MSIXAppInstallerData.xml'),
@@ -208,6 +209,7 @@ def pyshellext(ext='.exe', **props):
208209
),
209210

210211
# Directory for MSIX resources
212+
ResourcesXml('src/pymanager/resources.xml'),
211213
Package(
212214
'_resources',
213215
File('src/pymanager/_resources/*.png'),

ci/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ stages:
9393
workingDirectory: $(Build.BinariesDirectory)
9494
9595
- powershell: |
96-
python -m pip install "pymsbuild>=1.2.0b1"
96+
python -m pip install "pymsbuild>=1.2.2b1" "pymsbuild-msix>=0.1.0a1"
9797
displayName: 'Install build dependencies'
9898
9999
- ${{ if eq(parameters.PreTest, 'true') }}:

make-msi.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
DIRS = get_dirs()
1313
BUILD = DIRS["build"]
1414
TEMP = DIRS["temp"]
15-
LAYOUT = DIRS["out"]
15+
LAYOUT = DIRS["out"] / "python-manager"
1616
SRC = DIRS["src"]
1717
DIST = DIRS["dist"]
1818

1919
# Calculate output names (must be after building)
20-
NAME = get_output_name(DIRS)
21-
VERSION = get_msix_version(DIRS)
20+
NAME = get_output_name(DIRS["out"])
21+
VERSION = get_msix_version(LAYOUT / "appxmanifest.xml")
2222

2323
# Package into MSI
2424
pydllname = [p.stem for p in (LAYOUT / "runtime").glob("python*.dll")][0]

make-msix.py

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,11 @@
99
copyfile,
1010
copytree,
1111
get_dirs,
12-
get_msix_version,
1312
get_output_name,
14-
get_sdk_bins,
1513
rmtree,
1614
unlink,
1715
)
1816

19-
SDK_BINS = get_sdk_bins()
20-
21-
MAKEAPPX = SDK_BINS / "makeappx.exe"
22-
MAKEPRI = SDK_BINS / "makepri.exe"
23-
24-
for tool in [MAKEAPPX, MAKEPRI]:
25-
if not tool.is_file():
26-
print("Unable to locate Windows Kit tool", tool.name, file=sys.stderr)
27-
sys.exit(3)
28-
2917
DIRS = get_dirs()
3018
BUILD = DIRS["build"]
3119
TEMP = DIRS["temp"]
@@ -35,51 +23,25 @@
3523
DIST = DIRS["dist"]
3624

3725
# Calculate output names (must be after building)
38-
NAME = get_output_name(DIRS)
39-
VERSION = get_msix_version(DIRS)
40-
DIST_MSIX = DIST / f"{NAME}.msix"
41-
DIST_STORE_MSIX = DIST / f"{NAME}-store.msix"
42-
DIST_APPXSYM = DIST / f"{NAME}-store.appxsym"
43-
DIST_MSIXUPLOAD = DIST / f"{NAME}-store.msixupload"
26+
DIST_MSIX = DIST / get_output_name(LAYOUT)
27+
DIST_STORE_MSIX = DIST_MSIX.with_name(f"{DIST_MSIX.stem}-store.msix")
28+
DIST_APPXSYM = DIST_STORE_MSIX.with_suffix(".appxsym")
29+
DIST_MSIXUPLOAD = DIST_STORE_MSIX.with_suffix(".msixupload")
4430

4531
unlink(DIST_MSIX, DIST_STORE_MSIX, DIST_APPXSYM, DIST_MSIXUPLOAD)
4632

47-
# Generate resources info in LAYOUT
48-
if not (LAYOUT / "_resources.pri").is_file():
49-
run([MAKEPRI, "new", "/o",
50-
"/pr", LAYOUT,
51-
"/cf", SRC / "pymanager/resources.xml",
52-
"/of", LAYOUT / "_resources.pri",
53-
"/mf", "appx"])
54-
55-
# Clean up non-shipping files from LAYOUT
56-
preserved = [
57-
*LAYOUT.glob("pyshellext*.dll"),
58-
]
59-
60-
for f in preserved:
61-
print("Preserving", f, "as", TEMP / f.name)
62-
copyfile(f, TEMP / f.name)
63-
64-
unlink(
65-
*LAYOUT.rglob("*.pdb"),
66-
*LAYOUT.rglob("*.pyc"),
67-
*LAYOUT.rglob("__pycache__"),
68-
*preserved,
69-
)
70-
7133
# Package into DIST
72-
run([MAKEAPPX, "pack", "/o", "/d", LAYOUT, "/p", DIST_MSIX])
34+
run([sys.executable, "-m", "pymsbuild", "pack", "-v"])
7335

7436
print("Copying appinstaller file to", DIST)
75-
copyfile(LAYOUT / "pymanager.appinstaller", DIST / "pymanager.appinstaller")
37+
copyfile(LAYOUT / "python-manager/pymanager.appinstaller", DIST / "pymanager.appinstaller")
7638

7739

7840
if os.getenv("PYMANAGER_APPX_STORE_PUBLISHER"):
7941
# Clone and update layout for Store build
8042
rmtree(LAYOUT2)
8143
copytree(LAYOUT, LAYOUT2)
82-
unlink(*LAYOUT2.glob("*.appinstaller"))
44+
unlink(*LAYOUT2.glob("python-manager/*.appinstaller"))
8345

8446
def patch_appx(source):
8547
from xml.etree import ElementTree as ET
@@ -116,9 +78,16 @@ def patch_appx(source):
11678
with open(source, "wb") as f:
11779
xml.write(f, "utf-8")
11880

119-
patch_appx(LAYOUT2 / "appxmanifest.xml")
81+
patch_appx(LAYOUT2 / "python-manager/appxmanifest.xml")
12082

121-
run([MAKEAPPX, "pack", "/o", "/d", LAYOUT2, "/p", DIST_STORE_MSIX])
83+
run(
84+
[sys.executable, "-m", "pymsbuild", "pack", "-v"],
85+
env={
86+
**os.environ,
87+
"PYMSBUILD_LAYOUT_DIR": str(LAYOUT2),
88+
"PYMSBUILD_MSIX_NAME": DIST_STORE_MSIX.name,
89+
}
90+
)
12291

12392
# Pack symbols
12493
print("Packing symbols to", DIST_APPXSYM)
@@ -131,9 +100,3 @@ def patch_appx(source):
131100
with zipfile.ZipFile(DIST_MSIXUPLOAD, "w") as zf:
132101
zf.write(DIST_STORE_MSIX, arcname=DIST_STORE_MSIX.name)
133102
zf.write(DIST_APPXSYM, arcname=DIST_APPXSYM.name)
134-
135-
136-
for f in preserved:
137-
print("Restoring", f, "from", TEMP / f.name)
138-
copyfile(TEMP / f.name, f)
139-
unlink(TEMP / f.name)

make.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import subprocess
33
import sys
4+
from pathlib import PurePath
45
from subprocess import check_call as run
56
from _make_helper import get_dirs, rmtree, unlink
67

@@ -38,13 +39,27 @@
3839
pass
3940

4041
# Run main build - this fills in BUILD and LAYOUT
41-
run([sys.executable, "-m", "pymsbuild", "wheel"],
42+
run([sys.executable, "-m", "pymsbuild", "msix"],
4243
cwd=DIRS["root"],
4344
env={**os.environ, "BUILD_SOURCEBRANCH": ref})
4445

4546
# Bundle current latest release
46-
run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", TEMP / "bundle", "default"])
47-
(LAYOUT / "bundled").mkdir(parents=True, exist_ok=True)
48-
(TEMP / "bundle" / "index.json").rename(LAYOUT / "bundled" / "fallback-index.json")
49-
for f in (TEMP / "bundle").iterdir():
50-
f.rename(LAYOUT / "bundled" / f.name)
47+
run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", LAYOUT / "bundled", "default"])
48+
(LAYOUT / "bundled" / "index.json").rename(LAYOUT / "bundled" / "fallback-index.json")
49+
50+
# Update package state for when we pack
51+
new_lines = []
52+
state_txt = LAYOUT.parent / "__state.txt"
53+
for line in state_txt.read_text("utf-8").splitlines():
54+
if not line or "=" in line or line.startswith("#"):
55+
new_lines.append(line)
56+
continue
57+
# Exclude the in-proc shell extension from the MSIX
58+
if PurePath(line).match("pyshellext*.dll"):
59+
continue
60+
new_lines.append(line)
61+
# Include the bundled files in the MSIX
62+
for f in LAYOUT.rglob(r"bundled\*"):
63+
new_lines.append(str(f.relative_to(state_txt.parent)))
64+
65+
state_txt.write_text("\n".join(new_lines), encoding="utf-8")

0 commit comments

Comments
 (0)