Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 83 additions & 23 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: qret-ci

on:
push:
branches: [main]
paths:
- .github/workflows/release.yml
- quration
Expand All @@ -21,23 +22,72 @@ jobs:
include:
- os: macos-15-intel
asset_suffix: macos-15-intel
archive_ext: tar.gz
- os: macos-latest
asset_suffix: macos-latest
archive_ext: tar.gz
- os: ubuntu-latest
asset_suffix: ubuntu-latest
archive_ext: tar.gz
- os: windows-latest
asset_suffix: windows-latest
archive_ext: zip

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Restore newsynth cache
id: newsynth-cache
uses: actions/cache@v4
with:
path: |
.newsynth/bin
.newsynth/license
key: newsynth-${{ matrix.os }}-v1

- name: Setup Haskell (GHC/Cabal)
if: steps.newsynth-cache.outputs.cache-hit != 'true'
uses: haskell-actions/setup@v2
with:
ghc-version: "9.6.6"
cabal-version: "3.12.1.0"

- name: Build newsynth binaries from Hackage
if: steps.newsynth-cache.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p "$PWD/.newsynth/bin"
cabal update
cabal install newsynth --installdir "$PWD/.newsynth/bin" --install-method=copy --overwrite-policy=always
if [ "$RUNNER_OS" != "Windows" ]; then
chmod +x "$PWD/.newsynth/bin/gridsynth"
fi
ls -la "$PWD/.newsynth/bin"

- name: Download newsynth LICENSE files
if: steps.newsynth-cache.outputs.cache-hit != 'true'
shell: bash
run: |
rm -rf "$PWD/.newsynth/src"
rm -rf "$PWD/.newsynth/license"
mkdir -p "$PWD/.newsynth/src"
mkdir -p "$PWD/.newsynth/license"
cabal get newsynth --destdir "$PWD/.newsynth/src" --pristine
newsynth_src_dir=$(find "$PWD/.newsynth/src" -maxdepth 1 -type d -name "newsynth-*" | head -n 1)
if [ -n "$newsynth_src_dir" ]; then
find "$newsynth_src_dir" -maxdepth 2 -type f \
\( -iname "LICENSE*" -o -iname "COPYING*" -o -iname "README*" -o -iname "GPL*" \) \
-exec cp {} "$PWD/.newsynth/license/" \;
fi
ls -la "$PWD/.newsynth/license"

