mirror of
				https://github.com/flatcar/scripts.git
				synced 2025-10-31 00:01:03 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1178 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			1178 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| #!/bin/bash
 | |
| 
 | |
| # This file implements parsing the md5-metadata cache files and
 | |
| # accessing the parsed results. Not the entirety of the cache file is
 | |
| # parsed, only the parts that were needed at the time of writing
 | |
| # it. So currently the exposed parts of parsed cache files are EAPI,
 | |
| # IUSE, KEYWORDS, LICENSE, {B,R,P,I,}DEPEND and _eclasses_. The
 | |
| # _eclasses_ part discards the checksums, though, so only names are
 | |
| # available.
 | |
| 
 | |
| if [[ -z ${__MD5_CACHE_LIB_SH_INCLUDED__:-} ]]; then
 | |
| __MD5_CACHE_LIB_SH_INCLUDED__=x
 | |
| 
 | |
| source "$(dirname "${BASH_SOURCE[0]}")/util.sh"
 | |
| source "${PKG_AUTO_IMPL_DIR}/debug.sh"
 | |
| source "${PKG_AUTO_IMPL_DIR}/gentoo_ver.sh"
 | |
| 
 | |
| #
 | |
| # Cache file
 | |
| #
 | |
| 
 | |
| # Indices to access fields of the cache file:
 | |
| # PCF_EAPI_IDX     - a string/number describing EAPI
 | |
| # PCF_KEYWORDS_IDX - a name of an array containing keyword objects
 | |
| # PCF_IUSE_IDX     - a name of an array containing iuse objects
 | |
| # PCF_BDEPEND_IDX  - a name of a group object with build dependencies
 | |
| # PCF_DEPEND_IDX   - a name of a group object with dependencies
 | |
| # PCF_IDEPEND_IDX  - a name of a group object with install dependencies
 | |
| # PCF_PDEPEND_IDX  - a name of a group object with post dependencies
 | |
| # PCF_RDEPEND_IDX  - a name of a group object with runtime dependencies
 | |
| # PCF_LICENSE_IDX  - a name of a group object with licenses
 | |
| # PCF_ECLASSES_IDX - a name of an array with used eclasses
 | |
| declare -gri PCF_EAPI_IDX=0 PCF_KEYWORDS_IDX=1 PCF_IUSE_IDX=2 PCF_BDEPEND_IDX=3 PCF_DEPEND_IDX=4 PCF_IDEPEND_IDX=5 PCF_PDEPEND_IDX=6 PCF_RDEPEND_IDX=7 PCF_LICENSE_IDX=8 PCF_ECLASSES_IDX=9
 | |
| 
 | |
| # Declares empty cache files. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function cache_file_declare() {
 | |
|     struct_declare -ga "${@}" "( '0' 'EMPTY_ARRAY' 'EMPTY_ARRAY' 'EMPTY_GROUP' 'EMPTY_GROUP' 'EMPTY_GROUP' 'EMPTY_GROUP' 'EMPTY_GROUP' 'EMPTY_GROUP' 'EMPTY_ARRAY' )"
 | |
| }
 | |
| 
 | |
| # Unsets cache files, can take several names, just like unset.
 | |
| function cache_file_unset() {
 | |
|     local name
 | |
|     for name; do
 | |
|         local -n cache_file_ref=${name}
 | |
| 
 | |
|         __mcl_unset_array "${cache_file_ref[PCF_KEYWORDS_IDX]}" kw_unset
 | |
|         __mcl_unset_array "${cache_file_ref[PCF_IUSE_IDX]}" iuse_unset
 | |
|         __mcl_unset_array "${cache_file_ref[PCF_ECLASSES_IDX]}" unset
 | |
| 
 | |
|         group_unset \
 | |
|             "${cache_file_ref[PCF_BDEPEND_IDX]}" \
 | |
|             "${cache_file_ref[PCF_DEPEND_IDX]}" \
 | |
|             "${cache_file_ref[PCF_IDEPEND_IDX]}" \
 | |
|             "${cache_file_ref[PCF_PDEPEND_IDX]}" \
 | |
|             "${cache_file_ref[PCF_RDEPEND_IDX]}" \
 | |
|             "${cache_file_ref[PCF_LICENSE_IDX]}"
 | |
| 
 | |
|         unset -n cache_file_ref
 | |
|     done
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Parses a cache file under the passed path.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - cache file
 | |
| # 2 - path to the cache file
 | |
| function parse_cache_file() {
 | |
|     local -n cache_file_ref=${1}; shift
 | |
|     local path=${1}; shift
 | |
|     # rest are architectures
 | |
| 
 | |
|     if pkg_debug_enabled; then
 | |
|         local -a file_lines
 | |
|         mapfile -t file_lines <"${path}"
 | |
|         pkg_debug_print_lines "parsing ${path@Q}" "${file_lines[@]}"
 | |
|         unset file_lines
 | |
|     fi
 | |
| 
 | |
|     local -n pkg_eapi_ref='cache_file_ref[PCF_EAPI_IDX]'
 | |
|     local -n pkg_keywords_ref='cache_file_ref[PCF_KEYWORDS_IDX]'
 | |
|     local -n pkg_iuse_ref='cache_file_ref[PCF_IUSE_IDX]'
 | |
|     local -n pkg_bdepend_group_name_ref='cache_file_ref[PCF_BDEPEND_IDX]'
 | |
|     local -n pkg_depend_group_name_ref='cache_file_ref[PCF_DEPEND_IDX]'
 | |
|     local -n pkg_idepend_group_name_ref='cache_file_ref[PCF_IDEPEND_IDX]'
 | |
|     local -n pkg_pdepend_group_name_ref='cache_file_ref[PCF_PDEPEND_IDX]'
 | |
|     local -n pkg_rdepend_group_name_ref='cache_file_ref[PCF_RDEPEND_IDX]'
 | |
|     local -n pkg_license_group_name_ref='cache_file_ref[PCF_LICENSE_IDX]'
 | |
|     local -n pkg_eclasses_ref='cache_file_ref[PCF_ECLASSES_IDX]'
 | |
| 
 | |
|     local l key
 | |
|     while read -r l; do
 | |
|         key=${l%%=*}
 | |
|         pkg_debug "parsing ${key@Q}"
 | |
|         case ${key} in
 | |
|             'EAPI')
 | |
|                 pkg_eapi_ref=${l#*=}
 | |
|                 pkg_debug "EAPI: ${pkg_eapi_ref}"
 | |
|                 ;;
 | |
|             'KEYWORDS')
 | |
|                 __mcl_parse_keywords "${l#*=}" pkg_keywords_ref "${@}"
 | |
|                 ;;
 | |
|             'IUSE')
 | |
