Skip to content

Commit

Permalink
we are back in business
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek committed May 21, 2024
1 parent 462163c commit 2a0edd1
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 6 deletions.
19 changes: 15 additions & 4 deletions .github/workflows/build-distributions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ jobs:
fail-fast: false
matrix:
job:
# - target: x86_64-pc-windows-msvc
# os: windows-2019
- target: x86_64-pc-windows-msvc
os: windows-2019
- target: aarch64-apple-darwin
os: macos-14
- target: x86_64-apple-darwin
Expand All @@ -160,9 +160,20 @@ jobs:
-m pip install
${{ inputs.version && format('hatch=={0}', inputs.version) || '.' }}
- name: Set up Windows trampoline
if: startsWith(matrix.job.os, 'windows-')
run: |-
git clone -q --depth 1 -b relative-trampoline https://github.com/ofek/uv.git
cd uv/crates/uv-trampoline
rustup toolchain install nightly-2024-03-19
rustup target add ${{ matrix.job.target }}
rustup component add rust-src --toolchain nightly-2024-03-19-${{ matrix.job.target }}
cargo build --release --target ${{ matrix.job.target }}
- name: Make scripts portable
if: startsWith(matrix.job.os, 'macos-')
run: ./python/bin/python release/unix/make_scripts_portable.py
run: >-
${{ startsWith(matrix.job.os, 'windows-') && '.\\python\\python.exe' || './python/bin/python' }}
release/${{ startsWith(matrix.job.os, 'windows-') && 'windows' || 'unix' }}/make_scripts_portable.py
- name: Strip debug symbols
if: startsWith(matrix.job.os, 'macos-')
Expand Down
36 changes: 34 additions & 2 deletions .github/workflows/build-hatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
# Windows
- target: x86_64-pc-windows-msvc
os: windows-2022
# use-dist: true
use-dist: true
- target: i686-pc-windows-msvc
os: windows-2022
# macOS
Expand Down Expand Up @@ -514,7 +514,39 @@ jobs:
uses: ./.github/workflows/build-distributions.yml
# This actually does not need the binary jobs but we want to prioritize
# resources for the test jobs therefore this forces these later on
needs: binaries
# needs: binaries

test-distributions:
name: Test distribution ${{ matrix.job.target }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
needs:
- distributions-dev
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- target: x86_64-unknown-linux-gnu
os: ubuntu-22.04
- target: x86_64-pc-windows-msvc
os: windows-2022
- target: aarch64-apple-darwin
os: macos-14
- target: x86_64-apple-darwin
os: macos-12

steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: distribution-${{ matrix.job.target }}

- name: Unpack distribution
run: |-
mkdir out
tar xzf hatch-dist-${{ matrix.job.target }}.tar.gz -C out
- name: Try to run
run: ./out/python/bin/hatch --version

distributions-release:
name: Build release distributions
Expand Down
87 changes: 87 additions & 0 deletions release/windows/make_scripts_portable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from __future__ import annotations

import sys
import sysconfig
from contextlib import closing
from importlib.metadata import entry_points
from io import BytesIO
from os.path import relpath
from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo

LAUNCHERS_DIR = Path('uv\\crates\\uv-trampoline\\target\\x86_64-pc-windows-msvc\\release').resolve()
SCRIPT_TEMPLATE = """\
#!{executable}
# -*- coding: utf-8 -*-
import re
import sys
from {module} import {import_name}
if __name__ == "__main__":
sys.argv[0] = re.sub(r"(-script\\.pyw|\\.exe)?$", "", sys.argv[0])
sys.exit({function}())
"""


def main():
interpreters_dir = Path(sys.executable).parent
scripts_dir = Path(sysconfig.get_path('scripts'))

ep = entry_points()
for group, interpreter_name, launcher_name in (
('console_scripts', 'python.exe', 'uv-trampoline-console.exe'),
('gui_scripts', 'pythonw.exe', 'uv-trampoline-gui.exe'),
):
try:
scripts = ep[group]
except KeyError:
continue

interpreter = interpreters_dir / interpreter_name
relative_interpreter_path = relpath(interpreter, scripts_dir)
launcher_data = (LAUNCHERS_DIR / launcher_name).read_bytes()

for script in scripts:
# https://github.com/astral-sh/uv/tree/main/crates/uv-trampoline#how-do-you-use-it
with closing(BytesIO()) as buf:
# Launcher
buf.write(launcher_data)

# Zipped script
with TemporaryDirectory() as td:
zip_path = Path(td) / 'script.zip'
with ZipFile(zip_path, 'w') as zf:
# Ensure reproducibility
zip_info = ZipInfo('__main__.py', (2020, 2, 2, 0, 0, 0))
zip_info.external_attr = (0o644 & 0xFFFF) << 16

module, _, attrs = script.value.partition(':')
contents = SCRIPT_TEMPLATE.format(
executable=relative_interpreter_path,
module=module,
import_name=attrs.split('.')[0],
function=attrs
)
zf.writestr(zip_info, contents, compress_type=ZIP_DEFLATED)

buf.write(zip_path.read_bytes())

# Interpreter path
interpreter_path = relative_interpreter_path.encode('utf-8')
buf.write(interpreter_path)

# Interpreter path length
interpreter_path_length = len(interpreter_path).to_bytes(4, 'little')
buf.write(interpreter_path_length)

# Magic number
buf.write(b'UVUV')

script_data = buf.getvalue()

script_path = scripts_dir / f'{script.name}.exe'
script_path.write_bytes(script_data)


if __name__ == '__main__':
main()

0 comments on commit 2a0edd1

Please sign in to comment.