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