Re: [PATCH] libxfs-apply: allow stgit users to force-apply a patch

Andrey Albershteyn
2025-02-20T17:58:33Z

On 2025-02-20 08:49:33, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Currently, libxfs-apply handles merge conflicts in the auto-backported
> patches in a somewhat unfriendly way -- either it applies completely
> cleanly, or the user has to ^Z, find the raw diff file in /tmp, apply it
> by hand, resume the process, and then tell it to skip the patch.
>
> This is annoying, and I've long worked around that by using my handy
> stg-force-import script that imports the patch with --reject, undoes the
> partially-complete diff, uses patch(1) to import as much of the diff as
> possible, and then starts an editor so the caller can clean up the rest.
>
> When patches are fuzzy, patch(1) is /much/ less strict about applying
> changes than stg-import. Since Carlos sent in his own workaround for
> guilt, I figured I might as well port stg-force-import into libxfs-apply
> and contribute that.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> ---
> per maintainer request
> ---
> tools/libxfs-apply | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/tools/libxfs-apply b/tools/libxfs-apply
> index 097a695f942bb8..9fb31f74d5c9af 100755
> --- a/tools/libxfs-apply
> +++ b/tools/libxfs-apply
> @@ -297,6 +297,64 @@ fixup_header_format()
>
> }
>
> +editor() {
> + if [ -n "${EDITOR}" ]; then
> + ${EDITOR} "$@"
> + elif [ -n "${VISUAL}" ]; then
> + ${VISUAL} "$@"
> + elif command -v editor &>/dev/null; then
> + editor "$@"
> + elif command -v nano &>/dev/null; then
> + nano "$@"
> + else
> + echo "No editor available, aborting messily."
> + exit 1
> + fi
> +}
> +
> +stg_force_import()
> +{
> + local patch_name="$1"
> + local patch="$2"
> +
> + # Import patch to get the metadata even though the diff application
> + # might fail due to stg import being very picky. If the patch applies
> + # cleanly, we're done.
> + stg import --reject -n "${patch_name}" "${patch}" && return 0
> +
> + local tmpfile="${patch}.stgit"
> + rm -f "${tmpfile}"
> +
> + # Erase whatever stgit managed to apply, then use patch(1)'s more
> + # flexible heuristics. Capture the output for later use.
> + stg diff | patch -p1 -R
> + patch -p1 < "${patch}" &> "${tmpfile}"
> + cat "${tmpfile}"
> +
> + # Attach any new files created by the patch
> + grep 'create mode' "${patch}" | sed -e 's/^.* mode [0-7]* //g' | while read -r f; do
> + git add "$f"
> + done
> +
> + # Remove any existing files deleted by the patch
> + grep 'delete mode' "${patch}" | sed -e 's/^.* mode [0-7]* //g' | while read -r f; do
> + git rm "$f"
> + done
> +
> + # Open an editor so the user can clean up the rejects. Use readarray
> + # instead of "<<<" because the latter picks up empty output as a single
> + # line and does variable expansion... stupid bash.
> + readarray -t rej_files < <(grep 'saving rejects to' "${tmpfile}" | \
> + sed -e 's/^.*saving rejects to file //g')
> + rm -f "${tmpfile}"
> + if [ "${#rej_files[@]}" -gt 0 ]; then
> + echo "Opening editor to deal with rejects. Changes commit when you close the editor."
> + editor "${rej_files[@]}"
> + fi
> +
> + stg refresh
> +}
> +
> apply_patch()
> {
> local _patch=$1
> @@ -385,11 +443,13 @@ apply_patch()
> stg import -n $_patch_name $_new_patch.2
> if [ $? -ne 0 ]; then
> echo "stgit push failed!"
> - read -r -p "Skip or Fail [s|F]? " response
> - if [ -z "$response" -o "$response" != "s" ]; then
> + read -r -p "Skip, force Apply, or Fail [s|a|F]? " response
> + if [ -z "$response" -o "$response" = "F" -o "$response" = "f" ]; then
> echo "Force push patch, fix and refresh."
> echo "Restart from commit $_current_commit"
> fail "Manual cleanup required!"
> + elif [ "$response" = "a" -o "$response" = "A" ]; then
> + stg_force_import "$_patch_name" "$_new_patch.2"
> else
> echo "Skipping. Manual series file cleanup needed!"
> fi
>

Thanks! Works great, lgtm
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>

Sending fix for stgit detection in reply to this patch

--
- Andrey