|                 __mcl_parse_iuse "${l#*=}" pkg_iuse_ref
 | |
|                 ;;
 | |
|             'BDEPEND')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_DEPEND}" "${l#*=}" pkg_bdepend_group_name_ref
 | |
|                 ;;
 | |
|             'DEPEND')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_DEPEND}" "${l#*=}" pkg_depend_group_name_ref
 | |
|                 ;;
 | |
|             'IDEPEND')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_DEPEND}" "${l#*=}" pkg_idepend_group_name_ref
 | |
|                 ;;
 | |
|             'PDEPEND')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_DEPEND}" "${l#*=}" pkg_pdepend_group_name_ref
 | |
|                 ;;
 | |
|             'RDEPEND')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_DEPEND}" "${l#*=}" pkg_rdepend_group_name_ref
 | |
|                 ;;
 | |
|             'LICENSE')
 | |
|                 __mcl_parse_dsf "${__MCL_DSF_LICENSE}" "${l#*=}" pkg_license_group_name_ref
 | |
|                 ;;
 | |
|             '_eclasses_')
 | |
|                 __mcl_parse_eclasses "${l#*=}" pkg_eclasses_ref
 | |
|                 ;;
 | |
|             *)
 | |
|                 pkg_debug "Not parsing ${key@Q}, ignoring"
 | |
|                 ;;
 | |
|         esac
 | |
|     done <"${path}"
 | |
| }
 | |
| 
 | |
| #
 | |
| # Use requirement (the part in the square brackets in the package
 | |
| # dependency specification).
 | |
| #
 | |
| 
 | |
| # Indices to access fields of the use requirement:
 | |
| # UR_NAME_IDX    - a use name
 | |
| # UR_MODE_IDX    - a string describing the mode: "+" is enabled, "="
 | |
| #                  is strict relation, "!=" reversed strict relation,
 | |
| #                  "?"  is "enabled if enabled in the ebuild", "!?" is
 | |
| #                  "disabled if disabled in the ebuild", and "-" is
 | |
| #                  disabled)
 | |
| # UR_PRETEND_IDX - a string describing pretend mode: it can be either
 | |
| #                  empty (no pretending if use is missing in the
 | |
| #                  package), "+" (pretend enabled if missing in the
 | |
| #                  package), or "-" (pretend disabled if missing in
 | |
| #                  the package)
 | |
| declare -gri UR_NAME_IDX=0 UR_MODE_IDX=1 UR_PRETEND_IDX=2
 | |
| 
 | |
| # Declares empty use requirements. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function ur_declare() {
 | |
|     struct_declare -ga "${@}" "( 'ITS_UNSET' '+' '' )"
 | |
| }
 | |
| 
 | |
| # Unsets use requirements, can take several names, just like unset.
 | |
| function ur_unset() {
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Copies use requirement into another.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - use requirement to be clobbered
 | |
| # 2 - the source use requirement
 | |
| function ur_copy() {
 | |
|     local -n to_clobber_ref=${1}; shift
 | |
|     local -n to_copy_ref=${1}; shift
 | |
| 
 | |
|     local -i idx
 | |
|     for idx in UR_NAME_IDX UR_MODE_IDX UR_PRETEND_IDX; do
 | |
|         to_clobber_ref[idx]=${to_copy_ref[idx]}
 | |
|     done
 | |
| }
 | |
| 
 | |
| # Stringifies use requirement.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - use requirement
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function ur_to_string() {
 | |
|     local -n ur_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     case ${ur_ref[UR_MODE_IDX]} in
 | |
|         '!'*)
 | |
|             str_ref='!'
 | |
|             ;;
 | |
|         '-'*)
 | |
|             str_ref='-'
 | |
|             ;;
 | |
|         *)
 | |
|             str_ref=''
 | |
|             ;;
 | |
|     esac
 | |
|     str_ref+=${ur_ref[UR_NAME_IDX]}
 | |
| 
 | |
|     local p=${ur_ref[UR_PRETEND_IDX]}
 | |
|     if [[ -n ${p} ]]; then
 | |
|         str_ref+="(${p})"
 | |
|     fi
 | |
|     case ${ur_ref[UR_MODE_IDX]} in
 | |
|         *'=')
 | |
|             str_ref+='='
 | |
|             ;;
 | |
|         *'?')
 | |
|             str_ref+='?'
 | |
|             ;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| #
 | |
| # Package depedency specification (or PDS)
 | |
| #
 | |
| 
 | |
| # Enumeration describing blocker mode of a package. Self-describing.
 | |
| declare -gri PDS_NO_BLOCK=0 PDS_WEAK_BLOCK=1 PDS_STRONG_BLOCK=2
 | |
| 
 | |
| # Indices to access fields of the package dependency specification:
 | |
| # PDS_BLOCKS_IDX - a number describing blocker mode (use PDS_NO_BLOCK,
 | |
| #                  PDS_WEAK_BLOCK and PDS_STRONG_BLOCK)
 | |
| # PDS_OP_IDX     - a string describing the relational operator, can be
 | |
| #                  empty or one of "<", "<=", "=", "=*", "~", ">=", or
 | |
| #                  ">" ("=*" is same as "=" with asterisk appended to
 | |
| #                  version)
 | |
| #                  if empty, the version will also be empty
 | |
| # PDS_NAME_IDX   - a qualified package name (so category/name)
 | |
| # PDS_VER_IDX    - a version of the package, may be empty (if so,
 | |
| #                  operator is also empty)
 | |
| # PDS_SLOT_IDX   - a string describing the slot operator, without the
 | |
| #                  preceding colon
 | |
| # PDS_UR_IDX     - a name of an array variable containing use
 | |
| #                  requirements
 | |
| declare -gri PDS_BLOCKS_IDX=0 PDS_OP_IDX=1 PDS_NAME_IDX=2 PDS_VER_IDX=3 PDS_SLOT_IDX=4 PDS_UR_IDX=5
 | |
| 
 | |
| # Declares empty package definition specifications. Can take flags
 | |
| # that are passed to declare. Usually only -r or -t make sense to
 | |
| # pass. Can take several names, just like declare. Takes no
 | |
| # initializers - this is hardcoded.
 | |
| function pds_declare() {
 | |
|     struct_declare -ga "${@}" "( ${PDS_NO_BLOCK@Q} '' 'ITS_UNSET' '' '' 'EMPTY_ARRAY' )"
 | |
| }
 | |
