Build 1.21.11 with Stonecutter from a shared src/
Step 1 of #8. 1.21.11's version-specific code moves from versions/1.21.11/src to the top-level src/, built by Stonecutter as the project :1.21.11. The other versions still build from their own copies as :mc-<v> until they're folded in. - settings.gradle: applies Stonecutter (Groovy controller) with stonecutterVersions = ["1.21.11"] and skips those folders when including the old mc-<v> projects. - The old root build.gradle becomes stonecutter.gradle (the root project's script, with the shared repositories, common wiring and buildAll), and 1.21.11's build.gradle becomes the root build.gradle that Stonecutter runs for each version. versions/1.21.11 keeps its gradle.properties and run/. - The jar has the same 415 entries, fabric.mod.json and mixin configs as before; the only class differences also appear when rebuilding an untouched version today. - scripts/port.sh treats src/ as the active Stonecutter version, so changes port between it and the old copies both ways. - README and VERSION_GUIDE describe the layout, version comments and how to add a version. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+46
-18
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
# Port a change made in one Minecraft version's code to the other versions.
|
||||
#
|
||||
# Takes the diff under versions/<from>/src and applies it to versions/<to>/src
|
||||
# Takes the diff under one version's source folder and applies it to the others
|
||||
# with `git apply --3way`: it applies cleanly where the files match, and leaves
|
||||
# normal merge conflicts only where a version really differs. Only src/ is
|
||||
# normal merge conflicts only where a version really differs. Only source is
|
||||
# ported; build.gradle and gradle.properties are version-specific on purpose.
|
||||
#
|
||||
# Versions moved to Stonecutter (stonecutterVersions in settings.gradle) share
|
||||
# the top-level src/, which counts as one version: the active one set in
|
||||
# stonecutter.gradle. The others keep their own copy in versions/<v>/src.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/port.sh [--from VERSION] [--to V1,V2,...] [--commit REV] [--dry-run]
|
||||
#
|
||||
@@ -33,25 +37,39 @@ while [ $# -gt 0 ]; do
|
||||
--to) to="$2"; shift 2 ;;
|
||||
--commit) commit="$2"; shift 2 ;;
|
||||
--dry-run) dry_run=true; shift ;;
|
||||
-h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
-h|--help) sed -n '2,23p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "Unknown option: $1 (see --help)" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
all_versions=$(ls -d versions/*/ | xargs -n1 basename | sort -t. -k1,1n -k2,2n -k3,3n)
|
||||
# Versions sharing the Stonecutter src/, and the one that stands for them.
|
||||
stonecutter_versions=$(sed -n 's/^def stonecutterVersions = \[\(.*\)\]/\1/p' settings.gradle | tr -d '" ' | tr ',' ' ')
|
||||
stonecutter_active=$(sed -n 's/^stonecutter\.active "\(.*\)"/\1/p' stonecutter.gradle 2>/dev/null || true)
|
||||
|
||||
is_stonecutter() {
|
||||
printf '%s\n' $stonecutter_versions | grep -qx "$1"
|
||||
}
|
||||
|
||||
# Where a version's source lives.
|
||||
src_of() {
|
||||
if is_stonecutter "$1"; then echo "src"; else echo "versions/$1/src"; fi
|
||||
}
|
||||
|
||||
old_versions=$(for d in versions/*/; do [ -d "$d/src" ] && basename "$d"; done)
|
||||
all_versions=$(printf '%s\n' $old_versions $stonecutter_active | grep . | sort -t. -k1,1n -k2,2n -k3,3n)
|
||||
|
||||
version_exists() {
|
||||
[ -d "versions/$1/src" ]
|
||||
[ -d "$(src_of "$1")" ]
|
||||
}
|
||||
|
||||
# Versions with changes, from the working tree or from the given commit.
|
||||
changed_versions() {
|
||||
if [ -n "$commit" ]; then
|
||||
git show --name-only --format= "$commit" -- versions/
|
||||
git show --name-only --format= "$commit" -- versions/ src/
|
||||
else
|
||||
git diff HEAD --name-only -- versions/
|
||||
git ls-files --others --exclude-standard -- versions/
|
||||
fi | sed -n 's#^versions/\([^/]*\)/src/.*#\1#p' | sort -u
|
||||
git diff HEAD --name-only -- versions/ src/
|
||||
git ls-files --others --exclude-standard -- versions/ src/
|
||||
fi | sed -n -e 's#^versions/\([^/]*\)/src/.*#\1#p' -e "s#^src/.*#${stonecutter_active}#p" | sort -u
|
||||
}
|
||||
|
||||
if [ -z "$from" ]; then
|
||||
@@ -65,6 +83,10 @@ if [ -z "$from" ]; then
|
||||
fi
|
||||
|
||||
version_exists "$from" || { echo "No such version: $from" >&2; exit 2; }
|
||||
if is_stonecutter "$from"; then
|
||||
from="$stonecutter_active"
|
||||
fi
|
||||
from_src=$(src_of "$from")
|
||||
|
||||
if [ -z "$to" ]; then
|
||||
to=$(printf '%s\n' $all_versions | grep -vx "$from" | paste -sd, -)
|
||||
@@ -72,10 +94,10 @@ fi
|
||||
|
||||
# New files are only included in `git diff HEAD` once git knows about them.
|
||||
if [ -z "$commit" ]; then
|
||||
untracked=$(git ls-files --others --exclude-standard -- "versions/$from/src")
|
||||
untracked=$(git ls-files --others --exclude-standard -- "$from_src")
|
||||
if [ -n "$untracked" ]; then
|
||||
if $dry_run; then
|
||||
echo "note: new files in versions/$from/src are untracked and won't be ported in a dry run:" >&2
|
||||
echo "note: new files in $from_src are untracked and won't be ported in a dry run:" >&2
|
||||
printf ' %s\n' $untracked >&2
|
||||
else
|
||||
printf '%s\n' "$untracked" | xargs git add --intent-to-add --
|
||||
@@ -85,20 +107,20 @@ fi
|
||||
|
||||
# --full-index gives --3way the real blob ids to merge against.
|
||||
if [ -n "$commit" ]; then
|
||||
patch=$(git show --full-index --binary --format= "$commit" -- "versions/$from/src")
|
||||
patch=$(git show --full-index --binary --format= "$commit" -- "$from_src")
|
||||
else
|
||||
patch=$(git diff HEAD --full-index --binary -- "versions/$from/src")
|
||||
patch=$(git diff HEAD --full-index --binary -- "$from_src")
|
||||
fi
|
||||
|
||||
if [ -z "$patch" ]; then
|
||||
echo "No changes under versions/$from/src to port." >&2
|
||||
echo "No changes under $from_src to port." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
files=$(printf '%s\n' "$patch" | grep -c '^diff --git' || true)
|
||||
echo "Porting $files file(s) from $from${commit:+ (commit $commit)}"
|
||||
|
||||
from_re=$(printf '%s' "$from" | sed 's/\./\\./g')
|
||||
from_re=$(printf '%s' "$from_src" | sed 's/\./\\./g')
|
||||
tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
|
||||
@@ -109,14 +131,20 @@ for target in "${targets[@]}"; do
|
||||
if [ "$target" = "$from" ]; then
|
||||
continue
|
||||
fi
|
||||
if is_stonecutter "$target" && [ "$target" != "$stonecutter_active" ]; then
|
||||
printf ' %-8s skipped: shares src/ with %s\n' "$target" "$stonecutter_active"
|
||||
[ "$from" = "$stonecutter_active" ] || status=1
|
||||
continue
|
||||
fi
|
||||
if ! version_exists "$target"; then
|
||||
printf ' %-8s skipped: no such version\n' "$target"
|
||||
status=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# Point the patch's file headers at the target version.
|
||||
printf '%s\n' "$patch" | sed -E "/^(diff --git |--- |\+\+\+ |rename (from|to) |copy (from|to) )/ s#versions/${from_re}/#versions/${target}/#g" > "$tmp/$target.patch"
|
||||
# Point the patch's file headers at the target version's source folder.
|
||||
target_src=$(src_of "$target")
|
||||
printf '%s\n' "$patch" | sed -E "/^(diff --git |--- |\+\+\+ |rename (from|to) |copy (from|to) )/ s#([ab]/|(from|to) )${from_re}/#\1${target_src}/#g" > "$tmp/$target.patch"
|
||||
|
||||
if git apply --check --reverse "$tmp/$target.patch" 2>/dev/null; then
|
||||
printf ' %-8s already has this change\n' "$target"
|
||||
@@ -135,7 +163,7 @@ for target in "${targets[@]}"; do
|
||||
if output=$(git apply --3way "$tmp/$target.patch" 2>&1); then
|
||||
printf ' %-8s applied\n' "$target"
|
||||
else
|
||||
conflicts=$(git diff --name-only --diff-filter=U -- "versions/$target")
|
||||
conflicts=$(git diff --name-only --diff-filter=U -- "$target_src")
|
||||
if [ -n "$conflicts" ]; then
|
||||
printf ' %-8s CONFLICTS in:\n' "$target"
|
||||
printf '%s\n' "$conflicts" | sed 's/^/ /'
|
||||
|
||||
Reference in New Issue
Block a user