X-Git-Url: http://git.iain.cx/?p=profile.git;a=blobdiff_plain;f=.profile.d%2FPATH.bashrc;h=38bb82558f7b760c423768c39e9415f08ad7a5c5;hp=1a271aa46a80c305e316d8f618312baa99059487;hb=88bb919af5a85d1d7f791408058f9eee96140907;hpb=6b44a934006d39120df7760d7e55b6148a4e818a diff --git a/.profile.d/PATH.bashrc b/.profile.d/PATH.bashrc index 1a271aa..38bb825 100644 --- a/.profile.d/PATH.bashrc +++ b/.profile.d/PATH.bashrc @@ -1,58 +1,179 @@ -# $Id$ -# # Path information is stored on separate lines in XXXdirs. -# We extract each directory exists and add it to the appropriate PATH. +# We check each directory exists and add it to the appropriate PATH. +# Prepend paths with XXXdirs.pre. They are guaranteed to precede other paths. +# Append paths with XXXdirs.post. They are not guaranteed to follow others. +# Set per-OS files in $SYSTEM[/$ARCHITECTURE] subdirectories of $DIR. # # Location of the XXXdirs files. -DIR=$HOME/.profile.d +DIR=${PROFILE_HOME:-~}/.PATH + +# Paths to set and the file to get them from @variable to copy from. +PATHS=" +PATH:bindirs +C_INCLUDE_PATH:incdirs +CPLUS_INCLUDE_PATH:@C_INCLUDE_PATH +LD_LIBRARY_PATH:libdirs +MANPATH:mandirs +PKG_CONFIG_PATH:pkgdirs +" + +function sanitisepath() { + local paths="${@//:/ }" + local sane + + for path in $paths; do + paths="${paths## }" + paths="${paths%% }" + paths="${paths#$path} " + if [ "${sane/:$path:/}" = "$sane" ]; then + sane="$sane:$path:" + fi + done + + sane="${sane//::/:}" + sane="${sane#:}" + sane="${sane%:}" + + echo "$sane" +} # Set one path to be the same as another. function copypath() { - newpath="$1"; shift - oldpath="$1"; shift + local newpath="$1"; shift + local oldpath="$1"; shift # Sanitise and export. - path="$(eval echo \$$oldpath)" - [ -z "$path" ] || eval export $newpath="$path" + local path="$(eval echo \$$oldpath)" + [ -z "$path" ] || eval "export $newpath='$path'" +} + +# Try to expand variables in a path definition, discarding it if expansion fails. +function expandpath() { + local path="$1"; shift + + while [ -n "$path" ]; do + [ "${path/\$/}" = "$path" ] && return 0 + path="${path#*\$}" + + local var="${path%%/*}" + eval "[ -n \"\$$var\" ] || return 1" + done + + return 0 +} - unset path newpath oldpath +# Helper. +function addpath() { + local path="$1"; shift + local dir="$1"; shift + + if ! expandpath "$dir"; then + echo "$path" + else + dir=$(eval echo "$dir") + if [ -d "$dir" ]; then + echo "$path:$dir" + else + echo "$path" + fi + fi } # Set a path from directories. function makepath() { - newpath="$1"; shift - dirs="$1"; shift - - # Check the file exists. - [ -e "$DIR/$dirs" ] || return + local newpath="$1"; shift + local dirs="$1"; shift + # Set IFS to newline only so that we can read $(embedded shell commands). + local JGD=$IFS + IFS=' +' # Read them. - path= - for dir in $(cat "$DIR/$dirs"); do - dir=$(eval echo "$dir") - [ -d "$dir" ] || continue + local path= + while read dir; do + path=$(addpath "$path" "$dir") + if [ -n "$PROFILE_HOME" -a ! "${dir#\$HOME}" = "$dir" ]; then + dir="$PROFILE_HOME${dir#\$HOME}" + path=$(addpath "$path" "$dir") + fi + done < "$dirs" - path="$path:$dir" - done - unset dir + # Restore IFS. + IFS=$JGD + + # Are we setting, prepending or appending? + local existing="$(eval echo \$$newpath)" + dirs="${dirs##*/}" + local where="${dirs##*.}" + case "$where" in + "$dirs") ;; + pre) path="$path:$existing";; + post) path="$existing:$path";; + *) return;; + esac # Sanitise path. - path=${path#:} + path=$(sanitisepath "$path") [ -z "$path" ] && return # Export. - eval export $newpath="$path" + eval "export $newpath='$path'" +} + +# Remove entries which are symlinks to other existing entries. +function canonicalisepath() { + local path="$1"; shift + local newpath= - unset path newpath dirs + local JGD=$IFS + IFS=' +' + + local dirs=$(eval echo "\$$path") + local check=":$dirs:" + for dir in ${dirs//:/ +}; do + if [ -L "$dir" ]; then + # Is this a symlink to another entry? + local canon=$(readlink -f "$dir" 2>/dev/null) + if [ -n "$canon" ]; then + [ "${check/:$canon:/}" = "$check" ] || continue + fi + fi + + newpath="$newpath:$dir" + done + + IFS=$JGD + + eval "export $path='${newpath##:}'" } -makepath PATH bindirs -makepath C_INCLUDE_PATH incdirs -copypath CPLUS_INCLUDE_PATH C_INCLUDE_PATH -makepath LD_LIBRARY_PATH libdirs -copypath LD_RUN_PATH PATH -makepath MANPATH mandirs -makepath PKG_CONFIG_PATH pkgdirs +# Construct directory list, omitting nonexistent and undefined ones. +dirs= +for dir in "${SYSTEM:-@}/${ARCHITECTURE:-@}" "${SYSTEM:-@}" ""; do + [ "${dir/@/}" = "$dir" ] || continue + [ -d "$DIR/$dir" ] || continue + dirs="$dirs,$DIR/$dir" + dirs="${dirs%%/}" +done +dirs="${dirs##,}" +[ "${dirs/,/}" = "$dirs" ] || dirs="{$dirs}" + +for path in $PATHS; do + var="${path%:*}" + source="${path#*:}" + + if [ "${source#@}" = "$source" ]; then + for dir in $(eval echo $dirs/$source{,.pre,.post}); do + [ -e "$dir" ] || continue + makepath "$var" "$dir" + done + canonicalisepath "$var" + else + copypath "$var" "${source#@}" + fi +done -unset dirs copypath makepath newpath +unset DIR PATHS dir dirs path var source expandpath sanitisepath copypath makepath newpath addpath canonicalisepath