147 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| # Eryn Wells <eryn@erynwells.me>
 | |
| # vim: set ft=zsh:
 | |
| 
 | |
| function _update-path-usage
 | |
| {
 | |
|     local -r function_name=$1
 | |
| 
 | |
|     local usage_string=$(cat <<EOF
 | |
| Usage: $function_name <arguments> [<path>...]
 | |
| 
 | |
| Modify the target path-like variable by adding or removing paths provided as
 | |
| positional arguments. Before adding, check that the target path variable doesn't
 | |
| already contain the path and that the directory exists.
 | |
| 
 | |
| This function returns the number of paths that were skipped in the input. If all
 | |
| paths were processed, it returns 0. It returns 255 if an error occurred while
 | |
| processing arguments.
 | |
| 
 | |
| Arguments
 | |
| ---------
 | |
| 
 | |
| %B-e%b | %B--export%b | %B--no-export%b
 | |
|     Export the variable after modification. The default is to export if the
 | |
|     variable is modified.
 | |
| 
 | |
| %B-f%b | %B--force%b
 | |
|     Unconditionally add the path, even if it doesn't exist.
 | |
| 
 | |
| %B-h%b | %B--help%b
 | |
|     Print this message.
 | |
| 
 | |
| %B-p%b | %B--prepend%b
 | |
|     Prepend paths to the target path variable, instead of appending. When
 | |
|     prepending, directories will be added in reverse order so their precedence
 | |
|     is preserved. That is, the first directory in the list will be at the start
 | |
|     of the path.
 | |
| 
 | |
| %B-P%b | %B--path%b <path_variable_name>
 | |
|     The name of a path-like variable to modify. The default is 'path'.
 | |
| 
 | |
| %B-r%b | %B--remove%b
 | |
|     Remove paths instead of adding. -p and -f are ignored when removing
 | |
|     directories from the path.
 | |
| 
 | |
| %B-v%b | %B--verbose%b
 | |
|     Print extra information while processing directories.
 | |
| EOF
 | |
| )
 | |
| 
 | |
|     print -P $usage_string
 | |
| }
 | |
| 
 | |
| function update-path
 | |
| {
 | |
|     zmodload zsh/zutil
 | |
| 
 | |
|     local -a o_args o_export o_force o_help o_prepend o_remove o_verbose o_pathvar
 | |
|     zparseopts -a o_args -D -E -F - \
 | |
|         {e,-export,-no-export}=o_export \
 | |
|         {f,-force}=o_force \
 | |
|         {h,-help}=o_help \
 | |
|         {p,-prepend}=o_prepend \
 | |
|         {P,-path}:=o_pathvar \
 | |
|         {r,-remove}=o_remove \
 | |
|         {v,-verbose}=o_verbose
 | |
| 
 | |
|     local -ri parse_status=$?
 | |
|     if (( parse_status )); then
 | |
|         _update-path-usage $0
 | |
|         return 255
 | |
|     fi
 | |
| 
 | |
|     if [[ $#o_help -ne 0 ]]; then
 | |
|         _update-path-usage $0
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     local -r verbose=$#o_verbose
 | |
|     local -r path_variable_name=${o_pathvar[-1]:-path}
 | |
| 
 | |
|     if ! typeset -p $path_variable_name &> /dev/null; then
 | |
|         print "Invalid path variable: \$$path_variable_name" 1>&2
 | |
|         return 255
 | |
|     fi
 | |
| 
 | |
|     [[ $verbose -ne 0 ]] && print "Modifying $path_variable_name"
 | |
| 
 | |
|     local -i candidates_skipped=0
 | |
|     local did_update_path
 | |
| 
 | |
|     local -a candidates=($@)
 | |
|     if [[ $#o_prepend -ne 0 ]]; then
 | |
|         # If prepending, reverse the list so paths are added in the right order.
 | |
|         candidates=(${(Oa)@})
 | |
|     fi
 | |
| 
 | |
|     for candidate in $candidates; do
 | |
|         local candidate_index=${${(P)path_variable_name}[(Ie)$candidate]}
 | |
| 
 | |
|         # An empty $o_remove means we're adding to the array.
 | |
|         if [[ $#o_remove -eq 0 ]]; then
 | |
|             if [[ $candidate_index -ne 0 ]]; then
 | |
|                 [[ $verbose -ne 0 ]] && print "Skipping $candidate"
 | |
|                 (( candidates_skipped++ ))
 | |
|                 continue
 | |
|             fi
 | |
| 
 | |
|             if [[ $#force -eq 0 && ! -d "$candidate" ]]; then
 | |
|                 [[ $verbose -ne 0 ]] && print "$candidate doesn't exist"
 | |
|                 (( candidates_skipped++ ))
 | |
|                 continue
 | |
|             fi
 | |
| 
 | |
|             did_update_path=yes
 | |
| 
 | |
|             [[ $verbose -ne 0 ]] && print "Adding $candidate"
 | |
|             if [[ $#o_prepend -ne 0 ]]; then
 | |
|                 eval "${path_variable_name}=(${candidate} ${path})"
 | |
|             else
 | |
|                 eval "${path_variable_name}+=${candidate}"
 | |
|             fi
 | |
|         else
 | |
|             if [[ $candidate_index -eq 0 ]]; then
 | |
|                 [[ $verbose -ne 0 ]] && print "Skipping $candidate"
 | |
|                 (( candidates_skipped++ ))
 | |
|                 continue
 | |
|             fi
 | |
| 
 | |
|             [[ $verbose -ne 0 ]] && print "Removing $candidate"
 | |
| 
 | |
|             did_update_path=yes
 | |
|             eval "${path_variable_name}[${candidate_index}]=()"
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     if [[ -n $did_update_path && $o_export[(I)--no-export] -ne 0 ]]; then
 | |
|         [[ $verbose -ne 0 ]] && print "Exporting $path_variable_name"
 | |
|         export $path_variable_name
 | |
|         if [[ "$path_variable_name" == "path" ]]; then
 | |
|             rehash
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     return $candidates_skipped
 | |
| }
 | |
| 
 | |
| update-path "$@"
 |