11#! /usr/bin/env bash
22set -euo pipefail
33
4+ # =============================================================================
5+ # pylocks_generator.sh
6+ #
7+ # This script generates Python dependency lock files (pylock.toml) for multiple
8+ # directories using either internal AIPCC wheel indexes or the public PyPI index.
9+ #
10+ # Features:
11+ # • Supports multiple Python project directories, detected by pyproject.toml.
12+ # • Detects available Dockerfile flavors (CPU, CUDA, ROCm) for AIPCC index mode.
13+ # • Validates Python version extracted from directory name (expects format .../ubi9-python-X.Y).
14+ # • Generates per-flavor locks in 'uv.lock/' for AIPCC index mode.
15+ # • Overwrites existing pylock.toml in-place for public PyPI index mode.
16+ #
17+ # Index Modes:
18+ # • aipcc-index -> Uses internal Red Hat AIPCC wheel indexes. Generates uv.lock/pylock.<flavor>.toml for each detected flavor.
19+ # • public-index -> Uses public PyPI index. Updates pylock.toml in the project directory.
20+ # Default mode if not specified.
21+ #
22+ # Usage:
23+ # 1. Lock using default public index for all projects in MAIN_DIRS:
24+ # bash pylocks_generator.sh
25+ #
26+ # 2. Lock using AIPCC index for a specific directory:
27+ # bash pylocks_generator.sh aipcc-index jupyter/minimal/ubi9-python-3.12
28+ #
29+ # 3. Lock using public index for a specific directory:
30+ # bash pylocks_generator.sh public-index jupyter/minimal/ubi9-python-3.12
31+ #
32+ # Notes:
33+ # • If the script fails for a directory, it lists the failed directories at the end.
34+ # • Public index mode does not create uv.lock directories keeps the old format.
35+ # • Python version extraction depends on directory naming convention; invalid formats are skipped.
36+ # =============================================================================
37+
438# ----------------------------
539# CONFIGURATION
640# ----------------------------
741CPU_INDEX=" --index-url=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.0/cpu-ubi9/simple/"
842CUDA_INDEX=" --index-url=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.0/cuda-ubi9/simple/"
943ROCM_INDEX=" --index-url=https://console.redhat.com/api/pypi/public-rhai/rhoai/3.0/rocm-ubi9/simple/"
44+ PUBLIC_INDEX=" --index-url=https://pypi.org/simple"
1045
1146MAIN_DIRS=(" jupyter" " runtimes" " rstudio" " codeserver" )
1247
@@ -26,12 +61,10 @@ if ! command -v uv &>/dev/null; then
2661 exit 1
2762fi
2863
29- # (Optional) check uv version (requires version >= 0.4.0)
3064UV_MIN_VERSION=" 0.4.0"
3165UV_VERSION=$( uv --version 2> /dev/null | awk ' {print $2}' || echo " 0.0.0" )
3266
3367version_ge () {
34- # returns 0 if $1 >= $2
3568 [ " $( printf ' %s\n' " $2 " " $1 " | sort -V | head -n1) " = " $2 " ]
3669}
3770
@@ -41,11 +74,25 @@ if ! version_ge "$UV_VERSION" "$UV_MIN_VERSION"; then
4174 exit 1
4275fi
4376
77+ # ----------------------------
78+ # ARGUMENT PARSING
79+ # ----------------------------
80+ # default to public-index if not provided
81+ INDEX_MODE=" ${1:- public-index} "
82+ TARGET_DIR_ARG=" ${2:- } "
83+
84+ # Validate mode
85+ if [[ " $INDEX_MODE " != " aipcc-index" && " $INDEX_MODE " != " public-index" ]]; then
86+ error " Invalid mode '$INDEX_MODE '. Valid options: aipcc-index, public-index"
87+ exit 1
88+ fi
89+ info " Using index mode: $INDEX_MODE "
90+
4491# ----------------------------
4592# GET TARGET DIRECTORIES
4693# ----------------------------
47- if [ $# -gt 0 ]; then
48- TARGET_DIRS=(" $1 " )
94+ if [ -n " $TARGET_DIR_ARG " ]; then
95+ TARGET_DIRS=(" $TARGET_DIR_ARG " )
4996else
5097 info " Scanning main directories for Python projects..."
5198 TARGET_DIRS=()
@@ -76,7 +123,6 @@ for TARGET_DIR in "${TARGET_DIRS[@]}"; do
76123 echo " ==================================================================="
77124
78125 cd " $TARGET_DIR " || continue
79- mkdir -p uv.lock
80126 PYTHON_VERSION=" ${PWD##* -} "
81127
82128 # Validate Python version extraction
@@ -113,9 +159,20 @@ for TARGET_DIR in "${TARGET_DIRS[@]}"; do
113159 run_lock () {
114160 local flavor=" $1 "
115161 local index=" $2 "
116- local output=" uv.lock/pylock.${flavor} .toml"
162+ local output
163+ local desc
164+
165+ if [[ " $INDEX_MODE " == " public-index" ]]; then
166+ output=" pylock.toml"
167+ desc=" pylock.toml (public index)"
168+ echo " ➡️ Generating pylock.toml from public PyPI index..."
169+ else
170+ mkdir -p uv.lock
171+ output=" uv.lock/pylock.${flavor} .toml"
172+ desc=" ${flavor^^} lock file"
173+ echo " ➡️ Generating ${flavor^^} lock file..."
174+ fi
117175
118- echo " ➡️ Generating ${flavor^^} lock file..."
119176 set +e
120177 uv pip compile pyproject.toml \
121178 --output-file " $output " \
@@ -130,17 +187,27 @@ for TARGET_DIR in "${TARGET_DIRS[@]}"; do
130187 set -e
131188
132189 if [ $status -ne 0 ]; then
133- warn " ${flavor^^} lock failed in $TARGET_DIR "
190+ warn " Failed to generate $desc in $TARGET_DIR "
134191 rm -f " $output "
135192 DIR_SUCCESS=false
136193 else
137- ok " ${flavor^^} lock generated successfully."
194+ if [[ " $INDEX_MODE " == " public-index" ]]; then
195+ ok " pylock.toml generated successfully."
196+ else
197+ ok " ${flavor^^} lock generated successfully."
198+ fi
138199 fi
139200 }
140201
141- $HAS_CPU && run_lock " cpu" " $CPU_INDEX "
142- $HAS_CUDA && run_lock " cuda" " $CUDA_INDEX "
143- $HAS_ROCM && run_lock " rocm" " $ROCM_INDEX "
202+ # Run lock generation
203+ if [[ " $INDEX_MODE " == " public-index" ]]; then
204+ # public-index always updates pylock.toml in place
205+ run_lock " cpu" " $PUBLIC_INDEX "
206+ else
207+ $HAS_CPU && run_lock " cpu" " $CPU_INDEX "
208+ $HAS_CUDA && run_lock " cuda" " $CUDA_INDEX "
209+ $HAS_ROCM && run_lock " rocm" " $ROCM_INDEX "
210+ fi
144211
145212 if $DIR_SUCCESS ; then
146213 SUCCESS_DIRS+=(" $TARGET_DIR " )
0 commit comments