From 2e06b13a6983dea70aec2d6ac7ceac05c0d5895c Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sun, 22 Aug 2021 19:41:30 +0200 Subject: [PATCH] Manager: Major restructure of arguments Optional arguments with spaces aren't supported by GNU getopt. So instead lets restructure the arguments to make sense without them. The manager now supports stdin. This patch also separates file pulling and pushing into separate functions. --- dotfiles.sh | 211 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 75 deletions(-) diff --git a/dotfiles.sh b/dotfiles.sh index 02db81d..19d73e7 100755 --- a/dotfiles.sh +++ b/dotfiles.sh @@ -20,16 +20,18 @@ aurHelper="trizen" # -------------------------------------- +b="$(tput bold)" +red="$(tput setf 4)" +n="$(tput sgr0)" + if [ "$(dirname "$0")" != "." ]; then - echo "Please run this script from the directory it resides." >&2 + echo "${b}${red}Error: Please run this script from the directory it resides.${n}" >&2 exit 1 fi help() { - b=$(tput bold) u=$(tput smul) - n=$(tput sgr0) cat << EOF ${b}NAME${n} @@ -75,24 +77,30 @@ EOF # Files # -------------------------------------- -setFiles() +getFileList() { - files="$(find . -type f -o -type l \ + fileList="$(find . -type f -o -type l \ | awk -v e="^./($excludeFiles)" '$0 !~ e { print $0 }')" } -listFiles() +getFilteredFileLists() { - # If unset - [ -z "${files+x}" ] && setFiles + [ -z "$fileList" ] && getFileList + + match="^./($systemDir)/" + + # Filter system directories and remove leading ./ from filepaths + homeFileList="$(echo "$fileList" \ + | awk -v m="$match" '$0 !~ m { print substr($0, 3) }')" - # Remove leading ./ from filepaths - echo "$files" | sed 's/^\.\///' + # Filter non-system directories and remove leading ./ from filepaths + systemFileList="$(echo "$fileList" \ + | awk -v m="$match" '$0 ~ m { print substr($0, 3) }')" } -add() +fileAdd() { - [ -z "$1" ] && return 1 + [ -z "$1" ] && exit 1 file="$(readlink -f "$(dirname "$1")")/$(basename "$1")" fileCutHome="$(echo "$file" \ @@ -109,52 +117,55 @@ add() fi } -pullPush() +filePull() { - # If unset or empty string - [ -z "$1" ] && return 1 - - # If unset - [ -z "${files+x}" ] && setFiles - - match="^./($systemDir)/" - - # Filter system directories and remove leading ./ from filepaths - homeFiles="$(echo "$files" \ - | awk -v m="$match" '$0 !~ m { print substr($0, 3) }')" + if [ -z "$homeFileList" ] || [ -z "$systemFileList" ]; then + getFilteredFileLists + fi - for f in $homeFiles; do - if [ "$1" = "pull" ]; then - # cp /home// /[/]dotfiles/ - cp -a "$HOME/$f" "$(pwd)/$f" - elif [ "$1" = "push" ]; then - mkdir -p "$(dirname "$HOME/$f")" - cp -a "$(pwd)/$f" "$HOME/$f" - fi + for file in $homeFileList; do + # /home// -> dotfiles/ + cp -a "$HOME/$file" "$(pwd)/$file" done - # Filter non-system directories and remove leading ./ from filepaths - systemFiles="$(echo "$files" \ - | awk -v m="$match" '$0 ~ m { print substr($0, 3) }')" - - for f in $systemFiles; do - if [ "$1" = "pull" ]; then - # cp / /[/]dotfiles/ - sudo cp -a "/$f" "$(pwd)/$f" - elif [ "$1" = "push" ]; then - sudo cp -a "$(pwd)/$f" "/$f" - fi + for file in $systemFileList; do + # / -> dotfiles/ + sudo cp -a "/$file" "$(pwd)/$file" done } -pull() +filePush() { - pullPush "pull" + if [ -z "$homeFileList" ] || [ -z "$systemFileList" ]; then + getFilteredFileLists + fi + + for file in $homeFileList; do + # dotfiles/ -> /home// + mkdir -p "$(dirname "$HOME/$file")" + cp -a "$(pwd)/$file" "$HOME/$file" + done + + for file in $systemFileList; do + # dotfiles/ -> / + sudo mkdir -p "$(dirname "/$file")" + sudo cp -a "$(pwd)/$file" "/$file" + done } -push() +files() { - pullPush "push" + if [ "$1" = "list" ] || [ "$1" = "" ]; then + [ -z "$fileList" ] && getFileList + # Remove leading ./ from filepaths + echo "$fileList" | sed 's/^\.\///' | grep "$2" + elif [ "$1" = "add" ]; then + fileAdd "$2" + elif [ "$1" = "pull" ]; then + filePull "$2" + elif [ "$1" = "push" ]; then + filePush "$2" + fi } # Packages @@ -206,7 +217,7 @@ osDependencies() done } -packageList() +getPackageList() { if [ "$os" = "arch" ]; then filterList="$( (pacman -Qqg base base-devel; pactree -u base | tail -n +2) | sort)" @@ -227,16 +238,15 @@ packageInstall() # Grab everything off enabled official repositories that is in the list repoList="$(pacman -Ssq | grep -xf $packageFile)" - if [ "$1" = "install" ]; then - # Install packages - echo "$repoList" | xargs --open-tty sudo pacman -Sy --needed - fi - if [ "$1" = "install-aur" ]; then + if [ "$1" = "aur-install" ]; then # Determine which packages in the list are from the AUR aurList="$(grep -vx "$repoList" < $packageFile)" # Install AUR packages echo "$aurList" | xargs --open-tty "$aurHelper" -Sy --needed --noconfirm + elif [ "$1" = "install" ]; then + # Install packages + echo "$repoList" | xargs --open-tty sudo pacman -Sy --needed fi elif [ "$os" = "debian" ]; then # Grab everything off enabled official repositories that is in the list @@ -253,60 +263,67 @@ packages() if [ -z "$os" ]; then osDetect osDependencies - packageList fi if [ "$1" = "list" ] || [ "$1" = "" ]; then - echo "$packageList" + [ -z "$packageList" ] && getPackageList + echo "$packageList" | grep "$2" elif [ "$1" = "store" ]; then + [ -z "$packageList" ] && getPackageList echo "$packageList" > "$packageFile" + elif [ "$1" = "aur-install" ]; then + packageInstall "aur-install" elif [ "$1" = "install" ]; then packageInstall "install" - elif [ "$1" = "install-aur" ]; then - packageInstall "install-aur" fi } -# Option handling +# Option parsing # -------------------------------------- script="$(basename "$0")" -options="$(getopt --options "ha:fp::ls" --longoptions "help,add:,files,packages::,pull,push" -n "$script" -- "$@" 2>&1)" +parsed="$(getopt --options "hFPails" \ + --longoptions "help,file,package,add,aur-install,install,pull,push,store" \ + -n "$script" -- "$@" 2>&1)" result="$?" # Exit if invalid option is provided if [ "$result" -ne 0 ]; then - echo "$options" | head -n 1 >&2 + echo "$parsed" | head -n 1 >&2 echo "Try './$script --help' for more information." >&2 exit 1 fi -eval set -- "$options" +eval set -- "$parsed" while true; do case "$1" in - -a | --add) - add "$2" - shift 2 + -F | --file) + [ -n "$mode" ] && echo "${b}${red}Error: only one operation may be used at a time." >&2 && exit 1 + mode="file" + shift ;; - -f | --files) - listFiles + -P | --package) + [ -n "$mode" ] && echo "${b}${red}Error: only one operation may be used at a time." >&2 && exit 1 + mode="package" shift ;; - -h | --help) - help - exit + -a | --add | --aur-install) + [ "$mode" = "file" ] && options="${options}add " + [ "$mode" = "package" ] && options="${options}aur-install " + shift ;; - -p | --packages) - packages "$2" - shift 2 + -i | --install) + options="${options}install " + shift ;; -l | --pull) - pull + options="${options}pull " shift ;; - -s | --push) - push + -s | --push | --store) + [ "$mode" = "file" ] && options="${options}push " + [ "$mode" = "package" ] && options="${options}store " shift ;; --) @@ -321,3 +338,47 @@ done # @Todo: # push function to push just one file +# Target parsing +# -------------------------------------- + +targets="$*" +targetsNoHyphen="$(echo "$targets" | sed -E 's/(^-$|\s-|-\s)//g; s/(\s-\s)/ /;')" + +# Read targets from stdin +if [ "$targets" != "$targetsNoHyphen" ]; then + [ -t 0 ] && echo "${b}${red}Error: argument '-' specified without input on stdin." >&2 && exit 1 + eval set -- "$targetsNoHyphen $(cat /dev/stdin)" +fi + +# Execute +# -------------------------------------- + +if [ "$mode" = "file" ]; then + if [ -z "$options" ]; then + files "list" "$@" + exit + fi + + for option in $options; do + if [ -z "$*" ]; then + [ "$option" = "add" ] && echo "${b}${red}Error: No files or directories selected to add.${n}" >&2 && exit 1 + files "$option" + continue + fi + + for path; do + files "$option" "$path" + done + done +fi + +if [ "$mode" = "package" ]; then + if [ -z "$options" ]; then + packages "list" "$@" + exit + fi + + for option in $options; do + packages "$option" + done +fi