407 lines
10 KiB
Bash
Executable File
407 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
|
|
source "$BUILD_ROOT/helpers/message-helpers.sh"
|
|
source "$BUILD_ROOT/helpers/paths.sh"
|
|
source "$BUILD_ROOT/helpers/package-metadata.sh"
|
|
|
|
TEMP_DIR=$(mktemp -d)
|
|
trap 'rm -rf "$TEMP_DIR"' EXIT
|
|
|
|
SPECIFIC_PACKAGES=()
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $0 [PACKAGE...]
|
|
|
|
Sync AUR-backed packages into pkgbuilds/<package>/.
|
|
|
|
Package selection is driven by pkgbuilds/<package>/.omarchy/package.json:
|
|
{ "source": "aur" } # synced from matching AUR package name
|
|
{ "source": "aur", "aur": "yaru" } # synced from different AUR package name
|
|
{ "source": "aur", "sync": false } # AUR-origin, but not auto-synced
|
|
|
|
Arguments:
|
|
PACKAGE One or more package names to sync (optional)
|
|
|
|
Examples:
|
|
$0 # Sync all AUR packages with sync enabled
|
|
$0 yay cursor-bin # Sync specific packages
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--tier)
|
|
print_error "--tier is no longer supported; package metadata controls sync behavior"
|
|
exit 1
|
|
;;
|
|
--*)
|
|
print_error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
*)
|
|
SPECIFIC_PACKAGES+=("$1")
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
print_header "AUR Package Sync"
|
|
mkdir -p "$PKGBUILDS_DIR"
|
|
|
|
SYNCED=0
|
|
SKIPPED=0
|
|
FAILED=0
|
|
SYNCED_PACKAGES=()
|
|
SPECIFIC_MODE=false
|
|
|
|
get_pkgbuild_field() {
|
|
local package_dir="$1"
|
|
local field="$2"
|
|
local value=""
|
|
|
|
if [[ -f "$package_dir/PKGBUILD" ]]; then
|
|
value=$(grep -m1 "^${field}=" "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'") || true
|
|
if [[ -n "$value" ]]; then
|
|
echo "$value"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "$package_dir/.SRCINFO" ]]; then
|
|
awk -F' = ' -v field="$field" '$1 ~ "^[[:space:]]*" field "$" { print $2; exit }' "$package_dir/.SRCINFO"
|
|
fi
|
|
}
|
|
|
|
set_pkgrel() {
|
|
local package_dir="$1"
|
|
local pkgrel="$2"
|
|
local pkgbuild="$package_dir/PKGBUILD"
|
|
|
|
if [[ -f "$pkgbuild" ]]; then
|
|
sed -i "s/^pkgrel=.*/pkgrel=$pkgrel/" "$pkgbuild"
|
|
fi
|
|
}
|
|
|
|
display_package_name() {
|
|
local package_dir="$1"
|
|
local name
|
|
name=$(basename "$package_dir")
|
|
echo "${name%.work}"
|
|
}
|
|
|
|
remove_aur_only_files() {
|
|
local package_dir="$1"
|
|
|
|
rm -f "$package_dir/.SRCINFO" "$package_dir/.gitignore"
|
|
}
|
|
|
|
copy_aur_contents() {
|
|
local aur_dir="$1"
|
|
local target_dir="$2"
|
|
|
|
mkdir -p "$target_dir"
|
|
|
|
shopt -s dotglob nullglob
|
|
local item base
|
|
for item in "$aur_dir"/*; do
|
|
base=$(basename "$item")
|
|
[[ "$base" == ".git" ]] && continue
|
|
cp -a "$item" "$target_dir/"
|
|
done
|
|
shopt -u dotglob nullglob
|
|
}
|
|
|
|
commit_synced_worktree() {
|
|
local work_dir="$1"
|
|
local target_dir="$2"
|
|
local parent base staged_dir backup_root backup_dir
|
|
|
|
parent=$(dirname "$target_dir")
|
|
base=$(basename "$target_dir")
|
|
staged_dir=$(mktemp -d "$parent/.${base}.staged.XXXXXX")
|
|
backup_root=$(mktemp -d "$parent/.${base}.backup.XXXXXX")
|
|
backup_dir="$backup_root/$base"
|
|
|
|
# Copy to the package filesystem before swapping. This keeps the original
|
|
# package directory intact if copying from /tmp fails or is interrupted.
|
|
if ! cp -a "$work_dir/." "$staged_dir/"; then
|
|
print_error "Failed to stage synced package for $base"
|
|
rm -rf "$staged_dir" "$backup_root"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -e "$target_dir" ]]; then
|
|
if ! mv "$target_dir" "$backup_dir"; then
|
|
print_error "Failed to back up existing package directory: $target_dir"
|
|
rm -rf "$staged_dir" "$backup_root"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
if ! mv "$staged_dir" "$target_dir"; then
|
|
print_error "Failed to install synced package directory: $target_dir"
|
|
if [[ -e "$backup_dir" ]]; then
|
|
mv "$backup_dir" "$target_dir" || true
|
|
fi
|
|
rm -rf "$staged_dir" "$backup_root"
|
|
return 1
|
|
fi
|
|
|
|
rm -rf "$backup_root" "$work_dir"
|
|
}
|
|
|
|
set_upstream_commit() {
|
|
local package_dir="$1"
|
|
local commit="$2"
|
|
local metadata="$package_dir/.omarchy/package.json"
|
|
local tmpfile
|
|
|
|
tmpfile=$(mktemp)
|
|
jq --arg commit "$commit" '.upstream_commit = $commit' "$metadata" > "$tmpfile"
|
|
mv "$tmpfile" "$metadata"
|
|
}
|
|
|
|
apply_omarchy_patches() {
|
|
local package_dir="$1"
|
|
local patches_dir="$package_dir/.omarchy/patches"
|
|
local applied=false
|
|
|
|
[[ -d "$patches_dir" ]] || return 1
|
|
|
|
shopt -s nullglob
|
|
local patch_files=("$patches_dir"/*.patch)
|
|
local patch_dir_files=("$patches_dir"/*)
|
|
shopt -u nullglob
|
|
|
|
if [[ ${#patch_files[@]} -eq 0 ]]; then
|
|
if [[ ${#patch_dir_files[@]} -gt 0 ]]; then
|
|
print_warning "No .patch files found in $patches_dir"
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
print_info "Applying Omarchy patches for $(display_package_name "$package_dir")..."
|
|
local patch_file
|
|
for patch_file in "${patch_files[@]}"; do
|
|
print_info " $(basename "$patch_file")"
|
|
if ! (cd "$package_dir" && patch -p1 --forward --batch --no-backup-if-mismatch < "$patch_file"); then
|
|
print_error "Failed to apply patch: $patch_file"
|
|
return 2
|
|
fi
|
|
applied=true
|
|
done
|
|
|
|
[[ "$applied" == true ]]
|
|
}
|
|
|
|
run_omarchy_post_sync_hook() {
|
|
local package_dir="$1"
|
|
local package="$2"
|
|
local aur_package="$3"
|
|
local aur_pkgrel="$4"
|
|
local hook="$package_dir/.omarchy/post-sync.sh"
|
|
|
|
[[ -f "$hook" ]] || return 1
|
|
|
|
print_info "Running Omarchy post-sync hook for $(display_package_name "$package_dir")..."
|
|
if ! (
|
|
cd "$package_dir"
|
|
PACKAGE_NAME="$package" \
|
|
AUR_PACKAGE_NAME="$aur_package" \
|
|
AUR_PKGREL="$aur_pkgrel" \
|
|
bash ".omarchy/post-sync.sh"
|
|
); then
|
|
print_error "Failed to run post-sync hook: $hook"
|
|
return 2
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
apply_pkgrel_suffix_if_customized() {
|
|
local package_dir="$1"
|
|
local aur_pkgrel="$2"
|
|
|
|
[[ -n "$aur_pkgrel" ]] || return 0
|
|
|
|
print_info "Applying Omarchy pkgrel suffix for $(display_package_name "$package_dir"): pkgrel=$aur_pkgrel.1"
|
|
set_pkgrel "$package_dir" "$aur_pkgrel.1"
|
|
}
|
|
|
|
apply_pkgrel_override() {
|
|
local package_dir="$1"
|
|
local aur_pkgrel="$2"
|
|
local previous_pkgver="$3"
|
|
local metadata="$package_dir/.omarchy/package.json"
|
|
local pkgbuild="$package_dir/PKGBUILD"
|
|
|
|
[[ -f "$metadata" ]] || return 1
|
|
jq -e 'has("pkgrel")' "$metadata" >/dev/null || return 1
|
|
|
|
local current_pkgver suffix offset base rel tmpfile
|
|
current_pkgver=$(grep -m1 '^pkgver=' "$pkgbuild" | cut -d= -f2)
|
|
|
|
if [[ -n "$previous_pkgver" && "$current_pkgver" != "$previous_pkgver" ]]; then
|
|
print_info "Removing stale pkgrel metadata for $(display_package_name "$package_dir") (pkgver changed: $previous_pkgver -> $current_pkgver)"
|
|
tmpfile=$(mktemp)
|
|
jq 'del(.pkgrel)' "$metadata" > "$tmpfile"
|
|
mv "$tmpfile" "$metadata"
|
|
return 1
|
|
fi
|
|
|
|
suffix=$(jq -r '.pkgrel.suffix // 1' "$metadata")
|
|
offset=$(jq -r '.pkgrel.offset // 0' "$metadata")
|
|
|
|
if [[ ! "$offset" =~ ^[0-9]+$ || ! "$aur_pkgrel" =~ ^[0-9]+$ ]]; then
|
|
print_error "pkgrel offset requires numeric AUR pkgrel for $(display_package_name "$package_dir")"
|
|
return 2
|
|
fi
|
|
|
|
base=$((aur_pkgrel + offset))
|
|
rel="$base.$suffix"
|
|
|
|
print_info "Applying pkgrel suffix for $(display_package_name "$package_dir"): AUR pkgrel=$aur_pkgrel, offset=$offset, suffix=$suffix -> pkgrel=$rel"
|
|
set_pkgrel "$package_dir" "$rel"
|
|
return 0
|
|
}
|
|
|
|
sync_package() {
|
|
local package="$1"
|
|
local package_dir="$PKGBUILDS_DIR/$package"
|
|
local metadata="$package_dir/.omarchy/package.json"
|
|
|
|
if [[ ! -f "$metadata" ]]; then
|
|
if [[ "$SPECIFIC_MODE" == true ]]; then
|
|
print_error "Package $package is missing .omarchy/package.json"
|
|
((++FAILED))
|
|
else
|
|
print_warning "Skipping $package: missing .omarchy/package.json"
|
|
((++SKIPPED))
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$(jq -r '.source // ""' "$metadata")" != "aur" ]]; then
|
|
print_info "Skipping $package: source is not AUR"
|
|
((++SKIPPED))
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$(jq -r 'if has("sync") then .sync else true end' "$metadata")" == "false" ]]; then
|
|
print_info "Skipping $package: AUR sync disabled"
|
|
((++SKIPPED))
|
|
return 0
|
|
fi
|
|
|
|
local aur_package
|
|
aur_package=$(jq -r --arg package "$package" '.aur // $package' "$metadata")
|
|
|
|
if [[ "$aur_package" == "$package" ]]; then
|
|
print_info "Syncing $package from AUR..."
|
|
else
|
|
print_info "Syncing $package from AUR package $aur_package..."
|
|
fi
|
|
|
|
cd "$TEMP_DIR"
|
|
rm -rf "$aur_package"
|
|
|
|
if ! git clone "https://aur.archlinux.org/${aur_package}.git" "$aur_package" >/dev/null 2>&1; then
|
|
print_warning "Failed to clone $aur_package (may not exist in AUR)"
|
|
((++FAILED))
|
|
return 0
|
|
fi
|
|
|
|
local aur_dir="$TEMP_DIR/$aur_package"
|
|
local work_dir="$TEMP_DIR/${package}.work"
|
|
local aur_pkgrel previous_pkgver upstream_commit
|
|
aur_pkgrel=$(get_pkgbuild_field "$aur_dir" pkgrel)
|
|
previous_pkgver=$(get_pkgbuild_field "$package_dir" pkgver || true)
|
|
upstream_commit=$(git -C "$aur_dir" rev-parse HEAD)
|
|
|
|
rm -rf "$work_dir"
|
|
copy_aur_contents "$aur_dir" "$work_dir"
|
|
rm -rf "$work_dir/.omarchy"
|
|
cp -a "$package_dir/.omarchy" "$work_dir/.omarchy"
|
|
|
|
local customized=false
|
|
|
|
if apply_omarchy_patches "$work_dir"; then
|
|
customized=true
|
|
else
|
|
local patch_status=$?
|
|
if [[ $patch_status -eq 2 ]]; then
|
|
((++FAILED))
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
if run_omarchy_post_sync_hook "$work_dir" "$package" "$aur_package" "$aur_pkgrel"; then
|
|
customized=true
|
|
else
|
|
local hook_status=$?
|
|
if [[ $hook_status -eq 2 ]]; then
|
|
((++FAILED))
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
local pkgrel_overridden=false
|
|
set +e
|
|
apply_pkgrel_override "$work_dir" "$aur_pkgrel" "$previous_pkgver"
|
|
local pkgrel_status=$?
|
|
set -e
|
|
case "$pkgrel_status" in
|
|
0) pkgrel_overridden=true ;;
|
|
1) ;;
|
|
*) ((++FAILED)); return 0 ;;
|
|
esac
|
|
|
|
if [[ "$customized" == true && "$pkgrel_overridden" == false ]]; then
|
|
apply_pkgrel_suffix_if_customized "$work_dir" "$aur_pkgrel"
|
|
fi
|
|
|
|
remove_aur_only_files "$work_dir"
|
|
|
|
set_upstream_commit "$work_dir" "$upstream_commit"
|
|
if ! commit_synced_worktree "$work_dir" "$package_dir"; then
|
|
((++FAILED))
|
|
return 0
|
|
fi
|
|
|
|
SYNCED_PACKAGES+=("$package")
|
|
((++SYNCED))
|
|
}
|
|
|
|
if [[ ${#SPECIFIC_PACKAGES[@]} -gt 0 ]]; then
|
|
SPECIFIC_MODE=true
|
|
for package in "${SPECIFIC_PACKAGES[@]}"; do
|
|
sync_package "$package"
|
|
done
|
|
else
|
|
while IFS= read -r package; do
|
|
sync_package "$package"
|
|
done < <(packages_for_aur_sync)
|
|
fi
|
|
|
|
echo ""
|
|
if [[ $FAILED -gt 0 ]]; then
|
|
print_error "Sync completed with failures"
|
|
else
|
|
print_success "Sync complete!"
|
|
fi
|
|
echo " Target: $PKGBUILDS_DIR"
|
|
echo " Synced: $SYNCED"
|
|
echo " Skipped: $SKIPPED"
|
|
echo " Failed: $FAILED"
|
|
|
|
if [[ $FAILED -gt 0 ]]; then
|
|
exit 1
|
|
fi
|