# Functions for parsing dependency field values # # Copyright (C) 2012, 2018, 2019 Patrick McDermott # # This file is part of opkbuild. # # opkbuild is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # opkbuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with opkbuild. If not, see . ## @brief Parse a single package dependency string ## @details \fBob_parse_dep\fP() parses package dependencies in the format ## \fIpkg:archqual (rel ver) [arches] \fP, where the components ## \fI:archqual\fP, \fI(rel ver)\fP, \fI[arches]\fP, and \fI\fP ## are optional. ## @option -P pkg_var The name of the variable in which to store the ## package name. ## @option -q archqual_var The name of the variable in which to store the ## architecture qualifier, if any. ## @option -r rel_var The name of the variable in which to store the ## relationship operator, if any. ## @option -v ver_var The name of the variable in which to store the ## version, if any. ## @option -A arches_var The name of the variable in which to store the ## architecture restrictions, if any. ## @option -l plats_var The name of the variable in which to store the ## platform restrictions, if any. ## @option -a host_arch The host architecture. If given, the dependency will ## only be printed on standard output if it applies to ## the given architecture. ## @option -p host_plat The host platform. If given, the dependency will ## only be printed on standard output if it applies to ## the given platform. ## @operand dep req The dependency to parse. ## @return Returns 0. ## @stdout If \fB-a\fP and \fB\p\fP aren't given, the entire dependency string ## is printed, with normalized formatting. If \fB-a\fP and/or \fB-p\fP ## are given and the dependency applies to their arguments, the ## dependency string is printed, except for the architecture (if ## \fB-a\fP given) and/or platform (if \fB-p\fP given) restrictions, ## with normalized formatting. Normalized formatting is a string of the ## format \fIpkg:archqual\ (rel\ ver)\ [arches]\ \fP. ## @pure maybe This function has side effects when used with any of the options ## \fB-P\fP, \fB-q\fP, \fB-r\fP, \fB-v\fP, \fB-A\fP, or \fB-l\fP. ob_parse_dep() { local opt= local pkg_var= local archqual_var= local rel_var= local ver_var= local arches_var= local plats_var= local host_arch= local host_plat= local dep= local dep_re= local pkg= local archqual= local rel= local ver= local arches= local plats= local comp= local comp_var= OPTIND=1 while getopts 'P:q:r:v:A:l:a:p:' opt; do case "${opt}" in P) pkg_var="${OPTARG}" if ! _ob_validate_var_name "${pkg_var}"; then _ob_abort fi ;; q) archqual_var="${OPTARG}" if ! _ob_validate_var_name "${archqual_var}" then _ob_abort fi ;; r) rel_var="${OPTARG}" if ! _ob_validate_var_name "${rel_var}"; then _ob_abort fi ;; v) ver_var="${OPTARG}" if ! _ob_validate_var_name "${ver_var}"; then _ob_abort fi ;; A) arches_var="${OPTARG}" if ! _ob_validate_var_name "${arches_var}"; then _ob_abort fi ;; l) plats_var="${OPTARG}" if ! _ob_validate_var_name "${plats_var}"; then _ob_abort fi ;; a) host_arch="${OPTARG}" ;; p) host_plat="${OPTARG}" ;; ?) _ob_abort ;; esac done shift $((${OPTIND} - 1)) dep="${1}" shift 1 || _ob_abort # pkg[:archqual] [(rel ver)] [\[arches\]] [] dep_re='s/^ *([^ \(\[<]+) *(\((<<|<=|=|>=|>>) *(.+)\))?' dep_re="${dep_re}"' *(\[(.+)\])? *(<(.+)>)? *$/\1\n\3\n\4\n\6\n\8/;' # BusyBox sed supports -r and (as of version 1.22.0) -E. dep="$(printf '%s\n' "${dep}" | sed -nr ' H; ${ g; s/[\t\n]/ /g; '"${dep_re}"' p; }; ')" { IFS=':' read pkg archqual read rel || : read ver || : read arches || : read plats || : } <<-EOF ${dep} EOF # Set the specified variables. for comp in pkg archqual rel ver arches plats; do comp_var="$(eval "printf '%s' \"\${${comp}_var}\"")" [ -z "${comp_var}" ] && continue eval "${comp_var}=\"\${${comp}}\"" done if [ -n "${host_arch}" ] && ! ob_arch_is_concerned \ "${host_arch}" "${arches}"; then return 0 fi if [ -n "${host_plat}" ] && ! ob_plat_is_concerned \ "${host_plat}" "${plats}"; then return 0 fi printf '%s' "${pkg}" [ -n "${archqual}" ] && printf ':%s' "${archqual}" [ -n "${ver}" ] && printf ' (%s %s)' "${rel}" "${ver}" [ -z "${host_arch}" ] && [ -n "${arches}" ] && \ printf ' [%s]' "${arches}" [ -z "${host_plat}" ] && [ -n "${plats}" ] && \ printf ' [%s]' "${plats}" printf '\n' return 0 } ## @brief Reduce dependencies to a given architecture and platform ## @details \fBob_reduce_deps\fP() reduces a list of dependencies to only those ## that apply to a given architecture and platform. A list is either a ## "normal" list or a "union" list. A normal list is an "AND" list ## composed of "OR" lists, which in turn are composed of simple ## dependencies. A union list is an AND list composed of only simple ## dependencies. That is, a normal list is of the form ## \fIdep\ |\ dep,\ dep\fP, and a union list is of the form ## \fIdep,\ dep\fP. The "Conflicts", "Provides", and "Replaces" ## package relationships are union lists. ## @option -a host_arch The architecture to which dependencies should be ## reduced. Required. ## @option -p host_plat The platform to which dependencies should be reduced. ## Required. ## @option -u - Treat \fIdeps\fP as a union list. ## @operand deps req The list of dependencies to reduce. ## @return Returns 0 on success. ## @stdout Prints the reduced list of dependencies. ## @pure yes This function has no side effects. ob_reduce_deps() { local opt= local host_arch= local host_plat= local deps= local dep_and= local dep_or= local dep_list= local dep_or_list= local dep= union='false' OPTIND=1 while getopts 'a:p:u' opt; do case "${opt}" in a) host_arch="${OPTARG}" ;; p) host_plat="${OPTARG}" ;; u) union='true' ;; ?) _ob_abort ;; esac done shift $((${OPTIND} - 1)) local deps="${1}" shift 1 || _ob_abort IFS=',' for dep_and in ${deps}; do unset IFS if ! ${union}; then IFS='|' dep_or_list= for dep_or in ${dep_and}; do unset IFS dep="$(ob_parse_dep -a "${host_arch}" \ -p "${host_plat}" -- "${dep_or}")" if [ -n "${dep}" ]; then if [ -n "${dep_or_list}" ]; then dep_or_list="${dep_or_list} | " fi dep_or_list="${dep_or_list}${dep}" fi done unset IFS if [ -n "${dep_or_list}" ]; then if [ -n "${dep_list}" ]; then dep_list="${dep_list}, " fi dep_list="${dep_list}${dep_or_list}" fi else dep="$(ob_parse_dep -a "${host_arch}" \ -p "${host_plat}" -- "${dep_and}")" if [ -n "${dep}" ]; then if [ -n "${dep_list}" ]; then dep_list="${dep_list}, " fi dep_list="${dep_list}${dep}" fi fi done unset IFS printf '%s' "${dep_list}" return 0 }