| # Copyright 2020 Gentoo Authors |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| # @ECLASS: eapi8-dosym.eclass |
| # @MAINTAINER: |
| # PMS team <pms@gentoo.org> |
| # @AUTHOR: |
| # Ulrich Müller <ulm@gentoo.org> |
| # @SUPPORTED_EAPIS: 5 6 7 |
| # @BLURB: Testing implementation of EAPI 8 dosym -r option |
| # @DESCRIPTION: |
| # A stand-alone implementation of the dosym command aimed for EAPI 8. |
| # Intended to be used for wider testing of the proposed option and to |
| # allow ebuilds to switch to the new model early, with minimal change |
| # needed for actual EAPI 8. |
| # |
| # https://bugs.gentoo.org/708360 |
| |
| case ${EAPI} in |
| 5|6|7) ;; |
| *) die "${ECLASS}: EAPI=${EAPI:-0} not supported" ;; |
| esac |
| |
| # @FUNCTION: _dosym8_canonicalize |
| # @USAGE: <path> |
| # @INTERNAL |
| # @DESCRIPTION: |
| # Transparent bash-only replacement for GNU "realpath -m -s". |
| # Resolve references to "/./", "/../" and remove extra "/" characters |
| # from <path>, without touching any actual file. |
| _dosym8_canonicalize() { |
| local path slash i prev out IFS=/ |
| |
| path=( $1 ) |
| [[ $1 == /* ]] && slash=/ |
| |
| while true; do |
| # Find first instance of non-".." path component followed by "..", |
| # or as a special case, "/.." at the beginning of the path. |
| # Also drop empty and "." path components as we go along. |
| prev= |
| for i in ${!path[@]}; do |
| if [[ -z ${path[i]} || ${path[i]} == . ]]; then |
| unset "path[i]" |
| elif [[ ${path[i]} != .. ]]; then |
| prev=${i} |
| elif [[ ${prev} || ${slash} ]]; then |
| # Found, remove path components and reiterate |
| [[ ${prev} ]] && unset "path[prev]" |
| unset "path[i]" |
| continue 2 |
| fi |
| done |
| # No (further) instance found, so we're done |
| break |
| done |
| |
| out="${slash}${path[*]}" |
| echo "${out:-.}" |
| } |
| |
| # @FUNCTION: dosym8 |
| # @USAGE: [-r] <target> <link> |
| # @DESCRIPTION: |
| # Create a symbolic link <link>, pointing to <target>. If the |
| # directory containing the new link does not exist, create it. |
| # |
| # If called with option -r, expand <target> relative to the apparent |
| # path of the directory containing <link>. For example, "dosym8 -r |
| # /bin/foo /usr/bin/foo" will create a link named "../../bin/foo". |
| dosym8() { |
| local option_r |
| |
| case $1 in |
| -r) option_r=t; shift ;; |
| esac |
| |
| [[ $# -eq 2 ]] || die "${FUNCNAME}: bad number of arguments" |
| |
| local target=$1 link=$2 |
| |
| if [[ ${option_r} ]]; then |
| local linkdir comp |
| |
| # Expansion makes sense only for an absolute target path |
| [[ ${target} == /* ]] \ |
| || die "${FUNCNAME}: -r specified but no absolute target path" |
| |
| target=$(_dosym8_canonicalize "${target}") |
| linkdir=$(_dosym8_canonicalize "/${link#/}") |
| linkdir=${linkdir%/*} # poor man's dirname(1) |
| linkdir=${linkdir:-/} # always keep the initial "/" |
| |
| local ifs_save=${IFS-$' \t\n'} IFS=/ |
| for comp in ${linkdir}; do |
| if [[ ${target%%/*} == "${comp}" ]]; then |
| target=${target#"${comp}"} |
| target=${target#/} |
| else |
| target=..${target:+/}${target} |
| fi |
| done |
| IFS=${ifs_save} |
| target=${target:-.} |
| fi |
| |
| dosym "${target}" "${link}" |
| } |