gistore 1.0.0.rc4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +30 -0
  3. data/COPYING +340 -0
  4. data/README.md +98 -0
  5. data/exe/gistore +15 -0
  6. data/lib/gistore.rb +20 -0
  7. data/lib/gistore/cmd/add.rb +15 -0
  8. data/lib/gistore/cmd/checkout.rb +49 -0
  9. data/lib/gistore/cmd/commit.rb +171 -0
  10. data/lib/gistore/cmd/config.rb +23 -0
  11. data/lib/gistore/cmd/export-to-backups.rb +79 -0
  12. data/lib/gistore/cmd/gc.rb +15 -0
  13. data/lib/gistore/cmd/git-version.rb +14 -0
  14. data/lib/gistore/cmd/init.rb +36 -0
  15. data/lib/gistore/cmd/restore-from-backups.rb +91 -0
  16. data/lib/gistore/cmd/rm.rb +15 -0
  17. data/lib/gistore/cmd/safe-commands.rb +53 -0
  18. data/lib/gistore/cmd/status.rb +40 -0
  19. data/lib/gistore/cmd/task.rb +85 -0
  20. data/lib/gistore/cmd/version.rb +27 -0
  21. data/lib/gistore/config.rb +13 -0
  22. data/lib/gistore/config/gistore.yml +1 -0
  23. data/lib/gistore/error.rb +6 -0
  24. data/lib/gistore/repo.rb +683 -0
  25. data/lib/gistore/runner.rb +43 -0
  26. data/lib/gistore/templates/description +1 -0
  27. data/lib/gistore/templates/hooks/applypatch-msg.sample +15 -0
  28. data/lib/gistore/templates/hooks/commit-msg.sample +24 -0
  29. data/lib/gistore/templates/hooks/post-update.sample +8 -0
  30. data/lib/gistore/templates/hooks/pre-applypatch.sample +14 -0
  31. data/lib/gistore/templates/hooks/pre-commit.sample +49 -0
  32. data/lib/gistore/templates/hooks/pre-push.sample +54 -0
  33. data/lib/gistore/templates/hooks/pre-rebase.sample +169 -0
  34. data/lib/gistore/templates/hooks/prepare-commit-msg.sample +36 -0
  35. data/lib/gistore/templates/hooks/update.sample +128 -0
  36. data/lib/gistore/templates/info/exclude +6 -0
  37. data/lib/gistore/utils.rb +382 -0
  38. data/lib/gistore/version.rb +4 -0
  39. data/t/Makefile +80 -0
  40. data/t/README +745 -0
  41. data/t/aggregate-results.sh +46 -0
  42. data/t/lib-worktree.sh +76 -0
  43. data/t/t0000-init.sh +75 -0
  44. data/t/t0010-config.sh +75 -0
  45. data/t/t0020-version.sh +32 -0
  46. data/t/t1000-add-remove.sh +89 -0
  47. data/t/t1010-status.sh +87 -0
  48. data/t/t1020-commit.sh +134 -0
  49. data/t/t1030-commit-and-rotate.sh +266 -0
  50. data/t/t2000-task-and-commit-all.sh +132 -0
  51. data/t/t3000-checkout.sh +115 -0
  52. data/t/t3010-export-and-restore.sh +141 -0
  53. data/t/test-binary-1.png +0 -0
  54. data/t/test-binary-2.png +0 -0
  55. data/t/test-lib-functions.sh +722 -0
  56. data/t/test-lib.sh +684 -0
  57. metadata +161 -0
