# file : bpkg-util/package-archive.bash.in # license : MIT; see accompanying LICENSE file # Utility functions useful for managing package archives. if [ "$bpkg_util_package_archive" ]; then return 0 else bpkg_util_package_archive=true fi @import libbutl.bash/manifest-parser@ # We expect the user to set the bpkg_util_bpkg variable to the bpkg program # path. # if [ ! -v bpkg_util_bpkg ]; then echo "error: variable bpkg_util_bpkg is not set" >&2 exit 1 fi # Extract the package information from a package archive and print it to # stdout in the '\n\n\n' form, where the project field # is empty if the project value is not specified in the manifest. # # Note that, in particular, it verifies that the archive file name matches the # package name and version. # function bpkg_util_pkg_verify_archive () # { # We can't use the process substitution for input redirect here, since such # a process failure is not trapped. Thus, read the manifest file into a # variable and parse it afterwards, which is probably ok since package # manifests are normally not too big. # # Note that alternatively we could use the process substitution for running # bpkg, treat the name value absence as indication of a failure, and exit # with non-zero status if that's the case. Feels a bit hackish though. # local m m="$("$bpkg_util_bpkg" pkg-verify --manifest "$1")" butl_manifest_parser_start <<<"$m" local name= local version= local project= local n v while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do case "$n" in name) name="$v" ;; version) version="$v" ;; project) project="$v" ;; esac done butl_manifest_parser_finish echo "$name" echo "$version" echo "$project" } # Search for package archives in a directory using the package name and # version pattern and printing their paths one per line to stdout. If the # version argument is '*', then print archives for all package versions. # Otherwise if the version contains the trailing '*', then print archives for # all revisions of the specified version and for the exact version otherwise. # For example: # # bpkg_util_pkg_find_archives foo '*' dir/ # bpkg_util_pkg_find_archives foo '1.0*' dir/ # bpkg_util_pkg_find_archives foo '1.0' dir/ # # Note that the resulting archive paths include the specified directory as a # prefix. # function bpkg_util_pkg_find_archives () # { local nam="$1" local ver="$2" local dir="$3" local r=() local f if [ -d "$dir" ]; then local vr # Version with the revision stripped, if search for revisions. local np # File name pattern for archives search. if [ "$ver" != "*" -a "${ver: -1}" == "*" ]; then # * vr="$(sed -n -re 's%^(\+?[^+]+)(\+[0-9]+)?\*$%\1%p' <<<"$ver")" np="$nam-$vr*.*" # foo-1.0*.*, etc. else # * or np="$nam-$ver.*" # foo-*.*, foo-1.0.*, etc. fi # Go through the potentially matching archives (for example, for 'foo' # '1.2.3+2*': foo-1.2.3.tar.gz, foo-1.2.3+1.tar.gz, foo-1.2.30.tar.gz, # etc) and return those which package name and version match properly. # while read f; do local p bpkg_util_pkg_verify_archive "$f" | readarray -t p local n="${p[0]}" local v="${p[1]}" if [[ "$n" == "$nam" && ( "$ver" == "*" || \ "$v" == "$ver" || \ ( -n "$vr" && "$v" =~ ^"$vr"(\+[0-9]+)?$ )) ]]; then r+=("$f") fi done < <(find "$dir" -type f -name "$np") fi for f in "${r[@]}"; do echo "$f" done } # Search for a package archive in a directory using a file name pattern. If # the archive is found, then print the package information to stdout in the # '\n\n\n\n' form, where the project field is # empty if the project value is not specified in the manifest. # # Note that if there are multiple archives matching the pattern, then it is # unspecified which one is picked. # function bpkg_util_pkg_find_archive () # { local pat="$1" local dir="$2" if [ -d "$dir" ]; then local f # We could probably use -print -quit but this is not portable (NetBSD # needs -exit instead of -quit). # f="$(find "$dir" -type f -name "$pat" | sed -n -e '1p')" if [ -n "$f" ]; then local p bpkg_util_pkg_verify_archive "$f" | readarray -t p echo "$f" echo "${p[0]}" echo "${p[1]}" echo "${p[2]}" return fi fi }