#!/usr/bin/env python3 """Render .woodpecker.yaml for the pypi-wheel-attic fleet family. GENERATED files carry a "do not hand-edit" header; edit manifest.yaml instead and re-run this script. See manifest.yaml for scope notes (oleks/ci-scripts#1). """ import pathlib import sys import yaml HERE = pathlib.Path(__file__).parent BUILDING = HERE.parent / "building" HEADER = """# GENERATED by oleks/ci-scripts — do not hand-edit. # Source: oleks/ci-scripts manifest.yaml + generate.py (oleks/ci-scripts#1). # Re-render with: python3 generate.py """ def render(repo: dict) -> str: arch = repo["arch"] mem_req = repo["memory_request"] mem_lim = repo["memory_limit"] cores = repo.get("cores") max_jobs = repo.get("max_jobs", False) attic = repo.get("attic", True) redis_cache = repo.get("redis_cache", False) nix_conf_lines = [] if max_jobs: nix_conf_lines.append(' - echo "max-jobs = 1" >> /etc/nix/nix.conf') if cores: nix_conf_lines.append(f' - echo "cores = {cores}" >> /etc/nix/nix.conf') nix_conf_lines.append(' - echo "sandbox = false" >> /etc/nix/nix.conf') nix_conf_block = "\n".join(nix_conf_lines) env_lines = [ " GITEA_CLONE_TOKEN:", " from_secret: gitea_clone_token", " REGISTRY_TOKEN:", " from_secret: registry_token", ] if attic: env_lines += [ " ATTIC_TOKEN:", " from_secret: attic_token", ] if redis_cache: env_lines += [ " REDIS_PASSWORD:", " from_secret: redis_password", ] env_block = "\n".join(env_lines) redis_block = "" if redis_cache: redis_block = ( " # Set up sccache/ccache with Redis for the cross build.\n" " - export SCCACHE_REDIS_ENDPOINT=tcp://redis.default.svc.cluster.local:6379\n" " - export SCCACHE_REDIS_PASSWORD=$REDIS_PASSWORD\n" " - export CCACHE_REMOTE_STORAGE=redis://redis.default.svc.cluster.local:6379\n" " - export CCACHE_REMOTE_ONLY=1\n" ) if attic: attic_block = ( ' # Push built paths to the binary cache while we build.\n' ' - attic login ci https://nix-cache-upload.oleks.space "$ATTIC_TOKEN"\n' " - attic watch-store attic-infra-cache-k3s-1 &\n" " - ATTIC_PID=$!\n" " - sleep 2\n" ) attic_teardown = ( ' - if ! kill $ATTIC_PID 2>/dev/null; then echo "attic watch-store already exited"; fi\n' ' - if ! wait $ATTIC_PID 2>/dev/null; then echo "attic watch-store exited non-zero after kill (expected)"; fi\n' ) else: attic_block = "" attic_teardown = "" return f"""{HEADER}labels: arch: {arch} clone: - name: clone image: woodpeckerci/plugin-git environment: CI_NETRC_MACHINE: git.oleks.space CI_NETRC_USERNAME: oleks CI_NETRC_PASSWORD: from_secret: gitea_clone_token PLUGIN_TAGS: "false" PLUGIN_DEPTH: "1" when: - event: tag ref: "refs/tags/v*" steps: - name: build-and-publish image: git.oleks.space/oleks/nix-ci-ccpp-rust:latest backend_options: kubernetes: resources: requests: memory: {mem_req} limits: memory: {mem_lim} environment: {env_block} commands: - echo "▸ arch=$(uname -m)" - echo "nameserver 169.254.20.10" > /etc/resolv.conf && echo "options ndots:1" >> /etc/resolv.conf {nix_conf_block} - nixos-ci-entrypoint true {redis_block}{attic_block} # Thin parity entrypoint: build + publish all s390x wheels (CI mutates). - PUBLISH=1 nix run .#publish {attic_teardown}""" def main(): manifest = yaml.safe_load((HERE / "manifest.yaml").read_text()) check_only = "--check" in sys.argv changed = [] for repo in manifest["repos"]: target = BUILDING / repo["dir"] / ".woodpecker.yaml" rendered = render(repo) if check_only: current = target.read_text() if target.exists() else "" if current != rendered: changed.append(str(target)) else: target.write_text(rendered) print(f"wrote {target}") if check_only: if changed: print("NOT up to date:") for c in changed: print(f" {c}") sys.exit(1) print("all rendered files up to date") if __name__ == "__main__": main()