#!/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 # TODO: # include repository of package customizations . "${0%/*}/../conf/default.conf" # find the PKGBUILD of a given package in a given repository # TODO: # _properly_ 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 -- '-i686/PKGBUILD$' | \ 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 "${work_dir}/${repo}.revision" 2> /dev/null || \ echo NONE )" git -C "${repo_paths["${repo}"]}" rev-parse HEAD > \ "${work_dir}/${repo}.revision.new" done echo 'Check modified packages from the last update, and put them to the build list.' # 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. cp "${work_dir}/build-list"{,.new} cp "${work_dir}/deletion-list"{,.new} ( for repo in "${!repo_paths[@]}"; do current_HEAD="$(cat "${work_dir}/${repo}.revision.new")" ( if [ "${old_repo_revisions["${repo}"]}" == "NONE" ]; then git -C "${repo_paths["${repo}"]}" archive --format=tar HEAD | \ tar -t | \ sed 's|^|A\t|' else git -C "${repo_paths["${repo}"]}" diff --name-status "${old_repo_revisions["${repo}"]}" HEAD fi ) | \ grep '^.\s[^/]\+/repos/[^/]\+/PKGBUILD$' | \ grep -v -- '-i686/PKGBUILD$' | \ sed 's|^\(.\)\t\([^/]\+\)/repos/\([^/]\+\)-[^/-]\+/PKGBUILD$|\1 \2 '"${current_HEAD}"' \3|' | \ grep -v '\(staging\|testing\)$' done | \ sort -u sed "s|^\(.*\)\$|D \1 $(cat "${work_dir}/archlinux32.revision.new") archlinux32|" "${repo_paths["archlinux32"]}/blacklist" ) | \ while read -r mode package git_revision repository; do case "${mode}" in "A"|"M") sed -i "/^${package} /d" "${work_dir}/build-list" echo "${package} ${git_revision} ${repository}" >> \ "${work_dir}/build-list.new" sed -i "/^${package}\$/d" "${work_dir}/deletion-list.new" ;; "D") echo "${package}" >> \ "${work_dir}/deletion-list.new" sed -i "/^${package} /d" "${work_dir}/build-list.new" ;; *) >&2 echo "unknown git diff mode '${mode}'" exit 1 ;; esac done echo 'Extract dependencies of packages.' # Put the list in the proper build order. # First, we extract the dependencies of each package. # TODO: # package modifications need to be included here mkdir -p "${work_dir}/package-infos" rm -f "${work_dir}/build-order" touch "${work_dir}/build-order" while read -r package git_rev repository; do PKGBUILD="$(find_pkgbuild "${package}" "${repository}")" if [ ! -r "${PKGBUILD}" ]; then echo "can't find PKGBUILD to package '${package}' from repository '${repository}': '${PKGBUILD}'" exit 1 fi ls -1 "${work_dir}/package-infos" | \ grep "^${package}"'\.[0-9a-f]\{40\}\.\(builds\|needs\)$' | \ grep -v "^${package}\.${git_rev}"'\.\(builds\|needs\)$' | \ while read file; do echo rm "${work_dir}/package-infos/${file}" done if [ ! -e "${work_dir}/package-infos/${package}.${git_rev}.builds" ] || \ [ ! -e "${work_dir}/package-infos/${package}.${git_rev}.needs" ]; then ( cd "${PKGBUILD%/*}" mksrcinfo -o "${work_dir}/package-infos/${package}.${git_rev}.SRCINFO" ) grep '^\('$'\t''provides\|pkgname\) = ' "${work_dir}/package-infos/${package}.${git_rev}.SRCINFO" | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${work_dir}/package-infos/${package}.${git_rev}.builds" ( ( sed -n '/^pkgname = /q;/^'$'\t''depends = /p' "${work_dir}/package-infos/${package}.${git_rev}.SRCINFO" grep '^'$'\t''\(makedepends\|checkdepends\) = ' "${work_dir}/package-infos/${package}.${git_rev}.SRCINFO" ) | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u cat "${work_dir}/package-infos/${package}.${git_rev}.builds" | \ sed 'p' ) | \ sort | \ uniq -u > \ "${work_dir}/package-infos/${package}.${git_rev}.needs" rm "${work_dir}/package-infos/${package}.${git_rev}.SRCINFO" fi while read target; do echo "${package} ${target}" >> \ "${work_dir}/build-order" done < "${work_dir}/package-infos/${package}.${git_rev}.builds" while read dependency; do echo "${dependency} ${package}" >> \ "${work_dir}/build-order" done < "${work_dir}/package-infos/${package}.${git_rev}.needs" done < "${work_dir}/build-list.new" echo 'Now actually sort it.' ( tsort "${work_dir}/build-order" 2> "${work_dir}/tsort.error" | \ nl -ba | \ awk '{print $1 " not-git whatever " $2}' awk '{print "0 " $2 " " $3 " " $1}' < \ "${work_dir}/build-list.new" ) | \ sort -k4,4 -k1nr | \ uniq -f3 -D | \ sed '/^0 /d;N;s|\n| |' | \ sort -k1n,1 | \ awk '{print $4 " " $6 " " $7}' > \ "${work_dir}/build-list.new.new" if [ -s "${work_dir}/tsort.error" ]; then >&2 echo 'WARNING: There is a dependency cycle!' >&2 cat "${work_dir}/tsort.error" >&2 echo >&2 echo 'I will continue anyway.' else rm "${work_dir}/tsort.error" fi # Move the .new-files to the actual files ( echo "build-list.new" "build-list" "deletion-list" echo "${!repo_paths[@]}" | \ sed 's@\( \|$\)@.revision\1@g' ) | \ tr ' ' '\n' | \ while read -r file; do mv "${work_dir}/${file}.new" "${work_dir}/${file}" done # Remove the lock file rm -f "${lock_file}"