Skip to content

Commit 8691f8f

Browse files
committed
Adds the pipeline and workflow files to the repo
- Adds the pipeline and workflow files to the repo - Updates the README.md - Adds LICENSE file
1 parent e158002 commit 8691f8f

File tree

6 files changed

+222
-0
lines changed

6 files changed

+222
-0
lines changed

.github/scripts/package_python.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env python3
2+
"""Copies Python development files (headers, libs and dlls) into a structured directory for uploading to github artifacts."""
3+
4+
from __future__ import annotations
5+
6+
import shutil
7+
import subprocess
8+
from concurrent.futures import ProcessPoolExecutor
9+
from os import cpu_count
10+
from pathlib import Path
11+
12+
13+
def get_uv_python_dirs() -> list[Path]:
14+
"""Get paths of all the python installations by uv."""
15+
result = subprocess.run(["uv", "python", "dir"], capture_output=True, text=True, check=True) # noqa: S607
16+
python_dir = Path(result.stdout.strip())
17+
cpython_installation_dirs = python_dir.glob("cpython-*")
18+
return list(cpython_installation_dirs)
19+
20+
21+
def copy_python_dev_files(src_dir: Path, dest_root: Path) -> None:
22+
"""Copy Python development files from src_dir to dest_root."""
23+
include_dir = src_dir / "include"
24+
libs_dir = src_dir / "libs"
25+
dlls = src_dir.glob("python*.dll")
26+
dll_paths = [src_dir / dll_name for dll_name in dlls]
27+
28+
dest_root.mkdir(parents=True, exist_ok=True)
29+
30+
# Copy include and libs
31+
print(f"[INFO] Copying include -> {dest_root / 'include'}")
32+
shutil.copytree(include_dir, dest_root / "include", dirs_exist_ok=True)
33+
34+
print(f"[INFO] Copying libs -> {dest_root / 'libs'}")
35+
shutil.copytree(libs_dir, dest_root / "libs", dirs_exist_ok=True)
36+
37+
# Copy DLLs
38+
for dll_path in dll_paths:
39+
if dll_path.exists():
40+
print(f"[INFO] Copying DLL -> {dll_path.name}")
41+
shutil.copy2(dll_path, dest_root / dll_path.name)
42+
else:
43+
print(f"[WARN] DLL not found: {dll_path}")
44+
45+
46+
def main() -> None:
47+
"""Entry point."""
48+
cpython_installation_dirs = get_uv_python_dirs()
49+
50+
num_cores = cpu_count() or 1
51+
with ProcessPoolExecutor(max_workers=num_cores * 2) as executor:
52+
for cpython_dir in cpython_installation_dirs:
53+
if "x86_64" in cpython_dir.name:
54+
arch_dir_name = "x86_64"
55+
elif "x86" in cpython_dir.name:
56+
arch_dir_name = "x86"
57+
elif "aarch64" in cpython_dir.name:
58+
arch_dir_name = "aarch64"
59+
else:
60+
arch_dir_name = "unknown_arch"
61+
dest_root = Path("dist") / arch_dir_name / cpython_dir.name
62+
executor.submit(copy_python_dev_files, cpython_dir, dest_root)
63+
64+
65+
if __name__ == "__main__":
66+
main()

.github/scripts/uv_download.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env python3
2+
"""Script to download python using uv."""
3+
4+
from __future__ import annotations
5+
6+
import subprocess
7+
from concurrent.futures import ProcessPoolExecutor
8+
from os import cpu_count
9+
10+
11+
def list_available_versions() -> list[str]:
12+
"""Gets the list of available python version using the ``uv python list`` command."""
13+
result = subprocess.run(["uv", "python", "list", "--all-arches"], check=True, capture_output=True, text=True) # noqa: S607
14+
15+
raw_lines = result.stdout.splitlines()
16+
return [raw_line.split()[0] for raw_line in raw_lines if raw_line.startswith("cpython")]
17+
18+
19+
def install_python_version(python_version: str) -> None:
20+
"""Installs the given python version using uv."""
21+
print(f"Installing {python_version}...")
22+
subprocess.run(["uv", "python", "install", "--no-bin", python_version], check=True) # noqa: S607
23+
24+
25+
def main() -> None:
26+
"""Entry point."""
27+
cpython_versions = list_available_versions()
28+
29+
num_cores = cpu_count() or 1
30+
with ProcessPoolExecutor(max_workers=num_cores * 4) as executor:
31+
for cpython_version in cpython_versions:
32+
executor.submit(install_python_version, cpython_version)
33+
34+
35+
if __name__ == "__main__":
36+
main()

.github/workflows/publish.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Publish Artifacts to GitHub Releases
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
release-notes:
7+
description: "Release notes"
8+
required: false
9+
default: "Includes the latest build artifacts."
10+
11+
permissions:
12+
contents: write
13+
14+
jobs:
15+
publish-artifacts:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Download all build artifacts
19+
uses: dawidd6/action-download-artifact@v12
20+
with:
21+
workflow: "windows-python-dev-kit.yml"
22+
path: dist/
23+
skip_unpack: true
24+
25+
- name: Generate ISO8601 tag (git-safe)
26+
id: iso
27+
run: |
28+
echo "tag=$(date -u +'%Y-%m-%dT%H-%M-%SZ')" >> "$GITHUB_OUTPUT"
29+
30+
- name: Generate checksum
31+
run: |
32+
cd dist
33+
sha256sum *.zip > checksum.sha256
34+
cat checksum.sha256
35+
36+
- name: Create or update release
37+
uses: softprops/action-gh-release@v2
38+
with:
39+
tag_name: ${{ steps.iso.outputs.tag }}
40+
name: ${{ steps.iso.outputs.tag }}
41+
body: ${{ github.event.inputs.release-notes }}
42+
draft: false
43+
prerelease: false
44+
files: dist/*
45+
overwrite_files: true
46+
make_latest: true
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Windows Python Development Kit
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
package-python-dev:
8+
runs-on: ${{ 'windows-latest' }}
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v5
12+
13+
- name: Install uv
14+
uses: astral-sh/setup-uv@v7
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v6
18+
19+
- name: Download all Python versions using uv
20+
shell: pwsh
21+
run: |
22+
python -V
23+
python .github/scripts/uv_download.py
24+
25+
- name: Run packaging script
26+
run: python .github/scripts/package_python.py
27+
28+
- name: Upload x86_64 artifacts
29+
uses: actions/upload-artifact@v6
30+
with:
31+
name: python-windows-x86_64
32+
path: dist/x86_64/
33+
overwrite: true
34+
35+
- name: Upload x86 artifacts
36+
uses: actions/upload-artifact@v6
37+
with:
38+
name: python-windows-x86
39+
path: dist/x86/
40+
overwrite: true
41+
42+
- name: Upload aarch64 artifacts
43+
uses: actions/upload-artifact@v6
44+
with:
45+
name: python-windows-aarch64
46+
path: dist/aarch64/
47+
overwrite: true

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Yoshikage Kira
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Windows Python Builds
2+
3+
This repo contains the workflow files to download the Python Dev Libraries from Windows and publish them in
4+
Github release section.
5+
6+
The Dev libraries include the x86, x86_64, and aarch64 libraries and can be used to cross compile CPython extensions from non-Windows OS.

0 commit comments

Comments
 (0)