Commit d36c6f93d8dde634a1232495944a6f6adbce2ea4

Authored by Shrikant Sharat
1 parent d985103372

Implemented `antigen-snapshot` command.

Creates a snapshot file with some basic metadata information and pairs of repo
urls and their version hashes. Tests included.

Showing 2 changed files with 59 additions and 0 deletions Inline Diff

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