Skip to content

Instantly share code, notes, and snippets.

@jonwis
Created March 17, 2025 06:13
Show Gist options
  • Save jonwis/dd5c33737d5e02b35dfbe53074b28122 to your computer and use it in GitHub Desktop.
Save jonwis/dd5c33737d5e02b35dfbe53074b28122 to your computer and use it in GitHub Desktop.
Deploy WASDK with python
import os
import sys
import subprocess
import urllib.request
import argparse
from pathlib import Path
wasdk = {
"name": "Microsoft.WindowsAppSDK",
"version": "1.7.250127003-experimental3",
}
abiwinrt = {
"name": "Microsoft.Windows.AbiWinRT",
"version": "2.0.210330.2",
}
def find_nuget():
"""Find nuget.exe in PATH or common locations"""
# Check if nuget is in PATH
try:
subprocess.run(["nuget", "help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
return "nuget"
except FileNotFoundError:
pass
# Check common locations
common_locations = [
os.path.join(os.environ.get("ProgramFiles(x86)", ""), "NuGet", "nuget.exe"),
os.path.join(os.environ.get("ProgramFiles", ""), "NuGet", "nuget.exe"),
os.path.join(os.environ.get("LOCALAPPDATA", ""), "NuGet", "nuget.exe"),
os.path.join(os.path.expanduser("~"), ".nuget", "nuget.exe"),
]
for location in common_locations:
if os.path.exists(location):
return location
# Go download it to ~/.nuget
destination = os.path.join(os.path.expanduser("~"), ".nuget")
os.makedirs(destination, exist_ok=True)
nuget_path = os.path.join(destination, "nuget.exe")
if not os.path.exists(nuget_path):
print(f"nuget.exe not found in common locations. Downloading to {destination}...")
urllib.request.urlretrieve("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", nuget_path)
return nuget_path
def install_wasdk(nuget_path, output_dir):
"""Install the latest Windows App SDK using nuget"""
print(f"Installing latest Windows App SDK to {output_dir}...")
# Create output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)
# Use nuget to install the package
cmd = [
nuget_path,
"install", "Microsoft.WindowsAppSDK",
"-OutputDirectory", output_dir,
"-ExcludeVersion"
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
print("Windows App SDK installed successfully!")
print(f"Package installed to: {os.path.join(output_dir, 'Microsoft.WindowsAppSDK')}")
return True
except subprocess.CalledProcessError as e:
print(f"Error installing Windows App SDK: {e}")
print(f"NuGet output: {e.stdout}")
print(f"NuGet error: {e.stderr}")
return False
def fetch_packages(output_dir):
"""Fetch the Windows App SDK and AbiWinRT packages"""
nuget_path = find_nuget()
cmd = [
nuget_path,
"install", wasdk["name"],
"-Version", wasdk["version"],
"-OutputDirectory", output_dir,
"-ExcludeVersion"
]
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
if result.returncode != 0:
print(f"Error installing {wasdk['name']}: {result.stderr}")
sys.exit(1)
cmd = [
nuget_path,
"install", abiwinrt["name"],
"-Version", abiwinrt["version"],
"-OutputDirectory", output_dir,
"-ExcludeVersion"
]
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
if result.returncode != 0:
print(f"Error installing {abiwinrt['name']}: {result.stderr}")
sys.exit(1)
def winmds_in_path(path):
"""Check if any WinMD files are in the specified path"""
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".winmd"):
return True
return False
def project_abi_package(output_dir, sdk_dir, sdk_version):
"""Project the Windows App SDK package"""
sdk_references = os.path.join(sdk_dir, "References", sdk_version)
abi_output_path = os.path.join(output_dir, "abi")
# Grab all the WinMDs, recursively, from output_dir and {sdk_dir}/References/{sdk_version}
winmds_in = Path(output_dir).rglob("*.winmd");
winmds_refs = Path(sdk_references).rglob("*.winmd")
# Write those to a .rsp file along with the other arguments to abiwinrt
rsp_file = os.path.join(output_dir, "abiwinrt.rsp")
with open(rsp_file, "w") as f:
f.write(f"-output \"{abi_output_path}\"\n")
for winmd in winmds_in:
f.write(f"-in \"{winmd}\"\n")
for winmd in winmds_refs:
f.write(f"-ref \"{winmd}\"\n")
# Use the abiwinrt tool to project the WinMDs. Search under the output_dir\abiwinrt for abi.exe
abiwinrt_tool = list(Path(output_dir).rglob("abi.exe")).pop()
if (not abiwinrt_tool) or (not os.path.exists(abiwinrt_tool)):
print("abiwinrt tool not found in the output directory")
sys.exit(1)
result = subprocess.run(f"{abiwinrt_tool} @{rsp_file}", capture_output=True, text=True, check=False)
if result.returncode != 0:
print(f"Error projecting WinMD ABI: {result.stderr}")
sys.exit(1)
def guess_winsdk_version_and_dir():
"""Guess the Windows SDK version and directory"""
# Read the "KitsRoot10" under the "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots"
# registry key to find the Windows SDK installation directory
import winreg
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\\WOW6432Node\\Microsoft\\Windows Kits\\Installed Roots") as key:
kits_root = winreg.QueryValueEx(key, "KitsRoot10")[0]
sdk_dir = os.path.join(kits_root, "10")
# Enumerate the versions under the sdk_dir\Include directory, whose names
# are dotted four part versions like "10.0.22621.0". Pick the latest one.
include_dir = os.path.join(sdk_dir, "Include")
versions = os.listdir(include_dir)
versions.sort(reverse=True)
sdk_version = versions[0]
return sdk_dir, sdk_version
def main():
parser = argparse.ArgumentParser(description="Install Windows App SDK using NuGet")
parser.add_argument("output_dir", help="Directory to install the Windows App SDK package")
parser.add_argument("sdk_dir", help="Directory where the Windows SDK is installed")
parser.add_argument("sdk_version", help="Version of the Windows SDK to use")
args = parser.parse_args()
output_dir = os.path.abspath(args.output_dir)
if not args.sdk_dir or not args.sdk_version:
args.sdk_dir, args.sdk_version = guess_winsdk_version_and_dir()
fetch_packages(output_dir)
project_abi_package(output_dir, args.sdk_dir, args.sdk_version)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment