mirror of
https://github.com/devmobasa/wayscriber.git
synced 2026-11-01 07:36:42 +01:00
1778 lines
71 KiB
Bash
Executable File
1778 lines
71 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
PACKAGE_CONFIG="${REPO_ROOT}/packaging/package.wayscriber.yaml"
|
|
CONFIGURATOR_PACKAGE_CONFIG="${REPO_ROOT}/packaging/package.configurator.yaml"
|
|
RELEASE_WORKFLOW="${REPO_ROOT}/.github/workflows/build-packages.yml"
|
|
CI_WORKFLOW="${REPO_ROOT}/.github/workflows/ci.yml"
|
|
PACKAGE_SCRIPT="${REPO_ROOT}/tools/package.sh"
|
|
ARCH_INSTALLER_CHECKER="${REPO_ROOT}/tools/check-arch-installer-manifest.sh"
|
|
INSTALL_SCRIPT="${REPO_ROOT}/tools/install-gtk4-layer-shell.sh"
|
|
CONFIGURATOR_INSTALL_SCRIPT="${REPO_ROOT}/tools/install-configurator.sh"
|
|
STATIC_LINK_VERIFIER="${REPO_ROOT}/tools/verify-static-gtk4-layer-shell.sh"
|
|
VERSION_CHECKER="${REPO_ROOT}/tools/check-version-consistency.sh"
|
|
WORK_DIR="$(mktemp -d)"
|
|
|
|
cleanup() {
|
|
rm -rf "${WORK_DIR}"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
assert_contains() {
|
|
local file="$1" value="$2"
|
|
grep -Fq -- "${value}" "${file}" || {
|
|
echo "Expected ${file} to contain: ${value}" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
assert_not_contains() {
|
|
local file="$1" value="$2"
|
|
if grep -Fq -- "${value}" "${file}"; then
|
|
echo "Expected ${file} not to contain: ${value}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# A direct configurator install is a complete desktop application install, not
|
|
# only a binary copy. Exercise every character that needs a second escaping
|
|
# pass in a quoted desktop-entry Exec value without touching the live database.
|
|
CONFIG_INSTALL_REPO="${WORK_DIR}/configurator-install-repo"
|
|
CONFIG_INSTALL_PREFIX="${WORK_DIR}/configurator % install\\root\"quote\`tick\$cash"
|
|
CONFIG_INSTALL_FAKE_BIN="${WORK_DIR}/configurator-install-fake-bin"
|
|
mkdir -p \
|
|
"${CONFIG_INSTALL_REPO}/tools" \
|
|
"${CONFIG_INSTALL_REPO}/packaging/icons" \
|
|
"${CONFIG_INSTALL_REPO}/target/release" \
|
|
"${CONFIG_INSTALL_FAKE_BIN}"
|
|
cp "${CONFIGURATOR_INSTALL_SCRIPT}" \
|
|
"${CONFIG_INSTALL_REPO}/tools/install-configurator.sh"
|
|
cp "${REPO_ROOT}/packaging/wayscriber-configurator.desktop" \
|
|
"${CONFIG_INSTALL_REPO}/packaging/wayscriber-configurator.desktop"
|
|
cp "${REPO_ROOT}/packaging/icons/wayscriber-configurator.svg" \
|
|
"${CONFIG_INSTALL_REPO}/packaging/icons/wayscriber-configurator.svg"
|
|
for size in 16 19 22 24 38 64 128; do
|
|
cp "${REPO_ROOT}/packaging/icons/wayscriber-configurator-${size}.png" \
|
|
"${CONFIG_INSTALL_REPO}/packaging/icons/wayscriber-configurator-${size}.png"
|
|
done
|
|
cat > "${CONFIG_INSTALL_REPO}/target/release/wayscriber-configurator" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
exit 0
|
|
EOF
|
|
cat > "${CONFIG_INSTALL_FAKE_BIN}/cargo" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
exit 0
|
|
EOF
|
|
chmod +x \
|
|
"${CONFIG_INSTALL_REPO}/target/release/wayscriber-configurator" \
|
|
"${CONFIG_INSTALL_FAKE_BIN}/cargo"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
PATH="${CONFIG_INSTALL_FAKE_BIN}:${PATH}" \
|
|
WAYSCRIBER_INSTALL_DIR="${CONFIG_INSTALL_PREFIX}/bin" \
|
|
bash "${CONFIG_INSTALL_REPO}/tools/install-configurator.sh" >/dev/null
|
|
)
|
|
test -x "${CONFIG_INSTALL_PREFIX}/bin/wayscriber-configurator"
|
|
CONFIG_INSTALL_DESKTOP="${CONFIG_INSTALL_PREFIX}/share/applications/wayscriber-configurator.desktop"
|
|
test -f "${CONFIG_INSTALL_DESKTOP}"
|
|
assert_contains "${CONFIG_INSTALL_DESKTOP}" \
|
|
'configurator %% install\\\\root\\"quote\\`tick\\$cash/bin/wayscriber-configurator"'
|
|
assert_contains "${CONFIG_INSTALL_DESKTOP}" \
|
|
'TryExec='"${WORK_DIR}"'/configurator % install\\root"quote`tick$cash/bin/wayscriber-configurator'
|
|
assert_contains "${CONFIG_INSTALL_DESKTOP}" "Icon=wayscriber-configurator"
|
|
for size in 16 19 22 24 38 64 128; do
|
|
test -f "${CONFIG_INSTALL_PREFIX}/share/icons/hicolor/${size}x${size}/apps/wayscriber-configurator.png"
|
|
done
|
|
test -f "${CONFIG_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps/wayscriber-configurator.svg"
|
|
test -f "${CONFIG_INSTALL_PREFIX}/share/pixmaps/wayscriber-configurator.png"
|
|
if command -v desktop-file-validate >/dev/null 2>&1; then
|
|
desktop-file-validate "${CONFIG_INSTALL_DESKTOP}"
|
|
fi
|
|
|
|
# Binary and application-data destinations are independently configurable.
|
|
# A fake sudo records escalation while safely discarding writes to a synthetic
|
|
# privileged root; writable paths must never appear in that log.
|
|
CONFIG_INSTALL_SUDO_LOG="${WORK_DIR}/configurator-install-sudo.log"
|
|
cat > "${CONFIG_INSTALL_FAKE_BIN}/sudo" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf '%s\n' "$*" >> "${CONFIG_INSTALL_SUDO_LOG:?}"
|
|
if [[ "${CONFIG_INSTALL_DISCARD_SUDO:-0}" == 1 ]]; then
|
|
exit 0
|
|
fi
|
|
if [[ "$*" == *"${CONFIG_INSTALL_PRIVILEGED_ROOT:?}"* ]]; then
|
|
exit 0
|
|
fi
|
|
exec "$@"
|
|
EOF
|
|
chmod +x "${CONFIG_INSTALL_FAKE_BIN}/sudo"
|
|
|
|
CONFIG_INSTALL_PRIVILEGED_ROOT="/root/wayscriber-configurator-installer-test"
|
|
CONFIG_INSTALL_MIXED_DATA="${WORK_DIR}/configurator-mixed-data"
|
|
PATH="${CONFIG_INSTALL_FAKE_BIN}:${PATH}" \
|
|
CONFIG_INSTALL_SUDO_LOG="${CONFIG_INSTALL_SUDO_LOG}" \
|
|
CONFIG_INSTALL_PRIVILEGED_ROOT="${CONFIG_INSTALL_PRIVILEGED_ROOT}" \
|
|
WAYSCRIBER_INSTALL_DIR="${CONFIG_INSTALL_PRIVILEGED_ROOT}/bin" \
|
|
WAYSCRIBER_DATA_DIR="${CONFIG_INSTALL_MIXED_DATA}" \
|
|
bash "${CONFIG_INSTALL_REPO}/tools/install-configurator.sh" >/dev/null
|
|
assert_contains "${CONFIG_INSTALL_SUDO_LOG}" "${CONFIG_INSTALL_PRIVILEGED_ROOT}/bin"
|
|
assert_not_contains "${CONFIG_INSTALL_SUDO_LOG}" "${CONFIG_INSTALL_MIXED_DATA}"
|
|
test -f "${CONFIG_INSTALL_MIXED_DATA}/applications/wayscriber-configurator.desktop"
|
|
|
|
: > "${CONFIG_INSTALL_SUDO_LOG}"
|
|
CONFIG_INSTALL_MIXED_BIN="${WORK_DIR}/configurator-mixed-bin"
|
|
CONFIG_INSTALL_PRIVILEGED_DATA="${CONFIG_INSTALL_PRIVILEGED_ROOT}/share"
|
|
PATH="${CONFIG_INSTALL_FAKE_BIN}:${PATH}" \
|
|
CONFIG_INSTALL_SUDO_LOG="${CONFIG_INSTALL_SUDO_LOG}" \
|
|
CONFIG_INSTALL_PRIVILEGED_ROOT="${CONFIG_INSTALL_PRIVILEGED_ROOT}" \
|
|
WAYSCRIBER_INSTALL_DIR="${CONFIG_INSTALL_MIXED_BIN}" \
|
|
WAYSCRIBER_DATA_DIR="${CONFIG_INSTALL_PRIVILEGED_DATA}" \
|
|
bash "${CONFIG_INSTALL_REPO}/tools/install-configurator.sh" >/dev/null
|
|
assert_contains "${CONFIG_INSTALL_SUDO_LOG}" "${CONFIG_INSTALL_PRIVILEGED_DATA}"
|
|
assert_not_contains "${CONFIG_INSTALL_SUDO_LOG}" "${CONFIG_INSTALL_MIXED_BIN}"
|
|
test -x "${CONFIG_INSTALL_MIXED_BIN}/wayscriber-configurator"
|
|
|
|
VERSION_FAILURE_COUNT=0
|
|
expect_version_consistency_failure() {
|
|
local expected="$1" fixture_root="$2"
|
|
VERSION_FAILURE_COUNT=$((VERSION_FAILURE_COUNT + 1))
|
|
local output="${WORK_DIR}/version-failure-${VERSION_FAILURE_COUNT}.log"
|
|
|
|
set +e
|
|
(
|
|
cd "${fixture_root}"
|
|
bash tools/check-version-consistency.sh
|
|
) >"${output}" 2>&1
|
|
local status=$?
|
|
set -e
|
|
|
|
if [[ ${status} -eq 0 ]]; then
|
|
echo "Expected version consistency check to fail: ${expected}" >&2
|
|
exit 1
|
|
fi
|
|
assert_contains "${output}" "${expected}"
|
|
}
|
|
|
|
# Trimming trailing separators must not turn the filesystem root into the
|
|
# invocation directory. Discard the deliberately privileged writes after sudo
|
|
# records their normalized destinations.
|
|
: > "${CONFIG_INSTALL_SUDO_LOG}"
|
|
CONFIG_INSTALL_ROOT_CWD="${WORK_DIR}/configurator-root-cwd"
|
|
CONFIG_INSTALL_ROOT_DATA="${WORK_DIR}/configurator-root-data"
|
|
mkdir -p "${CONFIG_INSTALL_ROOT_CWD}"
|
|
(
|
|
cd "${CONFIG_INSTALL_ROOT_CWD}"
|
|
PATH="${CONFIG_INSTALL_FAKE_BIN}:${PATH}" \
|
|
CONFIG_INSTALL_SUDO_LOG="${CONFIG_INSTALL_SUDO_LOG}" \
|
|
CONFIG_INSTALL_PRIVILEGED_ROOT="${CONFIG_INSTALL_PRIVILEGED_ROOT}" \
|
|
CONFIG_INSTALL_DISCARD_SUDO=1 \
|
|
WAYSCRIBER_INSTALL_DIR=/ \
|
|
WAYSCRIBER_DATA_DIR="${CONFIG_INSTALL_ROOT_DATA}" \
|
|
bash "${CONFIG_INSTALL_REPO}/tools/install-configurator.sh" >/dev/null
|
|
)
|
|
assert_contains "${CONFIG_INSTALL_SUDO_LOG}" "install -d /"
|
|
CONFIG_INSTALL_ROOT_DESKTOP="${CONFIG_INSTALL_ROOT_DATA}/applications/wayscriber-configurator.desktop"
|
|
assert_contains "${CONFIG_INSTALL_ROOT_DESKTOP}" 'Exec="/wayscriber-configurator"'
|
|
assert_contains "${CONFIG_INSTALL_ROOT_DESKTOP}" 'TryExec=/wayscriber-configurator'
|
|
|
|
: > "${CONFIG_INSTALL_SUDO_LOG}"
|
|
CONFIG_INSTALL_ROOT_BIN="${WORK_DIR}/configurator-root-bin"
|
|
(
|
|
cd "${CONFIG_INSTALL_ROOT_CWD}"
|
|
PATH="${CONFIG_INSTALL_FAKE_BIN}:${PATH}" \
|
|
CONFIG_INSTALL_SUDO_LOG="${CONFIG_INSTALL_SUDO_LOG}" \
|
|
CONFIG_INSTALL_PRIVILEGED_ROOT="${CONFIG_INSTALL_PRIVILEGED_ROOT}" \
|
|
CONFIG_INSTALL_DISCARD_SUDO=1 \
|
|
WAYSCRIBER_INSTALL_DIR="${CONFIG_INSTALL_ROOT_BIN}" \
|
|
WAYSCRIBER_DATA_DIR=/ \
|
|
bash "${CONFIG_INSTALL_REPO}/tools/install-configurator.sh" >/dev/null
|
|
)
|
|
test -x "${CONFIG_INSTALL_ROOT_BIN}/wayscriber-configurator"
|
|
assert_contains "${CONFIG_INSTALL_SUDO_LOG}" "/applications/wayscriber-configurator.desktop"
|
|
test ! -e "${CONFIG_INSTALL_ROOT_CWD}/applications/wayscriber-configurator.desktop"
|
|
|
|
# Prebuilt deb/rpm packages must declare the supported ABI floors, while the
|
|
# statically embedded layer-shell implementation must not remain a dependency.
|
|
sed -n '/^overrides:/,$p' "${PACKAGE_CONFIG}" > "${WORK_DIR}/package-overrides.yml"
|
|
assert_contains "${PACKAGE_CONFIG}" "- libc6 (>= 2.39)"
|
|
assert_contains "${PACKAGE_CONFIG}" "- libgtk-4-1 (>= 4.12)"
|
|
assert_contains "${PACKAGE_CONFIG}" "- glibc >= 2.39"
|
|
assert_contains "${PACKAGE_CONFIG}" "- gtk4 >= 4.12"
|
|
assert_not_contains "${WORK_DIR}/package-overrides.yml" "- libgtk4-layer-shell0"
|
|
assert_not_contains "${WORK_DIR}/package-overrides.yml" "- gtk4-layer-shell"
|
|
assert_contains "${CONFIGURATOR_PACKAGE_CONFIG}" "- libc6 (>= 2.39)"
|
|
assert_contains "${CONFIGURATOR_PACKAGE_CONFIG}" "- glibc >= 2.39"
|
|
assert_contains "${CONFIGURATOR_PACKAGE_CONFIG}" "- libadwaita-1-0 (>= 1.4)"
|
|
assert_contains "${CONFIGURATOR_PACKAGE_CONFIG}" "- libadwaita >= 1.4"
|
|
|
|
# One supported libadwaita floor governs compilation and every package
|
|
# channel. Exercise the real consistency checker, then mutation-check each
|
|
# independently editable metadata surface so a partial floor bump cannot pass.
|
|
LIBADWAITA_FLOOR_REPO="${WORK_DIR}/libadwaita-floor-repo"
|
|
mkdir -p \
|
|
"${LIBADWAITA_FLOOR_REPO}/.github/workflows" \
|
|
"${LIBADWAITA_FLOOR_REPO}/configurator" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools"
|
|
cp "${REPO_ROOT}/Cargo.toml" \
|
|
"${REPO_ROOT}/Cargo.lock" \
|
|
"${REPO_ROOT}/README.md" \
|
|
"${REPO_ROOT}/flake.nix" \
|
|
"${REPO_ROOT}/global.json" \
|
|
"${LIBADWAITA_FLOOR_REPO}/"
|
|
cp "${REPO_ROOT}/configurator/Cargo.toml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/configurator/Cargo.toml"
|
|
cp "${REPO_ROOT}/packaging/PKGBUILD" \
|
|
"${REPO_ROOT}/packaging/.SRCINFO" \
|
|
"${REPO_ROOT}/packaging/package.configurator.yaml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/"
|
|
cp "${VERSION_CHECKER}" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/check-version-consistency.sh"
|
|
cp "${RELEASE_WORKFLOW}" \
|
|
"${LIBADWAITA_FLOOR_REPO}/.github/workflows/build-packages.yml"
|
|
cp "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
(
|
|
cd "${LIBADWAITA_FLOOR_REPO}"
|
|
bash tools/check-version-consistency.sh >/dev/null
|
|
)
|
|
|
|
printf '%s\n' '{"sdk":{"version":"11.0.100-rc.1.26425.128","rollForward":"disable","allowPrerelease":true}}' \
|
|
> "${LIBADWAITA_FLOOR_REPO}/global.json"
|
|
(
|
|
cd "${LIBADWAITA_FLOOR_REPO}"
|
|
bash tools/check-version-consistency.sh >/dev/null
|
|
)
|
|
|
|
printf '%s\n' '{"sdk":{}}' > "${LIBADWAITA_FLOOR_REPO}/global.json"
|
|
expect_version_consistency_failure \
|
|
"global.json SDK metadata is invalid" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
|
|
printf '%s\n' '{"sdk":{"version":"11.0.100-rc.1.26425.127","rollForward":"disable","allowPrerelease":true}}' \
|
|
> "${LIBADWAITA_FLOOR_REPO}/global.json"
|
|
expect_version_consistency_failure \
|
|
"global.json SDK: expected 11.0.100-rc.1.26425.128, got 11.0.100-rc.1.26425.127" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
|
|
printf '%s\n' '{"sdk":{"version":"11.0.100-rc.1.26425.128","rollForward":"latestPatch","allowPrerelease":false}}' \
|
|
> "${LIBADWAITA_FLOOR_REPO}/global.json"
|
|
expect_version_consistency_failure \
|
|
"global.json SDK rollForward must be disable" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
expect_version_consistency_failure \
|
|
"global.json SDK allowPrerelease must be true" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/global.json" "${LIBADWAITA_FLOOR_REPO}/global.json"
|
|
|
|
sed -i 's/features = \["v1_4"\]/features = ["v1_5"]/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/configurator/Cargo.toml"
|
|
expect_version_consistency_failure \
|
|
"configurator/Cargo.toml libadwaita features: expected ['v1_4'], got ['v1_5']" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/configurator/Cargo.toml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/configurator/Cargo.toml"
|
|
|
|
sed -i 's/libadwaita-1-0 (>= 1.4)/libadwaita-1-0 (>= 1.5)/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/package.configurator.yaml"
|
|
expect_version_consistency_failure \
|
|
"configurator deb libadwaita floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/packaging/package.configurator.yaml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/package.configurator.yaml"
|
|
|
|
sed -i 's/libadwaita >= 1.4/libadwaita >= 1.5/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/package.configurator.yaml"
|
|
expect_version_consistency_failure \
|
|
"configurator rpm libadwaita floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/packaging/package.configurator.yaml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/package.configurator.yaml"
|
|
|
|
sed -i 's/libadwaita>=1.4/libadwaita>=1.5/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/PKGBUILD"
|
|
expect_version_consistency_failure \
|
|
"packaging/PKGBUILD libadwaita floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/packaging/PKGBUILD" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/PKGBUILD"
|
|
|
|
sed -i 's/libadwaita>=1.4/libadwaita>=1.5/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/.SRCINFO"
|
|
expect_version_consistency_failure \
|
|
"packaging/.SRCINFO libadwaita floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
|
|
cp "${REPO_ROOT}/packaging/.SRCINFO" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/.SRCINFO"
|
|
|
|
sed -i \
|
|
"s/ensure_runtime_dependency 'libadwaita>=1.4'/ensure_runtime_dependency 'libadwaita>=1.5'/" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
expect_version_consistency_failure \
|
|
"AUR updater generated libadwaita floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
|
|
sed -i '/grep -Eq.*libadwaita/ s/libadwaita>=1.4/libadwaita>=1.5/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
expect_version_consistency_failure \
|
|
"AUR updater PKGBUILD validation floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
cp "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
|
|
sed -i '/grep -Fxq.*depends = libadwaita/ s/libadwaita>=1.4/libadwaita>=1.5/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
expect_version_consistency_failure \
|
|
"AUR updater .SRCINFO validation floor: expected 1.4, got 1.5" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
|
|
# Updating every metadata floor is still incomplete until the package runner
|
|
# moves to a reviewed release-platform contract that supports the new ABI.
|
|
cp "${REPO_ROOT}/packaging/.SRCINFO" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/.SRCINFO"
|
|
sed -i 's/supported_libadwaita_floor = "1.4"/supported_libadwaita_floor = "1.7"/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/check-version-consistency.sh"
|
|
sed -i 's/features = \["v1_4"\]/features = ["v1_7"]/' \
|
|
"${LIBADWAITA_FLOOR_REPO}/configurator/Cargo.toml"
|
|
sed -i 's/1\.4/1.7/g' \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/PKGBUILD" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/.SRCINFO" \
|
|
"${LIBADWAITA_FLOOR_REPO}/packaging/package.configurator.yaml" \
|
|
"${LIBADWAITA_FLOOR_REPO}/.github/workflows/build-packages.yml"
|
|
cp "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
sed -i 's/1\.4/1.7/g' \
|
|
"${LIBADWAITA_FLOOR_REPO}/tools/update-aur-from-manifest.sh"
|
|
expect_version_consistency_failure \
|
|
"release package runner ubuntu-24.04 libadwaita floor: expected 1.4, got 1.7" \
|
|
"${LIBADWAITA_FLOOR_REPO}"
|
|
|
|
# Release jobs must not silently raise the glibc floor when ubuntu-latest
|
|
# changes; the package job is the binary floor's defining runner.
|
|
sed -n '/^ package:/,/^ package-repos:/p' "${RELEASE_WORKFLOW}" \
|
|
> "${WORK_DIR}/release-package-job.yml"
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" "runs-on: ubuntu-24.04"
|
|
assert_not_contains "${RELEASE_WORKFLOW}" "runs-on: ubuntu-latest"
|
|
# Recipe URLs must not become public while GitHub asset upload is still running.
|
|
sed -n '/^ aur:/,/^ [a-z][a-z-]*:/p' "${RELEASE_WORKFLOW}" \
|
|
> "${WORK_DIR}/release-aur-job.yml"
|
|
assert_contains "${WORK_DIR}/release-aur-job.yml" 'needs: [package, release]'
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" 'package verify-artifacts --artifact-root dist'
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" 'wayscriber-configurator-v${{ steps.meta.outputs.version }}-linux-x86_64.tar.gz'
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" \
|
|
'package smoke-ubuntu --artifact-root dist'
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" "Check direct Arch installer compatibility"
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" "package check-live-arch-installer"
|
|
assert_contains "${WORK_DIR}/release-package-job.yml" 'wayscriber-v${{ steps.meta.outputs.version }}-linux-x86_64.tar.gz'
|
|
assert_not_contains "${RELEASE_WORKFLOW}" 'bash '
|
|
assert_contains "${REPO_ROOT}/README.md" "--replace-other"
|
|
assert_contains "${REPO_ROOT}/README.md" "--no-restart"
|
|
assert_contains "${REPO_ROOT}/README.md" "--remove-unmanaged-usr"
|
|
test -x "${ARCH_INSTALLER_CHECKER}"
|
|
assert_contains "${ARCH_INSTALLER_CHECKER}" "The installer is parsed as data and is not run."
|
|
|
|
# The deployed installer is parsed as a strict data contract. Unsupported
|
|
# shell syntax must fail instead of silently omitting a required release file.
|
|
ARCH_INSTALLER_FIXTURE_ROOT="wayscriber-v0.0.0-linux-x86_64"
|
|
ARCH_INSTALLER_FIXTURE_STAGE="${WORK_DIR}/arch-installer-stage"
|
|
ARCH_INSTALLER_FIXTURE_ARCHIVE="${WORK_DIR}/arch-installer.tar.gz"
|
|
ARCH_INSTALLER_VALID_FIXTURE="${WORK_DIR}/arch-installer-valid.sh"
|
|
ARCH_INSTALLER_MALFORMED_FIXTURE="${WORK_DIR}/arch-installer-malformed.sh"
|
|
ARCH_INSTALLER_MALFORMED_OUTPUT="${WORK_DIR}/arch-installer-malformed-output"
|
|
ARCH_INSTALLER_SERVICE_OUTPUT="${WORK_DIR}/arch-installer-service-output"
|
|
mkdir -p \
|
|
"${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/bin" \
|
|
"${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/lib/systemd/user"
|
|
touch "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/bin/wayscriber"
|
|
chmod 0755 "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/bin/wayscriber"
|
|
cat > "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/lib/systemd/user/wayscriber.service" <<'EOF'
|
|
[Service]
|
|
ExecStart="/usr/bin/wayscriber" --daemon
|
|
EOF
|
|
chmod 0644 "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/lib/systemd/user/wayscriber.service"
|
|
tar -czf "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" \
|
|
-C "${ARCH_INSTALLER_FIXTURE_STAGE}" "${ARCH_INSTALLER_FIXTURE_ROOT}"
|
|
|
|
cat > "${ARCH_INSTALLER_VALID_FIXTURE}" <<'EOF'
|
|
#!/bin/sh
|
|
# ARCH_INSTALL_MANIFEST_BEGIN
|
|
release_manifest() {
|
|
printf '%s\n' \
|
|
'0755 bin/wayscriber' \
|
|
'0644 lib/systemd/user/wayscriber.service'
|
|
}
|
|
# ARCH_INSTALL_MANIFEST_END
|
|
EOF
|
|
"${ARCH_INSTALLER_CHECKER}" \
|
|
--installer "${ARCH_INSTALLER_VALID_FIXTURE}" \
|
|
--archive "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" >/dev/null
|
|
|
|
printf '%s\n' 'ExecStartPost=/usr/bin/env \' '# ignored by systemd' ' wayscriber --active' \
|
|
>> "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/lib/systemd/user/wayscriber.service"
|
|
tar -czf "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" \
|
|
-C "${ARCH_INSTALLER_FIXTURE_STAGE}" "${ARCH_INSTALLER_FIXTURE_ROOT}"
|
|
set +e
|
|
"${ARCH_INSTALLER_CHECKER}" \
|
|
--installer "${ARCH_INSTALLER_VALID_FIXTURE}" \
|
|
--archive "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" \
|
|
>"${ARCH_INSTALLER_SERVICE_OUTPUT}" 2>&1
|
|
ARCH_INSTALLER_SERVICE_STATUS=$?
|
|
set -e
|
|
if [[ ${ARCH_INSTALLER_SERVICE_STATUS} -eq 0 ]]; then
|
|
echo "Expected an alternate Wayscriber service command to fail" >&2
|
|
exit 1
|
|
fi
|
|
assert_contains "${ARCH_INSTALLER_SERVICE_OUTPUT}" \
|
|
"release user service is incompatible"
|
|
cat > "${ARCH_INSTALLER_FIXTURE_STAGE}/${ARCH_INSTALLER_FIXTURE_ROOT}/usr/lib/systemd/user/wayscriber.service" <<'EOF'
|
|
[Service]
|
|
ExecStart="/usr/bin/wayscriber" --daemon
|
|
EOF
|
|
tar -czf "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" \
|
|
-C "${ARCH_INSTALLER_FIXTURE_STAGE}" "${ARCH_INSTALLER_FIXTURE_ROOT}"
|
|
|
|
cat > "${ARCH_INSTALLER_MALFORMED_FIXTURE}" <<'EOF'
|
|
#!/bin/sh
|
|
# ARCH_INSTALL_MANIFEST_BEGIN
|
|
release_manifest() {
|
|
printf '%s\n' \
|
|
'0755 bin/wayscriber' \
|
|
'0644 lib/systemd/user/wayscriber.service' \
|
|
"0644 share/foo"
|
|
}
|
|
# ARCH_INSTALL_MANIFEST_END
|
|
EOF
|
|
set +e
|
|
"${ARCH_INSTALLER_CHECKER}" \
|
|
--installer "${ARCH_INSTALLER_MALFORMED_FIXTURE}" \
|
|
--archive "${ARCH_INSTALLER_FIXTURE_ARCHIVE}" \
|
|
>"${ARCH_INSTALLER_MALFORMED_OUTPUT}" 2>&1
|
|
ARCH_INSTALLER_MALFORMED_STATUS=$?
|
|
set -e
|
|
if [[ ${ARCH_INSTALLER_MALFORMED_STATUS} -eq 0 ]]; then
|
|
echo "Expected unsupported installer manifest syntax to fail" >&2
|
|
exit 1
|
|
fi
|
|
assert_contains "${ARCH_INSTALLER_MALFORMED_OUTPUT}" \
|
|
"unsupported installer manifest syntax"
|
|
|
|
# Ordinary CI exercises the dynamic source-build path, while a dedicated step
|
|
# checks the static release path.
|
|
assert_contains "${CI_WORKFLOW}" "ci prepare-gtk4-layer-shell --library-mode both"
|
|
assert_contains "${CI_WORKFLOW}" "Check dynamic gtk4-layer-shell linkage"
|
|
assert_contains "${CI_WORKFLOW}" "Check static gtk4-layer-shell linkage"
|
|
if grep -Eq 'SYSTEM_DEPS_GTK4_LAYER_SHELL_0_LINK.*GITHUB_ENV|GITHUB_ENV.*SYSTEM_DEPS_GTK4_LAYER_SHELL_0_LINK' \
|
|
"${CI_WORKFLOW}"; then
|
|
echo "Static gtk4-layer-shell linkage must not be exported globally in CI" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Release builds use the private static archive. Reusable prefixes must carry
|
|
# the exact commit/checksum stamp rather than matching on version alone.
|
|
assert_contains "${PACKAGE_SCRIPT}" 'SYSTEM_DEPS_GTK4_LAYER_SHELL_0_LINK=static'
|
|
assert_contains "${PACKAGE_SCRIPT}" 'verify-static-gtk4-layer-shell.sh'
|
|
assert_contains "${INSTALL_SCRIPT}" 'PIN_STAMP='
|
|
assert_contains "${INSTALL_SCRIPT}" 'commit=%s'
|
|
assert_contains "${INSTALL_SCRIPT}" 'archive_sha256=%s'
|
|
|
|
# package.sh's documented default discovers the Cargo version itself. Exercise
|
|
# that public path with a fake nfpm and require the resolved version to cross
|
|
# the process boundary into nfpm's environment.
|
|
PACKAGE_VERSION_REPO="${WORK_DIR}/package-version-repo"
|
|
PACKAGE_VERSION_FAKE_BIN="${WORK_DIR}/package-version-fake-bin"
|
|
PACKAGE_VERSION_ARTIFACTS="${WORK_DIR}/package-version-artifacts"
|
|
mkdir -p "${PACKAGE_VERSION_REPO}/tools" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/icons" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/licenses" \
|
|
"${PACKAGE_VERSION_REPO}/target/release" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}"
|
|
cp "${PACKAGE_SCRIPT}" "${PACKAGE_VERSION_REPO}/tools/package.sh"
|
|
touch "${PACKAGE_VERSION_REPO}/Cargo.toml" \
|
|
"${PACKAGE_VERSION_REPO}/README.md" \
|
|
"${PACKAGE_VERSION_REPO}/config.example.toml" \
|
|
"${PACKAGE_VERSION_REPO}/LICENSE" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/package.wayscriber.yaml" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/package.configurator.yaml" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/wayscriber.service" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/wayscriber.desktop" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/wayscriber-configurator.desktop" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/licenses/gtk4-layer-shell.LICENSE" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/icons/wayscriber.svg" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/icons/wayscriber-symbolic.svg" \
|
|
"${PACKAGE_VERSION_REPO}/packaging/icons/wayscriber-configurator.svg"
|
|
for size in 16 19 22 24 38 64 128; do
|
|
touch "${PACKAGE_VERSION_REPO}/packaging/icons/wayscriber-${size}.png"
|
|
done
|
|
for size in 24 64 128; do
|
|
touch "${PACKAGE_VERSION_REPO}/packaging/icons/wayscriber-configurator-${size}.png"
|
|
done
|
|
|
|
cat > "${PACKAGE_VERSION_REPO}/tools/verify-static-gtk4-layer-shell.sh" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
exit 0
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_REPO}/target/release/wayscriber" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
exit 0
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_REPO}/target/release/wayscriber-configurator" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
exit 0
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_FAKE_BIN}/cargo" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
[[ "${1:-}" == "metadata" ]] || {
|
|
echo "Unexpected cargo arguments: $*" >&2
|
|
exit 2
|
|
}
|
|
[[ "${PWD}" == "${PACKAGE_VERSION_EXPECTED_ROOT:?}" ]] || {
|
|
echo "package.sh ran cargo metadata from ${PWD}, expected ${PACKAGE_VERSION_EXPECTED_ROOT}" >&2
|
|
exit 3
|
|
}
|
|
if [[ "${PACKAGE_VERSION_MISSING:-0}" == 1 ]]; then
|
|
printf '%s\n' '{"packages":[]}'
|
|
else
|
|
printf '%s\n' '{"packages":[{"name":"wayscriber","version":"0.9.22"}]}'
|
|
fi
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_FAKE_BIN}/readelf" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf '%s\n' ' 0x0010: Name: GLIBC_2.39 Flags: none Version: 4'
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_FAKE_BIN}/nfpm" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
[[ -n "${VERSION:-}" ]] || {
|
|
echo "nfpm did not receive the resolved package version" >&2
|
|
exit 91
|
|
}
|
|
target=""
|
|
while [[ $# -gt 0 ]]; do
|
|
if [[ "$1" == "--target" ]]; then
|
|
target="$2"
|
|
break
|
|
fi
|
|
shift
|
|
done
|
|
[[ -n "${target}" ]] || {
|
|
echo "nfpm did not receive --target" >&2
|
|
exit 92
|
|
}
|
|
mkdir -p "$(dirname "${target}")"
|
|
package_kind="main"
|
|
[[ "${target}" == *wayscriber-configurator* ]] && package_kind="configurator"
|
|
if [[ "${PACKAGE_NFPM_FAIL:-}" == "${package_kind}" ]]; then
|
|
printf '%s\n' 'partial package' > "${target}"
|
|
echo "PACKAGE_TEST_NFPM_FAILURE" >&2
|
|
exit 91
|
|
fi
|
|
printf '%s\n' "${VERSION}" > "${target}"
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_FAKE_BIN}/tar" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
target=""
|
|
while [[ $# -gt 0 ]]; do
|
|
if [[ "$1" == "-czf" ]]; then
|
|
target="$2"
|
|
break
|
|
fi
|
|
shift
|
|
done
|
|
[[ -n "${target}" ]] || {
|
|
echo "tar did not receive -czf" >&2
|
|
exit 92
|
|
}
|
|
mkdir -p "$(dirname "${target}")"
|
|
package_kind="main"
|
|
[[ "${target}" == *wayscriber-configurator* ]] && package_kind="configurator"
|
|
if [[ "${PACKAGE_TAR_FAIL:-}" == "${package_kind}" ]]; then
|
|
printf '%s\n' 'partial archive' > "${target}"
|
|
echo "PACKAGE_TEST_TAR_FAILURE" >&2
|
|
exit 93
|
|
fi
|
|
printf '%s\n' 'complete archive' > "${target}"
|
|
EOF
|
|
cat > "${PACKAGE_VERSION_FAKE_BIN}/cp" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
package_kind=""
|
|
case "${1:-}" in
|
|
*/target/release/wayscriber) package_kind="main" ;;
|
|
*/target/release/wayscriber-configurator) package_kind="configurator" ;;
|
|
esac
|
|
if [[ -n "${package_kind}" && "${PACKAGE_COPY_FAIL:-}" == "${package_kind}" ]]; then
|
|
echo "PACKAGE_TEST_COPY_FAILURE" >&2
|
|
exit 95
|
|
fi
|
|
command -p cp "$@"
|
|
EOF
|
|
chmod +x "${PACKAGE_VERSION_REPO}/tools/verify-static-gtk4-layer-shell.sh" \
|
|
"${PACKAGE_VERSION_REPO}/target/release/wayscriber" \
|
|
"${PACKAGE_VERSION_REPO}/target/release/wayscriber-configurator" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}/cargo" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}/readelf" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}/nfpm" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}/tar" \
|
|
"${PACKAGE_VERSION_FAKE_BIN}/cp"
|
|
|
|
expect_package_failure() {
|
|
local expected_message="$1"
|
|
local output_file="${WORK_DIR}/package-failure-output"
|
|
shift
|
|
|
|
set +e
|
|
"$@" >"${output_file}" 2>&1
|
|
local test_status=$?
|
|
set -e
|
|
|
|
if [[ ${test_status} -eq 0 ]]; then
|
|
echo "Expected package.sh to fail with: ${expected_message}" >&2
|
|
cat "${output_file}" >&2
|
|
exit 1
|
|
fi
|
|
if ! grep -Fq -- "${expected_message}" "${output_file}"; then
|
|
echo "package.sh failed for the wrong reason; expected: ${expected_message}" >&2
|
|
cat "${output_file}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
(
|
|
cd "${WORK_DIR}"
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_VERSION_EXPECTED_ROOT="${PACKAGE_VERSION_REPO}" \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_VERSION_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip >/dev/null
|
|
)
|
|
|
|
[[ "$(cat "${PACKAGE_VERSION_ARTIFACTS}/wayscriber-amd64.deb")" == "0.9.22" ]] || {
|
|
echo "package.sh did not pass its auto-detected version to nfpm" >&2
|
|
exit 1
|
|
}
|
|
[[ "$(cat "${PACKAGE_VERSION_ARTIFACTS}/wayscriber-configurator-amd64.deb")" == "0.9.22" ]] || {
|
|
echo "package.sh did not pass its auto-detected version to configurator nfpm" >&2
|
|
exit 1
|
|
}
|
|
|
|
PACKAGE_OVERRIDE_ARTIFACTS="${WORK_DIR}/package-override-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_VERSION_EXPECTED_ROOT="${PACKAGE_VERSION_REPO}" \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 9.8.7 \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_OVERRIDE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip >/dev/null
|
|
)
|
|
|
|
[[ "$(cat "${PACKAGE_OVERRIDE_ARTIFACTS}/wayscriber-amd64.deb")" == "9.8.7" ]] || {
|
|
echo "package.sh did not pass its explicit version override to nfpm" >&2
|
|
exit 1
|
|
}
|
|
[[ "$(cat "${PACKAGE_OVERRIDE_ARTIFACTS}/wayscriber-configurator-amd64.deb")" == "9.8.7" ]] || {
|
|
echo "package.sh did not pass its explicit version override to configurator nfpm" >&2
|
|
exit 1
|
|
}
|
|
|
|
PACKAGE_MISSING_VERSION_ARTIFACTS="${WORK_DIR}/package-missing-version-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure "Could not resolve the package version" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_VERSION_EXPECTED_ROOT="${PACKAGE_VERSION_REPO}" \
|
|
PACKAGE_VERSION_MISSING=1 \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_MISSING_VERSION_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
PACKAGE_NFPM_FAILURE_ARTIFACTS="${WORK_DIR}/package-nfpm-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure \
|
|
"Failed to build deb package: ${PACKAGE_NFPM_FAILURE_ARTIFACTS}/wayscriber-amd64.deb" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_NFPM_FAIL=main \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_NFPM_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
PACKAGE_CONFIGURATOR_NFPM_FAILURE_ARTIFACTS="${WORK_DIR}/package-configurator-nfpm-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure \
|
|
"Failed to build deb package: ${PACKAGE_CONFIGURATOR_NFPM_FAILURE_ARTIFACTS}/wayscriber-configurator-amd64.deb" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_NFPM_FAIL=configurator \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_CONFIGURATOR_NFPM_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
PACKAGE_TAR_FAILURE_ARTIFACTS="${WORK_DIR}/package-tar-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure \
|
|
"Failed to build tarball: ${PACKAGE_TAR_FAILURE_ARTIFACTS}/wayscriber-v0.9.22-linux-x86_64.tar.gz" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_TAR_FAIL=main \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats tar \
|
|
--artifact-root "${PACKAGE_TAR_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip \
|
|
--no-configurator
|
|
)
|
|
|
|
PACKAGE_CONFIGURATOR_TAR_FAILURE_ARTIFACTS="${WORK_DIR}/package-configurator-tar-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure \
|
|
"Failed to build tarball: ${PACKAGE_CONFIGURATOR_TAR_FAILURE_ARTIFACTS}/wayscriber-configurator-v0.9.22-linux-x86_64.tar.gz" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_TAR_FAIL=configurator \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats tar \
|
|
--artifact-root "${PACKAGE_CONFIGURATOR_TAR_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
PACKAGE_MAIN_COPY_FAILURE_ARTIFACTS="${WORK_DIR}/package-main-copy-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure "PACKAGE_TEST_COPY_FAILURE" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_COPY_FAIL=main \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats tar \
|
|
--artifact-root "${PACKAGE_MAIN_COPY_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip \
|
|
--no-configurator
|
|
)
|
|
|
|
PACKAGE_CONFIGURATOR_COPY_FAILURE_ARTIFACTS="${WORK_DIR}/package-configurator-copy-failure-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure "PACKAGE_TEST_COPY_FAILURE" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
PACKAGE_COPY_FAIL=configurator \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats tar \
|
|
--artifact-root "${PACKAGE_CONFIGURATOR_COPY_FAILURE_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
# PACKAGE_CONFIGURATOR=1 promises every requested configurator artifact. A
|
|
# missing executable must fail before packaging; --no-configurator is the
|
|
# explicit opt-out.
|
|
rm -f "${PACKAGE_VERSION_REPO}/target/release/wayscriber-configurator"
|
|
PACKAGE_MISSING_CONFIGURATOR_ARTIFACTS="${WORK_DIR}/package-missing-configurator-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
expect_package_failure \
|
|
"Missing release binary: ${PACKAGE_VERSION_REPO}/target/release/wayscriber-configurator" \
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats tar \
|
|
--artifact-root "${PACKAGE_MISSING_CONFIGURATOR_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip
|
|
)
|
|
|
|
PACKAGE_NO_CONFIGURATOR_ARTIFACTS="${WORK_DIR}/package-no-configurator-artifacts"
|
|
(
|
|
cd "${WORK_DIR}"
|
|
env -u VERSION \
|
|
PATH="${PACKAGE_VERSION_FAKE_BIN}:${PATH}" \
|
|
bash "${PACKAGE_VERSION_REPO}/tools/package.sh" \
|
|
--version 0.9.22 \
|
|
--formats deb \
|
|
--artifact-root "${PACKAGE_NO_CONFIGURATOR_ARTIFACTS}" \
|
|
--skip-build \
|
|
--no-strip \
|
|
--no-configurator >/dev/null
|
|
)
|
|
[[ -f "${PACKAGE_NO_CONFIGURATOR_ARTIFACTS}/wayscriber-amd64.deb" ]] || {
|
|
echo "--no-configurator did not produce the requested main package" >&2
|
|
exit 1
|
|
}
|
|
[[ ! -e "${PACKAGE_NO_CONFIGURATOR_ARTIFACTS}/wayscriber-configurator-amd64.deb" ]] || {
|
|
echo "--no-configurator unexpectedly produced a configurator package" >&2
|
|
exit 1
|
|
}
|
|
|
|
# A private cache created before the stamp recorded library mode must be
|
|
# rebuilt even when leftover shared/static artifacts satisfy the new request.
|
|
INSTALLER_FAKE_BIN="${WORK_DIR}/installer-fake-bin"
|
|
INSTALLER_PREFIX="${WORK_DIR}/installer-prefix"
|
|
INSTALLER_STAMP="${INSTALLER_PREFIX}/share/wayscriber/build-deps/gtk4-layer-shell.pin"
|
|
mkdir -p "${INSTALLER_FAKE_BIN}" "${INSTALLER_PREFIX}/lib" "$(dirname "${INSTALLER_STAMP}")"
|
|
touch "${INSTALLER_PREFIX}/lib/libgtk4-layer-shell.a" \
|
|
"${INSTALLER_PREFIX}/lib/libgtk4-layer-shell.so"
|
|
|
|
cat > "${INSTALLER_FAKE_BIN}/pkg-config" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
case "$*" in
|
|
*--atleast-version=*) exit 0 ;;
|
|
*--variable=libdir*) printf '%s\n' "${INSTALLER_TEST_LIBDIR:?}" ;;
|
|
*--modversion*) printf '%s\n' '1.3.0' ;;
|
|
*) echo "Unexpected pkg-config arguments: $*" >&2; exit 2 ;;
|
|
esac
|
|
EOF
|
|
cat > "${INSTALLER_FAKE_BIN}/curl" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
echo 'INSTALLER_TEST_REBUILD_REQUIRED' >&2
|
|
exit 97
|
|
EOF
|
|
cat > "${INSTALLER_FAKE_BIN}/meson" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
echo 'Meson must not run in installer cache tests' >&2
|
|
exit 98
|
|
EOF
|
|
chmod +x "${INSTALLER_FAKE_BIN}/pkg-config" \
|
|
"${INSTALLER_FAKE_BIN}/curl" \
|
|
"${INSTALLER_FAKE_BIN}/meson"
|
|
|
|
run_installer_cache_check() {
|
|
PATH="${INSTALLER_FAKE_BIN}:${PATH}" \
|
|
INSTALLER_TEST_LIBDIR="${INSTALLER_PREFIX}/lib" \
|
|
GTK4_LAYER_SHELL_PREFIX="${INSTALLER_PREFIX}" \
|
|
GTK4_LAYER_SHELL_SYSTEM_PREFIX="${2:-/usr}" \
|
|
GTK4_LAYER_SHELL_LIBRARY_MODE="$1" \
|
|
bash "${INSTALL_SCRIPT}"
|
|
}
|
|
|
|
expect_installer_rebuild() {
|
|
local description="$1" mode="$2" system_prefix="${3:-/usr}" output status
|
|
set +e
|
|
output="$(run_installer_cache_check "${mode}" "${system_prefix}" 2>&1)"
|
|
status=$?
|
|
set -e
|
|
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
echo "Installer unexpectedly reused ${description}" >&2
|
|
exit 1
|
|
fi
|
|
grep -Fq 'INSTALLER_TEST_REBUILD_REQUIRED' <<< "${output}" || {
|
|
echo "Installer rejected ${description} for an unrelated reason:" >&2
|
|
echo "${output}" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
expect_installer_skip() {
|
|
local description="$1" mode="$2" system_prefix="${3:-/usr}" output
|
|
output="$(run_installer_cache_check "${mode}" "${system_prefix}" 2>&1)" || {
|
|
echo "Installer failed to reuse ${description}:" >&2
|
|
echo "${output}" >&2
|
|
exit 1
|
|
}
|
|
grep -Fq 'skipping build' <<< "${output}" || {
|
|
echo "Installer did not report reusing ${description}" >&2
|
|
exit 1
|
|
}
|
|
if grep -Fq 'INSTALLER_TEST_REBUILD_REQUIRED' <<< "${output}"; then
|
|
echo "Installer downloaded while reusing ${description}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
write_installer_stamp() {
|
|
cat > "${INSTALLER_STAMP}" <<EOF
|
|
version=1.3.0
|
|
commit=1c963c51514581c41b9bdae08cdf69171265cdda
|
|
archive_sha256=22be5f5edf487cfb87266f0e71c400b11322082a4dc99832e5a54a4fca3d5a7c
|
|
library_mode=$1
|
|
EOF
|
|
}
|
|
|
|
cat > "${INSTALLER_STAMP}" <<'EOF'
|
|
version=1.3.0
|
|
commit=1c963c51514581c41b9bdae08cdf69171265cdda
|
|
archive_sha256=22be5f5edf487cfb87266f0e71c400b11322082a4dc99832e5a54a4fca3d5a7c
|
|
EOF
|
|
expect_installer_rebuild "a mode-less private cache" shared
|
|
|
|
write_installer_stamp static
|
|
expect_installer_skip "a matching static private cache" static
|
|
expect_installer_rebuild "a static private cache requested as shared" shared
|
|
|
|
write_installer_stamp shared
|
|
expect_installer_skip "a matching shared private cache" shared
|
|
|
|
rm -f "${INSTALLER_STAMP}"
|
|
expect_installer_rebuild "an unstamped private cache" shared
|
|
expect_installer_skip "an unstamped system-managed cache" shared "${INSTALLER_PREFIX}"
|
|
|
|
# Exercise the linkage verifier itself, including every exact shim name. The
|
|
# shorter marshal names must not pass by matching longer symbol substrings.
|
|
FAKE_BIN="${WORK_DIR}/fake-bin"
|
|
READELF_OK="${WORK_DIR}/readelf-ok.txt"
|
|
NM_OK="${WORK_DIR}/nm-ok.txt"
|
|
mkdir -p "${FAKE_BIN}"
|
|
|
|
cat > "${FAKE_BIN}/readelf" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
cat "${VERIFY_TEST_READELF_OUTPUT:?}"
|
|
EOF
|
|
cat > "${FAKE_BIN}/nm" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
cat "${VERIFY_TEST_NM_OUTPUT:?}"
|
|
EOF
|
|
chmod +x "${FAKE_BIN}/readelf" "${FAKE_BIN}/nm"
|
|
|
|
cat > "${READELF_OK}" <<'EOF'
|
|
Dynamic section at offset 0x1 contains 1 entry:
|
|
0x0000000000000001 (NEEDED) Shared library: [libwayland-client.so.0]
|
|
EOF
|
|
cat > "${NM_OK}" <<'EOF'
|
|
0000000000000001 T wl_proxy_destroy
|
|
0000000000000002 T wl_proxy_marshal_array_flags
|
|
0000000000000003 T wl_proxy_marshal_flags
|
|
0000000000000004 T wl_proxy_marshal
|
|
0000000000000005 T wl_proxy_marshal_array
|
|
0000000000000006 T wl_proxy_marshal_constructor
|
|
0000000000000007 T wl_proxy_marshal_constructor_versioned
|
|
0000000000000008 T wl_proxy_marshal_array_constructor
|
|
0000000000000009 T wl_proxy_marshal_array_constructor_versioned
|
|
EOF
|
|
|
|
run_link_verifier() {
|
|
PATH="${FAKE_BIN}:${PATH}" \
|
|
VERIFY_TEST_READELF_OUTPUT="$1" \
|
|
VERIFY_TEST_NM_OUTPUT="$2" \
|
|
bash "${STATIC_LINK_VERIFIER}" /bin/true
|
|
}
|
|
|
|
expect_link_verifier_failure() {
|
|
local description="$1" expected_message="$2" readelf_output="$3" nm_output="$4"
|
|
local output status
|
|
set +e
|
|
output="$(run_link_verifier "${readelf_output}" "${nm_output}" 2>&1)"
|
|
status=$?
|
|
set -e
|
|
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
echo "Static linkage verifier unexpectedly accepted ${description}" >&2
|
|
exit 1
|
|
fi
|
|
grep -Fq "${expected_message}" <<< "${output}" || {
|
|
echo "Static linkage verifier rejected ${description} for an unrelated reason:" >&2
|
|
echo "${output}" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
run_link_verifier "${READELF_OK}" "${NM_OK}" >/dev/null
|
|
|
|
READELF_DYNAMIC_LAYER="${WORK_DIR}/readelf-dynamic-layer.txt"
|
|
cp "${READELF_OK}" "${READELF_DYNAMIC_LAYER}"
|
|
printf '%s\n' ' 0x0000000000000001 (NEEDED) Shared library: [libgtk4-layer-shell.so.0]' \
|
|
>> "${READELF_DYNAMIC_LAYER}"
|
|
expect_link_verifier_failure "a dynamic layer-shell dependency" \
|
|
"still dynamically requires gtk4-layer-shell" \
|
|
"${READELF_DYNAMIC_LAYER}" "${NM_OK}"
|
|
|
|
READELF_NO_WAYLAND="${WORK_DIR}/readelf-no-wayland.txt"
|
|
grep -Fv 'libwayland-client.so.0' "${READELF_OK}" > "${READELF_NO_WAYLAND}"
|
|
expect_link_verifier_failure "a missing libwayland-client dependency" \
|
|
"does not retain libwayland-client.so.0 in DT_NEEDED" \
|
|
"${READELF_NO_WAYLAND}" "${NM_OK}"
|
|
|
|
for shim in \
|
|
wl_proxy_destroy \
|
|
wl_proxy_marshal_array_flags \
|
|
wl_proxy_marshal_flags \
|
|
wl_proxy_marshal \
|
|
wl_proxy_marshal_array \
|
|
wl_proxy_marshal_constructor \
|
|
wl_proxy_marshal_constructor_versioned \
|
|
wl_proxy_marshal_array_constructor \
|
|
wl_proxy_marshal_array_constructor_versioned; do
|
|
nm_without_shim="${WORK_DIR}/nm-without-${shim}.txt"
|
|
awk -v omitted="${shim}" '$3 != omitted' "${NM_OK}" > "${nm_without_shim}"
|
|
expect_link_verifier_failure "a binary missing ${shim}" \
|
|
"does not export required gtk4-layer-shell shim ${shim}" \
|
|
"${READELF_OK}" "${nm_without_shim}"
|
|
done
|
|
|
|
# All three release formats retain the notice for statically embedded code.
|
|
test -f "${REPO_ROOT}/packaging/licenses/gtk4-layer-shell.LICENSE"
|
|
assert_contains "${PACKAGE_CONFIG}" "dst: /usr/share/licenses/wayscriber/LICENSE.gtk4-layer-shell"
|
|
assert_contains "${PACKAGE_SCRIPT}" 'LICENSE.gtk4-layer-shell'
|
|
|
|
# Exercise the actual AUR updater against prebuilt metadata. The source AUR
|
|
# recipe intentionally keeps gtk4-layer-shell; wayscriber-bin must remove it.
|
|
AUR_BIN_DIR="${WORK_DIR}/wayscriber-bin"
|
|
MANIFEST="${WORK_DIR}/manifest.json"
|
|
mkdir -p "${AUR_BIN_DIR}"
|
|
|
|
cat > "${AUR_BIN_DIR}/PKGBUILD" <<'EOF'
|
|
pkgname=wayscriber-bin
|
|
pkgver=0.9.22
|
|
pkgrel=1
|
|
depends=(
|
|
'cairo'
|
|
'wayland'
|
|
'pango'
|
|
'gcc-libs'
|
|
'glibc'
|
|
'gtk4'
|
|
'gtk4-layer-shell'
|
|
'wl-clipboard'
|
|
)
|
|
source_x86_64=("old.tar.gz::https://example.invalid/old.tar.gz")
|
|
sha256sums_x86_64=('old')
|
|
|
|
_tarball="wayscriber-v${pkgver}-linux-${CARCH}.tar.gz"
|
|
|
|
package() {
|
|
local srcdir_tmp="${srcdir}/extract"
|
|
rm -rf "${srcdir_tmp}"
|
|
mkdir -p "${srcdir_tmp}"
|
|
tar -xzf "${srcdir}/${_tarball}" -C "${srcdir_tmp}" --strip-components=1
|
|
|
|
install -Dm755 "${srcdir_tmp}/usr/bin/wayscriber" "$pkgdir/usr/bin/wayscriber"
|
|
install -Dm644 "${srcdir_tmp}/usr/lib/systemd/user/wayscriber.service" "$pkgdir/usr/lib/systemd/user/wayscriber.service"
|
|
install -Dm644 "${srcdir_tmp}/usr/share/doc/wayscriber/config.example.toml" "$pkgdir/usr/share/doc/wayscriber/config.example.toml"
|
|
install -Dm644 "${srcdir_tmp}/usr/share/doc/wayscriber/README.md" "$pkgdir/usr/share/doc/wayscriber/README.md"
|
|
[ -f "${srcdir_tmp}/usr/share/doc/wayscriber/LICENSE" ] && install -Dm644 "${srcdir_tmp}/usr/share/doc/wayscriber/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE" || true
|
|
}
|
|
EOF
|
|
|
|
cat > "${AUR_BIN_DIR}/.SRCINFO" <<'EOF'
|
|
pkgbase = wayscriber-bin
|
|
pkgver = 0.9.22
|
|
pkgrel = 1
|
|
depends = gcc-libs
|
|
depends = gtk4-layer-shell
|
|
depends = wl-clipboard
|
|
source_x86_64 = old.tar.gz::https://example.invalid/old.tar.gz
|
|
sha256sums_x86_64 = old
|
|
|
|
pkgname = wayscriber-bin
|
|
EOF
|
|
|
|
cat > "${MANIFEST}" <<'EOF'
|
|
{
|
|
"version": "9.9.9",
|
|
"artifacts": [
|
|
{
|
|
"name": "wayscriber-v9.9.9-linux-x86_64.tar.gz",
|
|
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
"size": 1
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
git -C "${AUR_BIN_DIR}" init -q
|
|
git -C "${AUR_BIN_DIR}" add PKGBUILD .SRCINFO
|
|
|
|
bash "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
--version 9.9.9 \
|
|
--manifest "${MANIFEST}" \
|
|
--source-dir "${WORK_DIR}/missing-source" \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir "${WORK_DIR}/missing-config" \
|
|
--no-configurator >/dev/null
|
|
|
|
assert_contains "${AUR_BIN_DIR}/PKGBUILD" "'gtk4'"
|
|
assert_contains "${AUR_BIN_DIR}/.SRCINFO" "depends = gtk4"
|
|
assert_not_contains "${AUR_BIN_DIR}/PKGBUILD" "'gtk4-layer-shell'"
|
|
assert_not_contains "${AUR_BIN_DIR}/.SRCINFO" "depends = gtk4-layer-shell"
|
|
assert_contains "${AUR_BIN_DIR}/PKGBUILD" 'install -Dm644 "${srcdir_tmp}/usr/share/licenses/wayscriber/LICENSE.gtk4-layer-shell" "$pkgdir/usr/share/licenses/$pkgname/LICENSE.gtk4-layer-shell"'
|
|
[[ "$(grep -Fc 'LICENSE.gtk4-layer-shell' "${AUR_BIN_DIR}/PKGBUILD")" -eq 1 ]] || {
|
|
echo "wayscriber-bin must install the gtk4-layer-shell notice exactly once" >&2
|
|
exit 1
|
|
}
|
|
|
|
assert_contains "${REPO_ROOT}/packaging/PKGBUILD" "'gtk4-layer-shell'"
|
|
assert_contains "${REPO_ROOT}/packaging/.SRCINFO" "depends = gtk4-layer-shell"
|
|
assert_contains "${REPO_ROOT}/packaging/PKGBUILD" "'libadwaita>=1.4'"
|
|
assert_contains "${REPO_ROOT}/packaging/.SRCINFO" "depends = libadwaita>=1.4"
|
|
|
|
# The configurator AUR channel is required by default. The hosted clone step
|
|
# must fail before the updater runs rather than silently publish two channels.
|
|
assert_not_contains "${RELEASE_WORKFLOW}" \
|
|
"git clone ssh://aur@aur.archlinux.org/wayscriber-configurator.git aur-wayscriber-configurator || true"
|
|
|
|
AUR_SOURCE_SHA='abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789'
|
|
AUR_FAKE_BIN="${WORK_DIR}/aur-fake-bin"
|
|
AUR_REAL_GIT="$(command -v git)"
|
|
mkdir -p "${AUR_FAKE_BIN}"
|
|
cat > "${AUR_FAKE_BIN}/curl" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
output=""
|
|
while [[ $# -gt 0 ]]; do
|
|
if [[ "$1" == "-o" ]]; then
|
|
output="$2"
|
|
shift 2
|
|
else
|
|
shift
|
|
fi
|
|
done
|
|
case "${AUR_TEST_CURL_MODE:-fail}" in
|
|
empty)
|
|
: > "${output:?curl fixture did not receive -o}"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo 'AUR_TEST_NETWORK_ACCESS' >&2
|
|
exit 97
|
|
;;
|
|
esac
|
|
EOF
|
|
cat > "${AUR_FAKE_BIN}/git" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
for arg in "$@"; do
|
|
if [[ "$arg" == "push" && -n "${AUR_TEST_GIT_LOG:-}" ]]; then
|
|
printf 'push %s\n' "$*" >> "${AUR_TEST_GIT_LOG}"
|
|
exit 96
|
|
fi
|
|
done
|
|
exec "${AUR_TEST_REAL_GIT:?}" "$@"
|
|
EOF
|
|
chmod +x "${AUR_FAKE_BIN}/curl" "${AUR_FAKE_BIN}/git"
|
|
|
|
commit_aur_fixture() {
|
|
local dir="$1"
|
|
git -C "${dir}" -c user.name='Wayscriber Test' \
|
|
-c user.email='wayscriber-test@example.invalid' \
|
|
commit -qm 'test fixture'
|
|
}
|
|
|
|
assert_clean_checkout_at_head() {
|
|
local dir="$1" expected_head="$2" context="$3"
|
|
[[ "$(git -C "${dir}" rev-parse HEAD)" == "${expected_head}" ]] || {
|
|
echo "${context}: checkout HEAD changed" >&2
|
|
exit 1
|
|
}
|
|
[[ -z "$(git -C "${dir}" status --porcelain)" ]] || {
|
|
echo "${context}: checkout worktree changed" >&2
|
|
git -C "${dir}" status --short >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
write_source_clone() {
|
|
local dir="$1" pkgver="$2" pkgrel="$3"
|
|
mkdir -p "${dir}"
|
|
cat > "${dir}/PKGBUILD" <<EOF
|
|
pkgname=wayscriber
|
|
pkgver=${pkgver}
|
|
pkgrel=${pkgrel}
|
|
install=wayscriber.install
|
|
depends=(
|
|
'gcc-libs'
|
|
'wl-clipboard'
|
|
)
|
|
makedepends=(
|
|
'git'
|
|
)
|
|
source=("old.tar.gz::https://example.invalid/old.tar.gz")
|
|
sha256sums=('old')
|
|
package() {
|
|
cd "\$pkgname"
|
|
install -Dm755 "target/release/wayscriber" "\$pkgdir/usr/bin/wayscriber"
|
|
}
|
|
EOF
|
|
cat > "${dir}/.SRCINFO" <<EOF
|
|
pkgbase = wayscriber
|
|
pkgver = ${pkgver}
|
|
pkgrel = ${pkgrel}
|
|
install = wayscriber.install
|
|
depends = gcc-libs
|
|
depends = wl-clipboard
|
|
makedepends = git
|
|
source = old.tar.gz::https://example.invalid/old.tar.gz
|
|
sha256sums = old
|
|
|
|
pkgname = wayscriber
|
|
EOF
|
|
touch "${dir}/wayscriber.install"
|
|
git -C "${dir}" init -q
|
|
git -C "${dir}" add PKGBUILD .SRCINFO wayscriber.install
|
|
commit_aur_fixture "${dir}"
|
|
}
|
|
|
|
write_configurator_clone() {
|
|
local dir="$1" pkgver="$2" pkgrel="$3"
|
|
mkdir -p "${dir}"
|
|
cat > "${dir}/PKGBUILD" <<EOF
|
|
pkgname=wayscriber-configurator
|
|
pkgver=${pkgver}
|
|
pkgrel=${pkgrel}
|
|
pkgdesc='GUI configurator for wayscriber (Iced)'
|
|
depends=(
|
|
'gcc-libs'
|
|
)
|
|
makedepends=(
|
|
'git'
|
|
)
|
|
source=("old.tar.gz::https://example.invalid/old.tar.gz")
|
|
sha256sums=('old')
|
|
build() {
|
|
cd wayscriber
|
|
}
|
|
package() {
|
|
cd wayscriber
|
|
|
|
install -Dm755 "target/release/wayscriber-configurator" "\$pkgdir/usr/bin/wayscriber-configurator"
|
|
install -Dm644 README.md "\$pkgdir/usr/share/doc/\$pkgname/README.md"
|
|
[ -f LICENSE ] && install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE" || true
|
|
}
|
|
EOF
|
|
cat > "${dir}/.SRCINFO" <<EOF
|
|
pkgbase = wayscriber-configurator
|
|
pkgdesc = GUI configurator for wayscriber (Iced)
|
|
pkgver = ${pkgver}
|
|
pkgrel = ${pkgrel}
|
|
depends = gcc-libs
|
|
makedepends = git
|
|
source = old.tar.gz::https://example.invalid/old.tar.gz
|
|
sha256sums = old
|
|
|
|
pkgname = wayscriber-configurator
|
|
EOF
|
|
git -C "${dir}" init -q
|
|
git -C "${dir}" add PKGBUILD .SRCINFO
|
|
commit_aur_fixture "${dir}"
|
|
}
|
|
|
|
run_aur_updater() {
|
|
local cwd="$1"
|
|
shift
|
|
local version_args=()
|
|
if [[ "${AUR_TEST_USE_MANIFEST_VERSION:-0}" -eq 0 ]]; then
|
|
version_args=(--version 9.9.9)
|
|
fi
|
|
(
|
|
cd "${cwd}"
|
|
AUR_TEST_CURL_MODE="${AUR_TEST_CURL_MODE:-fail}" \
|
|
AUR_TEST_GIT_LOG="${AUR_TEST_GIT_LOG:-}" \
|
|
AUR_TEST_REAL_GIT="${AUR_REAL_GIT}" \
|
|
PATH="${AUR_FAKE_BIN}:${PATH}" \
|
|
bash "${REPO_ROOT}/tools/update-aur-from-manifest.sh" \
|
|
"${version_args[@]}" \
|
|
--manifest "${MANIFEST}" \
|
|
"$@"
|
|
)
|
|
}
|
|
|
|
expect_aur_failure() {
|
|
local expected="$1" cwd="$2"
|
|
shift 2
|
|
local output="${WORK_DIR}/aur-failure-output"
|
|
|
|
if run_aur_updater "${cwd}" "$@" >"${output}" 2>&1; then
|
|
echo "Expected AUR updater failure containing: ${expected}" >&2
|
|
exit 1
|
|
fi
|
|
assert_contains "${output}" "${expected}"
|
|
}
|
|
|
|
expect_invalid_aur_version() {
|
|
local expected="$1" manifest="$2"
|
|
shift 2
|
|
local push_log="${WORK_DIR}/aur-invalid-version-push-log"
|
|
|
|
AUR_TEST_USE_MANIFEST_VERSION=1 \
|
|
AUR_TEST_GIT_LOG="${push_log}" \
|
|
expect_aur_failure "${expected}" "${WORK_DIR}" \
|
|
--manifest "${manifest}" \
|
|
--source-dir aur-invalid-version-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator \
|
|
--source-sha256 "${AUR_SOURCE_SHA}" \
|
|
--push \
|
|
"$@"
|
|
assert_clean_checkout_at_head \
|
|
"${AUR_INVALID_VERSION_SOURCE}" \
|
|
"${AUR_INVALID_VERSION_HEAD}" \
|
|
"invalid release version"
|
|
[[ ! -s "${push_log}" ]] || {
|
|
echo "AUR updater pushed for an invalid release version" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Release identity is validated before checkout discovery or mutation. A JSON
|
|
# string is required when the manifest supplies it, and both input routes use
|
|
# the same MAJOR.MINOR.PATCH[.HOTFIX] grammar as the rest of the release tools.
|
|
AUR_INVALID_VERSION_SOURCE="${WORK_DIR}/aur-invalid-version-source"
|
|
AUR_VERSION_MISSING_MANIFEST="${WORK_DIR}/manifest-version-missing.json"
|
|
AUR_VERSION_NULL_MANIFEST="${WORK_DIR}/manifest-version-null.json"
|
|
AUR_VERSION_ARRAY_MANIFEST="${WORK_DIR}/manifest-version-array.json"
|
|
AUR_VERSION_OBJECT_MANIFEST="${WORK_DIR}/manifest-version-object.json"
|
|
AUR_VERSION_MALFORMED_MANIFEST="${WORK_DIR}/manifest-version-malformed.json"
|
|
write_source_clone "${AUR_INVALID_VERSION_SOURCE}" 9.9.8 2
|
|
AUR_INVALID_VERSION_HEAD="$(git -C "${AUR_INVALID_VERSION_SOURCE}" rev-parse HEAD)"
|
|
cat > "${AUR_VERSION_MISSING_MANIFEST}" <<'EOF'
|
|
{"artifacts":[]}
|
|
EOF
|
|
cat > "${AUR_VERSION_NULL_MANIFEST}" <<'EOF'
|
|
{"version":null,"artifacts":[]}
|
|
EOF
|
|
cat > "${AUR_VERSION_ARRAY_MANIFEST}" <<'EOF'
|
|
{"version":[9,9,9],"artifacts":[]}
|
|
EOF
|
|
cat > "${AUR_VERSION_OBJECT_MANIFEST}" <<'EOF'
|
|
{"version":{"major":9,"minor":9,"patch":9},"artifacts":[]}
|
|
EOF
|
|
cat > "${AUR_VERSION_MALFORMED_MANIFEST}" <<'EOF'
|
|
{"version":"9.9","artifacts":[]}
|
|
EOF
|
|
expect_invalid_aur_version "Manifest version must be a string" \
|
|
"${AUR_VERSION_MISSING_MANIFEST}"
|
|
expect_invalid_aur_version "Manifest version must be a string" \
|
|
"${AUR_VERSION_NULL_MANIFEST}"
|
|
expect_invalid_aur_version "Manifest version must be a string" \
|
|
"${AUR_VERSION_ARRAY_MANIFEST}"
|
|
expect_invalid_aur_version "Manifest version must be a string" \
|
|
"${AUR_VERSION_OBJECT_MANIFEST}"
|
|
expect_invalid_aur_version "Invalid manifest version '9.9'" \
|
|
"${AUR_VERSION_MALFORMED_MANIFEST}"
|
|
expect_invalid_aur_version "Invalid --version 'release-9.9.9'" \
|
|
"${MANIFEST}" \
|
|
--version release-9.9.9
|
|
|
|
# Relative clone paths used to be resolved after pushd, turning `dir/PKGBUILD`
|
|
# into `dir/dir/PKGBUILD` and resetting same-version hotfixes to pkgrel=1.
|
|
AUR_SOURCE_HOTFIX="${WORK_DIR}/aur-source-hotfix"
|
|
write_source_clone "${AUR_SOURCE_HOTFIX}" 9.9.9 3
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir aur-source-hotfix \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator \
|
|
--source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
assert_contains "${AUR_SOURCE_HOTFIX}/PKGBUILD" "pkgrel=4"
|
|
assert_contains "${AUR_SOURCE_HOTFIX}/.SRCINFO" "pkgrel = 4"
|
|
|
|
AUR_CONFIG_HOTFIX="${WORK_DIR}/aur-config-hotfix"
|
|
write_configurator_clone "${AUR_CONFIG_HOTFIX}" 9.9.9 3
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir missing-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir aur-config-hotfix \
|
|
--source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" "pkgrel=4"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/.SRCINFO" "pkgrel = 4"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" \
|
|
"pkgdesc='GUI configurator for wayscriber (GTK4/libadwaita)'"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" "'gtk4'"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" "'libadwaita>=1.4'"
|
|
assert_not_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" "(Iced)"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/.SRCINFO" \
|
|
"pkgdesc = GUI configurator for wayscriber (GTK4/libadwaita)"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/.SRCINFO" "depends = gtk4"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/.SRCINFO" "depends = libadwaita>=1.4"
|
|
assert_not_contains "${AUR_CONFIG_HOTFIX}/.SRCINFO" "(Iced)"
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" \
|
|
'packaging/wayscriber-configurator.desktop'
|
|
for size in 16 19 22 24 38 64 128; do
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" \
|
|
"packaging/icons/wayscriber-configurator-${size}.png"
|
|
done
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" \
|
|
'packaging/icons/wayscriber-configurator.svg'
|
|
|
|
# A missing required configurator clone aborts before an earlier source channel
|
|
# is touched. Skipping it remains available, but only as an explicit decision.
|
|
AUR_PREFLIGHT_SOURCE="${WORK_DIR}/aur-preflight-source"
|
|
write_source_clone "${AUR_PREFLIGHT_SOURCE}" 9.9.9 3
|
|
cp "${AUR_PREFLIGHT_SOURCE}/PKGBUILD" "${WORK_DIR}/aur-preflight-source.before"
|
|
expect_aur_failure "wayscriber-configurator AUR clone not found" "${WORK_DIR}" \
|
|
--source-dir aur-preflight-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--source-sha256 "${AUR_SOURCE_SHA}"
|
|
cmp "${WORK_DIR}/aur-preflight-source.before" "${AUR_PREFLIGHT_SOURCE}/PKGBUILD"
|
|
|
|
AUR_NOT_GIT="${WORK_DIR}/aur-not-git"
|
|
mkdir -p "${AUR_NOT_GIT}"
|
|
touch "${AUR_NOT_GIT}/PKGBUILD" "${AUR_NOT_GIT}/.SRCINFO"
|
|
expect_aur_failure "wayscriber AUR path is not a Git worktree" "${WORK_DIR}" \
|
|
--source-dir aur-not-git \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator \
|
|
--source-sha256 "${AUR_SOURCE_SHA}"
|
|
|
|
AUR_SKIP_OUTPUT="${WORK_DIR}/aur-skip-output"
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir missing-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator >"${AUR_SKIP_OUTPUT}" 2>&1
|
|
assert_contains "${AUR_SKIP_OUTPUT}" "--no-configurator was passed"
|
|
|
|
# Download and checksum validation also run before mutation. The fake curl
|
|
# makes accidental network use deterministic and proves the clone stays intact.
|
|
AUR_CHECKSUM_SOURCE="${WORK_DIR}/aur-checksum-source"
|
|
write_source_clone "${AUR_CHECKSUM_SOURCE}" 9.9.8 2
|
|
cp "${AUR_CHECKSUM_SOURCE}/PKGBUILD" "${WORK_DIR}/aur-checksum-source.before"
|
|
expect_aur_failure "Failed to download the source archive" "${WORK_DIR}" \
|
|
--source-dir aur-checksum-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
cmp "${WORK_DIR}/aur-checksum-source.before" "${AUR_CHECKSUM_SOURCE}/PKGBUILD"
|
|
|
|
AUR_TEST_CURL_MODE=empty expect_aur_failure \
|
|
"Downloaded an empty source archive" "${WORK_DIR}" \
|
|
--source-dir aur-checksum-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
cmp "${WORK_DIR}/aur-checksum-source.before" "${AUR_CHECKSUM_SOURCE}/PKGBUILD"
|
|
|
|
expect_aur_failure "Source archive checksum is not a sha256 digest" "${WORK_DIR}" \
|
|
--source-dir aur-checksum-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir missing-config \
|
|
--no-configurator \
|
|
--source-sha256 invalid
|
|
|
|
# Binary artifact lookup is a cardinality-and-shape contract, not merely a
|
|
# nonempty string check. All failures happen before the bin checkout mutates.
|
|
AUR_BIN_MISSING_MANIFEST="${WORK_DIR}/manifest-bin-missing.json"
|
|
AUR_BIN_DUPLICATE_MANIFEST="${WORK_DIR}/manifest-bin-duplicate.json"
|
|
AUR_BIN_DUPLICATE_NULL_MANIFEST="${WORK_DIR}/manifest-bin-duplicate-null.json"
|
|
AUR_BIN_MALFORMED_MANIFEST="${WORK_DIR}/manifest-bin-malformed.json"
|
|
cp "${AUR_BIN_DIR}/PKGBUILD" "${WORK_DIR}/aur-bin-checksum.before"
|
|
cat > "${AUR_BIN_MISSING_MANIFEST}" <<'EOF'
|
|
{"version":"9.9.9","artifacts":[]}
|
|
EOF
|
|
cat > "${AUR_BIN_DUPLICATE_MANIFEST}" <<EOF
|
|
{"version":"9.9.9","artifacts":[
|
|
{"name":"wayscriber-v9.9.9-linux-x86_64.tar.gz","sha256":"${AUR_SOURCE_SHA}"},
|
|
{"name":"wayscriber-v9.9.9-linux-x86_64.tar.gz","sha256":"${AUR_SOURCE_SHA}"}
|
|
]}
|
|
EOF
|
|
cat > "${AUR_BIN_DUPLICATE_NULL_MANIFEST}" <<EOF
|
|
{"version":"9.9.9","artifacts":[
|
|
{"name":"wayscriber-v9.9.9-linux-x86_64.tar.gz","sha256":"${AUR_SOURCE_SHA}"},
|
|
{"name":"wayscriber-v9.9.9-linux-x86_64.tar.gz","sha256":null}
|
|
]}
|
|
EOF
|
|
cat > "${AUR_BIN_MALFORMED_MANIFEST}" <<'EOF'
|
|
{"version":"9.9.9","artifacts":[
|
|
{"name":"wayscriber-v9.9.9-linux-x86_64.tar.gz","sha256":"not-a-digest"}
|
|
]}
|
|
EOF
|
|
expect_aur_failure "found 0" "${WORK_DIR}" \
|
|
--manifest "${AUR_BIN_MISSING_MANIFEST}" \
|
|
--source-dir missing-source \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
expect_aur_failure "found 2" "${WORK_DIR}" \
|
|
--manifest "${AUR_BIN_DUPLICATE_MANIFEST}" \
|
|
--source-dir missing-source \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
expect_aur_failure "found 2" "${WORK_DIR}" \
|
|
--manifest "${AUR_BIN_DUPLICATE_NULL_MANIFEST}" \
|
|
--source-dir missing-source \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
expect_aur_failure "not a 64-character hexadecimal digest" "${WORK_DIR}" \
|
|
--manifest "${AUR_BIN_MALFORMED_MANIFEST}" \
|
|
--source-dir missing-source \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir missing-config \
|
|
--no-configurator
|
|
cmp "${WORK_DIR}/aur-bin-checksum.before" "${AUR_BIN_DIR}/PKGBUILD"
|
|
|
|
# A deterministic failure in the last selected checkout must happen before
|
|
# any earlier checkout is committed or pushed. This configurator fixture lacks
|
|
# the dependency anchor needed by its GTK migration.
|
|
AUR_LATE_SOURCE="${WORK_DIR}/aur-late-source"
|
|
AUR_LATE_CONFIG="${WORK_DIR}/aur-late-config"
|
|
AUR_PUSH_LOG="${WORK_DIR}/aur-push-log"
|
|
write_source_clone "${AUR_LATE_SOURCE}" 9.9.8 1
|
|
write_configurator_clone "${AUR_LATE_CONFIG}" 9.9.8 1
|
|
AUR_LATE_SOURCE_HEAD="$(git -C "${AUR_LATE_SOURCE}" rev-parse HEAD)"
|
|
sed -i "/'gcc-libs'/d" "${AUR_LATE_CONFIG}/PKGBUILD"
|
|
sed -i '/depends = gcc-libs/d' "${AUR_LATE_CONFIG}/.SRCINFO"
|
|
AUR_TEST_GIT_LOG="${AUR_PUSH_LOG}" expect_aur_failure \
|
|
"missing dependency anchor 'gcc-libs'" "${WORK_DIR}" \
|
|
--source-dir aur-late-source \
|
|
--bin-dir missing-bin \
|
|
--config-dir aur-late-config \
|
|
--source-sha256 "${AUR_SOURCE_SHA}" \
|
|
--push
|
|
assert_clean_checkout_at_head \
|
|
"${AUR_LATE_SOURCE}" \
|
|
"${AUR_LATE_SOURCE_HEAD}" \
|
|
"late configurator preflight failure"
|
|
[[ ! -s "${AUR_PUSH_LOG}" ]] || {
|
|
echo "AUR updater pushed before every selected checkout was prepared" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Reapply to prove idempotence, then execute both generated package() bodies.
|
|
# Compare installed assets with the canonical package manifest, rather than
|
|
# only matching the updater's own generated text.
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir "${AUR_SOURCE_HOTFIX}" \
|
|
--bin-dir "${AUR_BIN_DIR}" \
|
|
--no-configurator \
|
|
--source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
for recipe in "${AUR_SOURCE_HOTFIX}" "${AUR_BIN_DIR}"; do
|
|
[[ "$(grep -Fxc '# Wayscriber desktop integration' "$recipe/PKGBUILD")" == 1 ]] || {
|
|
echo "Expected exactly one managed desktop block in $recipe/PKGBUILD" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
|
|
# A managed block is exact state, so assets removed from the manifest must not
|
|
# survive merely because every current line is also present.
|
|
STALE_AUR_ASSET_LINE=' install -Dm644 packaging/icons/retired-icon.png "$pkgdir/usr/share/icons/hicolor/obsolete/retired-icon.png"'
|
|
STALE_CONFIGURATOR_ASSET_LINE=' install -Dm644 packaging/icons/retired-legacy-icon.png "$pkgdir/usr/share/icons/hicolor/obsolete/retired-legacy-icon.png"'
|
|
STALE_AUR_ASSET_LINE="${STALE_AUR_ASSET_LINE}" perl -0pi -e '
|
|
s{^# End Wayscriber desktop integration$}{$ENV{STALE_AUR_ASSET_LINE} . "\n" . $&}me
|
|
' "${AUR_SOURCE_HOTFIX}/PKGBUILD"
|
|
STALE_CONFIGURATOR_ASSET_LINE="${STALE_CONFIGURATOR_ASSET_LINE}" perl -0pi -e '
|
|
s{^# End Wayscriber configurator desktop integration$}{$ENV{STALE_CONFIGURATOR_ASSET_LINE} . "\n" . $&}me
|
|
' "${AUR_CONFIG_HOTFIX}/PKGBUILD"
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir "${AUR_SOURCE_HOTFIX}" --bin-dir missing-bin \
|
|
--config-dir "${AUR_CONFIG_HOTFIX}" --source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
assert_not_contains "${AUR_SOURCE_HOTFIX}/PKGBUILD" "${STALE_AUR_ASSET_LINE}"
|
|
assert_not_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" "${STALE_CONFIGURATOR_ASSET_LINE}"
|
|
|
|
# Pre-marker recipes can contain an older manifest subset and retain removed
|
|
# assets. Migrate each legacy set to an exact managed block.
|
|
AUR_MARKERLESS_SOURCE="${WORK_DIR}/aur-markerless-source"
|
|
AUR_MARKERLESS_BIN="${WORK_DIR}/aur-markerless-bin"
|
|
AUR_MARKERLESS_CONFIG="${WORK_DIR}/aur-markerless-config"
|
|
cp -a "${AUR_SOURCE_HOTFIX}" "${AUR_MARKERLESS_SOURCE}"
|
|
cp -a "${AUR_BIN_DIR}" "${AUR_MARKERLESS_BIN}"
|
|
cp -a "${AUR_CONFIG_HOTFIX}" "${AUR_MARKERLESS_CONFIG}"
|
|
for recipe in "${AUR_MARKERLESS_SOURCE}" "${AUR_MARKERLESS_BIN}"; do
|
|
sed -i '/^# \(End \)\?Wayscriber desktop integration$/d' "${recipe}/PKGBUILD"
|
|
sed -i '/wayscriber-symbolic\.svg/d' "${recipe}/PKGBUILD"
|
|
printf '%s\n' "${STALE_AUR_ASSET_LINE}" >> "${recipe}/PKGBUILD"
|
|
done
|
|
sed -i '/^# \(End \)\?Wayscriber configurator desktop integration$/d' "${AUR_MARKERLESS_CONFIG}/PKGBUILD"
|
|
sed -i '/wayscriber-configurator\.svg/d' "${AUR_MARKERLESS_CONFIG}/PKGBUILD"
|
|
printf '%s\n' "${STALE_CONFIGURATOR_ASSET_LINE}" >> "${AUR_MARKERLESS_CONFIG}/PKGBUILD"
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir "${AUR_MARKERLESS_SOURCE}" --bin-dir "${AUR_MARKERLESS_BIN}" \
|
|
--config-dir "${AUR_MARKERLESS_CONFIG}" --source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
for recipe in "${AUR_MARKERLESS_SOURCE}" "${AUR_MARKERLESS_BIN}"; do
|
|
[[ "$(grep -Fxc '# Wayscriber desktop integration' "${recipe}/PKGBUILD")" == 1 ]] || {
|
|
echo "Markerless Wayscriber desktop assets were not normalized in ${recipe}" >&2
|
|
exit 1
|
|
}
|
|
assert_not_contains "${recipe}/PKGBUILD" "${STALE_AUR_ASSET_LINE}"
|
|
done
|
|
[[ "$(grep -Fxc '# Wayscriber configurator desktop integration' "${AUR_MARKERLESS_CONFIG}/PKGBUILD")" == 1 ]] || {
|
|
echo "Markerless configurator desktop assets were not normalized" >&2
|
|
exit 1
|
|
}
|
|
assert_not_contains "${AUR_MARKERLESS_CONFIG}/PKGBUILD" "${STALE_CONFIGURATOR_ASSET_LINE}"
|
|
|
|
AUR_ASSET_SOURCE="${WORK_DIR}/aur-asset-source"
|
|
AUR_ASSET_STAGE="${WORK_DIR}/aur-asset-stage"
|
|
mkdir -p "${AUR_ASSET_SOURCE}/wayscriber-9.9.9/target/release"
|
|
cp -a "${REPO_ROOT}/packaging" "${AUR_ASSET_SOURCE}/wayscriber-9.9.9/"
|
|
printf '#!/usr/bin/env bash\nexit 0\n' > "${AUR_ASSET_SOURCE}/wayscriber-9.9.9/target/release/wayscriber"
|
|
srcdir="${AUR_ASSET_SOURCE}" pkgdir="${AUR_ASSET_STAGE}" \
|
|
bash -c 'source "$1"; cd "$srcdir"; package' -- "${AUR_SOURCE_HOTFIX}/PKGBUILD"
|
|
|
|
# Complete the mock release tarball's non-desktop payload for the binary recipe.
|
|
mkdir -p "${AUR_ASSET_STAGE}/usr/lib/systemd/user" \
|
|
"${AUR_ASSET_STAGE}/usr/share/doc/wayscriber" \
|
|
"${AUR_ASSET_STAGE}/usr/share/licenses/wayscriber"
|
|
cp "${REPO_ROOT}/packaging/wayscriber.service" "${AUR_ASSET_STAGE}/usr/lib/systemd/user/"
|
|
cp "${REPO_ROOT}/config.example.toml" "${REPO_ROOT}/README.md" "${REPO_ROOT}/LICENSE" \
|
|
"${AUR_ASSET_STAGE}/usr/share/doc/wayscriber/"
|
|
cp "${REPO_ROOT}/packaging/licenses/gtk4-layer-shell.LICENSE" \
|
|
"${AUR_ASSET_STAGE}/usr/share/licenses/wayscriber/LICENSE.gtk4-layer-shell"
|
|
tar -czf "${AUR_ASSET_SOURCE}/wayscriber-v9.9.9-linux-x86_64.tar.gz" \
|
|
-C "${WORK_DIR}" aur-asset-stage
|
|
AUR_BIN_STAGE="${WORK_DIR}/aur-bin-stage"
|
|
srcdir="${AUR_ASSET_SOURCE}" pkgdir="${AUR_BIN_STAGE}" CARCH=x86_64 \
|
|
bash -c 'source "$1"; cd "$srcdir"; package' -- "${AUR_BIN_DIR}/PKGBUILD"
|
|
while read -r asset; do
|
|
for stage in "${AUR_ASSET_STAGE}" "${AUR_BIN_STAGE}"; do
|
|
[[ -f "$stage$asset" && "$(stat -c '%a' "$stage$asset")" == 644 ]] || {
|
|
echo "Expected installed desktop asset with mode 644: $stage$asset" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
cmp "${AUR_ASSET_STAGE}${asset}" "${AUR_BIN_STAGE}${asset}" || {
|
|
echo "Source and binary package assets differ: $asset" >&2
|
|
exit 1
|
|
}
|
|
done < <(awk '/^ dst: \/usr\/share\/(applications|icons|pixmaps)\// { print $2 }' "${PACKAGE_CONFIG}")
|
|
[[ ! -e "${AUR_BIN_STAGE}/usr/bin/wayscriber-configurator" ]] || {
|
|
echo 'The binary package unexpectedly includes the configurator' >&2
|
|
exit 1
|
|
}
|
|
|
|
# Repair missing assets in both current and legacy managed blocks.
|
|
SOURCE_CONFIGURATOR_BLOCK_BEFORE="$(awk '
|
|
/^# Wayscriber configurator desktop integration$/ { inside = 1 }
|
|
inside { print }
|
|
/^# End Wayscriber configurator desktop integration$/ { exit }
|
|
' "${AUR_SOURCE_HOTFIX}/PKGBUILD")"
|
|
sed -i '/^# End Wayscriber configurator desktop integration$/d; /install .*scalable\/apps\/wayscriber-configurator.svg/d' "${AUR_CONFIG_HOTFIX}/PKGBUILD"
|
|
sed -i '/install .*symbolic\/apps\/wayscriber-symbolic.svg/d' "${AUR_BIN_DIR}/PKGBUILD"
|
|
sed -i '/^# End Wayscriber desktop integration$/d; /install .*symbolic\/apps\/wayscriber-symbolic.svg/d' "${AUR_SOURCE_HOTFIX}/PKGBUILD"
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir "${AUR_SOURCE_HOTFIX}" --bin-dir "${AUR_BIN_DIR}" \
|
|
--config-dir "${AUR_CONFIG_HOTFIX}" --source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
for recipe in "${AUR_SOURCE_HOTFIX}" "${AUR_BIN_DIR}"; do
|
|
assert_contains "$recipe/PKGBUILD" 'symbolic/apps/wayscriber-symbolic.svg'
|
|
assert_contains "$recipe/PKGBUILD" '# End Wayscriber desktop integration'
|
|
done
|
|
SOURCE_CONFIGURATOR_BLOCK_AFTER="$(awk '
|
|
/^# Wayscriber configurator desktop integration$/ { inside = 1 }
|
|
inside { print }
|
|
/^# End Wayscriber configurator desktop integration$/ { exit }
|
|
' "${AUR_SOURCE_HOTFIX}/PKGBUILD")"
|
|
[[ "${SOURCE_CONFIGURATOR_BLOCK_AFTER}" == "${SOURCE_CONFIGURATOR_BLOCK_BEFORE}" ]] || {
|
|
echo 'Repairing the source desktop block changed configurator assets' >&2
|
|
exit 1
|
|
}
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" 'scalable/apps/wayscriber-configurator.svg'
|
|
assert_contains "${AUR_CONFIG_HOTFIX}/PKGBUILD" '# End Wayscriber configurator desktop integration'
|
|
|
|
# The interactive updater installs the canonical template, which already has
|
|
# desktop assets. The manifest updater must accept that route without duplicates.
|
|
AUR_TEMPLATE_SOURCE="${WORK_DIR}/aur-template-source"
|
|
mkdir -p "${AUR_TEMPLATE_SOURCE}"
|
|
cp "${REPO_ROOT}/packaging/PKGBUILD" "${REPO_ROOT}/packaging/.SRCINFO" "${AUR_TEMPLATE_SOURCE}/"
|
|
git -C "${AUR_TEMPLATE_SOURCE}" init -q
|
|
run_aur_updater "${WORK_DIR}" \
|
|
--source-dir "${AUR_TEMPLATE_SOURCE}" --bin-dir missing-bin \
|
|
--no-configurator --source-sha256 "${AUR_SOURCE_SHA}" >/dev/null
|
|
[[ "$(grep -Fc 'packaging/wayscriber.desktop' "${AUR_TEMPLATE_SOURCE}/PKGBUILD")" == 1 ]] || {
|
|
echo 'Canonical template received duplicate desktop integration' >&2
|
|
exit 1
|
|
}
|
|
|
|
# A version bump must retain a locked registry dependency even when a newer
|
|
# compatible release exists. A local directory source makes this fully offline.
|
|
BUMP_REPO="${WORK_DIR}/bump-repo"
|
|
BUMP_FAKE_BIN="${WORK_DIR}/bump-fake-bin"
|
|
mkdir -p "${BUMP_REPO}/tools" "${BUMP_REPO}/src" \
|
|
"${BUMP_REPO}/configurator/src" "${BUMP_REPO}/packaging" \
|
|
"${BUMP_REPO}/.cargo" "${BUMP_FAKE_BIN}"
|
|
cp "${REPO_ROOT}/tools/bump-version.sh" "${BUMP_REPO}/tools/"
|
|
# This test isolates the bump's Cargo operation; real metadata consistency is
|
|
# checked separately by the canonical gate on this repository.
|
|
printf '#!/usr/bin/env bash\nexit 0\n' > "${BUMP_REPO}/tools/check-version-consistency.sh"
|
|
printf '#!/usr/bin/env bash\nprintf "pkgbase = wayscriber\\n"\n' > "${BUMP_FAKE_BIN}/makepkg"
|
|
chmod +x "${BUMP_FAKE_BIN}/makepkg"
|
|
cat > "${BUMP_REPO}/Cargo.toml" <<'EOF'
|
|
[package]
|
|
name = "wayscriber"
|
|
version = "1.0.0"
|
|
edition = "2024"
|
|
[workspace]
|
|
members = ["configurator"]
|
|
[dependencies]
|
|
release-fixture = "1"
|
|
EOF
|
|
cat > "${BUMP_REPO}/configurator/Cargo.toml" <<'EOF'
|
|
[package]
|
|
name = "wayscriber-configurator"
|
|
version = "1.0.0"
|
|
edition = "2024"
|
|
[dependencies]
|
|
wayscriber = { path = ".." }
|
|
EOF
|
|
touch "${BUMP_REPO}/src/lib.rs" "${BUMP_REPO}/configurator/src/lib.rs"
|
|
printf "pkgver=1.0.0\nsha256sums=('SKIP')\n" > "${BUMP_REPO}/packaging/PKGBUILD"
|
|
cat > "${BUMP_REPO}/.cargo/config.toml" <<EOF
|
|
[source.crates-io]
|
|
replace-with = "fixture"
|
|
[source.fixture]
|
|
directory = "${BUMP_REPO}/vendor"
|
|
EOF
|
|
for fixture_version in 1.0.0 1.1.0; do
|
|
fixture_dir="${BUMP_REPO}/vendor/release-fixture-${fixture_version}"
|
|
mkdir -p "${fixture_dir}/src"
|
|
printf '[package]\nname = "release-fixture"\nversion = "%s"\nedition = "2024"\n' \
|
|
"${fixture_version}" > "${fixture_dir}/Cargo.toml"
|
|
touch "${fixture_dir}/src/lib.rs"
|
|
printf '{"files":{},"package":"%s"}\n' "${AUR_SOURCE_SHA}" > "${fixture_dir}/.cargo-checksum.json"
|
|
if [[ "$fixture_version" == 1.0.0 ]]; then
|
|
(cd "${BUMP_REPO}" && cargo generate-lockfile --offline)
|
|
fi
|
|
done
|
|
BUMP_FAIL_BIN="${WORK_DIR}/bump-fail-bin"
|
|
BUMP_DRY_RUN_OUTPUT="${WORK_DIR}/bump-dry-run-output"
|
|
mkdir -p "${BUMP_FAIL_BIN}"
|
|
cat > "${BUMP_FAIL_BIN}/cargo" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
if [[ "$*" == "update --workspace --offline --dry-run" ]]; then
|
|
exit 1
|
|
fi
|
|
exec "${BUMP_REAL_CARGO:?}" "$@"
|
|
EOF
|
|
chmod +x "${BUMP_FAIL_BIN}/cargo"
|
|
if BUMP_REAL_CARGO="$(command -v cargo)" PATH="${BUMP_FAIL_BIN}:${BUMP_FAKE_BIN}:${PATH}" \
|
|
bash "${BUMP_REPO}/tools/bump-version.sh" --dry-run 1.0.1 >"${BUMP_DRY_RUN_OUTPUT}" 2>&1; then
|
|
echo 'Expected the version-bump dry run to fail when offline resolution fails' >&2
|
|
exit 1
|
|
fi
|
|
assert_contains "${BUMP_DRY_RUN_OUTPUT}" 'cannot resolve locked dependencies offline'
|
|
|
|
cp "${BUMP_REPO}/Cargo.lock" "${WORK_DIR}/before-bump.lock"
|
|
for version in 1.0.1 1.0.1.1; do
|
|
PATH="${BUMP_FAKE_BIN}:${PATH}" bash "${BUMP_REPO}/tools/bump-version.sh" "$version" >/dev/null
|
|
# Both workspace packages change, but all remaining bytes must stay put.
|
|
sed 's/version = "1.0.1"/version = "1.0.0"/g' "${BUMP_REPO}/Cargo.lock" \
|
|
> "${WORK_DIR}/normalized-bump.lock"
|
|
cmp "${WORK_DIR}/before-bump.lock" "${WORK_DIR}/normalized-bump.lock"
|
|
done
|
|
# Prove the fixture exposes the original bug: resolving afresh selects 1.1.0.
|
|
(cd "${BUMP_REPO}" && cargo generate-lockfile --offline)
|
|
assert_contains "${BUMP_REPO}/Cargo.lock" 'version = "1.1.0"'
|
|
|
|
echo "Release packaging contract checks passed."
|