]> arthur.barton.de Git - ax-zsh.git/blob - bin/axzshctl
axzshctl: Use ax_error to show error messages
[ax-zsh.git] / bin / axzshctl
1 #!/usr/bin/env zsh
2 #
3 # AX-ZSH: Alex' Modular ZSH Configuration
4 # Copyright (c) 2015-2017 Alexander Barton <alex@barton.de>
5 #
6
7 # Include "ax-common.sh", if available:
8 for dir ("$HOME/lib" "$HOME/.ax" /usr/local /opt/ax /usr); do
9         [[ -z "$ax_common_sourced" ]] || break
10         ax_common="${dir}/lib/ax/ax-common.sh"
11         [[ -r "$ax_common" ]] && source "$ax_common"
12 done
13 if [[ -z "$ax_common_sourced" ]]; then
14         function ax_msg {
15                 shift
16                 echo "$@"
17         }
18         function ax_error {
19                 ax_msg 2 "$@" >&2
20         }
21 fi
22 unset dir ax_common ax_common_sourced
23
24 function Usage {
25         echo "Usage: $NAME <command> [...]"
26         echo
27         echo "  enable"
28         echo "    Enable AX-ZSH altogether."
29         echo "  disable"
30         echo "    Disable AX-ZSH altogether."
31         echo
32         echo "  enable-plugin <name|directory> [<name|directory> [...]]"
33         echo "    Enable plugin(s)."
34         echo "  disable-plugin <name> [<name> [...]]"
35         echo "    Disable plugin(s)."
36         echo "  list-enabled"
37         echo "    List enabled plugins."
38         echo
39         echo "  reset-plugins"
40         echo "    Reset active plugins to the default set."
41         echo "  enable-default-plugins"
42         echo "    Enable all default plugins."
43         echo "  check-plugins"
44         echo "    Detect plugins which are \"useful\" on this system."
45         echo
46         echo "  set-theme <name>|-"
47         echo "    Set active theme to <name>, or to the default."
48         echo
49         echo "  upgrade"
50         echo "    Upgrade AX-ZSH installation (requires Git)."
51         echo "  update-caches"
52         echo "    Force rebuild of all cache files."
53         echo
54         exit 2
55 }
56
57 function UpdatePluginCache {
58         [[ -r "$AXZSH/cache" ]] || return 0
59
60         ax_msg - "Updating plugin cache ..."
61         rm -rf \
62                 $AXZSH/cache/zlogin.cache \
63                 $AXZSH/cache/zlogout.cache \
64                 $AXZSH/cache/zprofile.cache \
65                 $AXZSH/cache/zshrc.cache \
66                 || return 1
67         echo "Regenerating cache files ..."
68         zsh -ilc '' >/dev/null
69 }
70
71 function NormalizedPluginName {
72         if [[ "$1" =~ "^[[:alnum:]-]+/[[:alnum:]_-]+$" ]]; then
73                 echo "${1:gs/\//#}"
74         elif [[ "$1" =~ "/" ]]; then
75                 echo "${1:t}"
76         else
77                 echo "$1"
78         fi
79 }
80
81 function EnableAXZSH {
82         for f (~/.zlogin ~/.zlogout ~/.zprofile ~/.zshrc); do
83                 ln -sv "$AXZSH/ax.zsh" "$f" \
84                         || ax_error "Failed to create symbolic link for \"$f\"!"
85         done
86 }
87
88 function DisableAXZSH {
89         for f (~/.zlogin ~/.zlogout ~/.zprofile ~/.zshrc); do
90                 if [ -h "$f" ]; then
91                         rm -v "$f" || ax_msg 2 "Failed to remove \"$f\"!"
92                 elif [ -e "$f" ]; then
93                         ax_error "Error: Not removing \"$f\", it is not a symbolic link!"
94                 else
95                         ax_msg 1 "Warning: \"$f\" already does not exist. Ok."
96                 fi
97         done
98 }
99
100 function EnablePlugin {
101         local plugin=$(NormalizedPluginName "$1")
102         local dir="$AXZSH/active_plugins"
103
104         if [[ -h "$dir/$plugin" ]]; then
105                 ax_msg 1 "Plugin \"$1\" already active!"
106                 return 1
107         fi
108
109         if [[ "$1" =~ "^[[:alnum:]-]+/[[:alnum:]_-]+$" ]]; then
110                 # GitHub plugin
111                 mkdir -p "$AXZSH/repos"
112                 if [[ ! -e "$AXZSH/repos/$plugin" ]]; then
113                         ax_msg - "Cloning module from GitHub ..."
114                         git clone --depth=1 "https://github.com/$1.git" \
115                          "$AXZSH/repos/$plugin"
116                 fi
117                 # Try to enable a theme in this "foreign module", but ignore
118                 # errors: we don't know if this module provides a theme or is
119                 # a "regular" plugin ...
120                 if SetTheme "${plugin#*#}" 2>/dev/null; then
121                         ax_msg 1 "Module \"$1\" was enabled as theme \"${plugin#*#}\"."
122                         # A theme was enabled: So assume that this is a theme
123                         # and don't enable it as plugin.
124                         return 0
125                 fi
126                 echo "Module \"$1\" will be enabled as plugin ..."
127         fi
128
129         for dname (
130                 "$plugin:A"
131                 "$AXZSH_PLUGIN_D/$plugin"
132                 "$ZSH_CUSTOM/$plugin"
133                 "$AXZSH/custom_plugins/$plugin"
134                 "$AXZSH/repos/$plugin"
135                 "$AXZSH/plugins/$plugin"
136                 "$AXZSH/default_plugins/$plugin"
137                 "$AXZSH/core/$plugin"
138         ); do
139                 [[ ! -d "$dname" ]] && continue
140                 mkdir -p "$dir"
141                 (
142                         cd "$dir" || exit 9
143                         ln -sv "$dname" "$PWD"
144                 )
145                 return $?
146         done
147
148         ax_error "Plugin \"$1\" not found!"
149         return 1
150 }
151
152 function DisablePlugin {
153         local plugin=$(NormalizedPluginName "$1")
154         local dir="$AXZSH/active_plugins"
155
156         if [[ ! -h "$dir/$plugin" ]]; then
157                 ax_msg 1 "Plugin \"$1\" not active?"
158                 return 1
159         fi
160
161         rm -v "$dir/$plugin"; r=$?
162         [ $r -eq 0 ] && rm -fr "$AXZSH/repos/$plugin"
163         return $r
164 }
165
166 function ListEnabledPlugins {
167         for plugin ($AXZSH/active_plugins/*(N)); do
168                 print ${plugin:t:s/#/\//}
169         done
170         return 0
171 }
172
173 function ResetPlugins {
174         local dir="$AXZSH/active_plugins"
175         local r1=0, r2=0
176
177         if [[ -e "$dir" ]]; then
178                 ax_msg - "Removing all symbolic links in $dir ..."
179                 find "$dir" -type l -print -delete; r1=$?
180         fi
181
182         ax_msg - "Removing all external repositories in \"$AXZSH/repos\" ..."
183         rm -fr "$AXZSH/repos"; r2=$?
184
185         [[ $r1 == 0 && $r2 == 0 ]] && return 0 || return 1
186 }
187
188 function EnableDefaultPlugins {
189         local dir="$AXZSH/active_plugins"
190
191         ax_msg - "Activating (linking) default plugins ..."
192         mkdir -p "$dir"
193         (
194                 cd "$dir" || exit 9
195                 ln -sfv "$AXZSH/default_plugins/"* "$PWD"
196         )
197         return $?
198 }
199
200 function SetTheme {
201         local link_name="$AXZSH/active_theme"
202
203         if [ "$1" = "-" ]; then
204                 rm -f "$link_name" || return 1
205                 ax_msg 0 "Theme settings have been reset."
206                 return 0
207         fi
208
209         if [ -r "$1" ]; then
210                 theme="$1"
211         elif [ -r "$AXZSH/custom_themes/$1.axzshtheme" ]; then
212                 theme="$AXZSH/custom_themes/$1.axzshtheme"
213         elif [ -r "$AXZSH/themes/$1.axzshtheme" ]; then
214                 theme="$AXZSH/themes/$1.axzshtheme"
215         else
216                 # Look for theme inside of installed plugins:
217                 for dname (
218                         "$AXZSH/custom_themes"
219                         "$AXZSH/custom_plugins/"*(N)
220                         "$AXZSH/repos/"*(N)
221                 ); do
222                         if [[ -r "$dname/$1.axzshtheme" ]]; then
223                                 theme="$dname/$1.axzshtheme"
224                                 break
225                         elif [[ -r "$dname/$1.zsh-theme" ]]; then
226                                 theme="$dname/$1.zsh-theme"
227                                 break
228                         fi
229                 done
230                 if [[ -z "$theme" ]]; then
231                         ax_error "Theme \"$1\" not found!"
232                         return 1
233                 fi
234         fi
235         ln -fsv "$theme" "$link_name" || return 1
236         return $?
237 }
238
239 function UpgradeAXZSH {
240         if [[ $+commands[git] -eq 0 ]]; then
241                 ax_error "The git(1) command is not available!"
242                 return 1
243         fi
244         if [[ ! -d "$AXZSH/.git" ]]; then
245                 ax_error "AX-ZSH seems not to be installed using Git. Can't upgrade!"
246                 return 1
247         fi
248
249         ax_msg - "Upgrading AX-ZSH in \"$AXZSH\" using git(1) ..."
250         ( cd "$AXZSH" && git pull --ff-only )
251 }
252
253 function UpgradeForeignPlugins {
254         if [[ $+commands[git] -eq 0 ]]; then
255                 ax_error "The git(1) command is not available!"
256                 return 1
257         fi
258
259         for dir ($AXZSH/repos/*(N)); do
260                 name=${dir:t:s/#/\//}
261                 if [ -d "$dir/.git" ]; then
262                         ax_msg - "Upgrading \"$name\" [git] ..."
263                         (
264                                 cd "$dir"
265                                 git pull --ff-only || ax_error "Pull failed!"
266                         )
267                 else
268                         ax_error "Unknown repository type!"
269                 fi
270         done
271 }
272
273 function CheckPlugins {
274         missing_plugins=()
275         invalid_plugins=()
276
277         ax_msg - "Checking plugins ..."
278         for dir ($AXZSH/plugins/*(N)); do
279                 plugin=${dir:t}
280
281                 # Test if plugin is already enabled
282                 [[ -e "$AXZSH/active_plugins/$plugin" ]] \
283                         && enabled=" (enabled)" \
284                         || unset enabled
285
286                 # Test plugin ...
287                 printf " - \"%s\"%s ... " "$plugin" "$enabled"
288                 new_plugin=""
289                 for script ($AXZSH/plugins/$plugin/$plugin.{zshrc,zprofile}); do
290                         [[ -r "$script" ]] || continue
291                         AXZSH_PLUGIN_CHECK=1 zsh -i -c "source $script"; r=$?
292                         if [[ $r -eq 0 ]]; then
293                                 new_plugin=$plugin
294                                 break
295                         fi
296                 done
297                 if [[ -n "$new_plugin" ]]; then
298                         detected_plugins+=($new_plugin)
299                         [[ -n "$enabled" ]] || missing_plugins+=($new_plugin)
300                         ax_msg 0 "OK."
301                 elif [[ $r -eq 91 ]]; then
302                         ax_msg 1 "ignored."
303                 elif [[ $r -eq 92 ]]; then
304                         ax_msg 1 "optional."
305                 else
306                         [[ -n "$enabled" ]] && invalid_plugins+=($plugin)
307                         ax_msg 2 "failed."
308                 fi
309         done
310         echo
311
312         result=0
313         if [[ -n "$missing_plugins" ]]; then
314                 ax_msg 1 "Run the following command to enable all missing plugins:"
315                 echo "$AXZSH/bin/axzshctl enable-plugin" $missing_plugins
316                 echo
317                 result=1
318         else
319                 ax_msg 0 "All detected plugins are already enabled."
320         fi
321
322         if [[ -n "$invalid_plugins" ]]; then
323                 ax_msg 1 "Run the following command to disable all failed plugins:"
324                 echo "$AXZSH/bin/axzshctl disable-plugin" $invalid_plugins
325                 result=1
326         else
327                 ax_msg 0 "No failed plugins are enabled."
328         fi
329
330         echo
331         return $result
332 }
333
334 NAME="$0:t"
335
336 [[ $# -gt 0 ]] || Usage
337
338 if [[ -z "$AXZSH" || ! -r "$AXZSH/ax.zsh" ]]; then
339         [[ -r "$HOME/.axzsh/ax.zsh" ]] && AXZSH="$HOME/.axzsh"
340         if [[ ! -r "$AXZSH/ax.zsh" ]]; then
341                 ax_error "Oops, \"AXZSH\" is not set or invalid and can't be autodetected!"
342                 exit 3
343         fi
344 fi
345
346 cmd="$1"
347 shift
348
349 case "$cmd" in
350         "enable")
351                 [[ $# -eq 0 ]] || Usage
352                 EnableAXZSH
353                 ;;
354         "disable")
355                 [[ $# -eq 0 ]] || Usage
356                 DisableAXZSH
357                 ;;
358         "enable-plugin")
359                 [[ $# -gt 0 ]] || Usage
360                 for plugin in "$@"; do
361                         EnablePlugin "$plugin"
362                 done
363                 UpdatePluginCache
364                 ;;
365         "disable-plugin")
366                 [[ $# -gt 0 ]] || Usage
367                 for plugin in "$@"; do
368                         DisablePlugin "$plugin"
369                 done
370                 UpdatePluginCache
371                 ;;
372         "list-enabled")
373                 [[ $# -eq 0 ]] || Usage
374                 ListEnabledPlugins
375                 ;;
376         "reset-plugins")
377                 [[ $# -eq 0 ]] || Usage
378                 ResetPlugins
379                 EnableDefaultPlugins
380                 UpdatePluginCache
381                 ;;
382         "enable-default-plugins")
383                 [[ $# -eq 0 ]] || Usage
384                 EnableDefaultPlugins && UpdatePluginCache
385                 ;;
386         "check-plugins")
387                 [[ $# -eq 0 ]] || Usage
388                 CheckPlugins
389                 ;;
390         "set-theme")
391                 [[ $# -eq 1 ]] || Usage
392                 SetTheme "$1"
393                 ;;
394         "upgrade")
395                 [[ $# -eq 0 ]] || Usage
396                 UpgradeAXZSH
397                 UpgradeForeignPlugins
398                 UpdatePluginCache
399                 ;;
400         "update-caches")
401                 [[ $# -eq 0 ]] || Usage
402                 UpdatePluginCache
403                 ;;
404         *)
405                 Usage
406 esac