From 25af0c8be8d3d18de6e131459d5192ac7c8a5ed5 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Tue, 5 Jan 2016 19:50:42 -0800 Subject: [PATCH] New path management system --- dotfiles/lib/python/shell_path.py | 117 +++++++++++++++++++++++++++++ dotfiles/lib/shellenv.sh | 41 +++++----- dotfiles/lib/shellenv/functions.sh | 43 +---------- 3 files changed, 141 insertions(+), 60 deletions(-) create mode 100755 dotfiles/lib/python/shell_path.py diff --git a/dotfiles/lib/python/shell_path.py b/dotfiles/lib/python/shell_path.py new file mode 100755 index 00000000..ac373fdb --- /dev/null +++ b/dotfiles/lib/python/shell_path.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +import argparse +import os + + +class PathList(object): + + @classmethod + def from_string(cls, path_string, separator=':'): + non_empty_paths = [path for path in path_string.split(separator) if path] + return cls(non_empty_paths, separator=':') + + def __init__(self, paths, separator=':'): + self.paths = paths + self.separator = separator + + def __str__(self): + return self.with_separator(self.separator) + + def with_separator(self, separator=None): + separator = separator or self.separator + deduped = [] + included = set() + for path in self.paths: + normalized = os.path.normpath(path) + if normalized not in included: + included.add(normalized) + deduped.append(path) + return separator.join( + os.path.normpath(path) for path in deduped + ) + + def add(self, new_paths, after=False, target=None): + if target: + target_index = self.paths.index(target) + else: + target_index = 0 + + if after: + increment = 1 if target else len(self.paths) + target_index += increment + + self.paths = self.paths[:target_index] + new_paths + self.paths[target_index:] + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Manipulate path variables.') + parser.add_argument( + 'paths', + metavar='PATH', + type=str, + nargs='*', + help='paths to add', + ) + parser.add_argument( + '--path-var', + help='the path var to add to.', + default='PATH', + ) + parser.add_argument( + '--separator', + help='the separator of the path variable', + default=':', + ) + parser.add_argument( + '--path-string', + help='the path string to edit', + default=None, + ) + parser.add_argument( + '--after', + help=('whether to do the action after the target (if target is specified)' + 'or the entire path variable'), + action='store_true', + default=True, + ) + parser.add_argument( + '--before', + help='inverse of after', + dest='after', + action='store_false', + ) + parser.add_argument( + '--target', + help='the target path', + default=None + ) + parser.add_argument( + '--include-assignment', + action='store_true', + help='include the assignment command in output', + ) + parser.add_argument( + '--print-separator', + help='separator to use for output', + default=None, + ) + parser.add_argument( + '--path-lines', + help='use newlines to separate path output', + action='store_true', + default=False, + ) + args = parser.parse_args() + + path_string = args.path_string or os.environ.get(args.path_var, '') + path_list = PathList.from_string(path_string, separator=args.separator) + path_list.add(args.paths, after=args.after, target=args.target) + + output_separator = '\n' if args.path_lines else args.print_separator + output_path = path_list.with_separator(separator=output_separator) + if args.include_assignment: + output = "export {}='{}'".format(args.path_var, output_path) + else: + output = output_path + + print(output) diff --git a/dotfiles/lib/shellenv.sh b/dotfiles/lib/shellenv.sh index d6117805..4eceb45c 100644 --- a/dotfiles/lib/shellenv.sh +++ b/dotfiles/lib/shellenv.sh @@ -7,26 +7,31 @@ function _source_shellenv_files { done } +function add_to_path { + local result=$($HOME/.lib/python/shell_path.py --include-assignment "$@") + eval "$result" +} + function _setup_env { _path_helper - idem_add_to_back_of_path "$HOME/.local/lib/python2.6/site-packages" - idem_add_to_back_of_path "$HOME/.rvm/bin" - idem_add_to_front_of_path "$HOME/bin" - hash brew 2>/dev/null && idem_add_to_front_of_path "$(brew --prefix coreutils)/libexec/gnubin" - idem_add_to_front_of_path "/usr/local/bin" + add_to_path "$HOME/.local/lib/python2.6/site-packages" --after + add_to_path "$HOME/.rvm/bin" --after + add_to_path "$HOME/bin" + hash brew 2>/dev/null && add_to_path "$(brew --prefix coreutils)/libexec/gnubin" + add_to_path "/usr/local/bin" - idem_add_to_back_of_path `python -c 'import sysconfig; print sysconfig.get_path("scripts")'` + add_to_path $(python -c 'import sysconfig; print sysconfig.get_path("scripts")') --before if is_osx; then export CFLAGS=-Qunused-arguments export CPPFLAGS=-Qunused-arguments - idem_add_to_back_of_path "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources" + add_to_path "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources" --after local JDK_LOCATION="$(find /Library/Java/JavaVirtualMachines -depth 1 | head -n 1)" export JAVA_HOME="$JDK_LOCATION/Contents/Home" export STUDIO_JDK=$JDK_LOCATION export GRADLE_HOME="$(brew --prefix gradle)" export ANDROID_HOME="$(brew --prefix android-sdk)" - idem_add_to_back_of_path "$ANDROID_HOME" + add_to_path "$ANDROID_HOME" --after # Access gnu man pages. hash brew 2> /dev/null && export MANPATH="$(brew --prefix)/opt/coreutils/libexec/gnuman:$MANPATH" @@ -35,10 +40,10 @@ function _setup_env { is_osx && export VISUAL="which emacsclient -c -n" fi - idem_add_to_front_of_path "$JAVA_HOME/bin" + add_to_path "$JAVA_HOME/bin" - idem_add_to_back_of_path "$HOME/.lib/python" - idem_add_to_back_of_path "/usr/local/sbin" + add_to_path "$HOME/.lib/python" --after + add_to_path "/usr/local/sbin" --after # Load RVM into a shell session *as a function* [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" @@ -54,18 +59,18 @@ function _setup_env { [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm export NODE_PATH="/usr/local/lib/node_modules/" - idem_add_to_front_of_path "$HOME/.local/bin" - idem_add_to_front_of_path "$HOME/.lib/python" 'PYTHONPATH' + add_to_path "$HOME/.local/bin" + add_to_path "$HOME/.lib/python" --path-var 'PYTHONPATH' - idem_add_to_front_of_path "$HOME/go" 'GOPATH' - idem_add_to_front_of_path "${GOPATH//://bin:}/bin" + add_to_path "$HOME/go" --path-var 'GOPATH' + add_to_path "${GOPATH//://bin:}/bin" export RBENV_ROOT=/usr/local/var/rbenv - idem_add_to_front_of_path "$HOME/.rbenv/bin" + add_to_path "$HOME/.rbenv/bin" hash rbenv 2> /dev/null && eval "$(rbenv init -)" - hash brew 2>/dev/null && idem_add_to_front_of_path "$(brew --prefix coreutils)/libexec/gnubin" + hash brew 2>/dev/null && add_to_path "$(brew --prefix coreutils)/libexec/gnubin" - idem_add_to_front_of_path "$HOME/.lib/bin" + add_to_path "$HOME/.lib/bin" export ENVIRONMENT_SETUP_DONE="$(date)" } diff --git a/dotfiles/lib/shellenv/functions.sh b/dotfiles/lib/shellenv/functions.sh index bbaa8a37..a9c1a392 100644 --- a/dotfiles/lib/shellenv/functions.sh +++ b/dotfiles/lib/shellenv/functions.sh @@ -1,46 +1,5 @@ function path_lines { - target=${1-PATH} - if is_zsh; then - echo ${(P)target} | tr ':' '\n' - else - echo ${!target} | tr ':' '\n' - fi -} - -function _add_to_front_of_path_lines { - target=${2-PATH} - echo $1 - path_lines $target | grep -Ev "^$1$" -} - -function _add_to_back_of_path_lines { - target=${2-PATH} - path_lines $target | grep -Ev "^$1$" - echo $1 -} - -function remove_trailing_colon { - sed 's|:*$||' -} - -function add_to_front_of_path { - target=${2-PATH} - export $target="$(_add_to_front_of_path_lines $1 $target | tr '\n' ':' | remove_trailing_colon)" -} - -function add_to_back_of_path { - target=${2-PATH} - export $target="$(_add_to_back_of_path_lines $1 $target | tr '\n' ':' | remove_trailing_colon)" -} - -function idem_add_to_front_of_path { - target=${2-PATH} - exists_in_path_var $1 $target || add_to_front_of_path $1 $target -} - -function idem_add_to_back_of_path { - target=${2-PATH} - exists_in_path_var $1 $target || add_to_back_of_path $1 $target + shell_path.py --path-lines "$@" } function indirect_expand {