BastionGuard/debian/patches-ubuntu-lts/ubuntu-lts-gtkmm4-patch.sh

264 lines
8.1 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(pwd)"
SRC_DIR="$ROOT/src"
PATCH_OUT="$ROOT/ubuntu-lts-gtkmm4.generated.patch"
COMPAT_HPP="$SRC_DIR/GtkCompat.hpp"
if [[ ! -d "$SRC_DIR" ]]; then
echo "ERROR: src/ not found. Run from project root." >&2
exit 1
fi
mapfile -t FILES_TO_PATCH < <(find "$SRC_DIR" -type f -name "*.cpp" | sort)
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
backup_key() { echo "$1" | sed 's|/|__|g'; }
echo "[1/6] Backups"
for f in "${FILES_TO_PATCH[@]}"; do
[[ -f "$f" ]] || continue
cp -a "$f" "$TMPDIR/$(backup_key "$f").orig"
done
if [[ -f "$COMPAT_HPP" ]]; then
cp -a "$COMPAT_HPP" "$TMPDIR/GtkCompat.hpp.orig"
else
: > "$TMPDIR/GtkCompat.hpp.orig"
fi
echo "[2/6] Writing $COMPAT_HPP (Qt macro-safe)"
cat > "$COMPAT_HPP" <<'EOF'
#pragma once
#if defined(_MSC_VER) || defined(__clang__) || defined(__GNUC__)
#define GTKCOMPAT_HAS_PUSH_POP_MACRO 1
#else
#define GTKCOMPAT_HAS_PUSH_POP_MACRO 0
#endif
#if GTKCOMPAT_HAS_PUSH_POP_MACRO
#ifdef signals
#pragma push_macro("signals")
#undef signals
#define GTKCOMPAT_RESTORE_signals 1
#endif
#ifdef slots
#pragma push_macro("slots")
#undef slots
#define GTKCOMPAT_RESTORE_slots 1
#endif
#ifdef emit
#pragma push_macro("emit")
#undef emit
#define GTKCOMPAT_RESTORE_emit 1
#endif
#ifdef foreach
#pragma push_macro("foreach")
#undef foreach
#define GTKCOMPAT_RESTORE_foreach 1
#endif
#ifdef Q_FOREACH
#pragma push_macro("Q_FOREACH")
#undef Q_FOREACH
#define GTKCOMPAT_RESTORE_Q_FOREACH 1
#endif
#else
#ifdef signals
#undef signals
#endif
#ifdef slots
#undef slots
#endif
#ifdef emit
#undef emit
#endif
#ifdef foreach
#undef foreach
#endif
#ifdef Q_FOREACH
#undef Q_FOREACH
#endif
#endif
#include <gtkmm.h>
#include <string>
#include <vector>
#include <functional>
namespace GtkCompat
{
inline void for_each_child(Gtk::Widget& parent, const std::function<void(Gtk::Widget*)>& fn)
{
for (auto* child = parent.get_first_child(); child != nullptr; child = child->get_next_sibling())
fn(child);
}
inline std::vector<Gtk::Widget*> children(Gtk::Widget& parent)
{
std::vector<Gtk::Widget*> out;
for_each_child(parent, [&](Gtk::Widget* w){ out.push_back(w); });
return out;
}
inline void listbox_clear(Gtk::ListBox& lb)
{
for (auto* child = lb.get_first_child(); child != nullptr; )
{
auto* next = child->get_next_sibling();
lb.remove(*child);
child = next;
}
}
}
inline bool operator==(const Glib::ustring& lhs, const std::string& rhs) { return lhs.raw() == rhs; }
inline bool operator==(const std::string& lhs, const Glib::ustring& rhs) { return lhs == rhs.raw(); }
inline bool operator!=(const Glib::ustring& lhs, const std::string& rhs) { return !(lhs == rhs); }
inline bool operator!=(const std::string& lhs, const Glib::ustring& rhs) { return !(lhs == rhs); }
#if GTKCOMPAT_HAS_PUSH_POP_MACRO
#ifdef GTKCOMPAT_RESTORE_Q_FOREACH
#pragma pop_macro("Q_FOREACH")
#undef GTKCOMPAT_RESTORE_Q_FOREACH
#endif
#ifdef GTKCOMPAT_RESTORE_foreach
#pragma pop_macro("foreach")
#undef GTKCOMPAT_RESTORE_foreach
#endif
#ifdef GTKCOMPAT_RESTORE_emit
#pragma pop_macro("emit")
#undef GTKCOMPAT_RESTORE_emit
#endif
#ifdef GTKCOMPAT_RESTORE_slots
#pragma pop_macro("slots")
#undef GTKCOMPAT_RESTORE_slots
#endif
#ifdef GTKCOMPAT_RESTORE_signals
#pragma pop_macro("signals")
#undef GTKCOMPAT_RESTORE_signals
#endif
#endif
#undef GTKCOMPAT_HAS_PUSH_POP_MACRO
EOF
echo "[3/6] Ensuring includes"
for f in "${FILES_TO_PATCH[@]}"; do
[[ -f "$f" ]] || continue
if ! grep -q '^[[:space:]]*#include[[:space:]]*"GtkCompat\.hpp"[[:space:]]*$' "$f"; then
perl -0777 -i -pe '
if (s/(#include\s+"[^"]+\.hpp"\s*\n)/$1#include "GtkCompat.hpp"\n/s) {
} else {
$_ = "#include \"GtkCompat.hpp\"\n" . $_;
}
' "$f"
fi
done
echo "[4/6] Fix ListBox::remove_all()"
perl -pi -e 's/\b([A-Za-z_][A-Za-z0-9_]*)\.remove_all\(\)\s*;/GtkCompat::listbox_clear($1);/g' "${FILES_TO_PATCH[@]}"
echo "[5/6] Fix get_children() vars and loops (supports auto, auto&, auto*, braced and single-line)"
for f in "${FILES_TO_PATCH[@]}"; do
[[ -f "$f" ]] || continue
perl -i -pe '
s/\bauto\s+(\w+)\s*=\s*([A-Za-z_][A-Za-z0-9_:>\-\.\(\)\s]*)\s*\.get_children\s*\(\s*\)\s*;/
auto $1 = GtkCompat::children($2);/gx
' "$f"
perl -i -pe '
s/\bauto\s+(\w+)\s*=\s*([A-Za-z_][A-Za-z0-9_:>\-\.\(\)\s]*)\s*->get_children\s*\(\s*\)\s*;/
auto $1 = GtkCompat::children(*($2));/gx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s+(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\)]+?)\.get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2).get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s+(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s/for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\)]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\{/
for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; $1 = $1->get_next_sibling()) {/gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s+(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\n;]+?)\.get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2).get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s+(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s*&\s*(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
perl -0777 -i -pe '
s@for\s*\(\s*auto\s*\*\s*(\w+)\s*:\s*([^\n;]+?)\-\>get_children\s*\(\s*\)\s*\)\s*\n(\s*)([^\n;][^\n]*;)@
$3for (auto* $1 = ($2)->get_first_child(); $1 != nullptr; ) {\n$3 auto* next = $1->get_next_sibling();\n$3 $4\n$3 $1 = next;\n$3}@gsx
' "$f"
done
echo "[6/6] Generate patch artifact: $PATCH_OUT"
{
echo "--- a/src/GtkCompat.hpp"
echo "+++ b/src/GtkCompat.hpp"
diff -u "$TMPDIR/GtkCompat.hpp.orig" "$COMPAT_HPP" || true
echo
for f in "${FILES_TO_PATCH[@]}"; do
[[ -f "$f" ]] || continue
orig="$TMPDIR/$(backup_key "$f").orig"
[[ -f "$orig" ]] || continue
rel="${f#$ROOT/}"
echo "--- a/$rel"
echo "+++ b/$rel"
diff -u "$orig" "$f" || true
echo
done
} > "$PATCH_OUT"
echo "DONE. Residual get_children() occurrences (should be 0):"
grep -R --line-number "get_children()" -n "$SRC_DIR" || true
echo
echo "Patch written to: $PATCH_OUT"