A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 9, 10:00 UTC
[Release] [CI] Optim release pipeline (#33156)
Signed-off-by: tjtanaa <tunjian.tan@embeddedllm.com>
TJian committed
Jan 29, 2026 at 14:45 UTC
f9d03599ef1528b1b1d35f90d858db88b5857ce1
5 files changed
+399
-24
.buildkite/release-pipeline.yaml
+84
@@ -638,9 +638,93 @@ steps:
638
depends_on:
639
- step: upload-rocm-wheels
640
allow_failure: true
641
+ - step: input-release-version
642
+ allow_failure: true
643
agents:
644
queue: cpu_queue_postmerge
645
commands:
646
- "bash .buildkite/scripts/annotate-rocm-release.sh"
647
env:
648
S3_BUCKET: "vllm-wheels"
649
+
650
+ # ROCm Job 5: Generate Root Index for ROCm Wheels (for release only)
651
+ # This is the job to create https://wheels.vllm.ai/rocm/ index allowing
652
+ # users to install with `uv pip install vllm --extra-index-url https://wheels.vllm.ai/rocm/`
653
+ - block: "Generate Root Index for ROCm Wheels for Release"
654
+ key: block-generate-root-index-rocm-wheels
655
+ depends_on: upload-rocm-wheels
656
+
657
+ - label: ":package: Generate Root Index for ROCm Wheels for Release"
658
+ depends_on: block-generate-root-index-rocm-wheels
659
+ id: generate-root-index-rocm-wheels
660
+ agents:
661
+ queue: cpu_queue_postmerge
662
+ commands:
663
+ - "bash tools/vllm-rocm/generate-rocm-wheels-root-index.sh"
664
+ env:
665
+ S3_BUCKET: "vllm-wheels"
666
+ VARIANT: "rocm700"
667
+
668
+ # ROCm Job 5: Build ROCm Release Docker Image
669
+ - label: ":rocm: :docker: Build ROCm Release Docker Image"
670
+ id: build-rocm-release-image
671
+ depends_on:
672
+ - step: build-rocm-base-wheels
673
+ allow_failure: false
674
+ agents:
675
+ queue: cpu_queue_postmerge
676
+ timeout_in_minutes: 60
677
+ commands:
678
+ - |
679
+ set -euo pipefail
680
+
681
+ # Login to ECR
682
+ aws ecr-public get-login-password --region us-east-1 | \
683
+ docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7
684
+
685
+ # Download Docker image from S3 (set by build-rocm-base-wheels)
686
+ DOCKER_IMAGE_S3_PATH="$$(buildkite-agent meta-data get rocm-docker-image-s3-path 2>/dev/null || echo '')"
687
+ if [ -z "$${DOCKER_IMAGE_S3_PATH}" ]; then
688
+ echo "ERROR: rocm-docker-image-s3-path metadata not found"
689
+ exit 1
690
+ fi
691
+
692
+ echo "Downloading base image from $${DOCKER_IMAGE_S3_PATH}"
693
+ mkdir -p artifacts/rocm-docker-image
694
+ aws s3 cp "$${DOCKER_IMAGE_S3_PATH}" artifacts/rocm-docker-image/rocm-base-image.tar.gz
695
+
696
+ # Load base Docker image
697
+ echo "Loading base Docker image..."
698
+ LOAD_OUTPUT=$$(gunzip -c artifacts/rocm-docker-image/rocm-base-image.tar.gz | docker load)
699
+ BASE_IMAGE_TAG=$$(echo "$${LOAD_OUTPUT}" | grep "Loaded image:" | sed 's/Loaded image: //')
700
+ echo "Loaded base image: $${BASE_IMAGE_TAG}"
701
+
702
+ # Tag and push the base image to ECR
703
+ docker tag "$${BASE_IMAGE_TAG}" public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm-base
704
+ docker push public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm-base
705
+ echo "Pushed base image: public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm-base"
706
+
707
+ # Get GPU architectures from meta-data
708
+ PYTORCH_ROCM_ARCH="$$(buildkite-agent meta-data get rocm-pytorch-rocm-arch 2>/dev/null || echo '')"
709
+ PYTORCH_ROCM_ARCH="$${PYTORCH_ROCM_ARCH:-gfx90a;gfx942;gfx950;gfx1100;gfx1101;gfx1200;gfx1201;gfx1150;gfx1151}"
710
+
711
+ # Build vLLM ROCm release image using cached base
712
+ DOCKER_BUILDKIT=1 docker build \
713
+ --build-arg max_jobs=16 \
714
+ --build-arg BASE_IMAGE="$${BASE_IMAGE_TAG}" \
715
+ --build-arg ARG_PYTORCH_ROCM_ARCH="$${PYTORCH_ROCM_ARCH}" \
716
+ --build-arg USE_SCCACHE=1 \
717
+ --build-arg SCCACHE_BUCKET_NAME=vllm-build-sccache \
718
+ --build-arg SCCACHE_REGION_NAME=us-west-2 \
719
+ --build-arg SCCACHE_S3_NO_CREDENTIALS=0 \
720
+ --tag public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm \
721
+ --target vllm-openai \
722
+ --progress plain \
723
+ -f docker/Dockerfile.rocm .
724
+
725
+ # Push to ECR
726
+ docker push public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm
727
+ echo "Pushed: public.ecr.aws/q9t5s3a7/vllm-release-repo:$${BUILDKITE_COMMIT}-rocm"
728
+ env:
729
+ DOCKER_BUILDKIT: "1"
730
+ S3_BUCKET: "vllm-wheels"
.buildkite/scripts/annotate-release.sh
+12
-5
@@ -32,6 +32,7 @@ To download and upload the image:
32
\`\`\`
33
docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-x86_64
34
docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-aarch64
35
+docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm-base
36
docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm
37
38
docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-x86_64 vllm/vllm-openai:x86_64
@@ -46,11 +47,17 @@ docker tag vllm/vllm-openai:aarch64 vllm/vllm-openai:v${RELEASE_VERSION}-aarch64
47
docker push vllm/vllm-openai:latest-aarch64
48
docker push vllm/vllm-openai:v${RELEASE_VERSION}-aarch64
49
49
-docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm vllm/vllm-openai:rocm
50
-docker tag vllm/vllm-openai:rocm vllm/vllm-openai:latest-rocm
51
-docker tag vllm/vllm-openai:rocm vllm/vllm-openai:v${RELEASE_VERSION}-rocm
52
-docker push vllm/vllm-openai:latest-rocm
53
-docker push vllm/vllm-openai:v${RELEASE_VERSION}-rocm
50
+docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm-base vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base
51
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base vllm/vllm-openai-rocm:latest-base
52
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base vllm/vllm-openai-rocm:v${RELEASE_VERSION}-base
53
+docker push vllm/vllm-openai-rocm:latest-base
54
+docker push vllm/vllm-openai-rocm:v${RELEASE_VERSION}-base
55
+
56
+docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}
57
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT} vllm/vllm-openai-rocm:latest
58
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT} vllm/vllm-openai-rocm:v${RELEASE_VERSION}
59
+docker push vllm/vllm-openai-rocm:latest
60
+docker push vllm/vllm-openai-rocm:v${RELEASE_VERSION}
61
62
docker manifest rm vllm/vllm-openai:latest
63
docker manifest create vllm/vllm-openai:latest vllm/vllm-openai:latest-x86_64 vllm/vllm-openai:latest-aarch64
.buildkite/scripts/annotate-rocm-release.sh
+56
-18
@@ -3,25 +3,32 @@
3
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4
#
5
# Generate Buildkite annotation for ROCm wheel release
6
-
6
set -ex
7
8
# Get build configuration from meta-data
9
# Extract ROCm version dynamically from Dockerfile.rocm_base
11
-# BASE_IMAGE format: rocm/dev-ubuntu-22.04:7.1-complete -> extracts "7.1"
10
+# BASE_IMAGE format: rocm/dev-ubuntu-22.04:7.0-complete -> extracts "7.0"
11
ROCM_VERSION=$(grep -E '^ARG BASE_IMAGE=' docker/Dockerfile.rocm_base | sed -E 's/.*:([0-9]+\.[0-9]+).*/\1/' || echo "unknown")
12
PYTHON_VERSION=$(buildkite-agent meta-data get rocm-python-version 2>/dev/null || echo "3.12")
13
PYTORCH_ROCM_ARCH=$(buildkite-agent meta-data get rocm-pytorch-rocm-arch 2>/dev/null || echo "gfx90a;gfx942;gfx950;gfx1100;gfx1101;gfx1200;gfx1201;gfx1150;gfx1151")
14
15
+# TODO: Enable the nightly build for ROCm
16
+# Get release version, default to 1.0.0.dev for nightly/per-commit builds
17
+RELEASE_VERSION=$(buildkite-agent meta-data get release-version 2>/dev/null || echo "")
18
+if [ -z "${RELEASE_VERSION}" ]; then
19
+ RELEASE_VERSION="1.0.0.dev"
20
+fi
21
+
22
# S3 URLs
23
S3_BUCKET="${S3_BUCKET:-vllm-wheels}"
24
S3_REGION="${AWS_DEFAULT_REGION:-us-west-2}"
19
-S3_URL="https://${S3_BUCKET}.s3.${S3_REGION}.amazonaws.com"
20
-ROCM_PATH="rocm/${BUILDKITE_COMMIT}"
25
+S3_URL="http://${S3_BUCKET}.s3-website-${S3_REGION}.amazonaws.com"
26
27
+# Format ROCm version for path (e.g., "7.1" -> "rocm710")
28
+ROCM_VERSION_PATH="rocm$(echo ${ROCM_VERSION} | tr -d '.')"
29
+ROCM_PATH="rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}"
30
buildkite-agent annotate --style 'success' --context 'rocm-release-workflow' << EOF
23
-## :rocm: ROCm Wheel Release
24
-
31
+## ROCm Wheel and Docker Image Releases
32
### Build Configuration
33
| Setting | Value |
34
|---------|-------|
@@ -34,41 +41,72 @@ buildkite-agent annotate --style 'success' --context 'rocm-release-workflow' <<
41
### :package: Installation
42
43
**Install from this build (by commit):**
44
+
45
\`\`\`bash
38
-uv pip install vllm --extra-index-url ${S3_URL}/${ROCM_PATH}/{rocm_variant}/
46
+pip install vllm --extra-index-url ${S3_URL}/${ROCM_PATH}/ --trusted-host ${S3_BUCKET}.s3-website-${S3_REGION}.amazonaws.com
47
40
-# Example:
41
-uv pip install vllm --extra-index-url ${S3_URL}/${ROCM_PATH}/rocm700/
48
+# Example for ROCm ${ROCM_VERSION}:
49
+pip install vllm --extra-index-url ${S3_URL}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/ --trusted-host ${S3_BUCKET}.s3-website-${S3_REGION}.amazonaws.com
50
\`\`\`
51
52
**Install from nightly (if published):**
53
+
54
\`\`\`bash
46
-uv pip install vllm --extra-index-url ${S3_URL}/rocm/nightly/
55
+pip install vllm --extra-index-url ${S3_URL}/rocm/nightly/ --trusted-host ${S3_BUCKET}.s3-website-${S3_REGION}.amazonaws.com
56
\`\`\`
57
58
### :floppy_disk: Download Wheels Directly
59
60
\`\`\`bash
61
# List all ROCm wheels
53
-aws s3 ls s3://${S3_BUCKET}/${ROCM_PATH}/
54
-
62
+aws s3 ls s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/
63
# Download specific wheels
56
-aws s3 cp s3://${S3_BUCKET}/${ROCM_PATH}/vllm-*.whl .
57
-aws s3 cp s3://${S3_BUCKET}/${ROCM_PATH}/torch-*.whl .
58
-aws s3 cp s3://${S3_BUCKET}/${ROCM_PATH}/triton_rocm-*.whl .
59
-aws s3 cp s3://${S3_BUCKET}/${ROCM_PATH}/torchvision-*.whl .
60
-aws s3 cp s3://${S3_BUCKET}/${ROCM_PATH}/amdsmi-*.whl .
64
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/vllm-*.whl .
65
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/torch-*.whl .
66
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/triton-*.whl .
67
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/triton-kernels-*.whl .
68
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/torchvision-*.whl .
69
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/torchaudio-*.whl .
70
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/amdsmi-*.whl .
71
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/aiter-*.whl .
72
+aws s3 cp s3://${S3_BUCKET}/rocm/${BUILDKITE_COMMIT}/${ROCM_VERSION_PATH}/flash-attn-*.whl .
73
\`\`\`
74
75
### :gear: Included Packages
76
- **vllm**: vLLM with ROCm support
77
- **torch**: PyTorch built for ROCm ${ROCM_VERSION}
66
-- **triton_rocm**: Triton built for ROCm
78
+- **triton**: Triton
79
+- **triton-kernels**: Triton kernels
80
- **torchvision**: TorchVision for ROCm PyTorch
81
+- **torchaudio**: Torchaudio for ROCm PyTorch
82
- **amdsmi**: AMD SMI Python bindings
83
+- **aiter**: Aiter for ROCm
84
+- **flash-attn**: Flash Attention for ROCm
85
86
### :warning: Notes
87
- These wheels are built for **ROCm ${ROCM_VERSION}** and will NOT work with CUDA GPUs
88
- Supported GPU architectures: ${PYTORCH_ROCM_ARCH}
89
- Platform: Linux x86_64 only
90
+
91
+### :package: Docker Image Release
92
+
93
+To download and upload the image:
94
+
95
+\`\`\`
96
+docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm-base
97
+docker pull public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm
98
+
99
+docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm-base vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base
100
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base vllm/vllm-openai-rocm:latest-base
101
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}-base vllm/vllm-openai-rocm:v${RELEASE_VERSION}-base
102
+docker push vllm/vllm-openai-rocm:latest-base
103
+docker push vllm/vllm-openai-rocm:v${RELEASE_VERSION}-base
104
+
105
+docker tag public.ecr.aws/q9t5s3a7/vllm-release-repo:${BUILDKITE_COMMIT}-rocm vllm/vllm-openai-rocm:${BUILDKITE_COMMIT}
106
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT} vllm/vllm-openai-rocm:latest
107
+docker tag vllm/vllm-openai-rocm:${BUILDKITE_COMMIT} vllm/vllm-openai-rocm:v${RELEASE_VERSION}
108
+docker push vllm/vllm-openai-rocm:latest
109
+docker push vllm/vllm-openai-rocm:v${RELEASE_VERSION}
110
+\`\`\`
111
+
112
EOF
docker/Dockerfile.rocm
+14
-1
@@ -227,7 +227,7 @@ RUN if [ "$GIT_REPO_CHECK" != "0" ]; then \
227
# This ensures setuptools_scm sees clean repo state for version detection
228
RUN --mount=type=bind,source=.git,target=vllm/.git \
229
cd vllm \
230
- && pip install setuptools_scm \
230
+ && pip install setuptools_scm regex \
231
&& VLLM_VERSION=$(python3 -c "import setuptools_scm; print(setuptools_scm.get_version())") \
232
&& echo "Detected vLLM version: ${VLLM_VERSION}" \
233
&& echo "${VLLM_VERSION}" > /tmp/vllm_version.txt
@@ -342,6 +342,19 @@ RUN mkdir src && mv vllm src/vllm
342
FROM base AS final
343
344
RUN python3 -m pip install --upgrade pip && rm -rf /var/lib/apt/lists/*
345
+
346
+# Clean up sccache from release image (not needed at runtime)
347
+# This removes the binary and wrappers that may have been installed during build
348
+RUN rm -f /usr/bin/sccache || true \
349
+ && rm -rf /opt/sccache-wrappers || true
350
+
351
+# Unset sccache environment variables for the release image
352
+# This prevents S3 bucket config from leaking into production images
353
+ENV SCCACHE_BUCKET=
354
+ENV SCCACHE_REGION=
355
+ENV SCCACHE_S3_NO_CREDENTIALS=
356
+ENV SCCACHE_IDLE_TIMEOUT=
357
+
358
# Error related to odd state for numpy 1.20.3 where there is no METADATA etc, but an extra LICENSES_bundled.txt.
359
# Manually remove it so that later steps of numpy upgrade can continue
360
RUN case "$(which python3)" in \
tools/vllm-rocm/generate-rocm-wheels-root-index.sh
new
+233
@@ -0,0 +1,233 @@
1
+#!/usr/bin/env bash
2
+# SPDX-License-Identifier: Apache-2.0
3
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4
+#
5
+# Generate S3 PyPI Root Index for Latest Version
6
+#
7
+# Creates a PEP 503 compatible index.html at rocm/ pointing to the latest
8
+# semantic version's packages. This enables users to install with:
9
+# uv pip install vllm --extra-index-url s3://vllm-wheels/rocm
10
+#
11
+# Usage:
12
+# generate-root-index.sh [options]
13
+#
14
+# Options:
15
+# --dry-run Preview changes without uploading
16
+# --version VER Use specific version instead of auto-detecting latest
17
+#
18
+# Environment variables:
19
+# S3_BUCKET - Bucket name (default: vllm-wheels)
20
+# VARIANT - ROCm variant (default: rocm700)
21
+# DRY_RUN - Set to 1 for preview mode (same as --dry-run)
22
+
23
+set -euo pipefail
24
+
25
+# ======== Configuration ========
26
+BUCKET="${S3_BUCKET:-vllm-wheels}"
27
+VARIANT="${VARIANT:-rocm700}"
28
+DRY_RUN="${DRY_RUN:-0}"
29
+FORCE_VERSION=""
30
+
31
+# Parse command line arguments
32
+while [[ $# -gt 0 ]]; do
33
+ case $1 in
34
+ --dry-run)
35
+ DRY_RUN=1
36
+ shift
37
+ ;;
38
+ --version)
39
+ FORCE_VERSION="$2"
40
+ shift 2
41
+ ;;
42
+ *)
43
+ echo "Unknown option: $1"
44
+ exit 1
45
+ ;;
46
+ esac
47
+done
48
+
49
+# Working directory for generated files
50
+WORK_DIR=$(mktemp -d)
51
+trap 'rm -rf "$WORK_DIR"' EXIT
52
+
53
+echo "========================================"
54
+echo "Generate Root Index for Latest Version"
55
+echo "========================================"
56
+echo "S3 Bucket: $BUCKET"
57
+echo "ROCm Variant: $VARIANT"
58
+echo "Dry Run: $DRY_RUN"
59
+echo "========================================"
60
+echo ""
61
+
62
+# ======== Step 1: Find latest semantic version ========
63
+
64
+echo "Step 1: Finding latest semantic version..."
65
+
66
+# List all directories under rocm/
67
+aws s3api list-objects-v2 \
68
+ --bucket "$BUCKET" \
69
+ --prefix "rocm/" \
70
+ --delimiter "/" \
71
+ --query 'CommonPrefixes[].Prefix' \
72
+ --output text | tr '\t' '\n' > "$WORK_DIR/all_prefixes.txt"
73
+
74
+# Filter for semantic versions (x.y.z pattern)
75
+grep -oE 'rocm/[0-9]+\.[0-9]+\.[0-9]+/' "$WORK_DIR/all_prefixes.txt" | \
76
+ sed 's|rocm/||; s|/||' | \
77
+ sort -V > "$WORK_DIR/versions.txt" || true
78
+
79
+if [[ ! -s "$WORK_DIR/versions.txt" ]]; then
80
+ echo "ERROR: No semantic versions found under s3://$BUCKET/rocm/"
81
+ exit 1
82
+fi
83
+
84
+echo "Found versions:"
85
+cat "$WORK_DIR/versions.txt"
86
+echo ""
87
+
88
+if [[ -n "$FORCE_VERSION" ]]; then
89
+ LATEST_VERSION="$FORCE_VERSION"
90
+ echo "Using forced version: $LATEST_VERSION"
91
+else
92
+ LATEST_VERSION=$(tail -1 "$WORK_DIR/versions.txt")
93
+ echo "Latest version (auto-detected): $LATEST_VERSION"
94
+fi
95
+
96
+# Verify the version exists
97
+if ! grep -qx "$LATEST_VERSION" "$WORK_DIR/versions.txt"; then
98
+ echo "ERROR: Version $LATEST_VERSION not found in bucket"
99
+ exit 1
100
+fi
101
+
102
+# ======== Step 2: List packages from latest version ========
103
+
104
+echo ""
105
+echo "Step 2: Listing packages from rocm/$LATEST_VERSION/$VARIANT/..."
106
+
107
+VERSION_PREFIX="rocm/$LATEST_VERSION/$VARIANT/"
108
+
109
+# List package directories
110
+aws s3api list-objects-v2 \
111
+ --bucket "$BUCKET" \
112
+ --prefix "$VERSION_PREFIX" \
113
+ --delimiter "/" \
114
+ --query 'CommonPrefixes[].Prefix' \
115
+ --output text | tr '\t' '\n' > "$WORK_DIR/package_prefixes.txt" || true
116
+
117
+if [[ ! -s "$WORK_DIR/package_prefixes.txt" ]]; then
118
+ echo "ERROR: No packages found under s3://$BUCKET/$VERSION_PREFIX"
119
+ exit 1
120
+fi
121
+
122
+# Extract package names
123
+sed "s|${VERSION_PREFIX}||; s|/||g" "$WORK_DIR/package_prefixes.txt" | \
124
+ grep -v '^$' > "$WORK_DIR/packages.txt"
125
+
126
+echo "Found packages:"
127
+cat "$WORK_DIR/packages.txt"
128
+echo ""
129
+
130
+# ======== Step 3: Generate root index.html ========
131
+
132
+echo "Step 3: Generating root index.html..."
133
+
134
+mkdir -p "$WORK_DIR/output"
135
+
136
+{
137
+ cat <<'EOF'
138
+<!DOCTYPE html>
139
+<html>
140
+<head>
141
+ <meta name="pypi:repository-version" content="1.0">
142
+</head>
143
+<body>
144
+EOF
145
+
146
+ while read -r pkg; do
147
+ echo " <a href=\"$pkg/\">$pkg</a><br>"
148
+ done < "$WORK_DIR/packages.txt"
149
+
150
+ cat <<'EOF'
151
+</body>
152
+</html>
153
+EOF
154
+} > "$WORK_DIR/output/index.html"
155
+
156
+echo "Generated root index.html:"
157
+cat "$WORK_DIR/output/index.html"
158
+echo ""
159
+
160
+# ======== Step 4: Copy and adjust package index files ========
161
+
162
+echo "Step 4: Copying and adjusting package index files..."
163
+
164
+while read -r pkg; do
165
+ echo "Processing package: $pkg"
166
+
167
+ # Download existing index.html from versioned path
168
+ SOURCE_INDEX="s3://$BUCKET/$VERSION_PREFIX$pkg/index.html"
169
+
170
+ mkdir -p "$WORK_DIR/output/$pkg"
171
+
172
+ if aws s3 cp "$SOURCE_INDEX" "$WORK_DIR/output/$pkg/index.html" 2>/dev/null; then
173
+ # Adjust relative paths:
174
+ # Original: href="../../../{commit}/wheel.whl" (from rocm/0.13.0/rocm710/vllm/)
175
+ # New: href="../{commit}/wheel.whl" (from rocm/vllm/)
176
+ sed -i 's|href="\.\./\.\./\.\./|href="../|g' "$WORK_DIR/output/$pkg/index.html"
177
+ echo " - Downloaded and adjusted: $pkg/index.html"
178
+ else
179
+ echo " - WARNING: Could not download index for $pkg"
180
+ fi
181
+done < "$WORK_DIR/packages.txt"
182
+
183
+echo ""
184
+
185
+# ======== Step 5: Upload to S3 ========
186
+
187
+echo "Step 5: Uploading to s3://$BUCKET/rocm/..."
188
+echo ""
189
+
190
+# List what would be uploaded
191
+echo "Files to upload:"
192
+find "$WORK_DIR/output" -name "*.html" -type f | while read -r file; do
193
+ rel_path="${file#$WORK_DIR/output/}"
194
+ echo " rocm/$rel_path"
195
+done
196
+echo ""
197
+
198
+if [[ "$DRY_RUN" == "1" ]]; then
199
+ echo "DRY RUN - Skipping upload"
200
+ echo ""
201
+ echo "Preview of generated files:"
202
+ echo "----------------------------------------"
203
+ echo "rocm/index.html:"
204
+ cat "$WORK_DIR/output/index.html"
205
+ echo ""
206
+ echo "----------------------------------------"
207
+ echo "Sample package index (first package):"
208
+ FIRST_PKG=$(head -1 "$WORK_DIR/packages.txt")
209
+ if [[ -f "$WORK_DIR/output/$FIRST_PKG/index.html" ]]; then
210
+ echo "rocm/$FIRST_PKG/index.html:"
211
+ cat "$WORK_DIR/output/$FIRST_PKG/index.html"
212
+ fi
213
+else
214
+ # Upload all generated files
215
+ aws s3 cp --recursive "$WORK_DIR/output/" "s3://$BUCKET/rocm/" \
216
+ --content-type "text/html"
217
+
218
+ echo "Upload complete!"
219
+fi
220
+
221
+# ======== Summary ========
222
+
223
+echo ""
224
+echo "========================================"
225
+echo "Root Index Generation Complete!"
226
+echo "========================================"
227
+echo ""
228
+echo "Latest version: $LATEST_VERSION"
229
+echo "Packages indexed: $(wc -l < "$WORK_DIR/packages.txt")"
230
+echo ""
231
+echo "Install command:"
232
+echo " uv pip install vllm --extra-index-url https://wheels.vllm.ai/rocm/"
233
+echo "========================================"