From 37c69cd1714de351db1eee895107f4cf8126a77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Hern=C3=A1ndez?= Date: Mon, 16 Mar 2026 10:09:10 +0100 Subject: [PATCH] feat: Bootclasspath patch generator tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pedro Hernández --- scripts/build-patch.sh | 119 ++++++++++++++++++++++++++++++++ scripts/list-changed-classes.sh | 94 +++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100755 scripts/build-patch.sh create mode 100755 scripts/list-changed-classes.sh diff --git a/scripts/build-patch.sh b/scripts/build-patch.sh new file mode 100755 index 0000000000..35aa5732d3 --- /dev/null +++ b/scripts/build-patch.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +set -eu + +help() { + cat <&2; exit 1 ;; + *) break ;; + esac +done + +if [ "$#" -gt 1 ]; then + echo "$0: too many arguments" >&2 + exit 1 +fi +SOURCES_FILE="${1:-}" + +REPO_ROOT="$(git rev-parse --show-toplevel)" + +if [ -z "$OUTPUT_PATH" ]; then + OUTPUT_PATH="${REPO_ROOT}/lib/glibj-patch.zip" +elif [ "${OUTPUT_PATH#/}" = "$OUTPUT_PATH" ]; then + OUTPUT_PATH="$PWD/$OUTPUT_PATH" +fi + +if [ -n "$SOURCES_FILE" ]; then + CHANGED_SOURCES=$(cat "$SOURCES_FILE") +else + if [ -t 0 ]; then + # true if stdin is a terminal (i.e. no pipe or redirect) + echo "$0: expected list of .java paths on stdin or as a file argument" >&2 + exit 1 + fi + + CHANGED_SOURCES=$(cat) +fi + +if [ -z "$CHANGED_SOURCES" ]; then + echo "No modified Java sources to build." + exit 0 +fi + +source_base() { + src=$1 + + awk -v root="$REPO_ROOT" -v src="$src" ' + { + full = $2 "/" $3 + prefix = root "/" + + if (index(full, prefix) == 1) { + full = substr(full, length(prefix) + 1) + } + + if (full == src) { + sub(/\.java$/, "", $3) + print $3 + exit + } + } + ' "$REPO_ROOT/lib/classes.1" +} + +PATCH_LIST="$(mktemp "${TMPDIR:-/tmp}/build-patch-archive.XXXXXX")" + +cleanup() { + rm -f "$PATCH_LIST" +} +trap cleanup EXIT +trap 'exit 1' HUP INT QUIT TERM + +printf '%s\n' "$CHANGED_SOURCES" | +while IFS= read -r src; do + base=$(source_base "$src") + + [ -n "$base" ] || continue + + if [ -f "${REPO_ROOT}/lib/${base}.class" ]; then + printf '%s\n' "${base}.class" + fi + + for inner in "${REPO_ROOT}/lib/${base}"\$*.class; do + [ -f "$inner" ] || continue + printf '%s\n' "${inner#${REPO_ROOT}/lib/}" + done +done > "$PATCH_LIST" + +if [ ! -s "$PATCH_LIST" ]; then + echo "$0: no compiled class files found for modified Java sources" >&2 + exit 1 +fi + +rm -f "$OUTPUT_PATH" + +( + cd "${REPO_ROOT}/lib" + jar cf "$OUTPUT_PATH" @"$PATCH_LIST" +) + +echo "Patch archive created: $OUTPUT_PATH" diff --git a/scripts/list-changed-classes.sh b/scripts/list-changed-classes.sh new file mode 100755 index 0000000000..23ae9a43d1 --- /dev/null +++ b/scripts/list-changed-classes.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +set -eu + +help() { + cat < + +List glibj Java source files changed between and HEAD. + +Options: + -e, --exclude FILE + exclude sources listed in FILE + -h, --help display this help and exit +EOF + exit 0 +} + +EXCLUDE_PATH="" + +while [ "$#" -gt 0 ]; do + case "$1" in + -e|--exclude) EXCLUDE_PATH="$2"; shift 2 ;; + -h|--help) help ;; + -*) echo "$0: unknown option: $1" >&2; exit 1 ;; + *) break ;; + esac +done + +if [ "$#" -ne 1 ]; then + echo "$0: expected exactly one argument" >&2 + exit 1 +fi +OLD_REF=$1 +NEW_REF=HEAD + +if [ -n "$EXCLUDE_PATH" ] && [ ! -e "$EXCLUDE_PATH" ]; then + echo "error: exclude file not found: $EXCLUDE_PATH" >&2 + exit 1 +fi + +is_excluded() { + src=$1 + + while IFS= read -r exclude; do + exclude=$(printf '%s\n' "$exclude" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') + + case "$exclude" in + ''|\#*) continue ;; + */) exclude=${exclude%/} ;; + esac + + case "$exclude" in + *.java) + [ "$src" = "$exclude" ] && return 0 + ;; + *) + case "$src" in + "$exclude"/*) return 0 ;; + esac + ;; + esac + done < "$EXCLUDE_PATH" + + return 1 +} + +is_glibj_source() { + # Source dirs mirror what gen-classlist.sh scans + case "$1" in + java/*|javax/*|gnu/*|org/*|sun/*|external/*|vm/reference/*) return 0 ;; + *) return 1 ;; + esac +} + +CHANGED_SOURCES=$( + git diff --name-only --diff-filter=ACMR "$OLD_REF" "$NEW_REF" -- '*.java' | + while IFS= read -r src; do + is_glibj_source "$src" || continue + + if [ -n "$EXCLUDE_PATH" ] && is_excluded "$src"; then + continue + fi + + printf '%s\n' "$src" + done +) + +if [ -z "$CHANGED_SOURCES" ]; then + echo "No modified glibj Java sources found between ${OLD_REF} and ${NEW_REF}." + exit 0 +fi + +printf '%s\n' "$CHANGED_SOURCES"