Commit d43f31a79306c2a5a333981f96882c7e24e871f3

Authored by Shrikant Sharat
1 parent f76ba3b6c2

Initial implementation of antigen-revert command.

Use this command to revert an `antigen-update`.

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