| 
 | |
| # Unsets package definition specifications, can take several names,
 | |
| # just like unset.
 | |
| function pds_unset() {
 | |
|     local use_reqs_name name
 | |
|     for name; do
 | |
|         local -n pds_ref=${name}
 | |
| 
 | |
|         use_reqs_name=${pds_ref[PDS_UR_IDX]}
 | |
|         local -n use_reqs_ref=${use_reqs_name}
 | |
|         ur_unset "${use_reqs_ref[@]}"
 | |
|         unset -n use_reqs_ref
 | |
|         if [[ ${use_reqs_name} != 'EMPTY_ARRAY' ]]; then
 | |
|             unset "${use_reqs_name}"
 | |
|         fi
 | |
| 
 | |
|         unset -n pds_ref
 | |
|     done
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Copies package dependency specification into another.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - package dependency specification to be clobbered
 | |
| # 2 - the source package dependency specification
 | |
| function pds_copy() {
 | |
|     local -n to_clobber_ref=${1}; shift
 | |
|     local -n to_copy_ref=${1}; shift
 | |
| 
 | |
|     local -i idx
 | |
|     for idx in PDS_BLOCKS_IDX PDS_OP_IDX PDS_NAME_IDX PDS_VER_IDX PDS_SLOT_IDX; do
 | |
|         to_clobber_ref[idx]=${to_copy_ref[idx]}
 | |
|     done
 | |
| 
 | |
|     if [[ ${to_copy_ref[PDS_UR_IDX]} = 'EMPTY_ARRAY' || ${#to_copy_ref[PDS_UR_IDX]} -eq 0 ]]; then
 | |
|         to_clobber_ref[PDS_UR_IDX]='EMPTY_ARRAY'
 | |
|     else
 | |
|         local pc_ur_array_name
 | |
|         gen_varname pc_ur_array_name
 | |
|         declare -ga "${pc_ur_array_name}=()"
 | |
| 
 | |
|         local -n urs_to_copy_ref=${to_copy_ref[PDS_UR_IDX]} urs_ref=${pc_ur_array_name}
 | |
|         local ur_name pc_ur_name
 | |
|         for ur_name in "${urs_to_copy_ref[@]}"; do
 | |
|             gen_varname pc_ur_name
 | |
|             ur_declare "${pc_ur_name}"
 | |
|             ur_copy "${pc_ur_name}" "${ur_name}"
 | |
|             urs_ref+=( "${pc_ur_name}" )
 | |
|         done
 | |
| 
 | |
|         to_clobber_ref[PDS_UR_IDX]=${pc_ur_array_name}
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # Adds use requirements to the package dependency specification.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - package dependency specification
 | |
| # @ - use requirements
 | |
| function pds_add_urs() {
 | |
|     local -n pds_ref=${1}; shift
 | |
|     # rest are use requirements
 | |
| 
 | |
|     if [[ ${#} -eq 0 ]]; then
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     local use_reqs_name=${pds_ref[PDS_UR_IDX]}
 | |
|     if [[ ${use_reqs_name} = 'EMPTY_ARRAY' ]]; then
 | |
|         local ura_name
 | |
|         gen_varname ura_name
 | |
|         declare -ga "${ura_name}=()"
 | |
|         pds_ref[PDS_UR_IDX]=${ura_name}
 | |
|         use_reqs_name=${ura_name}
 | |
|         unset ura_name
 | |
|     fi
 | |
| 
 | |
|     local -n use_reqs_ref=${use_reqs_name}
 | |
|     use_reqs_ref+=( "${@}" )
 | |
| }
 | |
| 
 | |
| # Stringifies package dependency specification.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - package dependency specification
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function pds_to_string() {
 | |
|     local -n pds_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     case ${pds_ref[PDS_BLOCKS_IDX]} in
 | |
|         "${PDS_NO_BLOCK}")
 | |
|             str_ref=''
 | |
|             ;;
 | |
|         "${PDS_WEAK_BLOCK}")
 | |
|             str_ref='!'
 | |
|             ;;
 | |
|         "${PDS_STRONG_BLOCK}")
 | |
|             str_ref='!!'
 | |
|             ;;
 | |
|     esac
 | |
|     local op=${pds_ref[PDS_OP_IDX]}
 | |
|     local v=${pds_ref[PDS_VER_IDX]}
 | |
|     if [[ ${op} = '=*' ]]; then
 | |
|         op='='
 | |
|         # if there's an op, then we assume version is not empty - so
 | |
|         # version will never end up being just *
 | |
|         v+='*'
 | |
|     fi
 | |
|     str_ref+=${op}${pds_ref[PDS_NAME_IDX]}
 | |
|     if [[ -n ${v} ]]; then
 | |
|         str_ref+=-${v}
 | |
|     fi
 | |
|     local s=${pds_ref[PDS_SLOT_IDX]}
 | |
|     if [[ -n ${s} ]]; then
 | |
|         str_ref+=:${s}
 | |
|     fi
 | |
|     local -n urs_ref=${pds_ref[PDS_UR_IDX]}
 | |
|     if [[ ${#urs_ref[@]} -gt 0 ]]; then
 | |
|         str_ref+='['
 | |
|         local u ur_str
 | |
|         for u in "${urs_ref[@]}"; do
 | |
|             ur_to_string "${u}" ur_str
 | |
|             str_ref+=${ur_str},
 | |
|         done
 | |
|         unset ur_str u
 | |
|         str_ref=${str_ref:0:$(( ${#str_ref} - 1 ))}']'
 | |
|     fi
 | |
| }
 | |
| 
 | |
| #
 | |
| # Group. A structure for describing {B,R,I,P,}DEPEND and LICENSE
 | |
| # fields. Contains items, which can be either package dependency
 | |
| # specifications or another groups. So it is a recursive structure.
 | |
| #
 | |
| 
 | |
| # Enumeration describing type of a group. Self-describing.
 | |
| declare -gri GROUP_ALL_OF=0 GROUP_ANY_OF=1
 | |
| 
 | |
| # Enumeration describing whether items in group are for enabled or disabled USE. Self-describing.
 | |
| declare -gri GROUP_USE_ENABLED=0 GROUP_USE_DISABLED=1
 | |
| 
 | |
| # Indices to access fields of the group:
 | |
| # GROUP_TYPE_IDX    - a number describing a type of the group (use
 | |
| #                     GROUP_ALL_OF and GROUP_ANY_OF)
 | |
| # GROUP_USE_IDX     - a USE name of the group, may be empty, and must
 | |
| #                     be empty for GROUP_ANY_OF groups
 | |
| # GROUP_ENABLED_IDX - a number describing mode of the USE, should be
 | |
| #                     ignored if USE name is empty (use
 | |
| #                     GROUP_USE_ENABLED and GROUP_USE_DISABLED)
 | |
| # GROUP_ITEMS_IDX   - a name of an array containing items
 | |
| declare -gri GROUP_TYPE_IDX=0 GROUP_USE_IDX=1 GROUP_ENABLED_IDX=2 GROUP_ITEMS_IDX=3
 | |
| 
 | |
| # Declares empty groups. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function group_declare() {
 | |
|     struct_declare -ga "${@}" "( ${GROUP_ALL_OF@Q} '' ${GROUP_USE_ENABLED@Q} 'EMPTY_ARRAY' )"
 | |
| }
 | |
| 
 | |
| # An empty readonly group.
 | |
| group_declare -r EMPTY_GROUP
 | |
| 
 | |
| # Unsets groups, can take several names, just like unset.
 | |
| function group_unset() {
 | |
|     local -a to_unset=()
 | |
|     local name items_name
 | |
|     for name; do
 | |
|         if [[ ${name} == 'EMPTY_GROUP' ]]; then
 | |
|             continue
 | |
|         fi
 | |
| 
 | |
|         local -n group_ref=${name}
 | |
|         items_name=${group_ref[GROUP_ITEMS_IDX]}
 | |
|         unset -n group_ref
 | |
| 
 | |
|         to_unset+=( "${name}" )
 | |
|         if [[ ${items_name} == 'EMPTY_ARRAY' ]]; then
 | |
|             continue
 | |
|         fi
 | |
|         to_unset+=( "${items_name}" )
 | |
| 
 | |
|         local -n items_ref=${items_name}
 | |
|         item_unset "${items_ref[@]}"
 | |
|         unset -n items_ref
 | |
|     done
 | |
|     unset "${to_unset[@]}"
 | |
| }
 | |
| 
 | |
| # Copies group into another.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - group to be clobbered
 | |
| # 2 - the source group
 | |
| function group_copy() {
 | |
|     local -n to_clobber_ref=${1}; shift
 | |
|     local -n to_copy_ref=${1}; shift
 | |
| 
 | |
|     local -i idx
 | |
|     for idx in GROUP_TYPE_IDX GROUP_USE_IDX GROUP_ENABLED_IDX; do
 | |
|         to_clobber_ref[idx]=${to_copy_ref[idx]}
 | |
|     done
 | |
| 
 | |
|     if [[ ${to_copy_ref[GROUP_ITEMS_IDX]} = 'EMPTY_ARRAY' || ${#to_copy_ref[GROUP_ITEMS_IDX]} -eq 0 ]]; then
 | |
|         to_clobber_ref[GROUP_ITEMS_IDX]='EMPTY_ARRAY'
 | |
|     else
 | |
|         local gc_items_name
 | |
|         gen_varname gc_items_name
 | |
|         declare -ga "${gc_items_name}=()"
 | |
| 
 | |
|         local -n items_to_copy_ref=${to_copy_ref[GROUP_ITEMS_IDX]}
 | |
|         local -n items_ref=${gc_items_name}
 | |
|         local item_name_to_copy gc_item_name
 | |
|         for item_name_to_copy in "${items_to_copy_ref[@]}"; do
 | |
|             gen_varname gc_item_name
 | |
|             item_declare "${gc_item_name}"
 | |
|             item_copy "${gc_item_name}" "${item_name_to_copy}"
 | |
|             items_ref+=( "${gc_item_name}" )
 | |
|         done
 | |
|         unset -n items_ref items_to_copy_ref
 | |
|         to_clobber_ref[GROUP_ITEMS_IDX]="${gc_items_name}"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # Adds items to the group.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - group
 | |
| # @ - items
 | |
| function group_add_items() {
 | |
|     local -n group_ref=${1}; shift
 | |
|     # rest are items to add
 | |
| 
 | |
|     if [[ ${#} -eq 0 ]]; then
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     local items_name=${group_ref[GROUP_ITEMS_IDX]}
 | |
|     if [[ ${items_name} = 'EMPTY_ARRAY' ]]; then
 | |
|         local ia_name
 | |
|         gen_varname ia_name
 | |
|         declare -ga "${ia_name}=()"
 | |
|         group_ref[GROUP_ITEMS_IDX]=${ia_name}
 | |
|         items_name=${ia_name}
 | |
|         unset ia_name
 | |
|     fi
 | |
| 
 | |
|     local -n items_ref=${items_name}
 | |
|     items_ref+=( "${@}" )
 | |
| }
 | |
| 
 | |
| # Stringifies group.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - group
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function group_to_string() {
 | |
|     local -n group_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     local t=${group_ref[GROUP_TYPE_IDX]}
 | |
|     case ${t} in
 | |
|         "${GROUP_ALL_OF}")
 | |
|             local u=${group_ref[GROUP_USE_IDX]}
 | |
|             if [[ -n ${u} ]]; then
 | |
|                 local e=${group_ref[GROUP_ENABLED_IDX]}
 | |
|                 case ${e} in
 | |
|                     "${GROUP_USE_ENABLED}")
 | |
|                         str_ref=''
 | |
|                         ;;
 | |
|                     "${GROUP_USE_DISABLED}")
 | |
|                         str_ref='!'
 | |
|                 esac
 | |
|                 unset e
 | |
|                 str_ref+="${u}? "
 | |
|             else
 | |
|                 str_ref=''
 | |
|             fi
 | |
|             unset u
 | |
|             ;;
 | |
|         "${GROUP_ANY_OF}")
 | |
|             str_ref='|| '
 | |
|             ;;
 | |
|     esac
 | |
| 
 | |
|     str_ref+='( '
 | |
|     local -n item_names_ref=${group_ref[GROUP_ITEMS_IDX]}
 | |
|     if [[ ${#item_names_ref[@]} -gt 0 ]]; then
 | |
|         local item_name item_str
 | |
|         for item_name in "${item_names_ref[@]}"; do
 | |
|             item_to_string "${item_name}" item_str
 | |
|             str_ref+="${item_str} "
 | |
|         done
 | |
|         unset item_str item_name
 | |
|     fi
 | |
|     str_ref+=')'
 | |
| }
 | |
| 
 | |
| #
 | |
| # Item. A string of <mode>:<data>. Mode is a single char and describes
 | |
| # the data.
 | |
| #
 | |
| # Modes:
 | |
| # "e" - empty, data is meaningless and should be just empty.
 | |
| # "g" - group, data is a group (a name of a variable containing a
 | |
| #       group)
 | |
| # "l" - license, data is a name of a license (plain string)
 | |
| # "p" - package dependency specification, data is pds (a name of a
 | |
| #       variable containing a pds)
 | |
| 
 | |
| # Declares empty items. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function item_declare() {
 | |
|     struct_declare -g "${@}" 'e:'
 | |
| }
 | |
| 
 | |
| # Unsets items, can take several names, just like unset.
 | |
| function item_unset() {
 | |
|     local name
 | |
|     for name; do
 | |
|         local -n item_ref=${name}
 | |
| 
 | |
|         case ${item_ref} in
 | |
|             e:*)
 | |
|                 # noop
 | |
|                 :
 | |
|                 ;;
 | |
|             g:*)
 | |
|                 group_unset "${item_ref:2}"
 | |
|                 ;;
 | |
|             l:*)
 | |
|                 # noop, license is just a string
 | |
|                 ;;
 | |
|             p:*)
 | |
|                 pds_unset "${item_ref:2}"
 | |
|                 ;;
 | |
|         esac
 | |
|         unset -n item_ref
 | |
|     done
 | |
| 
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Copies item into another.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - item to be clobbered
 | |
| # 2 - the source item
 | |
| function item_copy() {
 | |
|     local -n to_clobber_ref=${1}; shift
 | |
|     local -n to_copy_ref=${1}; shift
 | |
| 
 | |
|     local ic_name
 | |
|     local t=${to_copy_ref:0:1} v=${to_copy_ref:2}
 | |
|     case ${t} in
 | |
|         'e'|'l')
 | |
|             to_clobber_ref=${to_copy_ref}
 | |
|             ;;
 | |
|         'g')
 | |
|             gen_varname ic_name
 | |
|             group_declare "${ic_name}"
 | |
|             group_copy "${ic_name}" "${v}"
 | |
|             to_clobber_ref="g:${ic_name}"
 | |
|             ;;
 | |
|         'p')
 | |
|             gen_varname ic_name
 | |
|             pds_declare "${ic_name}"
 | |
|             pds_copy "${ic_name}" "${v}"
 | |
|             to_clobber_ref="p:${ic_name}"
 | |
|             ;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| # Stringifies item.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - item
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function item_to_string() {
 | |
|     local -n item_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     local t=${item_ref:0:1}
 | |
|     case ${t} in
 | |
|         e)
 | |
|             str_ref=''
 | |
|             ;;
 | |
|         g)
 | |
|             local group_name=${item_ref:2}
 | |
|             local group_str
 | |
|             group_to_string "${group_name}" group_str
 | |
|             str_ref=${group_str}
 | |
|             unset group_str group_name
 | |
|             ;;
 | |
|         l)
 | |
|             str_ref=${item_ref:2}
 | |
|             ;;
 | |
|         p)
 | |
|             local pds_name=${item_ref:2}
 | |
|             local pds_str=''
 | |
|             pds_to_string "${pds_name}" pds_str
 | |
|             str_ref=${pds_str}
 | |
|             unset pds_str pds_name
 | |
|             ;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| #
 | |
| # Keyword
 | |
| #
 | |
| # n - name of keyword
 | |
| # m - stable (amd64), unstable (~amd64), broken (-amd64), unknown (absent in KEYWORDS)
 | |
| 
 | |
| # Enumeration describing mode of the keyword.
 | |
| # KW_STABLE   - like "amd64"
 | |
| # KW_UNSTABLE - like "~amd64"
 | |
| # KW_BROKEN   - like "-amd64"
 | |
| # KW_UNKNOWN  - missing from KEYWORDS entirely
 | |
| declare -gri KW_STABLE=0 KW_UNSTABLE=1 KW_BROKEN=2 KW_UNKNOWN=3
 | |
| 
 | |
| # Indices to access fields of the keyword:
 | |
| # KW_NAME_IDX  - name of the architecture
 | |
| # KW_LEVEL_IDX - mode of the keyword (use KW_STABLE, KW_UNSTABLE,
 | |
| #                KW_BROKEN and KW_UNKNOWN)
 | |
| declare -gri KW_NAME_IDX=0 KW_LEVEL_IDX=1
 | |
| 
 | |
| # Declares empty keywords. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function kw_declare() {
 | |
|     struct_declare -ga "${@}" "( 'ITS_UNSET' ${KW_UNSTABLE@Q} )"
 | |
| }
 | |
| 
 | |
| # Unsets keywords, can take several names, just like unset.
 | |
| function kw_unset() {
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Stringifies keyword.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - keyword
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function kw_to_string() {
 | |
|     local -n kw_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     local n=${kw_ref[KW_NAME_IDX]}
 | |
|     case ${kw_ref[KW_LEVEL_IDX]} in
 | |
|         "${KW_STABLE}")
 | |
|             str_ref=${n}
 | |
|             ;;
 | |
|         "${KW_UNSTABLE}")
 | |
|             str_ref="~${n}"
 | |
|             ;;
 | |
|         "${KW_BROKEN}")
 | |
|             str_ref="-${n}"
 | |
|             ;;
 | |
|         "${KW_UNKNOWN}")
 | |
|             str_ref=''
 | |
|             ;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| #
 | |
| # IUSE
 | |
| #
 | |
| 
 | |
| # n - name of IUSE flag
 | |
| # m - 0 or 1 (0 disabled, 1 enabled)
 | |
| 
 | |
| # Enumeration describing mode of the IUSE. Self-describing.
 | |
| declare -gri IUSE_DISABLED=0 IUSE_ENABLED=1
 | |
| 
 | |
| # Indices to access fields of the IUSE:
 | |
| # IUSE_NAME_IDX - IUSE name
 | |
| # IUSE_MODE_IDX - IUSE mode (use IUSE_DISABLED and IUSE_ENABLED)
 | |
| declare -gri IUSE_NAME_IDX=0 IUSE_MODE_IDX=1
 | |
| 
 | |
| # Declares empty IUSEs. Can take flags that are passed to
 | |
| # declare. Usually only -r or -t make sense to pass. Can take several
 | |
| # names, just like declare. Takes no initializers - this is hardcoded.
 | |
| function iuse_declare() {
 | |
|     struct_declare -ga "${@}" "( 'ITS_UNSET' ${IUSE_DISABLED@Q} )"
 | |
| }
 | |
| 
 | |
| # Unsets IUSEs, can take several names, just like unset.
 | |
| function iuse_unset() {
 | |
|     unset "${@}"
 | |
| }
 | |
| 
 | |
| # Stringifies IUSE.
 | |
| #
 | |
| # Params:
 | |
| #
 | |
| # 1 - IUSE
 | |
| # 2 - name of a variable where the string form will be stored
 | |
| function iuse_to_string() {
 | |
|     local -n iuse_ref=${1}; shift
 | |
|     local -n str_ref=${1}; shift
 | |
| 
 | |
|     case ${iuse_ref[IUSE_MODE_IDX]} in
 | |
|         "${IUSE_ENABLED}")
 | |
|             str_ref='+'
 | |
|             ;;
 | |
|         "${IUSE_DISABLED}")
 | |
|             str_ref=''
 | |
|             ;;
 | |
|     esac
 | |
|     str_ref+=${iuse_ref[IUSE_NAME_IDX]}
 | |
| }
 | |
| 
 | |
| #
 | |
| # Implementation details
 | |
| #
 | |
| 
 | |
| # parse dependency specification format (DSF)
 | |
| 
 | |
| declare -gri __MCL_DSF_DEPEND=0 __MCL_DSF_LICENSE=1
 | |
| 
 | |
| function __mcl_parse_dsf() {
 | |
|     local -i dsf_type=${1}; shift
 | |
|     local dep=${1}; shift
 | |
|     local -n top_group_out_var_name_ref=${1}; shift
 | |
| 
 | |
|     local -a group_stack
 | |
|     local pd_group pd_item pd_group_created='' pd_pds
 | |
| 
 | |
|     gen_varname pd_group
 | |
|     group_declare "${pd_group}"
 | |
|     group_stack+=( "${pd_group}" )
 | |
| 
 | |
|     local -a tokens
 | |
|     mapfile -t tokens <<<"${dep// /$'\n'}"
 | |
|     local -i last_index
 | |
| 
 | |
|     local token
 | |
|     for token in "${tokens[@]}"; do
 | |
|         if [[ ${token} = '||' ]]; then
 | |
|             # "any of" group, so create the group, make it an item, add
 | |
|             # to current group and mark the new group as current
 | |
|             gen_varname pd_group
 | |
|             group_declare "${pd_group}"
 | |
|             local -n g_ref=${pd_group}
 | |
|             g_ref[GROUP_TYPE_IDX]=${GROUP_ANY_OF}
 | |
|             unset -n g_ref
 | |
| 
 | |
|             gen_varname pd_item
 | |
|             item_declare "${pd_item}"
 | |
|             local -n i_ref=${pd_item}
 | |
|             i_ref="g:${pd_group}"
 | |
|             unset -n i_ref
 | |
| 
 | |
|             group_add_items "${group_stack[-1]}" "${pd_item}"
 | |
| 
 | |
|             group_stack+=( "${pd_group}" )
 | |
|             pd_group_created=x
 | |
|         elif [[ ${token} =~ ^!?[A-Za-z0-9][A-Za-z0-9+_-]*\?$ ]]; then
 | |
|             # "use" group, so create the group, make it an item, add
 | |
|             # to current group and mark the new group as current
 | |
|             local -i disabled=GROUP_USE_ENABLED
 | |
|             local use=${token%?}
 | |
| 
 | |
|             if [[ ${use} = '!'* ]]; then
 | |
|                 disabled=GROUP_USE_DISABLED
 | |
|                 use=${use:1}
 | |
|             fi
 | |
| 
 | |
|             gen_varname pd_group
 | |
|             group_declare "${pd_group}"
 | |
|             local -n g_ref=${pd_group}
 | |
|             g_ref[GROUP_TYPE_IDX]=${GROUP_ALL_OF}
 | |
|             g_ref[GROUP_USE_IDX]=${use}
 | |
|             g_ref[GROUP_ENABLED_IDX]=${disabled}
 | |
|             unset -n g_ref
 | |
| 
 | |
|             unset use disabled
 | |
| 
 | |
|             gen_varname pd_item
 | |
|             item_declare "${pd_item}"
 | |
|             local -n i_ref=${pd_item}
 | |
|             i_ref="g:${pd_group}"
 | |
|             unset -n i_ref
 | |
| 
 | |
|             group_add_items "${group_stack[-1]}" "${pd_item}"
 | |
| 
 | |
|             group_stack+=( "${pd_group}" )
 | |
|             pd_group_created=x
 | |
|         elif [[ ${token} = '(' ]]; then
 | |
|             # beginning of a group; usually it is already created,
 | |
|             # because it is an "any of" or "use" group, but it is
 | |
|             # legal to specify just a "all of" group
 | |
|             if [[ -n ${pd_group_created} ]]; then
 | |
|                 pd_group_created=
 | |
|             else
 | |
|                 gen_varname pd_group
 | |
|                 group_declare "${pd_group}"
 | |
| 
 | |
|                 gen_varname pd_item
 | |
|                 item_declare "${pd_item}"
 | |
|                 local -n i_ref=${pd_item}
 | |
|                 i_ref="g:${pd_group}"
 | |
|                 unset -n i_ref
 | |
| 
 | |
|                 group_add_items "${group_stack[-1]}" "${pd_item}"
 | |
| 
 | |
|                 group_stack+=( "${pd_group}" )
 | |
|             fi
 | |
|         elif [[ ${token} = ')' ]]; then
 | |
|             # end of a group, pop it from the stack
 | |
|             last_index=$(( ${#group_stack[@]} - 1 ))
 | |
|             unset "group_stack[${last_index}]"
 | |
|         elif [[ ${token} =~ ^[A-Za-z0-9_][A-Za-z0-9+_.-]*$ ]]; then
 | |
|             # license
 | |
|             if [[ dsf_type -ne __MCL_DSF_LICENSE ]]; then
 | |
|                 fail "license tokens are only allowed for LICENSE keys (token: ${token@Q})"
 | |
|             fi
 | |
| 
 | |
|             gen_varname pd_item
 | |
|             item_declare "${pd_item}"
 | |
|             local -n i_ref=${pd_item}
 | |
|             i_ref="l:${token}"
 | |
|             unset -n i_ref
 | |
|             group_add_items "${group_stack[-1]}" "${pd_item}"
 | |
|         elif [[ ${token} =~ ^!?!?(<|<=|=|~|>=|>)?[A-Za-z0-9_][A-Za-z0-9+_.-]*/[A-Za-z0-9_] ]]; then
 | |
|             # pds
 | |
|             if [[ dsf_type -ne __MCL_DSF_DEPEND ]]; then
 | |
|                 fail "package dependency specification is only allowed for DEPEND-like keys (token: ${token@Q})"
 | |
|             fi
 | |
| 
 | |
|             local -i blocks=PDS_NO_BLOCK
 | |
|             local operator='' name='' version='' slot=''
 | |
|             local -a use_requirements=()
 | |
| 
 | |
|             case ${token} in
 | |
|                 '!!'*)
 | |
|                     blocks=PDS_STRONG_BLOCK
 | |
|                     token=${token:2}
 | |
|                     ;;
 | |
|                 '!'*)
 | |
|                     blocks=PDS_WEAK_BLOCK
 | |
|                     token=${token:1}
 | |
|                     ;;
 | |
|             esac
 | |
| 
 | |
|             case ${token} in
 | |
|                 '<='*|'>='*)
 | |
|                     operator=${token:0:2}
 | |
|                     token=${token:2}
 | |
|                     ;;
 | |
|                 '<'*|'='*|'~'*|'>'*)
 | |
|                     operator=${token:0:1}
 | |
|                     token=${token:1}
 | |
|                     ;;
 | |
|             esac
 | |
| 
 | |
|             if [[ ${token} = *']' ]]; then
 | |
|                 local use_reqs_string=${token#*'['}
 | |
|                 use_reqs_string=${use_reqs_string%']'}
 | |
|                 token=${token%"[${use_reqs_string}]"}
 | |
|                 local -a use_reqs
 | |
|                 mapfile -t use_reqs <<<"${use_reqs_string//,/$'\n'}"
 | |
| 
 | |
|                 unset use_reqs_string
 | |
| 
 | |
|                 local ur name mode pretend pd_ur
 | |
|                 for ur in "${use_reqs[@]}"; do
 | |
|                     name=''
 | |
|                     mode=''
 | |
|                     pretend=''
 | |
|                     case ${ur} in
 | |
|                         '-'*)
 | |
|                             mode='-'
 | |
|                             ur=${ur:1}
 | |
|                             ;;
 | |
|                         '!'*)
 | |
|                             mode='!'
 | |
|                             ur=${ur:1}
 | |
|                             ;;
 | |
|                     esac
 | |
|                     if [[ ${mode} != '-' ]]; then
 | |
|                         case ${ur} in
 | |
|                             *'=')
 | |
|                                 mode+='='
 | |
|                                 ur=${ur%'='}
 | |
|                                 ;;
 | |
|                             *'?')
 | |
