212 lines · 7.5 KB · Shell
RawDownload
#!/bin/bash# patch-vendor.sh — Apply crate-level patches to vendored dependencies## Iterates std-patches/crates/<crate-name>/*.patch, finds the matching# vendor/<crate-name> directory, applies each patch, and nulls out# .cargo-checksum.json file hashes so Cargo accepts the modified source.## Usage:#   ./scripts/patch-vendor.sh [--check] [--reverse]## Options:#   --check    Dry-run: verify patches apply cleanly without modifying files#   --reverse  Reverse (unapply) previously applied patches set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"WASMCORE_DIR="$(dirname "$SCRIPT_DIR")"PATCHES_DIR="$WASMCORE_DIR/std-patches/crates"# VENDOR_DIR defaults to the toolchain's own vendor/ (the `make wasm` command# build) but can be overridden so the reproducible codex clone build# (clone-and-build-codex-wasi.sh) can apply the same crate patches to the codex# workspace's vendored sources.VENDOR_DIR="${VENDOR_DIR:-$WASMCORE_DIR/vendor}" # Parse argumentsMODE="apply"for arg in "$@"; do    case "$arg" in        --check)            MODE="check"            ;;        --reverse)            MODE="reverse"            ;;        *)            echo "Unknown argument: $arg"            echo "Usage: $0 [--check] [--reverse]"            exit 1            ;;    esacdone if [ ! -d "$PATCHES_DIR" ]; then    echo "No std-patches/crates/ directory found — nothing to patch"    exit 0fi if [ ! -d "$VENDOR_DIR" ]; then    echo "ERROR: vendor/ directory not found. Run 'cargo vendor' first."    exit 1fi # Find all crate patch directoriesCRATE_DIRS=$(find "$PATCHES_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort) if [ -z "$CRATE_DIRS" ]; then    echo "No crate patch directories found in $PATCHES_DIR — nothing to patch"    exit 0fi TOTAL_PATCHES=0FAILED=0 for CRATE_DIR in $CRATE_DIRS; do    CRATE_NAME="$(basename "$CRATE_DIR")"     # Find the matching vendor directory (crate-name or crate-name-version)    VENDOR_CRATE=""    if [ -d "$VENDOR_DIR/$CRATE_NAME" ]; then        VENDOR_CRATE="$VENDOR_DIR/$CRATE_NAME"    else        # Try matching crate-name-* (versioned directory)        MATCHES=$(find "$VENDOR_DIR" -maxdepth 1 -type d -name "${CRATE_NAME}-*" 2>/dev/null | sort -V | tail -1)        if [ -n "$MATCHES" ]; then            VENDOR_CRATE="$MATCHES"        fi    fi     if [ -z "$VENDOR_CRATE" ]; then        echo "WARNING: No vendor directory found for crate '$CRATE_NAME' — skipping"        continue    fi     # Find patch files for this crate    if [ "$MODE" = "reverse" ]; then        PATCH_FILES=$(find "$CRATE_DIR" -name '*.patch' -type f 2>/dev/null | sort -r)    else        PATCH_FILES=$(find "$CRATE_DIR" -name '*.patch' -type f 2>/dev/null | sort)    fi     if [ -z "$PATCH_FILES" ]; then        continue    fi     echo "=== $CRATE_NAME ($(basename "$VENDOR_CRATE")) ==="     for PATCH in $PATCH_FILES; do        PATCH_NAME="$(basename "$PATCH")"        TOTAL_PATCHES=$((TOTAL_PATCHES + 1))         case "$MODE" in            check)                echo -n "  Checking $PATCH_NAME ... "                if patch --dry-run -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then                    echo "OK (applies cleanly)"                elif patch --dry-run -R -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then                    echo "OK (already applied)"                else                    echo "FAIL (does not apply)"                    FAILED=$((FAILED + 1))                fi                ;;            apply)                echo -n "  Applying $PATCH_NAME ... "                if patch --dry-run -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then                    patch -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1                    echo "applied"                elif patch --dry-run -R -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then                    echo "already applied"                else                    # Mixed state (e.g. an interrupted earlier run left some                    # hunks applied): apply the remaining hunks, tolerating                    # already-applied ones; fail only on genuine rejects.                    set +e                    OUT=$(patch -p1 -N -r /dev/null -d "$VENDOR_CRATE" < "$PATCH" 2>&1)                    RC=$?                    set -e                    if [ $RC -le 1 ] && ! echo "$OUT" | grep -q "FAILED"; then                        echo "converged (mixed state)"                    else                        echo "FAIL (does not apply)"                        FAILED=$((FAILED + 1))                    fi                fi                ;;            reverse)                echo -n "  Reversing $PATCH_NAME ... "                if patch -R --dry-run -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then                    patch -R -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1                    echo "reversed"                else                    echo "not applied (skipping)"                fi                ;;        esac    done     # Install companion source files that a patch needs but cannot carry inline    # (a `diff`/`patch` cannot create a brand-new file in vendored sources whose    # parent doesn't exist as a tracked /dev/null hunk reliably across patch    # versions). Convention: `std-patches/crates/<crate>/copy.manifest` with lines    # "<src-relative-to-crate-patch-dir> <dest-relative-to-vendor-crate>".    # Example (tokio): `wasi-process-imp.rs src/process/wasi.rs` installs the    # cooperative wasm32-wasip1 process impl that the .patch's `#[path]` wiring    # references. Without this the patched tokio fails to compile (missing module).    MANIFEST="$CRATE_DIR/copy.manifest"    if [ "$MODE" = "apply" ] && [ -f "$MANIFEST" ]; then        while read -r SRC DEST; do            # Skip blank lines and comments.            case "$SRC" in ""|\#*) continue ;; esac            if [ ! -f "$CRATE_DIR/$SRC" ]; then                echo "  ERROR: copy.manifest source missing: $SRC"                FAILED=$((FAILED + 1))                continue            fi            mkdir -p "$(dirname "$VENDOR_CRATE/$DEST")"            cp "$CRATE_DIR/$SRC" "$VENDOR_CRATE/$DEST"            echo "  Installed companion: $SRC -> $DEST"        done < "$MANIFEST"    elif [ "$MODE" = "reverse" ] && [ -f "$MANIFEST" ]; then        while read -r SRC DEST; do            case "$SRC" in ""|\#*) continue ;; esac            rm -f "$VENDOR_CRATE/$DEST"        done < "$MANIFEST"    fi     # Null out .cargo-checksum.json hashes so Cargo accepts patched sources    if [ "$MODE" = "apply" ]; then        CHECKSUM_FILE="$VENDOR_CRATE/.cargo-checksum.json"        if [ -f "$CHECKSUM_FILE" ]; then            # Replace the "files" object with an empty object to skip checksum verification            python3 -c "import json, syspath = sys.argv[1]with open(path) as f:    data = json.load(f)data['files'] = {}with open(path, 'w') as f:    json.dump(data, f)" "$CHECKSUM_FILE" 2>/dev/null || \            # Fallback: use sed if python3 is not available            sed -i 's/"files":{[^}]*}/"files":{}/' "$CHECKSUM_FILE"        fi    fi     echo ""done echo "=== Summary ==="echo "Total patches processed: $TOTAL_PATCHES" if [ "$FAILED" -ne 0 ]; then    echo "FAILED: $FAILED patch(es) did not apply"    exit 1else    case "$MODE" in        check)   echo "All vendor patches verified." ;;        apply)   echo "All vendor patches applied successfully." ;;        reverse) echo "All vendor patches reversed." ;;    esacfi

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t