config
A simple configuration manager
config (4081B)
1 #!/bin/bash 2 # __ _ 3 # ___ ___ _ __ / _(_) __ _ 4 # / __/ _ \| '_ \| |_| |/ _` | 5 # | (_| (_) | | | | _| | (_| | 6 # \___\___/|_| |_|_| |_|\__, | 7 # |___/ 8 # 9 # A simple configuration manager 10 # 2021 (C) Pablo 11 # Free use of this software is granted under the terms of the GPL-3.0 License 12 13 print_files() 14 { 15 IFS='' read -r file 16 17 if [ -n "$file" ] 18 then 19 printf '\033[0;%sm%s files:\033[0m\n' "$2" "$1" 20 while true 21 do 22 printf '\033[0;%sm%s\033[0m\n' "$2" "$file" 23 IFS='' read -r file 24 [ -z "$file" ] && break 25 done 26 fi 27 } 28 29 # Get the path to the git repository that should be used for storing stuff 30 if [ -n "$DOTFILES_REPO" ] 31 then 32 dotfiles_repo="$DOTFILES_REPO" 33 elif [ -n "$XDG_DATA_HOME" ] 34 then 35 dotfiles_repo="$XDG_DATA_HOME/dotfiles" 36 else 37 dotfiles_repo="$HOME/.local/share/dotfiles" 38 fi 39 40 # Get the name of the files that holds the list of all dotfiles that should be 41 # tracked 42 if [ -n "$DOTFILES_LIST" ] 43 then 44 dotfiles_list="$DOTFILES_LIST" 45 elif [ -n "$XDG_CONFIG_HOME" ] 46 then 47 dotfiles_list="$XDG_CONFIG_HOME/dotfiles.list" 48 else 49 dotfiles_list="$HOME/.config/dotfiles.list" 50 fi 51 52 # Calls git in the appropriate repository 53 call_git() 54 { 55 git --git-dir="$dotfiles_repo" --work-tree="$HOME" "$@" 56 } 57 58 # Given a path, print the files and directories matching this path that are 59 # included in the list of dotfiles 60 get_pathspec() 61 { 62 path="$1" 63 64 if [ -f "$path" ] 65 then 66 tmp_path="$(realpath "$path")" 67 68 # Check if the file is contained in any of the directories listed in the 69 # dotfiles list are the parents of path. If this is the case, print path 70 while [ "$tmp_path" != '/' ] 71 do 72 if grep -Fx "$tmp_path" "$dotfiles_list" > /dev/null 73 then 74 echo "$path" 75 return 76 fi 77 78 tmp_path="$(dirname "$tmp_path")" 79 done 80 elif [ -d "$path" ] 81 then 82 # Print all of the files and directories from the list of dotfiles 83 # contained in path 84 85 # TODO: The regex should only math occurances of path starting at the 86 # beggining of the line 87 grep -F "$(realpath "$path")" "$dotfiles_list" 88 fi 89 90 # TODO: Print a warning if we get to here: No such file or directory 91 } 92 93 # Parse the commands 94 case "$1" in 95 # Add files to the list of tracked files 96 track) 97 shift 98 99 case "$1" in 100 # Remove files from the list of dotfiles 101 -d|--delete) 102 shift 103 104 # Remove files from the list of dotfiles 105 for item in "$@" 106 do 107 # TODO: Properly escape pattern 108 echo "Removing '$item' from the list of dotfile" 109 pattern="$(realpath "$item")" 110 pattern="${pattern//\//\\\/}" 111 112 # Remove the files from the git repository and from the list of files 113 # Awk is used because 'item' may be a directory 114 awk -i inplace "!/^$pattern/ { print }" "$dotfiles_list" 115 call_git rm "$item" --cached -r 116 done 117 ;; 118 *) 119 # Add files to the list of dotfiles 120 for item in "$@" 121 do 122 echo "Adding '$item' to the list of dotfiles" 123 realpath "$item" >> "$dotfiles_list" 124 done 125 ;; 126 esac 127 ;; 128 129 # Add the files 130 add) 131 shift 132 for item in "$@" 133 do 134 get_pathspec "$item" | call_git add --pathspec-from-file - 135 done 136 ;; 137 138 # List the dotfiles specified in configurations list 139 list) 140 cat "$dotfiles_list" 141 ;; 142 143 # Show the configuration files that have been modified or deleted 144 status) 145 call_git status --porcelain \ 146 | awk '/^A / { print "✔️ ~/"$2 }; /^ A/ { print " ~/"$2 }' \ 147 | print_files 'new' '30' 148 149 call_git status --porcelain \ 150 | awk '/^M / { print "✔️ ~/"$2 }; /^ M/ { print " ~/"$2 }' \ 151 | print_files 'modified' '33' 152 153 call_git status --porcelain \ 154 | awk '/^D / { print "✔️ ~/"$2 }; /^ D/ { print " ~/"$2 }' \ 155 | print_files 'deleted' '31' 156 ;; 157 158 # Just pass the following arguments to git 159 --) 160 shift 161 call_git "$@" 162 ;; 163 164 # Just pass the arguments to git 165 *) 166 call_git "$@" 167 ;; 168 esac 169