#!/bin/sh # contains functions used by more than one script # find_pkgbuilds package repository git_repository git_revision mod_git_revision # find the PKGBUILD and modification of $package from $repository # sets $PKGBUILD and $PKGBUILD_mod find_pkgbuilds() { local package="$1" local repository="$2" local git_repository="$3" local git_revision="$4" local mod_git_revision="$5" PKGBUILD="$( eval git -C "$(printf '"${repo_paths__%s}"' "${git_repository}")" 'archive "${git_revision}" -- "${package}/repos/"' 2> /dev/null | \ tar -t 2> /dev/null | \ grep "^$(str_to_regex "${package}/repos/${repository}")"'-.*/PKGBUILD$' | \ grep -v -- '-i686/PKGBUILD$' | \ grep -v -- '[-/]\(staging\|testing\|unstable\)-[^/]\+/PKGBUILD$' | \ sort | \ tail -n1 )" PKGBUILD_mod="$( git -C "${repo_paths__archlinux32}" archive "${mod_git_revision}" 2> /dev/null | \ tar -t "${repository}/${package}/PKGBUILD" 2> /dev/null )" || true if [ -z "${PKGBUILD}" ] && \ [ -z "${PKGBUILD_mod}" ]; then >&2 printf 'Neither PKGBUILD nor modification of PKGBUILD found for package "%s" from %s (%s), revisions %s and %s.\n' \ "${package}" \ "${repository}" \ "${git_repository}" \ "${git_revision}" \ "${mod_git_revision}" return 1 fi } # find_repository_with_commit commit # find the repository which has $commit find_repository_with_commit() { local repository for repository in ${repo_names}; do if [ "$(eval git -C "$(printf '"${repo_paths__%s}"' "${repository}")" cat-file -t '"$1"' 2> /dev/null)" = "commit" ]; then echo "${repository}" return 0 fi done >&2 printf 'find_repository_with_commit: Cannot find repository with commit "%s"\n' "$1" exit 1 } # find_git_repository_to_package_repository repository # find the git repository which tracks the package repository $repository find_git_repository_to_package_repository() { local repository local package_repository local repo_path package_repository="$1" if [ "$1" = 'build-support' ]; then echo 'packages' return 0 fi for repository in ${repo_names}; do if [ "${repository}" = "archlinux32" ]; then continue fi eval 'repo_path="${repo_paths__'"${repository}"'}"' if git -C "${repo_path}" archive "$(cat "${work_dir}/${repository}.revision")" -- | \ tar -t --wildcards '*/repos' | \ grep '^\([^/]\+/\)\{3\}PKGBUILD$' | \ cut -d/ -f3 | \ sed 's|-[^-]\+$||' | \ sort -u | \ grep -qxF "${package_repository}"; then echo "${repository}" return 0 fi done >&2 echo "can't find git repository with package repository '$1'" exit 1 } # package_locked_or_blocked package git_revision mod_git_revision repository # return if package - of given repository and revisions - is [locked or blocked] package_locked_or_blocked() { [ -f "${work_dir}/package-states/$1.$2.$3.$4.locked" ] || \ [ -f "${work_dir}/package-states/$1.$2.$3.$4.blocked" ] } # generate_package_metadata $package $git_revision $mod_git_revision $repository # or # generate_package_metadata $package.$git_revision.$mod_git_revision.$repository # generate the meta data files of a package (dependencies, built packages, ...) generate_package_metadata() { local package="$1" local git_revision="$2" local mod_git_revision="$3" local repository="$4" local file_prefix local file local PKGBUILD if [ $# -eq 1 ]; then # second form repository="${package##*.}" package="${package%.*}" mod_git_revision="${package##*.}" package="${package%.*}" git_revision="${package##*.}" package="${package%.*}" fi file_prefix="${work_dir}/package-infos/${package}.${git_revision}.${mod_git_revision}.${repository}" if [ -e "${file_prefix}.builds" ] && \ [ -e "${file_prefix}.depends" ] && \ [ -e "${file_prefix}.needs" ] && \ [ -e "${file_prefix}.groups" ] && \ [ -e "${file_prefix}.packages" ]; then return 0 fi if ! make_source_info "${package}" "${repository}" "${git_revision}" "${mod_git_revision}" "${file_prefix}.SRCINFO"; then echo "make_source_info failed." exit 1 fi if [ ! -s "${file_prefix}.SRCINFO" ]; then >&2 printf '"%s" not created by "make_source_info" - eh, what?' "${file_prefix}.SRCINFO" exit 1 fi # otherwise this just calls for trouble sed -i ' /^[^=]*=\s*$/d s/_i686\(\s*=\)/\1/ ' "${file_prefix}.SRCINFO" # extract "groups" = groups \cup provides grep "$(printf '^\t\\(groups\\|provides\\) = ')" "${file_prefix}.SRCINFO" | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${file_prefix}.groups" # extract "packages" = pkgname grep '^pkgname = ' "${file_prefix}.SRCINFO" | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${file_prefix}.packages" # extract "builds" = provides \cup pkgname \cup groups cat "${file_prefix}.groups" "${file_prefix}.packages" | \ sort -u > \ "${file_prefix}.builds" # extract "depends" = makedepends \cup checkdepends \cup depends \cup \{ base, base-devel \} ( printf 'all_depend = %s\n' 'base' 'base-devel' sed -n "$(printf '/^pkgname = /q;/^\tdepends = /p')" "${file_prefix}.SRCINFO" grep "$(printf '^\t\\(makedepends\\|checkdepends\\) = ')" "${file_prefix}.SRCINFO" ) | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${file_prefix}.depends" # extract "needs" = "depends" \setminus "builds" ( cat "${file_prefix}.depends" sed 'p' "${file_prefix}.builds" printf '%s\n' 'base-devel' 'base-devel' ) | \ sort | \ uniq -u > \ "${file_prefix}.needs" rm "${file_prefix}.SRCINFO" } # delete_old_metadata # delete old (=unneeded) meta data of packages delete_old_metadata() { local current_metadata current_metadata="$( ls "${work_dir}/package-infos" | \ sed ' s|\.[^.]\+$|| s|\.\([^.]\+\)\.\([^.]\+\)\.\([^.]\+\)$| \1 \2 \3| ' | \ sort -u )" ( # what we have echo "${current_metadata}" # package-states should stay ls -1 "${work_dir}/package-states" | \ sed ' s|\.\([^.]\+\)\.\([^.]\+\)\(\.[^.]\+\)\.\([^.]\+\)$| \1 \2 \3| ' | \ sort -u | \ sed 'p' # build-list items should stay sed 'p' "${work_dir}/build-list" tmp_dir="$(mktemp -d)" trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT echo "${current_metadata}" | \ sort -k1,1 > \ "${tmp_dir}/current-metadata" # the newest of the following should stay: ( # deletion-list items cat "${work_dir}/deletion-list" # all packages in the repos for repo in ${repo_names}; do eval 'git -C "${repo_paths__'"${repo}"'}" archive '"$(cat "${work_dir}/${repo}.revision")" | \ tar -t | \ sed ' s|/$|| /\//d ' done ) | \ sort -u | \ join -j 1 -o 2.2,2.3,2.4,2.1 - "${tmp_dir}/current-metadata" | \ sort -k4,4 > \ "${tmp_dir}/find-newest-revisions" uniq -uf3 < \ "${tmp_dir}/find-newest-revisions" | \ awk '{print $4 " " $1 " " $2 " " $3}' | \ sed 'p' uniq -Df3 < \ "${tmp_dir}/find-newest-revisions" | \ uniq --group=append -f3 | \ ( revs='' mod_revs='' opkg='' orepo='' while read -r rev mod_rev repo pkg; do if [ -z "${rev}" ] && \ [ -z "${mod_rev}" ] && \ [ -z "${repo}" ] && \ [ -z "${pkg}" ]; then printf '%s %s %s %s\n' \ "$( printf '%s\n' ${revs} | \ find_newest_of_git_revisions )" \ "$( printf '%s\n' ${mod_revs} | \ find_newest_of_git_revisions )" \ "${orepo}" \ "${opkg}" revs='' mod_revs='' orepo='' opkg='' continue fi revs="$( printf '%s\n' ${revs} ${rev} | \ sort -u )" mod_revs="$( printf '%s\n' ${mod_revs} ${mod_rev} | \ sort -u )" orepo="${repo}" opkg="${pkg}" done ) | \ awk '{print $4 " " $1 " " $2 " " $3}' | \ sed 'p' ) | \ sort | \ uniq -u | \ while read -r pkg rev mod_rev repo; do rm -f "${work_dir}/package-infos/${pkg}.${rev}.${mod_rev}.${repo}."* done } # repository_of_package $package.$repo_revision.$mod_repo_revision.$repository # print which (stable) repository a package belongs to repository_of_package() { local package="$1" local repository="${package##*.}" package="${package%.*}" local a32_rev="${package##*.}" package="${package%.*.*}" case "${repository}" in 'multilib') if git -C "${repo_paths__archlinux32}" archive --format=tar "${a32_rev}" -- 'extra-from-multilib' | \ tar -Ox | \ grep -qFx "${package%.*.*.*}"; then echo 'extra' else echo 'community' fi ;; *) echo "${repository}" esac } # official_or_community $package.$repo_revision.$mod_repo_revision.$repository $ending # print wether the specified package is an official package (print # $ending) or a community package (print 'community-$ending') or a # build-suppor package (print 'build-support') official_or_community() { local prepo prepo="$(repository_of_package "$1")" if [ "${prepo}" = 'community' ]; then echo 'community-'"$2" elif [ "${prepo}" = 'build-support' ]; then echo 'build-support' else echo "$2" fi } # ls_master_mirror $path # list content of $path on the master mirror (via rsync) ls_master_mirror() { local path="$1" ${master_mirror_rsync_command} \ "${master_mirror_rsync_directory}/${path}/" | \ grep -v '\s\.$' | \ awk '{print $5}' } # remove_old_package_versions $directory $package_file # removes all other versions of $package_file in $directory on the master mirror remove_old_package_versions() { local directory="$1" local package="$2" local pkgname="${package%-*-*-*.pkg.tar.xz}" ${master_mirror_rsync_command} \ --recursive \ --delete \ $( \ ls_master_mirror "${directory}" | \ grep "^$(str_to_regex "${pkgname}")\(-[^-]\+\)\{3\}\.pkg\.tar\.xz\(\.sig\)\?\$" | \ grep -v "^$(str_to_regex "${package}")\(\.sig\)\?\$" | \ sed 's|^|--include=|' ) \ '--exclude=*' \ ./ \ "${master_mirror_rsync_directory}/${directory}/" } # wait_some_time $minimum $diff # wait between minimum and minimum+diff seconds (diff defaults to 30) wait_some_time() { local minimum=$1 local diff=$2 local random if [ -z "${diff}" ]; then diff=30 fi random="$( dd if='/dev/urandom' count=1 2> /dev/null | \ cksum | \ cut -d' ' -f1 )" sleep $((${minimum} + ${random} % ${diff})) } # str_to_regex $string # escape dots for use in regex str_to_regex() { echo "$1" | \ sed 's|\.|\\.|g' } # make_source_info $package $repository $git_revision $mod_git_revision $output # create .SRCINFO from PKGBUILD within git repositories, output to $output make_source_info() { local package="$1" local repository="$2" local git_revision="$3" local mod_git_revision="$4" local output="$5" local git_repo local PKGBUILD local PKGBUILD_mod git_repo="$(find_repository_with_commit "${git_revision}")" if [ -z "${git_repo}" ]; then return 1 fi find_pkgbuilds "${package}" "${repository}" "${git_repo}" "${git_revision}" "${mod_git_revision}" ( tmp_dir="$(mktemp -d "${work_dir}/tmp.XXXXXX")" trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT extract_source_directory "${git_repo}" "${git_revision}" "${mod_git_revision}" "${tmp_dir}" ( cd "${tmp_dir}" makepkg --printsrcinfo ) > \ "${output}" ) } # recursively_umount_and_rm $dir # umount all mountpoints in $dir which are also in $dir's # filesystem, possibly also $dir itself and then # rm -rf --one-file-system $dir recursively_umount_and_rm() { local dir="$1" if [ -z "${dir}" ]; then >&2 echo 'ERROR: recursively_umount_and_rm requires an argument' exit 42 fi find "${dir}" \ -xdev -depth -type d \ -exec 'mountpoint' '-q' '{}' ';' \ -exec 'sudo' 'umount' '-l' '{}' ';' rm -rf --one-file-system "${dir}" } # insert_break_loops_orders $file # inserts the correct number of 'break_loops' order into $file insert_break_loops_orders() { local file="$1" local looped_packages local line looped_packages="$( ls "${work_dir}/build-list.loops" | \ grep '^loop_[0-9]\+$' | \ sed "s|^|${work_dir}/build-list.loops/|" | \ xargs -r cat | \ sort -u | \ wc -l )" ( while read -r line; do if [ "${line}" = 'break_loops' ]; then if [ ${looped_packages} -eq 0 ]; then continue fi looped_packages=$((${looped_packages}-1)) fi printf '%s\n' "${line}" done < \ "${file}" while [ ${looped_packages} -gt 0 ]; do looped_packages=$((${looped_packages}-1)) echo 'break_loops' done ) | \ sponge "${file}" } # append_architectures $PKGBUILD # mangle $arch in PKBUILDs to contain i486, i586, i686 append_architectures() { local PKGBUILD="$1" sed -i '/^arch=(/s/(/(i686 /' "${PKGBUILD}" } # find_newest_of_git_revisions # find newest git revision of the ones provided at stdin # (assuming linear history) find_newest_of_git_revisions() { local revisions local repo revisions="$(cat)" if [ $( echo "${revisions}" | \ wc -l ) -eq 1 ]; then echo "${revisions}" return fi repo="$( find_repository_with_commit \ "$( echo "${revisions}" | \ grep -xm1 '[0-9a-f]\{40\}' )" )" eval 'repo="${repo_paths__'"${repo}"'}"' echo "${revisions}" | \ xargs -rn1 git -C "${repo}" rev-parse | \ ( newest='' while read -r current; do if [ -z "${newest}" ] || \ git -C "${repo}" merge-base --is-ancestor "${newest}" "${current}"; then newest="${current}" fi done echo "${newest}" ) } # find_package_repository_to_package $package $git_repository # find the package repository a package from a given git repository # belongs to find_package_repository_to_package() { local package="$1" local git_repository="$2" local repo_path local repo eval 'repo_path="${repo_paths__'"${git_repository}"'}"' repo="$( git -C "${repo_path}" archive "$(cat "${work_dir}/${git_repository}.revision")" -- "${package}/repos" 2> /dev/null | \ tar -t | \ cut -d/ -f3 | \ grep -vxF '' | \ grep -v 'staging\|testing\|-unstable' | \ grep -v -- '-i686$' | \ sed 's|-[^-]\+$||' | \ sort -u )" if [ -z "${repo}" ]; then return 1 fi if [ "$( echo "${repo}" | \ wc -l )" -ne 1 ]; then return 1 fi echo "${repo}" } # extract_source_directory $git_repo $rev $mod_rev $output # extract files found in the svn/git source directories # $PKGBUILD and $PKGBUILD_mod are expected to be set correctly extract_source_directory() { local git_repo="$1" local rev="$2" local mod_rev="$3" local output="$4" if [ -n "${PKGBUILD}" ]; then eval 'git -C "${repo_paths__'"${git_repo}"'}" archive "${rev}" -- "${PKGBUILD%/*}"' | \ tar -x --strip-components=3 -C "${output}" fi if [ -n "${PKGBUILD_mod}" ]; then git -C "${repo_paths__archlinux32}" archive "${mod_rev}" -- "${PKGBUILD_mod%/*}" | \ tar -x --overwrite --exclude 'PKGBUILD' --strip-components=2 -C "${output}" 2> /dev/null || \ true git -C "${repo_paths__archlinux32}" archive "${mod_rev}" -- "${PKGBUILD_mod}" | \ tar -Ox "${PKGBUILD_mod}" >> \ "${output}/PKGBUILD" append_architectures "${output}/PKGBUILD" fi sed -i '/^\$Id\$$/d' "${output}/PKGBUILD" } # find_dependencies_on_build_list $package $git_revision $mod_git_revision $repository # return a list of packages on the build list which are dependencies of the given package find_dependencies_on_build_list() { local package="$1" local git_revision="$2" local mod_git_revision="$3" local repository="$4" generate_package_metadata "${package}" "${git_revision}" "${mod_git_revision}" "${repository}" ( cat "${work_dir}/package-infos/${package}.${git_revision}.${mod_git_revision}.${repository}.needs" grep -vxF 'break_loops' "${work_dir}/build-list" | \ awk '{print $1 "." $2 "." $3 "." $4}' | \ sed " s|^|${work_dir}/package-infos/| s|\$|\.builds| " | \ xargs -r cat | \ sort -u ) | \ sort | \ uniq -d }