#!/bin/sh # contains functions used by more than one script # TODO: # mangle $arch in PKBUILDs to contain i486, i586, i686 # 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\)-[^/]\+/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 for repository in ${repo_names}; do if [ "${repository}" = "archlinux32" ]; then continue fi if [ -n "$( ( eval ls "$(printf '"${repo_paths__%s}"' "${repository}")/"*"/repos" | \ grep -v ':$' | \ sed 's|-[^-]\+$||' | \ sort -u echo "$1" ) | \ sort | \ uniq -d )" ]; 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}" if [ -e "${file_prefix}.builds" ] && \ [ -e "${file_prefix}.depends" ] && \ [ -e "${file_prefix}.needs" ] && \ [ -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 [ ! -f "${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' "${file_prefix}.SRCINFO" # extract "builds" = provides \cup pkgname grep "$(printf '^\\(\tprovides\\|pkgname\\) = ')" "${file_prefix}.SRCINFO" | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${file_prefix}.builds" # extract "packages" = pkgname grep '^pkgname = ' "${file_prefix}.SRCINFO" | \ cut -d= -f2 | \ sed 's|^\s\+||; s|[<>]$||' | \ sort -u > \ "${file_prefix}.packages" # extract "depends" = makedepends \cup checkdepends \cup depends ( 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" ) | \ sort | \ uniq -u > \ "${file_prefix}.needs" rm "${file_prefix}.SRCINFO" } # delete_old_metadata # delete old (=unneeded) meta data of packages delete_old_metadata() { ( ls -1 "${work_dir}/package-infos" | \ sed ' s|\.\([^.]\+\)\.\([^.]\+\)\.[^.]\+$| \1 \2| ' | \ sort -u ls -1 "${work_dir}/package-states" | \ sed ' s|\.\([^.]\+\)\.\([^.]\+\)\(\.[^.]\+\)\{2\}$| \1 \2| ' | \ sort -u | \ sed 'p' cut -d' ' -f1,2,3 "${work_dir}/build-list" | \ sed 'p' ) | \ sort | \ uniq -u | \ while read -r pkg rev mod_rev; do rm -f "${work_dir}/package-infos/${pkg}.${rev}.${mod_rev}".* 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 # print wether the specified package is an official package (print # nothing) or a community package (print 'community-') official_or_community() { if [ "$(repository_of_package "$1")" = 'community' ]; then echo 'community-' 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="$(find_repository_with_commit "${git_revision}")" local PKGBUILD local PKGBUILD_mod local content if [ -z "${git_repo}" ]; then return 1 fi find_pkgbuilds "${package}" "${repository}" "${git_repo}" "${git_revision}" "${mod_git_revision}" if [ -n "${PKGBUILD}" ]; then content="$( eval git -C "$(printf '"${repo_paths__%s}"' "${git_repo}")" 'archive "${git_revision}" -- "${PKGBUILD}"' | \ tar -Ox )" else unset content fi if [ -n "${PKGBUILD_mod}" ]; then content="$( printf '%s\n' \ "${content}" \ "$( git -C "${repo_paths__archlinux32}" archive "${mod_git_revision}" -- "${PKGBUILD_mod}" | \ tar -Ox )" )" fi bail_out() { err=$? recursively_umount_and_rm "${overlays_dir}" exit ${err} } overlays_dir="$(mktemp -d)" sudo mount -t tmpfs none "${overlays_dir}" || \ bail_out mkdir \ "${overlays_dir}/lower" \ "${overlays_dir}/upper" \ "${overlays_dir}/work" \ "${overlays_dir}/merged" echo "${content}" | \ sed '/^\$Id\$$/d' > \ "${overlays_dir}/lower/PKGBUILD" mkdir "${overlays_dir}/lower/etc" hexdump -n 16 -e '4/4 "%08x" 1 "\n"' /dev/urandom > \ "${overlays_dir}/lower/etc/machine-id" sudo mount -t overlay overlay -o lowerdir="${overlays_dir}/lower":"/",upperdir="${overlays_dir}/upper",workdir="${overlays_dir}/work" "${overlays_dir}/merged" || \ bail_out sudo systemd-nspawn -q \ -D "${overlays_dir}/merged" \ --register=no \ ${base_dir}/bin/mksrcinfo || \ bail_out sudo umount -l "${overlays_dir}/merged" || \ bail_out mv \ "${overlays_dir}/upper/.SRCINFO" \ "${output}" sudo umount -l "${overlays_dir}" || \ bail_out rmdir "${overlays_dir}" } # 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}" }