ffbe098ef8
TLC (Twilight Commander) was missing from both ISO configs. Added
tlc = {} to [packages] in redbear-mini.toml and redbear-full.toml.
Created missing symlink: recipes/tui/tlc -> ../../local/recipes/tui/tlc.
244 lines
9.0 KiB
Bash
Executable File
244 lines
9.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Red Bear OS — C-7 direct-sed migration
|
|
#
|
|
# For KF6 recipes whose [build].script uses inline `sed -i`
|
|
# chains, this script:
|
|
# 1. Restores the pristine source from `source-pristine/`
|
|
# 2. Applies the same sed chain manually via `bash -c`
|
|
# 3. Diffs pristine vs post-sed source
|
|
# 4. Saves the diff as `local/patches/<name>/01-initial-migration.patch`
|
|
#
|
|
# Why direct-sed instead of `repo cook`: the cookbook's
|
|
# `cook` step does a full dep-tree build that often fails
|
|
# in offline mode (missing libffi/pcre2/mesa stage.pkgar
|
|
# etc.). The sed chain we care about is the FIRST thing
|
|
# in the recipe's [build].script and runs BEFORE cmake
|
|
# configure. We can run it standalone with a simple
|
|
# `bash -c "<sed chain>"` to capture the post-sed state.
|
|
#
|
|
# This is the same diff that `repo cook` would have
|
|
# produced, but without the dep-tree failure mode.
|
|
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
|
|
|
PATCHES_DIR="${REDBEAR_MIGRATE_PATCHES_DIR:-/home/kellito/Builds/RedBear-OS/local/patches}"
|
|
|
|
# All 17 KF6 recipes that previously had inline `sed -i`
|
|
# chains (all those whose upstream 6.26.0 still has the
|
|
# ecm_install_po_files_as_qm call). The 24 NO-OP recipes
|
|
# were cleaned separately by cleanup-kf6-noop-seds.sh.
|
|
recipe_dirs=(
|
|
"local/recipes/kde/kf6-karchive"
|
|
"local/recipes/kde/kf6-kauth"
|
|
"local/recipes/kde/kf6-kbookmarks"
|
|
"local/recipes/kde/kf6-kcodecs"
|
|
"local/recipes/kde/kf6-kcompletion"
|
|
"local/recipes/kde/kf6-kconfig"
|
|
"local/recipes/kde/kf6-kcoreaddons"
|
|
"local/recipes/kde/kf6-kdbusaddons"
|
|
"local/recipes/kde/kf6-kglobalaccel"
|
|
"local/recipes/kde/kf6-kitemviews"
|
|
"local/recipes/kde/kf6-kjobwidgets"
|
|
"local/recipes/kde/kf6-knotifications"
|
|
"local/recipes/kde/kf6-kwidgetsaddons"
|
|
"local/recipes/kde/kf6-kwindowsystem"
|
|
"local/recipes/kde/kf6-solid"
|
|
"local/recipes/kde/kf6-sonnet"
|
|
"local/recipes/kde/kf6-syntaxhighlighting"
|
|
"local/recipes/kde/sddm"
|
|
# 7 unclassified (git-sourced or kde/plasma). Their
|
|
# pristine state was snapshotted after a successful
|
|
# `repo fetch`. If the pristine doesn't exist, the
|
|
# script reports NO-OP and moves on.
|
|
"local/recipes/kde/breeze"
|
|
"local/recipes/kde/kde-cli-tools"
|
|
"local/recipes/kde/kdecoration"
|
|
"local/recipes/kde/kf6-kcmutils"
|
|
"local/recipes/kde/kf6-kdeclarative"
|
|
"local/recipes/kde/kf6-kded6"
|
|
"local/recipes/kde/kf6-kwayland"
|
|
"local/recipes/kde/kf6-notifyconfig"
|
|
"local/recipes/kde/kglobalacceld"
|
|
"local/recipes/kde/kirigami"
|
|
"local/recipes/kde/konsole"
|
|
"local/recipes/kde/kwin"
|
|
"local/recipes/kde/plasma-desktop"
|
|
"local/recipes/kde/plasma-workspace"
|
|
)
|
|
|
|
migrated=0
|
|
skipped=0
|
|
failed=0
|
|
no_op=0
|
|
|
|
for recipe_dir in "${recipe_dirs[@]}"; do
|
|
name=$(basename "$recipe_dir")
|
|
recipe="$recipe_dir/recipe.toml"
|
|
pristine_dir="$recipe_dir/source-pristine"
|
|
source_dir="$recipe_dir/source"
|
|
patch_dir="$PATCHES_DIR/$name"
|
|
patch_file="$patch_dir/01-initial-migration.patch"
|
|
|
|
if [ -e "$patch_file" ]; then
|
|
echo "SKIP: $name (patch already exists)"
|
|
skipped=$((skipped+1))
|
|
continue
|
|
fi
|
|
|
|
if [ ! -e "$pristine_dir" ] || [ ! -e "$source_dir" ]; then
|
|
echo "FAIL: $name (missing pristine or source dir)"
|
|
failed=$((failed+1))
|
|
continue
|
|
fi
|
|
|
|
# Restore pristine state (the previous cook may have
|
|
# partially modified source/).
|
|
rm -rf "$source_dir"
|
|
cp -r "$pristine_dir" "$source_dir"
|
|
|
|
# Extract the sed chain from the recipe's [build].script.
|
|
# The chain is everything between the first `sed -i` line
|
|
# and the next non-sed, non-continuation line. Continuation
|
|
# lines are those that either end with `\` (line-continuation
|
|
# within the sed command) or are indented-continuations
|
|
# (the file path / args of a multi-line sed).
|
|
sed_chain=$(python3 - "$recipe" <<'PY'
|
|
import sys
|
|
from pathlib import Path
|
|
text = Path(sys.argv[1]).read_text()
|
|
out = []
|
|
in_sed = False
|
|
prev_ended_with_continuation = False
|
|
BS = chr(92)
|
|
for line in text.splitlines():
|
|
if "sed -i" in line and not in_sed:
|
|
in_sed = True
|
|
out.append(line)
|
|
prev_ended_with_continuation = line.rstrip().endswith(BS)
|
|
elif in_sed:
|
|
ends_with_bs = line.rstrip().endswith(BS)
|
|
is_indented = line.startswith(" ") or line.startswith("\t")
|
|
if "sed -i" in line:
|
|
out.append(line)
|
|
prev_ended_with_continuation = ends_with_bs
|
|
elif ends_with_bs or is_indented or prev_ended_with_continuation:
|
|
out.append(line)
|
|
prev_ended_with_continuation = ends_with_bs
|
|
else:
|
|
break
|
|
print(chr(10).join(out))
|
|
PY
|
|
)
|
|
|
|
if [ -z "$sed_chain" ]; then
|
|
echo "FAIL: $name (no sed chain found in recipe)"
|
|
failed=$((failed+1))
|
|
continue
|
|
fi
|
|
|
|
# Apply the sed chain. Bash's `$(...)` command substitution
|
|
# strips trailing newlines, which would break the multi-line
|
|
# `sed -i ... \` continuation. Write the chain to a temp
|
|
# file and source it instead so the literal newlines are
|
|
# preserved.
|
|
sed_script=$(mktemp /tmp/sed-chain.XXXXXX.sh)
|
|
printf '%s\n' "$sed_chain" > "$sed_script"
|
|
# shellcheck disable=SC1090
|
|
# Use an absolute path for COOKBOOK_SOURCE because the cd
|
|
# below changes PWD, and a relative path in COOKBOOK_SOURCE
|
|
# would resolve against the new PWD.
|
|
abs_source_dir=$(cd "$source_dir" && pwd)
|
|
( export COOKBOOK_SOURCE="$abs_source_dir" && cd "$abs_source_dir" && bash "$sed_script" 2>/dev/null ) || true
|
|
rm -f "$sed_script"
|
|
|
|
# Diff pristine vs post-sed. The cookbook's
|
|
# `cookbook_apply_patches` helper runs `git apply` from
|
|
# inside `${COOKBOOK_SOURCE}` (the source directory), and
|
|
# `git apply` interprets the path in `---` and `+++`
|
|
# lines as relative-to-cwd. So the patch's labels must
|
|
# be the actual file paths relative to the source
|
|
# directory (e.g. `CMakeLists.txt` or `src/CMakeLists.txt`).
|
|
#
|
|
# Build a per-file diff so each file gets the right
|
|
# label. Use `diff -rq` to enumerate changed files
|
|
# (its output is locale-dependent so we just extract
|
|
# all the absolute paths that match the source dir).
|
|
abs_pristine_dir=$(cd "$pristine_dir" && pwd)
|
|
abs_source_dir2=$(cd "$source_dir" && pwd)
|
|
# Enumerate regular files in the source dir (we know
|
|
# pristine and source share the same file tree, only
|
|
# file contents differ).
|
|
diff_out=""
|
|
while IFS= read -r -d '' rel_file; do
|
|
# Skip ECM-generated noise.
|
|
case "$rel_file" in
|
|
.clang-format|.gitignore|target) continue ;;
|
|
esac
|
|
pristine_file="$abs_pristine_dir/$rel_file"
|
|
source_file="$abs_source_dir2/$rel_file"
|
|
if [ ! -f "$pristine_file" ] || [ ! -f "$source_file" ]; then
|
|
continue
|
|
fi
|
|
# Per-file diff with the relative path as the label.
|
|
file_diff=$(diff -uN \
|
|
--label="a/$rel_file" \
|
|
--label="b/$rel_file" \
|
|
"$pristine_file" "$source_file" 2>/dev/null || true)
|
|
if [ -n "$file_diff" ]; then
|
|
# Strip the `a/` and `b/` prefixes to get just
|
|
# the file path relative to source.
|
|
file_diff=$(echo "$file_diff" \
|
|
| sed -e "s#^--- a/#--- #g" -e "s#^+++ b/#+++ #g")
|
|
diff_out="${diff_out}${file_diff}"$'\n'
|
|
fi
|
|
done < <(cd "$abs_source_dir2" && find . -type f -not -path './.git/*' -not -path './target/*' -not -name '.clang-format' -not -name '.gitignore' -print0)
|
|
|
|
if [ -z "$diff_out" ]; then
|
|
echo "NO-OP: $name (sed produced no diff — line not in upstream)"
|
|
no_op=$((no_op+1))
|
|
continue
|
|
fi
|
|
|
|
# Save the patch.
|
|
mkdir -p "$patch_dir"
|
|
{
|
|
echo "# Initial migration of the inline sed -i chains in"
|
|
echo "# $recipe_dir's [build].script to a durable external"
|
|
echo "# patch. Captured by local/scripts/migrate-kf6-seds-direct.sh"
|
|
echo "# on $(date -Iseconds)."
|
|
echo "#"
|
|
echo "# After applying this patch via cookbook_apply_patches,"
|
|
echo "# the recipe's [build].script should call:"
|
|
echo "# REDBEAR_PATCHES_DIR=\"$PATCHES_DIR/$name\""
|
|
echo "# cookbook_apply_patches \"\${REDBEAR_PATCHES_DIR}\""
|
|
echo "# in place of the sed -i chains that produced these edits."
|
|
echo
|
|
echo "$diff_out"
|
|
} > "$patch_file"
|
|
|
|
# Verify the patch applies cleanly to pristine using
|
|
# `git apply --check` (the same tool the cookbook's
|
|
# `cookbook_apply_patches` helper uses). `patch -p1` does
|
|
# NOT work on these patches because they were generated
|
|
# by `diff -ruN` with absolute paths and include
|
|
# /home/kellito/Builds/RedBear-OS/... prefixes that
|
|
# `patch -p1` cannot strip.
|
|
if (cd "$pristine_dir" && git apply --check "$patch_file" >/dev/null 2>&1); then
|
|
echo "MIGRATED: $name"
|
|
migrated=$((migrated+1))
|
|
else
|
|
echo "FAIL: $name (patch does not apply cleanly)"
|
|
rm -f "$patch_file"
|
|
failed=$((failed+1))
|
|
fi
|
|
done
|
|
|
|
echo
|
|
echo "=== Summary ==="
|
|
echo "Migrated: $migrated"
|
|
echo "No-op: $no_op"
|
|
echo "Skipped: $skipped"
|
|
echo "Failed: $failed"
|