Commit 66bfd795223b05652064ea6c8d0eca6a42673040

Authored by Shrikant Sharat

Merge pull request #74 from coreyjewett/master

localize and don't leak cross-platform md5 function

Showing 1 changed file Inline Diff

1 # Antigen: A simple plugin manager for zsh 1 # Antigen: A simple plugin manager for zsh
2 # Authors: Shrikant Sharat Kandula 2 # Authors: Shrikant Sharat Kandula
3 # and Contributors <https://github.com/zsh-users/antigen/contributors> 3 # and Contributors <https://github.com/zsh-users/antigen/contributors>
4 # Homepage: http://antigen.sharats.me 4 # Homepage: http://antigen.sharats.me
5 # License: MIT License <mitl.sharats.me> 5 # License: MIT License <mitl.sharats.me>
6 6
7 # Each line in this string has the following entries separated by a space 7 # Each line in this string has the following entries separated by a space
8 # character. 8 # character.
9 # <repo-url>, <plugin-location>, <bundle-type>, <has-local-clone> 9 # <repo-url>, <plugin-location>, <bundle-type>, <has-local-clone>
10 # FIXME: Is not kept local by zsh! 10 # FIXME: Is not kept local by zsh!
11 local _ANTIGEN_BUNDLE_RECORD="" 11 local _ANTIGEN_BUNDLE_RECORD=""
12 local _ANTIGEN_INSTALL_DIR="$(cd "$(dirname "$0")" && pwd)" 12 local _ANTIGEN_INSTALL_DIR="$(cd "$(dirname "$0")" && pwd)"
13 13
14 # Used to defer compinit/compdef 14 # Used to defer compinit/compdef
15 typeset -a __deferred_compdefs 15 typeset -a __deferred_compdefs
16 compdef () { __deferred_compdefs=($__deferred_compdefs "$*") } 16 compdef () { __deferred_compdefs=($__deferred_compdefs "$*") }
17 17
18 # bsd/osx md5 v.s. linux md5sum
19 chksum() { (md5sum; test $? = 127 && md5) 2>/dev/null | cut -d' ' -f1 }
20
21 # Syntaxes 18 # Syntaxes
22 # antigen-bundle <url> [<loc>=/] 19 # antigen-bundle <url> [<loc>=/]
23 # Keyword only arguments: 20 # Keyword only arguments:
24 # branch - The branch of the repo to use for this bundle. 21 # branch - The branch of the repo to use for this bundle.
25 antigen-bundle () { 22 antigen-bundle () {
26 23
27 # Bundle spec arguments' default values. 24 # Bundle spec arguments' default values.
28 local url="$ANTIGEN_DEFAULT_REPO_URL" 25 local url="$ANTIGEN_DEFAULT_REPO_URL"
29 local loc=/ 26 local loc=/
30 local branch= 27 local branch=
31 local no_local_clone=false 28 local no_local_clone=false
32 local btype=plugin 29 local btype=plugin
33 30
34 # Parse the given arguments. (Will overwrite the above values). 31 # Parse the given arguments. (Will overwrite the above values).
35 eval "$(-antigen-parse-args \ 32 eval "$(-antigen-parse-args \
36 'url?, loc? ; branch:?, no-local-clone?, btype:?' \ 33 'url?, loc? ; branch:?, no-local-clone?, btype:?' \
37 "$@")" 34 "$@")"
38 35
39 # Check if url is just the plugin name. Super short syntax. 36 # Check if url is just the plugin name. Super short syntax.
40 if [[ "$url" != */* ]]; then 37 if [[ "$url" != */* ]]; then
41 loc="plugins/$url" 38 loc="plugins/$url"
42 url="$ANTIGEN_DEFAULT_REPO_URL" 39 url="$ANTIGEN_DEFAULT_REPO_URL"
43 fi 40 fi
44 41
45 # Resolve the url. 42 # Resolve the url.
46 url="$(-antigen-resolve-bundle-url "$url")" 43 url="$(-antigen-resolve-bundle-url "$url")"
47 44
48 # Add the branch information to the url. 45 # Add the branch information to the url.
49 if [[ ! -z $branch ]]; then 46 if [[ ! -z $branch ]]; then
50 url="$url|$branch" 47 url="$url|$branch"
51 fi 48 fi
52 49
53 # The `make_local_clone` variable better represents whether there should be 50 # The `make_local_clone` variable better represents whether there should be
54 # a local clone made. For cloning to be avoided, firstly, the `$url` should 51 # a local clone made. For cloning to be avoided, firstly, the `$url` should
55 # be an absolute local path and `$branch` should be empty. In addition to 52 # be an absolute local path and `$branch` should be empty. In addition to
56 # these two conditions, either the `--no-local-clone` option should be 53 # these two conditions, either the `--no-local-clone` option should be
57 # given, or `$url` should not a git repo. 54 # given, or `$url` should not a git repo.
58 local make_local_clone=true 55 local make_local_clone=true
59 if [[ $url == /* && -z $branch && 56 if [[ $url == /* && -z $branch &&
60 ( $no_local_clone == true || ! -d $url/.git ) ]]; then 57 ( $no_local_clone == true || ! -d $url/.git ) ]]; then
61 make_local_clone=false 58 make_local_clone=false
62 fi 59 fi
63 60
64 # Add the theme extension to `loc`, if this is a theme. 61 # Add the theme extension to `loc`, if this is a theme.
65 if [[ $btype == theme && $loc != *.zsh-theme ]]; then 62 if [[ $btype == theme && $loc != *.zsh-theme ]]; then
66 loc="$loc.zsh-theme" 63 loc="$loc.zsh-theme"
67 fi 64 fi
68 65
69 # Add it to the record. 66 # Add it to the record.
70 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD\n$url $loc $btype" 67 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD\n$url $loc $btype"
71 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD $make_local_clone" 68 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD $make_local_clone"
72 69
73 # Ensure a clone exists for this repo, if needed. 70 # Ensure a clone exists for this repo, if needed.
74 if $make_local_clone; then 71 if $make_local_clone; then
75 -antigen-ensure-repo "$url" 72 -antigen-ensure-repo "$url"
76 fi 73 fi
77 74
78 # Load the plugin. 75 # Load the plugin.
79 -antigen-load "$url" "$loc" "$btype" "$make_local_clone" 76 -antigen-load "$url" "$loc" "$btype" "$make_local_clone"
80 77
81 } 78 }
82 79
83 -antigen-resolve-bundle-url () { 80 -antigen-resolve-bundle-url () {
84 # Given an acceptable short/full form of a bundle's repo url, this function 81 # Given an acceptable short/full form of a bundle's repo url, this function
85 # echoes the full form of the repo's clone url. 82 # echoes the full form of the repo's clone url.
86 83
87 local url="$1" 84 local url="$1"
88 85
89 # Expand short github url syntax: `username/reponame`. 86 # Expand short github url syntax: `username/reponame`.
90 if [[ $url != git://* && 87 if [[ $url != git://* &&
91 $url != https://* && 88 $url != https://* &&
92 $url != http://* && 89 $url != http://* &&
93 $url != ssh://* && 90 $url != ssh://* &&
94 $url != /* && 91 $url != /* &&
95 $url != git@github.com:*/* 92 $url != git@github.com:*/*
96 ]]; then 93 ]]; then
97 url="https://github.com/${url%.git}.git" 94 url="https://github.com/${url%.git}.git"
98 fi 95 fi
99 96
100 echo "$url" 97 echo "$url"
101 } 98 }
102 99
103 antigen-bundles () { 100 antigen-bundles () {
104 # Bulk add many bundles at one go. Empty lines and lines starting with a `#` 101 # Bulk add many bundles at one go. Empty lines and lines starting with a `#`
105 # are ignored. Everything else is given to `antigen-bundle` as is, no 102 # are ignored. Everything else is given to `antigen-bundle` as is, no
106 # quoting rules applied. 103 # quoting rules applied.
107 104
108 local line 105 local line
109 106
110 grep '^[[:space:]]*[^[:space:]#]' | while read line; do 107 grep '^[[:space:]]*[^[:space:]#]' | while read line; do
111 # Using `eval` so that we can use the shell-style quoting in each line 108 # Using `eval` so that we can use the shell-style quoting in each line
112 # piped to `antigen-bundles`. 109 # piped to `antigen-bundles`.
113 eval "antigen-bundle $line" 110 eval "antigen-bundle $line"
114 done 111 done
115 } 112 }
116 113
117 antigen-update () { 114 antigen-update () {
118 # Update your bundles, i.e., `git pull` in all the plugin repos. 115 # Update your bundles, i.e., `git pull` in all the plugin repos.
119 116
120 date > $ADOTDIR/revert-info 117 date > $ADOTDIR/revert-info
121 118
122 -antigen-echo-record | 119 -antigen-echo-record |
123 awk '$4 == "true" {print $1}' | 120 awk '$4 == "true" {print $1}' |
124 sort -u | 121 sort -u |
125 while read url; do 122 while read url; do
126 echo "**** Pulling $url" 123 echo "**** Pulling $url"
127 124
128 local clone_dir="$(-antigen-get-clone-dir "$url")" 125 local clone_dir="$(-antigen-get-clone-dir "$url")"
129 if [[ -d "$clone_dir" ]]; then 126 if [[ -d "$clone_dir" ]]; then
130 (echo -n "$clone_dir:" 127 (echo -n "$clone_dir:"
131 cd "$clone_dir" 128 cd "$clone_dir"
132 git rev-parse HEAD) >> $ADOTDIR/revert-info 129 git rev-parse HEAD) >> $ADOTDIR/revert-info
133 fi 130 fi
134 131
135 -antigen-ensure-repo "$url" --update --verbose 132 -antigen-ensure-repo "$url" --update --verbose
136 133
137 echo 134 echo
138 done 135 done
139 } 136 }
140 137
141 antigen-revert () { 138 antigen-revert () {
142 if [[ -f $ADOTDIR/revert-info ]]; then 139 if [[ -f $ADOTDIR/revert-info ]]; then
143 cat $ADOTDIR/revert-info | sed '1!p' | while read line; do 140 cat $ADOTDIR/revert-info | sed '1!p' | while read line; do
144 dir="$(echo "$line" | cut -d: -f1)" 141 dir="$(echo "$line" | cut -d: -f1)"
145 git --git-dir="$dir/.git" --work-tree="$dir" \ 142 git --git-dir="$dir/.git" --work-tree="$dir" \
146 checkout "$(echo "$line" | cut -d: -f2)" 2> /dev/null 143 checkout "$(echo "$line" | cut -d: -f2)" 2> /dev/null
147 144
148 done 145 done
149 146
150 echo "Reverted to state before running -update on $( 147 echo "Reverted to state before running -update on $(
151 cat $ADOTDIR/revert-info | sed -n 1p)." 148 cat $ADOTDIR/revert-info | sed -n 1p)."
152 149
153 else 150 else
154 echo 'No revert information available. Cannot revert.' >&2 151 echo 'No revert information available. Cannot revert.' >&2
155 fi 152 fi
156 153
157 154
158 } 155 }
159 156
160 -antigen-get-clone-dir () { 157 -antigen-get-clone-dir () {
161 # Takes a repo url and gives out the path that this url needs to be cloned 158 # Takes a repo url and gives out the path that this url needs to be cloned
162 # to. Doesn't actually clone anything. 159 # to. Doesn't actually clone anything.
163 echo -n $ADOTDIR/repos/ 160 echo -n $ADOTDIR/repos/
164 161
165 if [[ "$1" == "https://github.com/sorin-ionescu/prezto.git" ]]; then 162 if [[ "$1" == "https://github.com/sorin-ionescu/prezto.git" ]]; then
166 # Prezto's directory *has* to be `.zprezto`. 163 # Prezto's directory *has* to be `.zprezto`.
167 echo .zprezto 164 echo .zprezto
168 165
169 else 166 else
170 echo "$1" | sed \ 167 echo "$1" | sed \
171 -e 's./.-SLASH-.g' \ 168 -e 's./.-SLASH-.g' \
172 -e 's.:.-COLON-.g' \ 169 -e 's.:.-COLON-.g' \
173 -e 's.|.-PIPE-.g' 170 -e 's.|.-PIPE-.g'
174 171
175 fi 172 fi
176 } 173 }
177 174
178 -antigen-get-clone-url () { 175 -antigen-get-clone-url () {
179 # Takes a repo's clone dir and gives out the repo's original url that was 176 # Takes a repo's clone dir and gives out the repo's original url that was
180 # used to create the given directory path. 177 # used to create the given directory path.
181 178
182 if [[ "$1" == ".zprezto" ]]; then 179 if [[ "$1" == ".zprezto" ]]; then
183 # Prezto's (in `.zprezto`), is assumed to be from `sorin-ionescu`'s 180 # Prezto's (in `.zprezto`), is assumed to be from `sorin-ionescu`'s
184 # remote. 181 # remote.
185 echo https://github.com/sorin-ionescu/prezto.git 182 echo https://github.com/sorin-ionescu/prezto.git
186 183
187 else 184 else
188 echo "$1" | sed \ 185 echo "$1" | sed \
189 -e "s:^$ADOTDIR/repos/::" \ 186 -e "s:^$ADOTDIR/repos/::" \
190 -e 's.-SLASH-./.g' \ 187 -e 's.-SLASH-./.g' \
191 -e 's.-COLON-.:.g' \ 188 -e 's.-COLON-.:.g' \
192 -e 's.-PIPE-.|.g' 189 -e 's.-PIPE-.|.g'
193 190
194 fi 191 fi
195 } 192 }
196 193
197 -antigen-ensure-repo () { 194 -antigen-ensure-repo () {
198 195
199 # Ensure that a clone exists for the given repo url and branch. If the first 196 # Ensure that a clone exists for the given repo url and branch. If the first
200 # argument is `--update` and if a clone already exists for the given repo 197 # argument is `--update` and if a clone already exists for the given repo
201 # and branch, it is pull-ed, i.e., updated. 198 # and branch, it is pull-ed, i.e., updated.
202 199
203 # Argument defaults. 200 # Argument defaults.
204 # The url. No sane default for this, so just empty. 201 # The url. No sane default for this, so just empty.
205 local url= 202 local url=
206 # Check if we have to update. 203 # Check if we have to update.
207 local update=false 204 local update=false
208 # Verbose output. 205 # Verbose output.
209 local verbose=false 206 local verbose=false
210 207
211 eval "$(-antigen-parse-args 'url ; update?, verbose?' "$@")" 208 eval "$(-antigen-parse-args 'url ; update?, verbose?' "$@")"
212 shift $# 209 shift $#
213 210
214 # Get the clone's directory as per the given repo url and branch. 211 # Get the clone's directory as per the given repo url and branch.
215 local clone_dir="$(-antigen-get-clone-dir $url)" 212 local clone_dir="$(-antigen-get-clone-dir $url)"
216 213
217 # A temporary function wrapping the `git` command with repeated arguments. 214 # A temporary function wrapping the `git` command with repeated arguments.
218 --plugin-git () { 215 --plugin-git () {
219 (cd "$clone_dir" && git --no-pager "$@") 216 (cd "$clone_dir" && git --no-pager "$@")
220 } 217 }
221 218
222 # Clone if it doesn't already exist. 219 # Clone if it doesn't already exist.
223 if [[ ! -d $clone_dir ]]; then 220 if [[ ! -d $clone_dir ]]; then
224 git clone --recursive "${url%|*}" "$clone_dir" 221 git clone --recursive "${url%|*}" "$clone_dir"
225 elif $update; then 222 elif $update; then
226 # Save current revision. 223 # Save current revision.
227 local old_rev="$(--plugin-git rev-parse HEAD)" 224 local old_rev="$(--plugin-git rev-parse HEAD)"
228 # Pull changes if update requested. 225 # Pull changes if update requested.
229 --plugin-git pull 226 --plugin-git pull
230 # Update submodules. 227 # Update submodules.
231 --plugin-git submodule update --recursive 228 --plugin-git submodule update --recursive
232 # Get the new revision. 229 # Get the new revision.
233 local new_rev="$(--plugin-git rev-parse HEAD)" 230 local new_rev="$(--plugin-git rev-parse HEAD)"
234 fi 231 fi
235 232
236 # If its a specific branch that we want, checkout that branch. 233 # If its a specific branch that we want, checkout that branch.
237 if [[ $url == *\|* ]]; then 234 if [[ $url == *\|* ]]; then
238 local current_branch=${$(--plugin-git symbolic-ref HEAD)##refs/heads/} 235 local current_branch=${$(--plugin-git symbolic-ref HEAD)##refs/heads/}
239 local requested_branch="${url#*|}" 236 local requested_branch="${url#*|}"
240 # Only do the checkout when we are not already on the branch. 237 # Only do the checkout when we are not already on the branch.
241 [[ $requested_branch != $current_branch ]] && 238 [[ $requested_branch != $current_branch ]] &&
242 --plugin-git checkout $requested_branch 239 --plugin-git checkout $requested_branch
243 fi 240 fi
244 241
245 if [[ -n $old_rev && $old_rev != $new_rev ]]; then 242 if [[ -n $old_rev && $old_rev != $new_rev ]]; then
246 echo Updated from ${old_rev:0:7} to ${new_rev:0:7}. 243 echo Updated from ${old_rev:0:7} to ${new_rev:0:7}.
247 if $verbose; then 244 if $verbose; then
248 --plugin-git log --oneline --reverse --no-merges --stat '@{1}..' 245 --plugin-git log --oneline --reverse --no-merges --stat '@{1}..'
249 fi 246 fi
250 fi 247 fi
251 248
252 # Remove the temporary git wrapper function. 249 # Remove the temporary git wrapper function.
253 unfunction -- --plugin-git 250 unfunction -- --plugin-git
254 251
255 } 252 }
256 253
257 -antigen-load () { 254 -antigen-load () {
258 255
259 local url="$1" 256 local url="$1"
260 local loc="$2" 257 local loc="$2"
261 local btype="$3" 258 local btype="$3"
262 local make_local_clone="$4" 259 local make_local_clone="$4"
263 260
264 # The full location where the plugin is located. 261 # The full location where the plugin is located.
265 local location 262 local location
266 if $make_local_clone; then 263 if $make_local_clone; then
267 location="$(-antigen-get-clone-dir "$url")/$loc" 264 location="$(-antigen-get-clone-dir "$url")/$loc"
268 else 265 else
269 location="$url" 266 location="$url"
270 fi 267 fi
271 268
272 if [[ $btype == theme ]]; then 269 if [[ $btype == theme ]]; then
273 270
274 # Of course, if its a theme, the location would point to the script 271 # Of course, if its a theme, the location would point to the script
275 # file. 272 # file.
276 source "$location" 273 source "$location"
277 274
278 else 275 else
279 276
280 # Source the plugin script. 277 # Source the plugin script.
281 # FIXME: I don't know. Looks very very ugly. Needs a better 278 # FIXME: I don't know. Looks very very ugly. Needs a better
282 # implementation once tests are ready. 279 # implementation once tests are ready.
283 local script_loc="$(ls "$location" | grep '\.plugin\.zsh$' | head -n1)" 280 local script_loc="$(ls "$location" | grep '\.plugin\.zsh$' | head -n1)"
284 281
285 if [[ -f $location/$script_loc ]]; then 282 if [[ -f $location/$script_loc ]]; then
286 # If we have a `*.plugin.zsh`, source it. 283 # If we have a `*.plugin.zsh`, source it.
287 source "$location/$script_loc" 284 source "$location/$script_loc"
288 285
289 elif [[ -f $location/init.zsh ]]; then 286 elif [[ -f $location/init.zsh ]]; then
290 # If we have a `init.zsh` 287 # If we have a `init.zsh`
291 if (( $+functions[pmodload] )); then 288 if (( $+functions[pmodload] )); then
292 # If pmodload is defined pmodload the module. Remove `modules/` 289 # If pmodload is defined pmodload the module. Remove `modules/`
293 # from loc to find module name. 290 # from loc to find module name.
294 pmodload "${loc#modules/}" 291 pmodload "${loc#modules/}"
295 else 292 else
296 # Otherwise source it. 293 # Otherwise source it.
297 source "$location/init.zsh" 294 source "$location/init.zsh"
298 fi 295 fi
299 296
300 elif ls "$location" | grep -l '\.zsh$' &> /dev/null; then 297 elif ls "$location" | grep -l '\.zsh$' &> /dev/null; then
301 # If there is no `*.plugin.zsh` file, source *all* the `*.zsh` 298 # If there is no `*.plugin.zsh` file, source *all* the `*.zsh`
302 # files. 299 # files.
303 for script ($location/*.zsh(N)) source "$script" 300 for script ($location/*.zsh(N)) source "$script"
304 301
305 elif ls "$location" | grep -l '\.sh$' &> /dev/null; then 302 elif ls "$location" | grep -l '\.sh$' &> /dev/null; then
306 # If there are no `*.zsh` files either, we look for and source any 303 # If there are no `*.zsh` files either, we look for and source any
307 # `*.sh` files instead. 304 # `*.sh` files instead.
308 for script ($location/*.sh(N)) source "$script" 305 for script ($location/*.sh(N)) source "$script"
309 306
310 fi 307 fi
311 308
312 # Add to $fpath, for completion(s). 309 # Add to $fpath, for completion(s).
313 fpath=($location $fpath) 310 fpath=($location $fpath)
314 311
315 fi 312 fi
316 313
317 } 314 }
318 315
319 # Update (with `git pull`) antigen itself. 316 # Update (with `git pull`) antigen itself.
320 # TODO: Once update is finished, show a summary of the new commits, as a kind of 317 # TODO: Once update is finished, show a summary of the new commits, as a kind of
321 # "what's new" message. 318 # "what's new" message.
322 antigen-selfupdate () { 319 antigen-selfupdate () {
323 ( cd $_ANTIGEN_INSTALL_DIR 320 ( cd $_ANTIGEN_INSTALL_DIR
324 if [[ ! ( -d .git || -f .git ) ]]; then 321 if [[ ! ( -d .git || -f .git ) ]]; then
325 echo "Your copy of antigen doesn't appear to be a git clone. " \ 322 echo "Your copy of antigen doesn't appear to be a git clone. " \
326 "The 'selfupdate' command cannot work in this case." 323 "The 'selfupdate' command cannot work in this case."
327 return 1 324 return 1
328 fi 325 fi
329 local head="$(git rev-parse --abbrev-ref HEAD)" 326 local head="$(git rev-parse --abbrev-ref HEAD)"
330 if [[ $head == "HEAD" ]]; then 327 if [[ $head == "HEAD" ]]; then
331 # If current head is detached HEAD, checkout to master branch. 328 # If current head is detached HEAD, checkout to master branch.
332 git checkout master 329 git checkout master
333 fi 330 fi
334 git pull 331 git pull
335 ) 332 )
336 } 333 }
337 334
338 antigen-cleanup () { 335 antigen-cleanup () {
339 336
340 # Cleanup unused repositories. 337 # Cleanup unused repositories.
341 338
342 local force=false 339 local force=false
343 if [[ $1 == --force ]]; then 340 if [[ $1 == --force ]]; then
344 force=true 341 force=true
345 fi 342 fi
346 343
347 if [[ ! -d "$ADOTDIR/repos" || -z "$(ls "$ADOTDIR/repos/")" ]]; then 344 if [[ ! -d "$ADOTDIR/repos" || -z "$(ls "$ADOTDIR/repos/")" ]]; then
348 echo "You don't have any bundles." 345 echo "You don't have any bundles."
349 return 0 346 return 0
350 fi 347 fi
351 348
352 # Find directores in ADOTDIR/repos, that are not in the bundles record. 349 # Find directores in ADOTDIR/repos, that are not in the bundles record.
353 local unused_clones="$(comm -13 \ 350 local unused_clones="$(comm -13 \
354 <(-antigen-echo-record | 351 <(-antigen-echo-record |
355 awk '$4 == "true" {print $1}' | 352 awk '$4 == "true" {print $1}' |
356 while read line; do 353 while read line; do
357 -antigen-get-clone-dir "$line" 354 -antigen-get-clone-dir "$line"
358 done | 355 done |
359 sort -u) \ 356 sort -u) \
360 <(ls -d "$ADOTDIR/repos/"* | sort -u))" 357 <(ls -d "$ADOTDIR/repos/"* | sort -u))"
361 358
362 if [[ -z $unused_clones ]]; then 359 if [[ -z $unused_clones ]]; then
363 echo "You don't have any unidentified bundles." 360 echo "You don't have any unidentified bundles."
364 return 0 361 return 0
365 fi 362 fi
366 363
367 echo 'You have clones for the following repos, but are not used.' 364 echo 'You have clones for the following repos, but are not used.'
368 echo "$unused_clones" | 365 echo "$unused_clones" |
369 while read line; do 366 while read line; do
370 -antigen-get-clone-url "$line" 367 -antigen-get-clone-url "$line"
371 done | 368 done |
372 sed -e 's/^/ /' -e 's/|/, branch /' 369 sed -e 's/^/ /' -e 's/|/, branch /'
373 370
374 if $force || (echo -n '\nDelete them all? [y/N] '; read -q); then 371 if $force || (echo -n '\nDelete them all? [y/N] '; read -q); then
375 echo 372 echo
376 echo 373 echo
377 echo "$unused_clones" | while read line; do 374 echo "$unused_clones" | while read line; do
378 echo -n "Deleting clone for $(-antigen-get-clone-url "$line")..." 375 echo -n "Deleting clone for $(-antigen-get-clone-url "$line")..."
379 rm -rf "$line" 376 rm -rf "$line"
380 echo ' done.' 377 echo ' done.'
381 done 378 done
382 else 379 else
383 echo 380 echo
384 echo Nothing deleted. 381 echo Nothing deleted.
385 fi 382 fi
386 } 383 }
387 384
388 antigen-use () { 385 antigen-use () {
389 if [[ $1 == oh-my-zsh ]]; then 386 if [[ $1 == oh-my-zsh ]]; then
390 -antigen-use-oh-my-zsh 387 -antigen-use-oh-my-zsh
391 elif [[ $1 == prezto ]]; then 388 elif [[ $1 == prezto ]]; then
392 -antigen-use-prezto 389 -antigen-use-prezto
393 else 390 else
394 echo 'Usage: antigen-use <library-name>' >&2 391 echo 'Usage: antigen-use <library-name>' >&2
395 echo 'Where <library-name> is any one of the following:' >&2 392 echo 'Where <library-name> is any one of the following:' >&2
396 echo ' * oh-my-zsh' >&2 393 echo ' * oh-my-zsh' >&2
397 echo ' * prezto' >&2 394 echo ' * prezto' >&2
398 return 1 395 return 1
399 fi 396 fi
400 } 397 }
401 398
402 -antigen-use-oh-my-zsh () { 399 -antigen-use-oh-my-zsh () {
403 if [[ -z "$ZSH" ]]; then 400 if [[ -z "$ZSH" ]]; then
404 export ZSH="$(-antigen-get-clone-dir "$ANTIGEN_DEFAULT_REPO_URL")" 401 export ZSH="$(-antigen-get-clone-dir "$ANTIGEN_DEFAULT_REPO_URL")"
405 fi 402 fi
406 antigen-bundle --loc=lib 403 antigen-bundle --loc=lib
407 } 404 }
408 405
409 -antigen-use-prezto () { 406 -antigen-use-prezto () {
410 antigen-bundle sorin-ionescu/prezto 407 antigen-bundle sorin-ionescu/prezto
411 export ZDOTDIR=$ADOTDIR/repos/ 408 export ZDOTDIR=$ADOTDIR/repos/
412 } 409 }
413 410
414 # For backwards compatibility. 411 # For backwards compatibility.
415 antigen-lib () { 412 antigen-lib () {
416 -antigen-use-oh-my-zsh 413 -antigen-use-oh-my-zsh
417 echo '`antigen-lib` is deprecated and will soon be removed.' 414 echo '`antigen-lib` is deprecated and will soon be removed.'
418 echo 'Use `antigen-use oh-my-zsh` instead.' 415 echo 'Use `antigen-use oh-my-zsh` instead.'
419 } 416 }
420 417
421 # For backwards compatibility. 418 # For backwards compatibility.
422 antigen-prezto-lib () { 419 antigen-prezto-lib () {
423 -antigen-use-prezto 420 -antigen-use-prezto
424 echo '`antigen-prezto-lib` is deprecated and will soon be removed.' 421 echo '`antigen-prezto-lib` is deprecated and will soon be removed.'
425 echo 'Use `antigen-use prezto` instead.' 422 echo 'Use `antigen-use prezto` instead.'
426 } 423 }
427 424
428 antigen-theme () { 425 antigen-theme () {
429 426
430 if [[ "$1" != */* && "$1" != --* ]]; then 427 if [[ "$1" != */* && "$1" != --* ]]; then
431 # The first argument is just a name of the plugin, to be picked up from 428 # The first argument is just a name of the plugin, to be picked up from
432 # the default repo. 429 # the default repo.
433 local name="${1:-robbyrussell}" 430 local name="${1:-robbyrussell}"
434 antigen-bundle --loc=themes/$name --btype=theme 431 antigen-bundle --loc=themes/$name --btype=theme
435 432
436 else 433 else
437 antigen-bundle "$@" --btype=theme 434 antigen-bundle "$@" --btype=theme
438 435
439 fi 436 fi
440 437
441 } 438 }
442 439
443 antigen-apply () { 440 antigen-apply () {
444 441
445 # Initialize completion. 442 # Initialize completion.
446 local cdef 443 local cdef
447 444
448 # Load the compinit module. This will readefine the `compdef` function to 445 # Load the compinit module. This will readefine the `compdef` function to
449 # the one that actually initializes completions. 446 # the one that actually initializes completions.
450 autoload -U compinit 447 autoload -U compinit
451 compinit -i 448 compinit -i
452 449
453 # Apply all `compinit`s that have been deferred. 450 # Apply all `compinit`s that have been deferred.
454 eval "$(for cdef in $__deferred_compdefs; do 451 eval "$(for cdef in $__deferred_compdefs; do
455 echo compdef $cdef 452 echo compdef $cdef
456 done)" 453 done)"
457 454
458 unset __deferred_compdefs 455 unset __deferred_compdefs
459 456
460 } 457 }
461 458
462 antigen-list () { 459 antigen-list () {
463 # List all currently installed bundles. 460 # List all currently installed bundles.
464 if [[ -z "$_ANTIGEN_BUNDLE_RECORD" ]]; then 461 if [[ -z "$_ANTIGEN_BUNDLE_RECORD" ]]; then
465 echo "You don't have any bundles." >&2 462 echo "You don't have any bundles." >&2
466 return 1 463 return 1
467 else 464 else
468 -antigen-echo-record | sort -u 465 -antigen-echo-record | sort -u
469 fi 466 fi
470 } 467 }
471 468
472 antigen-snapshot () { 469 antigen-snapshot () {
473 470
474 local snapshot_file="${1:-antigen-shapshot}" 471 local snapshot_file="${1:-antigen-shapshot}"
475 472
476 # The snapshot content lines are pairs of repo-url and git version hash, in 473 # The snapshot content lines are pairs of repo-url and git version hash, in
477 # the form: 474 # the form:
478 # <version-hash> <repo-url> 475 # <version-hash> <repo-url>
479 local snapshot_content="$(-antigen-echo-record | 476 local snapshot_content="$(-antigen-echo-record |
480 grep 'true$' | 477 grep 'true$' |
481 sed 's/ .*$//' | 478 sed 's/ .*$//' |
482 sort -u | 479 sort -u |
483 while read url; do 480 while read url; do
484 local dir="$(-antigen-get-clone-dir "$url")" 481 local dir="$(-antigen-get-clone-dir "$url")"
485 local version_hash="$(cd "$dir" && git rev-parse HEAD)" 482 local version_hash="$(cd "$dir" && git rev-parse HEAD)"
486 echo "$version_hash $url" 483 echo "$version_hash $url"
487 done)" 484 done)"
488 485
489 { 486 {
490 # The first line in the snapshot file is for metadata, in the form: 487 # The first line in the snapshot file is for metadata, in the form:
491 # key='value'; key='value'; key='value'; 488 # key='value'; key='value'; key='value';
492 # Where `key`s are valid shell variable names. 489 # Where `key`s are valid shell variable names.
493 490
494 # Snapshot version. Has no relation to antigen version. If the snapshot 491 # Snapshot version. Has no relation to antigen version. If the snapshot
495 # file format changes, this number can be incremented. 492 # file format changes, this number can be incremented.
496 echo -n "version='1';" 493 echo -n "version='1';"
497 494
498 # Snapshot creation date+time. 495 # Snapshot creation date+time.
499 echo -n " created_on='$(date)';" 496 echo -n " created_on='$(date)';"
497
500 498 # Add a checksum with the md5 checksum of all the snapshot lines.
499 chksum() { (md5sum; test $? = 127 && md5) 2>/dev/null | cut -d' ' -f1 }
501 # Add a checksum with the md5 checksum of all the snapshot lines. 500 local checksum="$(echo "$snapshot_content" | chksum)"
502 local checksum="$(echo "$snapshot_content" | chksum)" 501 unset -f chksum;
503 echo -n " checksum='${checksum%% *}';" 502 echo -n " checksum='${checksum%% *}';"
504 503
505 # A newline after the metadata and then the snapshot lines. 504 # A newline after the metadata and then the snapshot lines.
506 echo "\n$snapshot_content" 505 echo "\n$snapshot_content"
507 506
508 } > "$snapshot_file" 507 } > "$snapshot_file"
509 508
510 } 509 }
511 510
512 antigen-restore () { 511 antigen-restore () {
513 512
514 if [[ $# == 0 ]]; then 513 if [[ $# == 0 ]]; then
515 echo 'Please provide a snapshot file to restore from.' >&2 514 echo 'Please provide a snapshot file to restore from.' >&2
516 return 1 515 return 1
517 fi 516 fi
518 517
519 local snapshot_file="$1" 518 local snapshot_file="$1"
520 519
521 # TODO: Before doing anything with the snapshot file, verify its checksum. 520 # TODO: Before doing anything with the snapshot file, verify its checksum.
522 # If it fails, notify this to the user and confirm if restore should 521 # If it fails, notify this to the user and confirm if restore should
523 # proceed. 522 # proceed.
524 523
525 echo -n "Restoring from $snapshot_file..." 524 echo -n "Restoring from $snapshot_file..."
526 525
527 sed -n '1!p' "$snapshot_file" | 526 sed -n '1!p' "$snapshot_file" |
528 while read line; do 527 while read line; do
529 528
530 local version_hash="${line%% *}" 529 local version_hash="${line%% *}"
531 local url="${line##* }" 530 local url="${line##* }"
532 local clone_dir="$(-antigen-get-clone-dir "$url")" 531 local clone_dir="$(-antigen-get-clone-dir "$url")"
533 532
534 if [[ ! -d $clone_dir ]]; then 533 if [[ ! -d $clone_dir ]]; then
535 git clone "$url" "$clone_dir" > /dev/null 534 git clone "$url" "$clone_dir" > /dev/null
536 fi 535 fi
537 536
538 (cd "$clone_dir" && git checkout $version_hash) 2> /dev/null 537 (cd "$clone_dir" && git checkout $version_hash) 2> /dev/null
539 538
540 done 539 done
541 540
542 echo ' done.' 541 echo ' done.'
543 echo 'Please open a new shell to get the restored changes.' 542 echo 'Please open a new shell to get the restored changes.'
544 } 543 }
545 544
546 antigen-help () { 545 antigen-help () {
547 cat <<EOF 546 cat <<EOF
548 Antigen is a plugin management system for zsh. It makes it easy to grab awesome 547 Antigen is a plugin management system for zsh. It makes it easy to grab awesome
549 shell scripts and utilities, put up on github. For further details and complete 548 shell scripts and utilities, put up on github. For further details and complete
550 documentation, visit the project's page at 'http://antigen.sharats.me'. 549 documentation, visit the project's page at 'http://antigen.sharats.me'.
551 EOF 550 EOF
552 } 551 }
553 552
554 # A syntax sugar to avoid the `-` when calling antigen commands. With this 553 # A syntax sugar to avoid the `-` when calling antigen commands. With this
555 # function, you can write `antigen-bundle` as `antigen bundle` and so on. 554 # function, you can write `antigen-bundle` as `antigen bundle` and so on.
556 antigen () { 555 antigen () {
557 local cmd="$1" 556 local cmd="$1"
558 if [[ -z "$cmd" ]]; then 557 if [[ -z "$cmd" ]]; then
559 echo 'Antigen: Please give a command to run.' >&2 558 echo 'Antigen: Please give a command to run.' >&2
560 return 1 559 return 1
561 fi 560 fi
562 shift 561 shift
563 562
564 if functions "antigen-$cmd" > /dev/null; then 563 if functions "antigen-$cmd" > /dev/null; then
565 "antigen-$cmd" "$@" 564 "antigen-$cmd" "$@"
566 else 565 else
567 echo "Antigen: Unknown command: $cmd" >&2 566 echo "Antigen: Unknown command: $cmd" >&2
568 fi 567 fi
569 } 568 }
570 569
571 -antigen-parse-args () { 570 -antigen-parse-args () {
572 # An argument parsing functionality to parse arguments the *antigen* way :). 571 # An argument parsing functionality to parse arguments the *antigen* way :).
573 # Takes one first argument (called spec), which dictates how to parse and 572 # Takes one first argument (called spec), which dictates how to parse and
574 # the rest of the arguments are parsed. Outputs a piece of valid shell code 573 # the rest of the arguments are parsed. Outputs a piece of valid shell code
575 # that can be passed to `eval` inside a function which creates the arguments 574 # that can be passed to `eval` inside a function which creates the arguments
576 # and their values as local variables. Suggested use is to set the defaults 575 # and their values as local variables. Suggested use is to set the defaults
577 # to all arguments first and then eval the output of this function. 576 # to all arguments first and then eval the output of this function.
578 577
579 # Spec: Only long argument supported. No support for parsing short options. 578 # Spec: Only long argument supported. No support for parsing short options.
580 # The spec must have two sections, separated by a `;`. 579 # The spec must have two sections, separated by a `;`.
581 # '<positional-arguments>;<keyword-only-arguments>' 580 # '<positional-arguments>;<keyword-only-arguments>'
582 # Positional arguments are passed as just values, like `command a b`. 581 # Positional arguments are passed as just values, like `command a b`.
583 # Keyword arguments are passed as a `--name=value` pair, like `command 582 # Keyword arguments are passed as a `--name=value` pair, like `command
584 # --arg1=a --arg2=b`. 583 # --arg1=a --arg2=b`.
585 584
586 # Each argument in the spec is separated by a `,`. Each keyword argument can 585 # Each argument in the spec is separated by a `,`. Each keyword argument can
587 # end in a `:` to specifiy that this argument wants a value, otherwise it 586 # end in a `:` to specifiy that this argument wants a value, otherwise it
588 # doesn't take a value. (The value in the output when the keyword argument 587 # doesn't take a value. (The value in the output when the keyword argument
589 # doesn't have a `:` is `true`). 588 # doesn't have a `:` is `true`).
590 589
591 # Arguments in either section can end with a `?` (should come after `:`, if 590 # Arguments in either section can end with a `?` (should come after `:`, if
592 # both are present), means optional. FIXME: Not yet implemented. 591 # both are present), means optional. FIXME: Not yet implemented.
593 592
594 # See the test file, tests/arg-parser.t for (working) examples. 593 # See the test file, tests/arg-parser.t for (working) examples.
595 594
596 local spec="$1" 595 local spec="$1"
597 shift 596 shift
598 597
599 # Sanitize the spec 598 # Sanitize the spec
600 spec="$(echo "$spec" | tr '\n' ' ' | sed 's/[[:space:]]//g')" 599 spec="$(echo "$spec" | tr '\n' ' ' | sed 's/[[:space:]]//g')"
601 600
602 local code='' 601 local code=''
603 602
604 --add-var () { 603 --add-var () {
605 test -z "$code" || code="$code\n" 604 test -z "$code" || code="$code\n"
606 code="${code}local $1='$2'" 605 code="${code}local $1='$2'"
607 } 606 }
608 607
609 local positional_args="$(echo "$spec" | cut -d\; -f1)" 608 local positional_args="$(echo "$spec" | cut -d\; -f1)"
610 local positional_args_count="$(echo $positional_args | 609 local positional_args_count="$(echo $positional_args |
611 awk -F, '{print NF}')" 610 awk -F, '{print NF}')"
612 611
613 # Set spec values based on the positional arguments. 612 # Set spec values based on the positional arguments.
614 local i=1 613 local i=1
615 while [[ -n $1 && $1 != --* ]]; do 614 while [[ -n $1 && $1 != --* ]]; do
616 615
617 if (( $i > $positional_args_count )); then 616 if (( $i > $positional_args_count )); then
618 echo "Only $positional_args_count positional arguments allowed." >&2 617 echo "Only $positional_args_count positional arguments allowed." >&2
619 echo "Found at least one more: '$1'" >&2 618 echo "Found at least one more: '$1'" >&2
620 return 619 return
621 fi 620 fi
622 621
623 local name_spec="$(echo "$positional_args" | cut -d, -f$i)" 622 local name_spec="$(echo "$positional_args" | cut -d, -f$i)"
624 local name="${${name_spec%\?}%:}" 623 local name="${${name_spec%\?}%:}"
625 local value="$1" 624 local value="$1"
626 625
627 if echo "$code" | grep -l "^local $name=" &> /dev/null; then 626 if echo "$code" | grep -l "^local $name=" &> /dev/null; then
628 echo "Argument '$name' repeated with the value '$value'". >&2 627 echo "Argument '$name' repeated with the value '$value'". >&2
629 return 628 return
630 fi 629 fi
631 630
632 --add-var $name "$value" 631 --add-var $name "$value"
633 632
634 shift 633 shift
635 i=$(($i + 1)) 634 i=$(($i + 1))
636 done 635 done
637 636
638 local keyword_args="$( 637 local keyword_args="$(
639 # Positional arguments can double up as keyword arguments too. 638 # Positional arguments can double up as keyword arguments too.
640 echo "$positional_args" | tr , '\n' | 639 echo "$positional_args" | tr , '\n' |
641 while read line; do 640 while read line; do
642 if [[ $line == *\? ]]; then 641 if [[ $line == *\? ]]; then
643 echo "${line%?}:?" 642 echo "${line%?}:?"
644 else 643 else
645 echo "$line:" 644 echo "$line:"
646 fi 645 fi
647 done 646 done
648 647
649 # Specified keyword arguments. 648 # Specified keyword arguments.
650 echo "$spec" | cut -d\; -f2 | tr , '\n' 649 echo "$spec" | cut -d\; -f2 | tr , '\n'
651 )" 650 )"
652 local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')" 651 local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')"
653 652
654 # Set spec values from keyword arguments, if any. The remaining arguments 653 # Set spec values from keyword arguments, if any. The remaining arguments
655 # are all assumed to be keyword arguments. 654 # are all assumed to be keyword arguments.
656 while [[ $1 == --* ]]; do 655 while [[ $1 == --* ]]; do
657 # Remove the `--` at the start. 656 # Remove the `--` at the start.
658 local arg="${1#--}" 657 local arg="${1#--}"
659 658
660 # Get the argument name and value. 659 # Get the argument name and value.
661 if [[ $arg != *=* ]]; then 660 if [[ $arg != *=* ]]; then
662 local name="$arg" 661 local name="$arg"
663 local value='' 662 local value=''
664 else 663 else
665 local name="${arg%\=*}" 664 local name="${arg%\=*}"
666 local value="${arg#*=}" 665 local value="${arg#*=}"
667 fi 666 fi
668 667
669 if echo "$code" | grep -l "^local $name=" &> /dev/null; then 668 if echo "$code" | grep -l "^local $name=" &> /dev/null; then
670 echo "Argument '$name' repeated with the value '$value'". >&2 669 echo "Argument '$name' repeated with the value '$value'". >&2
671 return 670 return
672 fi 671 fi
673 672
674 # The specification for this argument, used for validations. 673 # The specification for this argument, used for validations.
675 local arg_line="$(echo "$keyword_args" | 674 local arg_line="$(echo "$keyword_args" |
676 egrep "^$name:?\??" | head -n1)" 675 egrep "^$name:?\??" | head -n1)"
677 676
678 # Validate argument and value. 677 # Validate argument and value.
679 if [[ -z $arg_line ]]; then 678 if [[ -z $arg_line ]]; then
680 # This argument is not known to us. 679 # This argument is not known to us.
681 echo "Unknown argument '$name'." >&2 680 echo "Unknown argument '$name'." >&2
682 return 681 return
683 682
684 elif (echo "$arg_line" | grep -l ':' &> /dev/null) && 683 elif (echo "$arg_line" | grep -l ':' &> /dev/null) &&
685 [[ -z $value ]]; then 684 [[ -z $value ]]; then
686 # This argument needs a value, but is not provided. 685 # This argument needs a value, but is not provided.
687 echo "Required argument for '$name' not provided." >&2 686 echo "Required argument for '$name' not provided." >&2
688 return 687 return
689 688
690 elif (echo "$arg_line" | grep -vl ':' &> /dev/null) && 689 elif (echo "$arg_line" | grep -vl ':' &> /dev/null) &&
691 [[ -n $value ]]; then 690 [[ -n $value ]]; then
692 # This argument doesn't need a value, but is provided. 691 # This argument doesn't need a value, but is provided.
693 echo "No argument required for '$name', but provided '$value'." >&2 692 echo "No argument required for '$name', but provided '$value'." >&2
694 return 693 return
695 694
696 fi 695 fi
697 696
698 if [[ -z $value ]]; then 697 if [[ -z $value ]]; then
699 value=true 698 value=true
700 fi 699 fi
701 700
702 --add-var "${name//-/_}" "$value" 701 --add-var "${name//-/_}" "$value"
703 shift 702 shift
704 done 703 done
705 704
706 echo "$code" 705 echo "$code"
707 706
708 unfunction -- --add-var 707 unfunction -- --add-var
709 708
710 } 709 }
711 710
712 # Echo the bundle specs as in the record. The first line is not echoed since it 711 # Echo the bundle specs as in the record. The first line is not echoed since it
713 # is a blank line. 712 # is a blank line.
714 -antigen-echo-record () { 713 -antigen-echo-record () {
715 echo "$_ANTIGEN_BUNDLE_RECORD" | sed -n '1!p' 714 echo "$_ANTIGEN_BUNDLE_RECORD" | sed -n '1!p'
716 } 715 }
717 716
718 -antigen-env-setup () { 717 -antigen-env-setup () {
719 718
720 # Helper function: Same as `export $1=$2`, but will only happen if the name 719 # Helper function: Same as `export $1=$2`, but will only happen if the name
721 # specified by `$1` is not already set. 720 # specified by `$1` is not already set.
722 -set-default () { 721 -set-default () {
723 local arg_name="$1" 722 local arg_name="$1"
724 local arg_value="$2" 723 local arg_value="$2"
725 eval "test -z \"\$$arg_name\" && export $arg_name='$arg_value'" 724 eval "test -z \"\$$arg_name\" && export $arg_name='$arg_value'"
726 } 725 }
727 726
728 # Pre-startup initializations. 727 # Pre-startup initializations.
729 -set-default ANTIGEN_DEFAULT_REPO_URL \ 728 -set-default ANTIGEN_DEFAULT_REPO_URL \
730 https://github.com/robbyrussell/oh-my-zsh.git 729 https://github.com/robbyrussell/oh-my-zsh.git
731 -set-default ADOTDIR $HOME/.antigen 730 -set-default ADOTDIR $HOME/.antigen
732 731
733 # Setup antigen's own completion. 732 # Setup antigen's own completion.
734 compdef _antigen antigen 733 compdef _antigen antigen
735 734
736 # Remove private functions. 735 # Remove private functions.
737 unfunction -- -set-default 736 unfunction -- -set-default
738 } 737 }
739 738
740 # Setup antigen's autocompletion 739 # Setup antigen's autocompletion
741 _antigen () { 740 _antigen () {
742 compadd \ 741 compadd \
743 bundle \ 742 bundle \
744 bundles \ 743 bundles \
745 update \ 744 update \
746 revert \ 745 revert \
747 list \ 746 list \
748 cleanup \ 747 cleanup \
749 use \ 748 use \
750 selfupdate \ 749 selfupdate \
751 theme \ 750 theme \
752 apply \ 751 apply \
753 snapshot \ 752 snapshot \
754 restore \ 753 restore \
755 help 754 help
756 } 755 }
757 756