@@ -0,0 +1,115 @@
1
+ #!/bin/sh
2
+ #
3
+ # Copyright (c) 2013 Jiang Xin
4
+ #
5
+
6
+ test_description='Test gistore checkout'
7
+
8
+ TEST_NO_CREATE_REPO=NoThanks
9
+ . ./lib-worktree.sh
10
+ . ./test-lib.sh
11
+
12
+ do_hack()
13
+ {
14
+ echo "hack $*" >> root/src/README.txt
15
+ echo "hack $*" >> root/doc/COPYRIGHT
16
+ }
17
+
18
+ cwd=$(pwd -P)
19
+
20
+ cat >expect << EOF
21
+ outdir/.git
22
+ outdir/root/doc/COPYRIGHT
23
+ EOF
24
+
25
+ test_expect_success 'initialize for checkout' '
26
+ prepare_work_tree &&
27
+ gistore init --repo repo.git &&
28
+ gistore init --repo repo2.git &&
29
+ gistore add --repo repo.git root/doc &&
30
+ gistore add --repo repo2.git root/doc &&
31
+ gistore commit --repo repo.git -m "initialize for checkout" &&
32
+ gistore commit --repo repo2.git -m "initialize for checkout" &&
33
+ test ! -d outdir &&
34
+ gistore checkout --repo repo.git --to outdir &&
35
+ find outdir -type f | sed -e "s#${cwd}##g" | LC_COLLATE=C sort > actual &&
36
+ test_cmp expect actual
37
+ '
38
+
39
+ cat >expect <<EOF
40
+ Error: Can not find repo at "non-exist-repo.git"
41
+ EOF
42
+
43
+ test_expect_success 'fail to checkout non-exist repo' '
44
+ test_must_fail gistore checkout --repo non-exist-repo.git --to non-exist-dir &&
45
+ (gistore checkout --repo non-exist-repo.git --to non-exist-dir 2>actual || true) &&
46
+ test_cmp expect actual
47
+ '
48
+
49
+ cat >expect <<EOF
50
+ fatal: invalid reference: bad-revision
51
+ Error: Failure while executing: git checkout bad-revision -- .
52
+ EOF
53
+
54
+ test_expect_success 'fail to checkout bad revision' '
55
+ test_must_fail gistore checkout --repo repo.git --to bad-rev-checkout --rev bad-revision &&
56
+ (export LC_ALL=C; LANG=C gistore checkout --repo repo.git --to bad-rev-checkout --rev bad-revision 2>&1 |
57
+ sed -e "s/ [^ ]*\/git/ git/" > actual || true) &&
58
+ test_cmp expect actual
59
+ '
60
+
61
+ cat >expect << EOF
62
+ outdir/.git
63
+ outdir/root/doc/COPYRIGHT
64
+ outdir/root/src/README.txt
65
+ outdir/root/src/images/test-binary-1.png
66
+ outdir/root/src/images/test-binary-2.png
67
+ outdir/root/src/lib/a/foo.c
68
+ outdir/root/src/lib/b/bar.o
69
+ outdir/root/src/lib/b/baz.a
70
+ EOF
71
+
72
+ test_expect_success 'checkout continue' '
73
+ gistore add --repo repo.git root/src &&
74
+ gistore commit --repo repo.git -m "checkout continue" &&
75
+ gistore checkout --repo repo.git --to outdir &&
76
+ find outdir -type f | sed -e "s#${cwd}##g" | LC_COLLATE=C sort > actual &&
77
+ test_cmp expect actual
78
+ '
79
+
80
+ cat >expect << EOF
81
+ partial/.git
82
+ partial/root/src/lib/a/foo.c
83
+ partial/root/src/lib/b/bar.o
84
+ partial/root/src/lib/b/baz.a
85
+ EOF
86
+
87
+ test_expect_success 'partial checkout' '
88
+ gistore checkout --repo repo.git --to partial "${cwd#/}/root/src/lib" &&
89
+ find partial -type f | sed -e "s#${cwd}##g" | LC_COLLATE=C sort > actual &&
90
+ test_cmp expect actual
91
+ '
92
+
93
+ cat >expect << EOF
94
+ history/.git
95
+ history/root/doc/COPYRIGHT
96
+ EOF
97
+
98
+ test_expect_success 'checkout history' '
99
+ gistore checkout --repo repo.git --to history --rev HEAD^ &&
100
+ find history -type f | sed -e "s#${cwd}##g" | LC_COLLATE=C sort > actual &&
101
+ test_cmp expect actual
102
+ '
103
+
104
+ test_expect_success 'worktree and gitdir unmatch' '
105
+ test_must_fail gistore checkout --repo repo2.git --to outdir
106
+ '
107
+
108
+ test_expect_success 'not checkout to no empty dir' '
109
+ mkdir outdir2 && touch outdir2/.hidden &&
110
+ test_must_fail gistore checkout --repo repo2.git --to outdir2 &&
111
+ rm outdir2/.hidden &&
112
+ gistore checkout --repo repo2.git --to outdir2
113
+ '
114
+
115
+ test_done
@@ -0,0 +1,141 @@
1
+ #!/bin/sh
2
+ #
3
+ # Copyright (c) 2013 Jiang Xin
4
+ #
5
+
6
+ test_description='Test gistore export and restore'
7
+
8
+ TEST_NO_CREATE_REPO=NoThanks
9
+ . ./lib-worktree.sh
10
+ . ./test-lib.sh
11
+
12
+ do_hack()
13
+ {
14
+ echo "hack $*" >> root/src/README.txt
15
+ echo "hack $*" >> root/doc/COPYRIGHT
16
+ }
17
+
18
+ cwd=$(pwd -P)
19
+ n=0
20
+
21
+ cat >expect <<EOF
22
+ Error: Can not find repo at "non-exist-repo.git"
23
+ EOF
24
+
25
+ test_expect_success 'fail to export non-exist repo' '
26
+ test_must_fail gistore export-to-backups --repo non-exist-repo.git --to non-exist-dir &&
27
+ (gistore export-to-backups --repo non-exist-repo.git --to non-exist-dir 2>actual || true) &&
28
+ test_cmp expect actual
29
+ '
30
+
31
+ cat >expect <<EOF
32
+ Error: Failed to restore-from-backups.
33
+ Error: Path "non-exist-dir" does not exist.
34
+ EOF
35
+
36
+ test_expect_success 'fail to restore from non-exist-dir' '
37
+ test_must_fail gistore restore-from-backups --from non-exist-dir --to no-exist-repo.git &&
38
+ (gistore restore-from-backups --from non-exist-dir --to no-exist-repo.git 2>actual || true) &&
39
+ test_cmp expect actual
40
+ '
41
+
42
+ cat >expect << EOF
43
+ Backup No. 24
44
+ Backup No. 23
45
+ Backup No. 22
46
+ Full backup of repo.git
47
+ Backup No. 20
48
+ Backup No. 19
49
+ Backup No. 18
50
+ Backup No. 17
51
+ Full backup of repo.git
52
+ Backup No. 15
53
+ Backup No. 14
54
+ Backup No. 13
55
+ Backup No. 12
56
+ Full backup of repo.git
57
+ Backup No. 10
58
+ Backup No. 9
59
+ Backup No. 8
60
+ Backup No. 7
61
+ Full backup of repo.git
62
+ EOF
63
+
64
+ test_expect_success 'initialize for export' '
65
+ prepare_work_tree &&
66
+ gistore init --repo repo.git &&
67
+ gistore config --repo repo.git full_backup_number 3 &&
68
+ gistore config --repo repo.git increment_backup_number 5 &&
69
+ gistore add --repo repo.git root/src &&
70
+ gistore add --repo repo.git root/doc &&
71
+ i=0 &&
72
+ while test $i -lt 24; do
73
+ i=$((i+1));
74
+ n=$((n+1));
75
+ do_hack $n;
76
+ gistore commit --repo repo.git -m "Backup No. $n";
77
+ done &&
78
+ test "$(count_git_commits repo.git)" = "19" &&
79
+ git_log_only_subject repo.git > actual &&
80
+ test_cmp expect actual &&
81
+ count=$(count_git_objects repo.git) &&
82
+ gistore gc --repo repo.git --force &&
83
+ test $(count_git_objects repo.git) -lt $count
84
+ '
85
+
86
+ test_expect_success 'export backups' '
87
+ gistore export-to-backups --repo repo.git --to backups &&
88
+ test $(ls backups/001-full-backup-*.pack | wc -l) -eq 1 &&
89
+ test $(ls backups/*-incremental-*.pack | wc -l) -eq 3
90
+ '
91
+
92
+ cat >expect <<EOF
93
+ Backup No. 24
94
+ Backup No. 23
95
+ Backup No. 22
96
+ Full backup of repo.git
97
+ EOF
98
+
99
+ test_expect_success 'restore from backups' '
100
+ gistore restore-from-backups --from backups --to restore.git &&
101
+ test $(count_git_commits restore.git) -eq 4 &&
102
+ git_log_only_subject restore.git > actual &&
103
+ test_cmp expect actual
104
+ '
105
+
106
+ test_expect_success 'export another repo' '
107
+ gistore init --repo repo2.git &&
108
+ gistore config --repo repo2.git full_backup_number 3 &&
109
+ gistore config --repo repo2.git increment_backup_number 5 &&
110
+ gistore add --repo repo2.git root/src &&
111
+ i=0 && n=0 &&
112
+ while test $i -lt 2; do
113
+ i=$((i+1));
114
+ n=$((n+1));
115
+ do_hack $n;
116
+ gistore commit --repo repo2.git -m "Repo2 commit No. $n";
117
+ done &&
118
+ test $(count_git_commits repo2.git) -eq 2 &&
119
+ gistore export-to-backups --repo repo2.git --to backups2 &&
120
+ test $(ls backups2/001-full-backup-*.pack | wc -l) -eq 1 &&
121
+ test $(ls backups2/*-incremental-*.pack | wc -l) -eq 1
122
+ '
123
+
124
+ cat >expect <<EOF
125
+ Repo2 commit No. 2
126
+ Repo2 commit No. 1
127
+ EOF
128
+
129
+ test_expect_success 'restore from backups2' '
130
+ gistore restore-from-backups --from backups2 --to restore.git >result 2>&1 &&
131
+ new_commit=$(grep $_x40 result) &&
132
+ test $(count_git_commits restore.git) -eq 4 &&
133
+ (
134
+ cd restore.git;
135
+ git update-ref refs/heads/master $new_commit;
136
+ ) &&
137
+ git_log_only_subject restore.git > actual &&
138
+ test_cmp expect actual
139
+ '
140
+
141
+ test_done
Binary file
Binary file
@@ -0,0 +1,722 @@
1
+ #!/bin/sh
2
+ #
3
+ # Copyright (c) 2005 Junio C Hamano
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 2 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see http://www.gnu.org/licenses/ .
17
+
18
+ # The semantics of the editor variables are that of invoking
19
+ # sh -c "$EDITOR \"$@\"" files ...
20
+ #
21
+ # If our trash directory contains shell metacharacters, they will be
22
+ # interpreted if we just set $EDITOR directly, so do a little dance with
23
+ # environment variables to work around this.
24
+ #
25
+ # In particular, quoting isn't enough, as the path may contain the same quote
26
+ # that we're using.
27
+ test_set_editor () {
28
+ FAKE_EDITOR="$1"
29
+ export FAKE_EDITOR
30
+ EDITOR='"$FAKE_EDITOR"'
31
+ export EDITOR
32
+ }
33
+
34
+ test_decode_color () {
35
+ awk '
36
+ function name(n) {
37
+ if (n == 0) return "RESET";
38
+ if (n == 1) return "BOLD";
39
+ if (n == 30) return "BLACK";
40
+ if (n == 31) return "RED";
41
+ if (n == 32) return "GREEN";
42
+ if (n == 33) return "YELLOW";
43
+ if (n == 34) return "BLUE";
44
+ if (n == 35) return "MAGENTA";
45
+ if (n == 36) return "CYAN";
46
+ if (n == 37) return "WHITE";
47
+ if (n == 40) return "BLACK";
48
+ if (n == 41) return "BRED";
49
+ if (n == 42) return "BGREEN";
50
+ if (n == 43) return "BYELLOW";
51
+ if (n == 44) return "BBLUE";
52
+ if (n == 45) return "BMAGENTA";
53
+ if (n == 46) return "BCYAN";
54
+ if (n == 47) return "BWHITE";
55
+ }
56
+ {
57
+ while (match($0, /\033\[[0-9;]*m/) != 0) {
58
+ printf "%s<", substr($0, 1, RSTART-1);
59
+ codes = substr($0, RSTART+2, RLENGTH-3);
60
+ if (length(codes) == 0)
61
+ printf "%s", name(0)
62
+ else {
63
+ n = split(codes, ary, ";");
64
+ sep = "";
65
+ for (i = 1; i <= n; i++) {
66
+ printf "%s%s", sep, name(ary[i]);
67
+ sep = ";"
68
+ }
69
+ }
70
+ printf ">";
71
+ $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1);
72
+ }
73
+ print
74
+ }
75
+ '
76
+ }
77
+
78
+ nul_to_q () {
79
+ "$PERL_PATH" -pe 'y/\000/Q/'
80
+ }
81
+
82
+ q_to_nul () {
83
+ "$PERL_PATH" -pe 'y/Q/\000/'
84
+ }
85
+
86
+ q_to_cr () {
87
+ tr Q '\015'
88
+ }
89
+
90
+ q_to_tab () {
91
+ tr Q '\011'
92
+ }
93
+
94
+ qz_to_tab_space () {
95
+ tr QZ '\011\040'
96
+ }
97
+
98
+ append_cr () {
99
+ sed -e 's/$/Q/' | tr Q '\015'
100
+ }
101
+
102
+ remove_cr () {
103
+ tr '\015' Q | sed -e 's/Q$//'
104
+ }
105
+
106
+ # In some bourne shell implementations, the "unset" builtin returns
107
+ # nonzero status when a variable to be unset was not set in the first
108
+ # place.
109
+ #
110
+ # Use sane_unset when that should not be considered an error.
111
+
112
+ sane_unset () {
113
+ unset "$@"
114
+ return 0
115
+ }
116
+
117
+ test_tick () {
118
+ if test -z "${test_tick+set}"
119
+ then
120
+ test_tick=1112911993
121
+ else
122
+ test_tick=$(($test_tick + 60))
123
+ fi
124
+ GIT_COMMITTER_DATE="$test_tick -0700"
125
+ GIT_AUTHOR_DATE="$test_tick -0700"
126
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
127
+ }
128
+
129
+ # Stop execution and start a shell. This is useful for debugging tests and
130
+ # only makes sense together with "-v".
131
+ #
132
+ # Be sure to remove all invocations of this command before submitting.
133
+
134
+ test_pause () {
135
+ if test "$verbose" = t; then
136
+ "$SHELL_PATH" <&6 >&3 2>&4
137
+ else
138
+ error >&5 "test_pause requires --verbose"
139
+ fi
140
+ }
141
+
142
+ # Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]"
143
+ #
144
+ # This will commit a file with the given contents and the given commit
145
+ # message, and tag the resulting commit with the given tag name.
146
+ #
147
+ # <file>, <contents>, and <tag> all default to <message>.
148
+
149
+ test_commit () {
150
+ notick= &&
151
+ signoff= &&
152
+ while test $# != 0
153
+ do
154
+ case "$1" in
155
+ --notick)
156
+ notick=yes
157
+ ;;
158
+ --signoff)
159
+ signoff="$1"
160
+ ;;
161
+ *)
162
+ break
163
+ ;;
164
+ esac
165
+ shift
166
+ done &&
167
+ file=${2:-"$1.t"} &&
168
+ echo "${3-$1}" > "$file" &&
169
+ git add "$file" &&
170
+ if test -z "$notick"
171
+ then
172
+ test_tick
173
+ fi &&
174
+ git commit $signoff -m "$1" &&
175
+ git tag "${4:-$1}"
176
+ }
177
+
178
+ # Call test_merge with the arguments "<message> <commit>", where <commit>
179
+ # can be a tag pointing to the commit-to-merge.
180
+
181
+ test_merge () {
182
+ test_tick &&
183
+ git merge -m "$1" "$2" &&
184
+ git tag "$1"
185
+ }
186
+
187
+ # This function helps systems where core.filemode=false is set.
188
+ # Use it instead of plain 'chmod +x' to set or unset the executable bit
189
+ # of a file in the working directory and add it to the index.
190
+
191
+ test_chmod () {
192
+ chmod "$@" &&
193
+ git update-index --add "--chmod=$@"
194
+ }
195
+
196
+ # Unset a configuration variable, but don't fail if it doesn't exist.
197
+ test_unconfig () {
198
+ git config --unset-all "$@"
199
+ config_status=$?
200
+ case "$config_status" in
201
+ 5) # ok, nothing to unset
202
+ config_status=0
203
+ ;;
204
+ esac
205
+ return $config_status
206
+ }
207
+
208
+ # Set git config, automatically unsetting it after the test is over.
209
+ test_config () {
210
+ test_when_finished "test_unconfig '$1'" &&
211
+ git config "$@"
212
+ }
213
+
214
+ test_config_global () {
215
+ test_when_finished "test_unconfig --global '$1'" &&
216
+ git config --global "$@"
217
+ }
218
+
219
+ write_script () {
220
+ {
221
+ echo "#!${2-"$SHELL_PATH"}" &&
222
+ cat
223
+ } >"$1" &&
224
+ chmod +x "$1"
225
+ }
226
+
227
+ # Use test_set_prereq to tell that a particular prerequisite is available.
228
+ # The prerequisite can later be checked for in two ways:
229
+ #
230
+ # - Explicitly using test_have_prereq.
231
+ #
232
+ # - Implicitly by specifying the prerequisite tag in the calls to
233
+ # test_expect_{success,failure,code}.
234
+ #
235
+ # The single parameter is the prerequisite tag (a simple word, in all
236
+ # capital letters by convention).
237
+
238
+ test_set_prereq () {
239
+ satisfied_prereq="$satisfied_prereq$1 "
240
+ }
241
+ satisfied_prereq=" "
242
+ lazily_testable_prereq= lazily_tested_prereq=
243
+
244
+ # Usage: test_lazy_prereq PREREQ 'script'
245
+ test_lazy_prereq () {
246
+ lazily_testable_prereq="$lazily_testable_prereq$1 "
247
+ eval test_prereq_lazily_$1=\$2
248
+ }
249
+
250
+ test_run_lazy_prereq_ () {
251
+ script='
252
+ mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
253
+ (
254
+ cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
255
+ )'
256
+ say >&3 "checking prerequisite: $1"
257
+ say >&3 "$script"
258
+ test_eval_ "$script"
259
+ eval_ret=$?
260
+ rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
261
+ if test "$eval_ret" = 0; then
262
+ say >&3 "prerequisite $1 ok"
263
+ else
264
+ say >&3 "prerequisite $1 not satisfied"
265
+ fi
266
+ return $eval_ret
267
+ }
268
+
269
+ test_have_prereq () {
270
+ # prerequisites can be concatenated with ','
271
+ save_IFS=$IFS
272
+ IFS=,
273
+ set -- $*
274
+ IFS=$save_IFS
275
+
276
+ total_prereq=0
277
+ ok_prereq=0
278
+ missing_prereq=
279
+
280
+ for prerequisite
281
+ do
282
+ case "$prerequisite" in
283
+ !*)
284
+ negative_prereq=t
285
+ prerequisite=${prerequisite#!}
286
+ ;;
287
+ *)
288
+ negative_prereq=
289
+ esac
290
+
291
+ case " $lazily_tested_prereq " in
292
+ *" $prerequisite "*)
293
+ ;;
294
+ *)
295
+ case " $lazily_testable_prereq " in
296
+ *" $prerequisite "*)
297
+ eval "script=\$test_prereq_lazily_$prerequisite" &&
298
+ if test_run_lazy_prereq_ "$prerequisite" "$script"
299
+ then
300
+ test_set_prereq $prerequisite
301
+ fi
302
+ lazily_tested_prereq="$lazily_tested_prereq$prerequisite "
303
+ esac
304
+ ;;
305
+ esac
306
+
307
+ total_prereq=$(($total_prereq + 1))
308
+ case "$satisfied_prereq" in
309
+ *" $prerequisite "*)
310
+ satisfied_this_prereq=t
311
+ ;;
312
+ *)
313
+ satisfied_this_prereq=
314
+ esac
315
+
316
+ case "$satisfied_this_prereq,$negative_prereq" in
317
+ t,|,t)
318
+ ok_prereq=$(($ok_prereq + 1))
319
+ ;;
320
+ *)
321
+ # Keep a list of missing prerequisites; restore
322
+ # the negative marker if necessary.
323
+ prerequisite=${negative_prereq:+!}$prerequisite
324
+ if test -z "$missing_prereq"
325
+ then
326
+ missing_prereq=$prerequisite
327
+ else
328
+ missing_prereq="$prerequisite,$missing_prereq"
329
+ fi
330
+ esac
331
+ done
332
+
333
+ test $total_prereq = $ok_prereq
334
+ }
335
+
336
+ test_declared_prereq () {
337
+ case ",$test_prereq," in
338
+ *,$1,*)
339
+ return 0
340
+ ;;
341
+ esac
342
+ return 1
343
+ }
344
+
345
+ test_expect_failure () {
346
+ test_start_
347
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
348
+ test "$#" = 2 ||
349
+ error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
350
+ export test_prereq
351
+ if ! test_skip "$@"
352
+ then
353
+ say >&3 "checking known breakage: $2"
354
+ if test_run_ "$2" expecting_failure
355
+ then
356
+ test_known_broken_ok_ "$1"
357
+ else
358
+ test_known_broken_failure_ "$1"
359
+ fi
360
+ fi
361
+ test_finish_
362
+ }
363
+
364
+ test_expect_success () {
365
+ test_start_
366
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
367
+ test "$#" = 2 ||
368
+ error "bug in the test script: not 2 or 3 parameters to test-expect-success"
369
+ export test_prereq
370
+ if ! test_skip "$@"
371
+ then
372
+ say >&3 "expecting success: $2"
373
+ if test_run_ "$2"
374
+ then
375
+ test_ok_ "$1"
376
+ else
377
+ test_failure_ "$@"
378
+ fi
379
+ fi
380
+ test_finish_
381
+ }
382
+
383
+ # test_external runs external test scripts that provide continuous
384
+ # test output about their progress, and succeeds/fails on
385
+ # zero/non-zero exit code. It outputs the test output on stdout even
386
+ # in non-verbose mode, and announces the external script with "# run
387
+ # <n>: ..." before running it. When providing relative paths, keep in
388
+ # mind that all scripts run in "trash directory".
389
+ # Usage: test_external description command arguments...
390
+ # Example: test_external 'Perl API' perl ../path/to/test.pl
391
+ test_external () {
392
+ test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
393
+ test "$#" = 3 ||
394
+ error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
395
+ descr="$1"
396
+ shift
397
+ export test_prereq
398
+ if ! test_skip "$descr" "$@"
399
+ then
400
+ # Announce the script to reduce confusion about the
401
+ # test output that follows.
402
+ say_color "" "# run $test_count: $descr ($*)"
403
+ # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
404
+ # to be able to use them in script
405
+ export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
406
+ # Run command; redirect its stderr to &4 as in
407
+ # test_run_, but keep its stdout on our stdout even in
408
+ # non-verbose mode.
409
+ "$@" 2>&4
410
+ if [ "$?" = 0 ]
411
+ then
412
+ if test $test_external_has_tap -eq 0; then
413
+ test_ok_ "$descr"
414
+ else
415
+ say_color "" "# test_external test $descr was ok"
416
+ test_success=$(($test_success + 1))
417
+ fi
418
+ else
419
+ if test $test_external_has_tap -eq 0; then
420
+ test_failure_ "$descr" "$@"
421
+ else
422
+ say_color error "# test_external test $descr failed: $@"
423
+ test_failure=$(($test_failure + 1))
424
+ fi
425
+ fi
426
+ fi
427
+ }
428
+
429
+ # Like test_external, but in addition tests that the command generated
430
+ # no output on stderr.
431
+ test_external_without_stderr () {
432
+ # The temporary file has no (and must have no) security
433
+ # implications.
434
+ tmp=${TMPDIR:-/tmp}
435
+ stderr="$tmp/git-external-stderr.$$.tmp"
436
+ test_external "$@" 4> "$stderr"
437
+ [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
438
+ descr="no stderr: $1"
439
+ shift
440
+ say >&3 "# expecting no stderr from previous command"
441
+ if [ ! -s "$stderr" ]; then
442
+ rm "$stderr"
443
+
444
+ if test $test_external_has_tap -eq 0; then
445
+ test_ok_ "$descr"
446
+ else
447
+ say_color "" "# test_external_without_stderr test $descr was ok"
448
+ test_success=$(($test_success + 1))
449
+ fi
450
+ else
451
+ if [ "$verbose" = t ]; then
452
+ output=`echo; echo "# Stderr is:"; cat "$stderr"`
453
+ else
454
+ output=
455
+ fi
456
+ # rm first in case test_failure exits.
457
+ rm "$stderr"
458
+ if test $test_external_has_tap -eq 0; then
459
+ test_failure_ "$descr" "$@" "$output"
460
+ else
461
+ say_color error "# test_external_without_stderr test $descr failed: $@: $output"
462
+ test_failure=$(($test_failure + 1))
463
+ fi
464
+ fi
465
+ }
466
+
467
+ # debugging-friendly alternatives to "test [-f|-d|-e]"
468
+ # The commands test the existence or non-existence of $1. $2 can be
469
+ # given to provide a more precise diagnosis.
470
+ test_path_is_file () {
471
+ if ! [ -f "$1" ]
472
+ then
473
+ echo "File $1 doesn't exist. $*"
474
+ false
475
+ fi
476
+ }
477
+
478
+ test_path_is_dir () {
479
+ if ! [ -d "$1" ]
480
+ then
481
+ echo "Directory $1 doesn't exist. $*"
482
+ false
483
+ fi
484
+ }
485
+
486
+ test_path_is_missing () {
487
+ if [ -e "$1" ]
488
+ then
489
+ echo "Path exists:"
490
+ ls -ld "$1"
491
+ if [ $# -ge 1 ]; then
492
+ echo "$*"
493
+ fi
494
+ false
495
+ fi
496
+ }
497
+
498
+ # test_line_count checks that a file has the number of lines it
499
+ # ought to. For example:
500
+ #
501
+ # test_expect_success 'produce exactly one line of output' '
502
+ # do something >output &&
503
+ # test_line_count = 1 output
504
+ # '
505
+ #
506
+ # is like "test $(wc -l <output) = 1" except that it passes the
507
+ # output through when the number of lines is wrong.
508
+
509
+ test_line_count () {
510
+ if test $# != 3
511
+ then
512
+ error "bug in the test script: not 3 parameters to test_line_count"
513
+ elif ! test $(wc -l <"$3") "$1" "$2"
514
+ then
515
+ echo "test_line_count: line count for $3 !$1 $2"
516
+ cat "$3"
517
+ return 1
518
+ fi
519
+ }
520
+
521
+ # This is not among top-level (test_expect_success | test_expect_failure)
522
+ # but is a prefix that can be used in the test script, like:
523
+ #
524
+ # test_expect_success 'complain and die' '
525
+ # do something &&
526
+ # do something else &&
527
+ # test_must_fail git checkout ../outerspace
528
+ # '
529
+ #
530
+ # Writing this as "! git checkout ../outerspace" is wrong, because
531
+ # the failure could be due to a segv. We want a controlled failure.
532
+
533
+ test_must_fail () {
534
+ "$@"
535
+ exit_code=$?
536
+ if test $exit_code = 0; then
537
+ echo >&2 "test_must_fail: command succeeded: $*"
538
+ return 1
539
+ elif test $exit_code -gt 129 -a $exit_code -le 192; then
540
+ echo >&2 "test_must_fail: died by signal: $*"
541
+ return 1
542
+ elif test $exit_code = 127; then
543
+ echo >&2 "test_must_fail: command not found: $*"
544
+ return 1
545
+ elif test $exit_code = 126; then
546
+ echo >&2 "test_must_fail: valgrind error: $*"
547
+ return 1
548
+ fi
549
+ return 0
550
+ }
551
+
552
+ # Similar to test_must_fail, but tolerates success, too. This is
553
+ # meant to be used in contexts like:
554
+ #
555
+ # test_expect_success 'some command works without configuration' '
556
+ # test_might_fail git config --unset all.configuration &&
557
+ # do something
558
+ # '
559
+ #
560
+ # Writing "git config --unset all.configuration || :" would be wrong,
561
+ # because we want to notice if it fails due to segv.
562
+
563
+ test_might_fail () {
564
+ "$@"
565
+ exit_code=$?
566
+ if test $exit_code -gt 129 -a $exit_code -le 192; then
567
+ echo >&2 "test_might_fail: died by signal: $*"
568
+ return 1
569
+ elif test $exit_code = 127; then
570
+ echo >&2 "test_might_fail: command not found: $*"
571
+ return 1
572
+ fi
573
+ return 0
574
+ }
575
+
576
+ # Similar to test_must_fail and test_might_fail, but check that a
577
+ # given command exited with a given exit code. Meant to be used as:
578
+ #
579
+ # test_expect_success 'Merge with d/f conflicts' '
580
+ # test_expect_code 1 git merge "merge msg" B master
581
+ # '
582
+
583
+ test_expect_code () {
584
+ want_code=$1
585
+ shift
586
+ "$@"
587
+ exit_code=$?
588
+ if test $exit_code = $want_code
589
+ then
590
+ return 0
591
+ fi
592
+
593
+ echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
594
+ return 1
595
+ }
596
+
597
+ # test_cmp is a helper function to compare actual and expected output.
598
+ # You can use it like:
599
+ #
600
+ # test_expect_success 'foo works' '
601
+ # echo expected >expected &&
602
+ # foo >actual &&
603
+ # test_cmp expected actual
604
+ # '
605
+ #
606
+ # This could be written as either "cmp" or "diff -u", but:
607
+ # - cmp's output is not nearly as easy to read as diff -u
608
+ # - not all diff versions understand "-u"
609
+
610
+ test_cmp() {
611
+ $GIT_TEST_CMP "$@"
612
+ }
613
+
614
+ # Check if the file expected to be empty is indeed empty, and barfs
615
+ # otherwise.
616
+
617
+ test_must_be_empty () {
618
+ if test -s "$1"
619
+ then
620
+ echo "'$1' is not empty, it contains:"
621
+ cat "$1"
622
+ return 1
623
+ fi
624
+ }
625
+
626
+ # Tests that its two parameters refer to the same revision
627
+ test_cmp_rev () {
628
+ git rev-parse --verify "$1" >expect.rev &&
629
+ git rev-parse --verify "$2" >actual.rev &&
630
+ test_cmp expect.rev actual.rev
631
+ }
632
+
633
+ # Print a sequence of numbers or letters in increasing order. This is
634
+ # similar to GNU seq(1), but the latter might not be available
635
+ # everywhere (and does not do letters). It may be used like:
636
+ #
637
+ # for i in `test_seq 100`; do
638
+ # for j in `test_seq 10 20`; do
639
+ # for k in `test_seq a z`; do
640
+ # echo $i-$j-$k
641
+ # done
642
+ # done
643
+ # done
644
+
645
+ test_seq () {
646
+ case $# in
647
+ 1) set 1 "$@" ;;
648
+ 2) ;;
649
+ *) error "bug in the test script: not 1 or 2 parameters to test_seq" ;;
650
+ esac
651
+ "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@"
652
+ }
653
+
654
+ # This function can be used to schedule some commands to be run
655
+ # unconditionally at the end of the test to restore sanity:
656
+ #
657
+ # test_expect_success 'test core.capslock' '
658
+ # git config core.capslock true &&
659
+ # test_when_finished "git config --unset core.capslock" &&
660
+ # hello world
661
+ # '
662
+ #
663
+ # That would be roughly equivalent to
664
+ #
665
+ # test_expect_success 'test core.capslock' '
666
+ # git config core.capslock true &&
667
+ # hello world
668
+ # git config --unset core.capslock
669
+ # '
670
+ #
671
+ # except that the greeting and config --unset must both succeed for
672
+ # the test to pass.
673
+ #
674
+ # Note that under --immediate mode, no clean-up is done to help diagnose
675
+ # what went wrong.
676
+
677
+ test_when_finished () {
678
+ test_cleanup="{ $*
679
+ } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
680
+ }
681
+
682
+ # Most tests can use the created repository, but some may need to create more.
683
+ # Usage: test_create_repo <directory>
684
+ test_create_repo () {
685
+ test "$#" = 1 ||
686
+ error "bug in the test script: not 1 parameter to test-create-repo"
687
+ repo="$1"
688
+ mkdir -p "$repo"
689
+ (
690
+ cd "$repo" || error "Cannot setup test environment"
691
+ gistore init --repo . >&3 2>&4 ||
692
+ error "cannot run git init -- have you built things yet?"
693
+ ) || exit
694
+ }
695
+
696
+ # This function helps on symlink challenged file systems when it is not
697
+ # important that the file system entry is a symbolic link.
698
+ # Use test_ln_s_add instead of "ln -s x y && git add y" to add a
699
+ # symbolic link entry y to the index.
700
+
701
+ test_ln_s_add () {
702
+ if test_have_prereq SYMLINKS
703
+ then
704
+ ln -s "$1" "$2" &&
705
+ git update-index --add "$2"
706
+ else
707
+ printf '%s' "$1" >"$2" &&
708
+ ln_s_obj=$(git hash-object -w "$2") &&
709
+ git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
710
+ fi
711
+ }
712
+
713
+ git_log_only_subject() {
714
+ repo=$1
715
+ shift
716
+ if test $(gistore check-git-version 1.6.3) -ge 0; then
717
+ gistore log --repo $repo --pretty="%s" $@
718
+ else
719
+ gistore log --repo $repo --pretty="format:%s" $@
720
+ printf "\n"
721
+ fi
722
+ }