|                                 mode+='?'
 | |
|                                 ur=${ur%'?'}
 | |
|                                 ;;
 | |
|                         esac
 | |
|                     fi
 | |
|                     if [[ -z ${mode} ]]; then
 | |
|                         mode='+'
 | |
|                     fi
 | |
|                     if [[ ${ur} =~ \(([+-])\)$ ]]; then
 | |
|                         pretend=${BASH_REMATCH[1]}
 | |
|                         ur=${ur%"(${pretend})"}
 | |
|                     fi
 | |
|                     name=${ur}
 | |
|                     gen_varname pd_ur
 | |
|                     ur_declare "${pd_ur}"
 | |
|                     local -n u_ref=${pd_ur}
 | |
|                     u_ref[UR_NAME_IDX]=${name}
 | |
|                     u_ref[UR_MODE_IDX]=${mode}
 | |
|                     u_ref[UR_PRETEND_IDX]=${pretend}
 | |
|                     unset -n u_ref
 | |
|                     use_requirements+=( "${pd_ur}" )
 | |
|                 done
 | |
|                 unset pd_ur pretend mode name ur use_reqs
 | |
|             fi
 | |
| 
 | |
|             if [[ ${token} = *:* ]]; then
 | |
|                 slot=${token#*:}
 | |
|                 token=${token%:"${slot}"}
 | |
|             fi
 | |
| 
 | |
|             if [[ ${token} = *'*' ]]; then
 | |
|                 operator='=*'
 | |
|                 token=${token%'*'}
 | |
|             fi
 | |
|             local ver_ere_with_dash="-(${VER_ERE_UNBOUNDED})$"
 | |
|             if [[ ${token} =~ ${ver_ere_with_dash} ]]; then
 | |
|                 version=${BASH_REMATCH[1]}
 | |
|                 token=${token%"-${version}"}
 | |
|             fi
 | |
|             name=${token}
 | |
| 
 | |
|             gen_varname pd_pds
 | |
|             pds_declare "${pd_pds}"
 | |
|             local -n p_ref=${pd_pds}
 | |
|             p_ref[PDS_BLOCKS_IDX]=${blocks}
 | |
|             p_ref[PDS_OP_IDX]=${operator}
 | |
|             p_ref[PDS_NAME_IDX]=${name}
 | |
|             p_ref[PDS_VER_IDX]=${version}
 | |
|             p_ref[PDS_SLOT_IDX]=${slot}
 | |
|             unset -n p_ref
 | |
|             pds_add_urs "${pd_pds}" "${use_requirements[@]}"
 | |
|             unset use_requirements slot version name operator blocks
 | |
| 
 | |
|             gen_varname pd_item
 | |
|             item_declare "${pd_item}"
 | |
|             local -n i_ref=${pd_item}
 | |
|             i_ref="p:${pd_pds}"
 | |
|             unset -n i_ref
 | |
| 
 | |
|             group_add_items "${group_stack[-1]}" "${pd_item}"
 | |
|         else
 | |
|             fail "unknown token ${token@Q}"
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     if [[ ${#group_stack[@]} -ne 1 ]]; then
 | |
|         fail "botched parsing, group stack has ${#group_stack[@]} groups instead of 1"
 | |
|     fi
 | |
| 
 | |
|     top_group_out_var_name_ref=${group_stack[0]}
 | |
| 
 | |
|     if pkg_debug_enabled; then
 | |
|         local pd_group_str
 | |
|         group_to_string "${group_stack[0]}" pd_group_str
 | |
|         pkg_debug_print "dsf: ${pd_group_str}"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function __mcl_parse_eclasses() {
 | |
|     local eclasses_string=${1}; shift
 | |
|     local -n eclasses_out_var_name_ref=${1}; shift
 | |
| 
 | |
|     local eclasses_var_name
 | |
|     gen_varname eclasses_var_name
 | |
|     declare -ga "${eclasses_var_name}=()"
 | |
|     local -n eclasses_ref=${eclasses_var_name}
 | |
| 
 | |
|     local -a tokens
 | |
|     mapfile -t tokens <<<"${eclasses_string//$'\t'/$'\n'}"
 | |
| 
 | |
|     local token
 | |
|     local -i eclass_name_now=1
 | |
|     for token in "${tokens[@]}"; do
 | |
|         if [[ eclass_name_now -eq 1 ]]; then
 | |
|             eclasses_ref+=( "${token}" )
 | |
|         fi
 | |
|         eclass_name_now=$((eclass_name_now ^ 1))
 | |
|     done
 | |
|     eclasses_out_var_name_ref=${eclasses_var_name}
 | |
| 
 | |
|     if pkg_debug_enabled; then
 | |
|         local joined_eclasses_string
 | |
|         join_by joined_eclasses_string ' ' "${eclasses_ref[@]}"
 | |
|         pkg_debug_print "eclasses: ${joined_eclasses_string}"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function __mcl_parse_keywords() {
 | |
|     local keywords_string=${1}; shift
 | |
|     local -n keywords_out_var_name_ref=${1}; shift
 | |
|     # rest are architectures
 | |
| 
 | |
|     local keywords_var_name
 | |
|     gen_varname keywords_var_name
 | |
|     declare -ga "${keywords_var_name}=()"
 | |
|     local -n keywords_ref=${keywords_var_name}
 | |
| 
 | |
|     local -A keywords_set=()
 | |
| 
 | |
|     local -a tokens
 | |
|     mapfile -t tokens <<<"${keywords_string// /$'\n'}"
 | |
|     local token
 | |
|     for token in "${tokens[@]}"; do
 | |
|         keywords_set["${token}"]=x
 | |
|     done
 | |
| 
 | |
|     local has_hyphen_star=${keywords_set['-*']:-}
 | |
|     local arch mark kw_level_pair kw kw_name
 | |
|     local -i level
 | |
|     for arch; do
 | |
|         for kw_level_pair in "${arch}@${KW_STABLE}" "~${arch}@${KW_UNSTABLE}" "-${arch}@${KW_BROKEN}"; do
 | |
|             kw=${kw_level_pair%@*}
 | |
|             level=${kw_level_pair#*@}
 | |
|             mark=${keywords_set["${kw}"]:-}
 | |
|             if [[ -n ${mark} ]]; then
 | |
|                 gen_varname kw_name
 | |
|                 kw_declare "${kw_name}"
 | |
|                 local -n k_ref=${kw_name}
 | |
|                 k_ref[KW_NAME_IDX]=${arch}
 | |
|                 k_ref[KW_LEVEL_IDX]=${level}
 | |
|                 unset -n k_ref
 | |
|                 keywords_ref+=( "${kw_name}" )
 | |
|                 break
 | |
|             fi
 | |
|         done
 | |
|         if [[ -z ${mark} ]]; then
 | |
|             gen_varname kw_name
 | |
|             kw_declare "${kw_name}"
 | |
|             local -n k_ref=${kw_name}
 | |
|             k_ref[KW_NAME_IDX]=${arch}
 | |
|             if [[ -n ${has_hyphen_star} ]]; then
 | |
|                 k_ref[KW_LEVEL_IDX]=${KW_BROKEN}
 | |
|             else
 | |
|                 k_ref[KW_LEVEL_IDX]=${KW_UNKNOWN}
 | |
|             fi
 | |
|             unset -n k_ref
 | |
|             keywords_ref+=( "${kw_name}" )
 | |
|         fi
 | |
|     done
 | |
|     keywords_out_var_name_ref=${keywords_var_name}
 | |
| 
 | |
|     if pkg_debug_enabled; then
 | |
|         local -a all_kws_strings=()
 | |
|         local kw_name pk_kw_str
 | |
|         local joined_kws_string
 | |
|         for kw_name in "${keywords_ref[@]}"; do
 | |
|             kw_to_string "${kw_name}" pk_kw_str
 | |
|             all_kws_strings+=( "${pk_kw_str}" )
 | |
|         done
 | |
|         join_by joined_kws_string ' ' "${all_kws_strings[@]}"
 | |
|         pkg_debug_print "keywords: ${joined_kws_string}"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function __mcl_parse_iuse() {
 | |
|     local iuse_string=${1}; shift
 | |
|     local -n iuse_out_var_name_ref=${1}; shift
 | |
| 
 | |
|     local iuse_var_name
 | |
|     gen_varname iuse_var_name
 | |
|     declare -ga "${iuse_var_name}=()"
 | |
|     local -n iuse_ref=${iuse_var_name}
 | |
| 
 | |
|     local -a tokens
 | |
|     mapfile -t tokens <<<"${iuse_string// /$'\n'}"
 | |
|     local token pi_iuse
 | |
|     for token in "${tokens[@]}"; do
 | |
|         gen_varname pi_iuse
 | |
|         iuse_declare "${pi_iuse}"
 | |
|         local -n i_ref=${pi_iuse}
 | |
|         if [[ ${token} = '+'* ]]; then
 | |
|             i_ref[IUSE_MODE_IDX]=${IUSE_ENABLED}
 | |
|             token=${token:1}
 | |
|         fi
 | |
|         i_ref[IUSE_NAME_IDX]=${token}
 | |
|         unset -n i_ref
 | |
|         iuse_ref+=( "${pi_iuse}" )
 | |
|     done
 | |
| 
 | |
|     iuse_out_var_name_ref=${iuse_var_name}
 | |
| 
 | |
|     if pkg_debug_enabled; then
 | |
|         local -a all_iuse_strings=()
 | |
|         local iuse_name pi_iuse_str
 | |
|         local joined_iuse_string
 | |
|         for iuse_name in "${iuse_ref[@]}"; do
 | |
|             iuse_to_string "${iuse_name}" pi_iuse_str
 | |
|             all_iuse_strings+=( "${pi_iuse_str}" )
 | |
|         done
 | |
|         join_by joined_iuse_string ' ' "${all_iuse_strings[@]}"
 | |
|         pkg_debug_print "IUSE: ${joined_iuse_string}"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function __mcl_unset_array() {
 | |
|     local array_name=${1}; shift
 | |
|     local item_unset_func=${1}; shift
 | |
| 
 | |
|     if [[ ${array_name} = EMPTY_ARRAY ]]; then
 | |
|         return 0
 | |
|     fi
 | |
|     local -n array_ref=${array_name}
 | |
|     "${item_unset_func}" "${array_ref[@]}"
 | |
|     unset -n array_ref
 | |
|     unset "${array_name}"
 | |
| }
 | |
| 
 | |
| fi
 |