- name: Fix newsynth permissions (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
if [ -d "$PWD/.newsynth/bin" ]; then
chmod +x "$PWD"/.newsynth/bin/* || true
fi

- name: Setup MSVC (Windows)
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
Expand Down Expand Up @@ -99,32 +149,42 @@ jobs:
- name: Install to stage
run: cmake --install build --config Release --prefix stage

- name: Package artifact (Unix)
if: runner.os != 'Windows'
- name: Prepare release stub contents
shell: bash
run: |
mkdir -p dist package
mkdir -p dist
root="qret-${{ matrix.asset_suffix }}"
mkdir -p "package/$root"
cp -R stage/. "package/$root/"
tar -C package -czf "dist/$root.${{ matrix.archive_ext }}" "$root"

- name: Package artifact (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
New-Item -ItemType Directory -Force -Path package | Out-Null
$root = "qret-${{ matrix.asset_suffix }}"
New-Item -ItemType Directory -Force -Path "package/$root" | Out-Null
Copy-Item -Recurse -Force stage\* "package/$root/"
Compress-Archive -Path "package/$root" -DestinationPath "dist/$root.${{ matrix.archive_ext }}" -Force
package_root="dist/$root"
mkdir -p "$package_root"
cp -R stage/. "$package_root/"
rm -rf "$package_root/include"
rm -rf "$package_root/lib/cmake"

mkdir -p "$package_root/bin"
mkdir -p "$package_root/licenses/qret"
mkdir -p "$package_root/licenses/newsynth"

for file in "$PWD"/.newsynth/bin/*; do
[ -f "$file" ] || continue
base_name="$(basename "$file")"
case "$base_name" in
README*|readme*)
continue
;;
esac
cp "$file" "$package_root/bin/"
done

find "$PWD/quration" -maxdepth 2 -type f \
\( -iname "LICENSE*" -o -iname "COPYING*" -o -iname "README*" -o -iname "NOTICE*" \) \
-exec cp {} "$package_root/licenses/qret/" \;
find "$PWD/.newsynth/license" -mindepth 1 -maxdepth 1 -type f -exec cp {} "$package_root/licenses/newsynth/" \;

- name: Upload qret artifact
uses: actions/upload-artifact@v4
with:
name: qret-${{ matrix.asset_suffix }}
path: dist/qret-${{ matrix.asset_suffix }}.${{ matrix.archive_ext }}
path: dist/qret-${{ matrix.asset_suffix }}

release:
if: github.event_name == 'release'
Expand All @@ -143,4 +203,4 @@ jobs:
- name: Upload artifacts to release
uses: softprops/action-gh-release@v2
with:
files: dist/*
files: dist/**/*
10 changes: 10 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: test

on:
push:
branches: [main]
paths:
- src/**
- tests/**
Expand Down Expand Up @@ -47,7 +48,12 @@ jobs:
#!/usr/bin/env sh
echo "qret 0.0.0-ci"
EOF
cat > .ci-bin/gridsynth <<'EOF'
#!/usr/bin/env sh
echo "gridsynth 0.0.0-ci"
EOF
chmod +x .ci-bin/qret
chmod +x .ci-bin/gridsynth
echo "$GITHUB_WORKSPACE/.ci-bin" >> "$GITHUB_PATH"

- name: Prepare qret stub for test (Windows)
Expand All @@ -59,6 +65,10 @@ jobs:
@echo off
echo qret 0.0.0-ci
'@ | Set-Content -Path .ci-bin/qret.cmd
@'
@echo off
echo gridsynth 0.0.0-ci
'@ | Set-Content -Path .ci-bin/gridsynth.cmd
"$env:GITHUB_WORKSPACE/.ci-bin" | Out-File -FilePath $env:GITHUB_PATH -Append

- name: Run pytest
Expand Down
50 changes: 44 additions & 6 deletions qret_cli_bundle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,57 @@ def _find_qret_binary(root: Path) -> Path:
raise QretBundleError(f"Could not find {exe_name} under {root}")


def _gridsynth_names() -> tuple[str, ...]:
if platform.system() == "Windows":
return ("gridsynth.exe", "gridsynth.cmd", "newsynth.exe", "newsynth.cmd")
return ("gridsynth", "newsynth")


def _find_gridsynth_binary(root: Path) -> Path | None:
for exe_name in _gridsynth_names():
for path in root.rglob(exe_name):
if path.is_file():
if platform.system() != "Windows":
mode = path.stat().st_mode
path.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
return path
return None


def _append_env_path(var_name: str, entry: str) -> None:
current = os.environ.get(var_name, "")
os.environ[var_name] = current + os.pathsep + entry if current else entry


def _find_existing_qret_in_path() -> Path | None:
exe_name = "qret.exe" if platform.system() == "Windows" else "qret"
qret_path = shutil.which(exe_name)
if qret_path:
candidate = Path(qret_path).resolve()
if candidate.is_file():
return candidate
exe_names = ("qret.exe", "qret.cmd") if platform.system() == "Windows" else ("qret",)
for exe_name in exe_names:
qret_path = shutil.which(exe_name)
if qret_path:
candidate = Path(qret_path).resolve()
if candidate.is_file():
return candidate
return None


def _find_existing_gridsynth_in_path() -> Path | None:
for exe_name in _gridsynth_names():
gridsynth_path = shutil.which(exe_name)
if gridsynth_path:
candidate = Path(gridsynth_path).resolve()
if candidate.is_file():
return candidate
return None


def _set_gridsynth_path(bin_dir: Path) -> None:
gridsynth = _find_gridsynth_binary(bin_dir)
if gridsynth is None:
gridsynth = _find_existing_gridsynth_in_path()
if gridsynth is not None:
os.environ["GRIDSYNTH_PATH"] = str(gridsynth)


def ensure_qret_on_path() -> Path:
"""Ensure qret is downloaded and available in PATH, returning its full path."""
existing_qret = _find_existing_qret_in_path()
Expand All @@ -100,6 +136,7 @@ def ensure_qret_on_path() -> Path:
lib_dir = qret.parent.parent / "lib"
if bin_dir.exists():
_append_env_path("PATH", str(bin_dir))
_set_gridsynth_path(bin_dir)
if platform.system() == "Linux" and lib_dir.exists():
_append_env_path("LD_LIBRARY_PATH", str(lib_dir))
return qret
Expand Down Expand Up @@ -137,6 +174,7 @@ def ensure_qret_on_path() -> Path:
lib_dir = qret.parent.parent / "lib"
if bin_dir.exists():
_append_env_path("PATH", str(bin_dir))
_set_gridsynth_path(bin_dir)
if platform.system() == "Linux" and lib_dir.exists():
_append_env_path("LD_LIBRARY_PATH", str(lib_dir))
return qret
Expand Down
4 changes: 4 additions & 0 deletions tests/test_qret_cli_bundle.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import importlib.util
import os
import subprocess
import shutil
from pathlib import Path
Expand All @@ -20,3 +21,6 @@ def test_import_and_qret_version() -> None:
)
assert result.returncode == 0, result.stderr
assert result.stdout.strip() or result.stderr.strip()

gridsynth_path = os.environ.get("GRIDSYNTH_PATH")
assert gridsynth_path is not None
Loading