#!/bin/bash # check for packages that need to be built, and build a list in the proper build order # Details: # https://github.com/archlinux32/builder/wiki/Build-system#get-package-updates set -e lock_file="/tmp/get-package-updates.lock" # TODO: # include repository of package customizations declare -A repo_paths repo_paths["packages"]="/usr/src/archlinux/packages" repo_paths["community"]="/usr/src/archlinux/community" base_dir="$(dirname "$(readlink -f "$0")")/.." # find the PKGBUILD of a given package in a given repository # TODO: # include repository of package customizations find_pkgbuild() { for prefix in "${repo_paths["packages"]}" "${repo_paths["community"]}"; do [ -d "${prefix}/$1" ] || continue ls "${prefix}/$1/repos/$2-"*"/PKGBUILD" 2> /dev/null && break done | \ tr ' ' '\n' | \ grep -v -- '-\(staging\|testing\)-[^/]\+/PKGBUILD$' | \ sort | \ tail -n1 } # Create a lock file for build list. exec 9>"${lock_file}" flock -n 9 || exit # Update git repositories (official packages, community packages and the repository of package customizations). for repo in "${repo_paths[@]}"; do git -C "${repo}" pull done # Read previous git revision numbers from files. declare -A old_repo_revisions for repo in "${!repo_paths[@]}"; do old_repo_revisions["${repo}"]="$(cat ${base_dir}/work/${repo}.revision)" done # Check modified packages from the last update, and put them to the build list. # If a package is updated, but already on the rebuild list, then just update the git revision number. # If a package is deleted, remove from the rebuild list, and add it to the deletion list. # If a new package is added, then ensure that it's not on the deletion list. for repo in "${!repo_paths[@]}"; do current_HEAD="$( git -C "${repo_paths["${repo}"]}" rev-parse HEAD )" git -C "${repo_paths["${repo}"]}" diff --name-status "${old_repo_revisions["${repo}"]}" HEAD | \ grep '^.\s[^/]\+/repos/[^/]\+/PKGBUILD$' | \ sed 's|^\(.\)\t\([^/]\+\)/repos/\([^/]\+\)-[^/-]\+/PKGBUILD$|\1 \2 '"${current_HEAD}"' \3|' | \ grep -v '\(staging\|testing\)$' done | \ sort -u | \ while read -r mode package git_revision repository; do case "${mode}" in "A"|"M") sed -i "/^${package} /d" "${base_dir}/work/build-list" echo "${package} ${git_revision} ${repository}" >> \ "${base_dir}/work/build-list" sed -i "/^${package}/d" "${base_dir}/work/deletion-list" ;; "D") echo "${package}" >> \ "${base_dir}/work/deletion-list" sed -i "/^${package} /d" "${base_dir}/work/build-list" ;; *) >&2 echo "unknown git diff mode '${mode}'" exit 1 ;; esac done # TODO: # Put the list in the proper build order. declare -A packages_built declare -A packages_needed while read -r package dummy repository; do PKGBUILD="$(find_pkgbuild "${package}" "${repository}")" if [ ! -r "${PKGBUILD}" ]; then echo "'${package}'" "'${repository}'" "'${PKGBUILD}'" exit 1 fi content="$( sed 's|#.*$||;s|^\s\+||;s|\s\+$||;/^$/d' "${PKGBUILD}" | \ sed ' :begin; $!N; s@^\([^=]\+=([^)]*\)\n\(.*\)$@\1 \2@; tbegin; P; D ' )" packages_built["${package}"]="$( echo "${content}" | \ grep '^provides=\|^pkgname=' | \ sed 's|^[^=]\+=||; s|=.*$||' | \ tr "' ()\"" '\n' | \ sort -u | \ sed '/^$/d' )" packages_needed["${package}"]="$( ( echo "${content}" | \ grep '^depends=\|^makedepends=' | \ sed 's|^[^=]\+=||; s|>\?=.*$||' | \ tr "' ()\"" '\n' | \ sort -u | \ sed '/^$/d' echo "${packages_built["${package}"]}" | \ sed 'p' ) | \ sort | \ uniq -u )" done < "${base_dir}/work/build-list" rm -f "${base_dir}/work/build-list.new" while [ ${#packages_built[@]} -gt 0 ]; do found_something=false for package in "${!packages_built[@]}"; do if [ -z "$( ( echo "${packages_needed["${package}"]}" echo "${!packages_built[@]}" | \ tr ' ' '\n' ) | \ sort | \ uniq -d )" ]; then grep "^${package} " "${base_dir}/work/build-list" >> \ "${base_dir}/work/build-list.new" unset packages_built["${package}"] unset packages_needed["${package}"] found_something=true fi done if ${found_something}; then continue fi >&2 echo 'uaagh: there seem to be cyclic dependencies - I give up.' >&2 echo "packages left: ${!packages_built[@]}" # TODO: Break circular dependencies exit 1 done mv "${base_dir}/work/build-list.new" "${base_dir}/work/build-list" # Write the current git revision numbers to files. for repo in "${!repo_paths[@]}"; do git -C "${repo_paths["${repo}"]}" rev-parse HEAD > \ "${base_dir}/work/${repo}.revision" done # Remove the lock file rm -f "${lock_file}"