|
| 1 | +# Goo to attempt to resolve dependency loops on individual packages. |
| 2 | +# If this becomes insufficient we will need to move to a full multi-stage |
| 3 | +# bootstrap process like we do with the SDK via catalyst. |
| 4 | +# |
| 5 | +# Called like: |
| 6 | +# |
| 7 | +# break_dep_loop [-v] [PKG_USE_PAIR]… |
| 8 | +# |
| 9 | +# Pass -v for verbose output. |
| 10 | +# |
| 11 | +# PKG_USE_PAIR consists of two arguments: a package name (for example: |
| 12 | +# sys-fs/lvm2), and a comma-separated list of USE flags to clear (for |
| 13 | +# example: udev,systemd). |
| 14 | +# |
| 15 | +# Env vars: |
| 16 | +# |
| 17 | +# BDL_ROOT, BDL_PORTAGEQ, BDL_EQUERY, BDL_EMERGE, BDL_INFO |
| 18 | +break_dep_loop() { |
| 19 | + local bdl_root=${BDL_ROOT:-/} |
| 20 | + local bdl_portageq=${BDL_PORTAGEQ:-portageq} |
| 21 | + local bdl_equery=${BDL_EQUERY:-equery} |
| 22 | + local bdl_emerge=${BDL_EMERGE:-emerge} |
| 23 | + local bdl_info=${BDL_INFO:-echo} |
| 24 | + local conf_dir="${bdl_root%/}/etc/portage" |
| 25 | + local flag_file="${conf_dir}/package.use/break_dep_loop" |
| 26 | + local force_flag_file="${conf_dir}/profile/package.use.force/break_dep_loop" |
| 27 | + |
| 28 | + local verbose= |
| 29 | + if [[ ${1:-} = '-v' ]]; then |
| 30 | + verbose=x |
| 31 | + shift |
| 32 | + fi |
| 33 | + |
| 34 | + # Be sure to clean up use flag hackery from previous failed runs |
| 35 | + sudo rm -f "${flag_file}" "${force_flag_file}" |
| 36 | + |
| 37 | + if [[ ${#} -eq 0 ]]; then |
| 38 | + return 0 |
| 39 | + fi |
| 40 | + |
| 41 | + function bdl_call() { |
| 42 | + local output_var_name=${1}; shift |
| 43 | + if [[ ${output_var_name} = '-' ]]; then |
| 44 | + local throw_away |
| 45 | + output_var_name=throw_away |
| 46 | + fi |
| 47 | + local -n output_ref=${output_var_name} |
| 48 | + if [[ -n ${verbose} ]]; then |
| 49 | + "${bdl_info}" "${*@Q}" |
| 50 | + fi |
| 51 | + local -i rv=0 |
| 52 | + output_ref=$("${@}") || rv=${?} |
| 53 | + if [[ -n ${verbose} ]]; then |
| 54 | + "${bdl_info}" "output: ${output_ref}" |
| 55 | + "${bdl_info}" "exit status: ${rv}" |
| 56 | + fi |
| 57 | + return ${rv} |
| 58 | + } |
| 59 | + |
| 60 | + # Temporarily compile/install packages with flags disabled. If a binary |
| 61 | + # package is available use it regardless of its version or use flags. |
| 62 | + local pkg use_flags disabled_flags |
| 63 | + local -a flags |
| 64 | + local -a pkgs args flag_file_entries pkg_summaries |
| 65 | + local -A per_pkg_flags=() |
| 66 | + while [[ $# -gt 1 ]]; do |
| 67 | + pkg=${1} |
| 68 | + use_flags=${2} |
| 69 | + shift 2 |
| 70 | + |
| 71 | + mapfile -t flags <<<"${use_flags//,/$'\n'}" |
| 72 | + disabled_flags="${flags[*]/#/-}" |
| 73 | + |
| 74 | + pkgs+=( "${pkg}" ) |
| 75 | + per_pkg_flags["${pkg}"]=${use_flags} |
| 76 | + flag_file_entries+=( "${pkg} ${disabled_flags}" ) |
| 77 | + args+=( "--buildpkg-exclude=${pkg}" ) |
| 78 | + pkg_summaries+=( "${pkg}[${disabled_flags}]" ) |
| 79 | + done |
| 80 | + unset pkg use_flags disabled_flags flags |
| 81 | + |
| 82 | + # If packages are already installed we have nothing to do |
| 83 | + local pkg any_package_uninstalled= |
| 84 | + for pkg in "${pkgs[@]}"; do |
| 85 | + if ! bdl_call - "${bdl_portageq}" has_version "${bdl_root}" "${pkg}"; then |
| 86 | + any_package_uninstalled=x |
| 87 | + break |
| 88 | + fi |
| 89 | + done |
| 90 | + if [[ -z ${any_package_uninstalled} ]]; then |
| 91 | + if [[ -n ${verbose} ]]; then |
| 92 | + "${bdl_info}" "all packages (${pkgs[*]}) are installed already, skipping" |
| 93 | + fi |
| 94 | + return 0 |
| 95 | + fi |
| 96 | + unset pkg any_package_uninstalled |
| 97 | + |
| 98 | + # Likewise, nothing to do if the flags aren't actually enabled. |
| 99 | + local pkg any_flag_enabled= equery_output flag flags_str |
| 100 | + local -a flags grep_args |
| 101 | + for pkg in "${pkgs[@]}"; do |
| 102 | + bdl_call equery_output "${bdl_equery}" -q uses "${pkg}" |
| 103 | + flags_str=${per_pkg_flags["${pkg}"]} |
| 104 | + mapfile -t flags <<<"${flags_str//,/$'\n'}" |
| 105 | + for flag in "${flags[@]}"; do |
| 106 | + grep_args+=( -e "${flag/#/+}" ) |
| 107 | + done |
| 108 | + if bdl_call - grep --quiet --line-regexp --fixed-strings "${grep_args[@]}" <<<"${equery_output}"; then |
| 109 | + any_flag_enabled=x |
| 110 | + break |
| 111 | + fi |
| 112 | + done |
| 113 | + if [[ -z ${any_flag_enabled} ]]; then |
| 114 | + if [[ -n ${verbose} ]]; then |
| 115 | + "${bdl_info}" "all packages (${pkgs[*]}) has all the desired USE flags already disabled, skipping" |
| 116 | + fi |
| 117 | + return 0 |
| 118 | + fi |
| 119 | + unset pkg any_flag_enabled equery_output flag flags_str flags grep_args |
| 120 | + |
| 121 | + "${bdl_info}" "Merging ${pkg_summaries[*]}" |
| 122 | + sudo mkdir -p "${flag_file%/*}" "${force_flag_file%/*}" |
| 123 | + printf '%s\n' "${flag_file_entries[@]}" | sudo tee "${flag_file}" >/dev/null |
| 124 | + cp -a "${flag_file}" "${force_flag_file}" |
| 125 | + if [[ -n ${verbose} ]]; then |
| 126 | + "${bdl_info}" "contents of ${flag_file@Q}:" |
| 127 | + "${bdl_info}" "$(<"${flag_file}")" |
| 128 | + "${bdl_info}" "${bdl_emerge}" --rebuild-if-unbuilt=n "${args[@]}" "${pkgs[@]}" |
| 129 | + fi |
| 130 | + # rebuild-if-unbuilt is disabled to prevent portage from needlessly |
| 131 | + # rebuilding zlib for some unknown reason, in turn triggering more rebuilds. |
| 132 | + "${bdl_emerge}" \ |
| 133 | + --rebuild-if-unbuilt=n \ |
| 134 | + "${args[@]}" "${pkgs[@]}" |
| 135 | + sudo rm -f "${flag_file}" "${force_flag_file}" |
| 136 | + unset bdl_call |
| 137 | +} |
0 commit comments