(command.CommandList children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:test_description) op: assign_op.Equal rhs: {(SQ <'concurrent git svn dcommit'>)} spids: [13] ) ] ) (C {<.>} {<'./lib-git-svn.sh'>}) (C {<test_expect_success>} {(SQ <'setup svn repository'>)} { (SQ <'\n'> <'\tsvn_cmd checkout "$svnrepo" work.svn &&\n'> <'\t(\n'> <'\t\tcd work.svn &&\n'> <'\t\techo >file && echo > auto_updated_file\n'> <'\t\tsvn_cmd add file auto_updated_file &&\n'> <'\t\tsvn_cmd commit -m "initial commit"\n'> <'\t) &&\n'> <'\tsvn_cmd checkout "$svnrepo" work-auto-commits.svn\n'> ) } ) (command.ShAssignment pairs: [(assign_pair lhs:(sh_lhs_expr.Name name:N) op:assign_op.Equal rhs:{<0>} spids:[43])] ) (command.ShFunction name: next_N body: (BraceGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:N) op: assign_op.Equal rhs: { (word_part.ArithSub anode: (arith_expr.Binary op_id: Id.Arith_Plus left: {($ Id.VSub_DollarName '$N')} right: {<Id.Lit_Digits 1>} ) ) } spids: [53] ) ] ) ] ) ) (command.ShFunction name: setup_hook body: (BraceGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:hook_type) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_Number '$1'))} spids: [108] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:skip_revs) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_Number '$2'))} spids: [117] ) ] ) (command.AndOr ops: [Id.Op_DPipe Id.Op_DPipe] children: [ (C {<Id.Lit_LBracket '['>} {(DQ ($ Id.VSub_DollarName '$hook_type'))} {<Id.Lit_Equals '='>} {(DQ <pre-commit>)} {<Id.Lit_RBracket ']'>} ) (C {<Id.Lit_LBracket '['>} {(DQ ($ Id.VSub_DollarName '$hook_type'))} {<Id.Lit_Equals '='>} {(DQ <post-commit>)} {<Id.Lit_RBracket ']'>} ) (BraceGroup children: [ (command.Sentence child: (command.Simple words: [ {<echo>} { (DQ <'ERROR: invalid argument ('> ($ Id.VSub_DollarName '$hook_type') <')'> ) } {(DQ <'passed to setup_hook'>)} ] redirects: [ (redir op: <Id.Redir_GreatAnd '>&'> loc: (redir_loc.Fd fd:1) arg: {<2>} ) ] do_fork: T ) terminator: <Id.Op_Semi _> ) (command.Sentence child: (command.ControlFlow token:<Id.ControlFlow_Return return> arg_word:{<1>}) terminator: <Id.Op_Semi _> ) ] ) ] ) (command.Simple words: [{<echo>} {(DQ <'cnt='> ($ Id.VSub_DollarName '$skip_revs'))}] redirects: [ (redir op: <Id.Redir_Great '>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook_type') <-counter>)} ) ] do_fork: T ) (C {<rm>} {<-f>} {(DQ ($ Id.VSub_DollarName '$rawsvnrepo') <'/hooks/'>) <Id.Lit_Star '*'> <-commit>} ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:hook) op: assign_op.Equal rhs: { (DQ ($ Id.VSub_DollarName '$rawsvnrepo') <'/hooks/'> ($ Id.VSub_DollarName '$hook_type') ) } spids: [216] ) ] ) (command.Simple words: [{<cat>}] redirects: [ (redir op: <Id.Redir_Great '>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook'))} ) (redir op: <Id.Redir_DLessDash '<<-'> loc: (redir_loc.Fd fd:0) arg: (redir_param.MultiLine here_begin: {(SQ <EOF1>)} here_end_span_id: 249 stdin_parts: [ <'#!/bin/sh\n'> <'set -e\n'> <'cd "$1/.." # "$1" is repository location\n'> <'exec >> svn-hook.log 2>&1\n'> <'hook="$(basename "$0")"\n'> <'echo "*** Executing $hook $@"\n'> <'set -x\n'> <'. ./$hook-counter\n'> <'cnt="$(($cnt - 1))"\n'> <'echo "cnt=$cnt" > ./$hook-counter\n'> <'[ "$cnt" = "0" ] || exit 0\n'> ] ) ) ] do_fork: T ) (command.If arms: [ (if_arm cond: [ (command.Sentence child: (C {<Id.Lit_LBracket '['>} {(DQ ($ Id.VSub_DollarName '$hook_type'))} {<Id.Lit_Equals '='>} {(DQ <pre-commit>)} {<Id.Lit_RBracket ']'>} ) terminator: <Id.Op_Semi _> ) ] action: [ (command.Simple words: [{<echo>} {(DQ <'echo \'commit disallowed\' >&2; exit 1'>)}] redirects: [ (redir op: <Id.Redir_DGreat '>>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook'))} ) ] do_fork: T ) ] spids: [251 268] ) ] else_action: [ (command.Simple words: [ {<echo>} { (DQ <'PATH='> (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\"'>) ($ Id.VSub_DollarName '$PATH') (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\"'>) <'; export PATH'> ) } ] redirects: [ (redir op: <Id.Redir_DGreat '>>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook'))} ) ] do_fork: T ) (command.Simple words: [ {<echo>} { (DQ <'svnconf='> (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\"'>) ($ Id.VSub_DollarName '$svnconf') (word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\"'>) ) } ] redirects: [ (redir op: <Id.Redir_DGreat '>>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook'))} ) ] do_fork: T ) (command.Simple words: [{<cat>}] redirects: [ (redir op: <Id.Redir_DGreat '>>'> loc: (redir_loc.Fd fd:1) arg: {(DQ ($ Id.VSub_DollarName '$hook'))} ) (redir op: <Id.Redir_DLessDash '<<-'> loc: (redir_loc.Fd fd:0) arg: (redir_param.MultiLine here_begin: {(SQ <EOF2>)} here_end_span_id: 336 stdin_parts: [ <'cd work-auto-commits.svn\n'> <'svn up --config-dir "$svnconf"\n'> <'echo "$$" >> auto_updated_file\n'> <'svn commit --config-dir "$svnconf" \\\n'> <'-m "auto-committing concurrent change"\n'> <'exit 0\n'> ] ) ) ] do_fork: T ) ] ) (C {<chmod>} {<755>} {(DQ ($ Id.VSub_DollarName '$hook'))}) ] ) ) (command.ShFunction name: check_contents body: (BraceGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:gitdir) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_Number '$1'))} spids: [359] ) ] ) (command.AndOr ops: [Id.Op_DAmp Id.Op_DAmp] children: [ (command.Subshell child: (command.AndOr ops: [Id.Op_DAmp] children: [(C {<cd>} {<'../work.svn'>}) (C {<svn_cmd>} {<up>})] ) ) (C {<test_cmp>} {<file>} {<'../work.svn/file'>}) (C {<test_cmp>} {<auto_updated_file>} {<'../work.svn/auto_updated_file'>}) ] ) ] ) ) (C {<test_expect_success>} {(SQ <'check if post-commit hook creates a concurrent commit'>)} { (SQ <'\n'> <'\tsetup_hook post-commit 1 &&\n'> <'\t(\n'> <'\t\tcd work.svn &&\n'> <'\t\tcp auto_updated_file au_file_saved &&\n'> <'\t\techo 1 >> file &&\n'> <'\t\tsvn_cmd commit -m "changing file" &&\n'> <'\t\tsvn_cmd up &&\n'> <'\t\ttest_must_fail test_cmp auto_updated_file au_file_saved\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'check if pre-commit hook fails'>)} { (SQ <'\n'> <'\tsetup_hook pre-commit 2 &&\n'> <'\t(\n'> <'\t\tcd work.svn &&\n'> <'\t\techo 2 >> file &&\n'> <'\t\tsvn_cmd commit -m "changing file once again" &&\n'> <'\t\techo 3 >> file &&\n'> <'\t\ttest_must_fail svn_cmd commit -m "this commit should fail" &&\n'> <'\t\tsvn_cmd revert file\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'dcommit error handling'>)} { (SQ <'\n'> <'\tsetup_hook pre-commit 2 &&\n'> <'\tnext_N && git svn clone "$svnrepo" work$N.git &&\n'> <'\t(\n'> <'\t\tcd work$N.git &&\n'> <'\t\techo 1 >> file && git commit -am "commit change $N.1" &&\n'> <'\t\techo 2 >> file && git commit -am "commit change $N.2" &&\n'> <'\t\techo 3 >> file && git commit -am "commit change $N.3" &&\n'> <'\t\t# should fail to dcommit 2nd and 3rd change\n'> <'\t\t# but still should leave the repository in reasonable state\n'> <'\t\ttest_must_fail git svn dcommit &&\n'> <'\t\tgit update-index --refresh &&\n'> <'\t\tgit show HEAD~2 | grep -q git-svn-id &&\n'> <'\t\t! git show HEAD~1 | grep -q git-svn-id &&\n'> <'\t\t! git show HEAD | grep -q git-svn-id\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'dcommit concurrent change in non-changed file'>)} { (SQ <'\n'> <'\tsetup_hook post-commit 2 &&\n'> <'\tnext_N && git svn clone "$svnrepo" work$N.git &&\n'> <'\t(\n'> <'\t\tcd work$N.git &&\n'> <'\t\techo 1 >> file && git commit -am "commit change $N.1" &&\n'> <'\t\techo 2 >> file && git commit -am "commit change $N.2" &&\n'> <'\t\techo 3 >> file && git commit -am "commit change $N.3" &&\n'> <'\t\t# should rebase and leave the repository in reasonable state\n'> <'\t\tgit svn dcommit &&\n'> <'\t\tgit update-index --refresh &&\n'> <'\t\tcheck_contents &&\n'> <'\t\tgit show HEAD~3 | grep -q git-svn-id &&\n'> <'\t\tgit show HEAD~2 | grep -q git-svn-id &&\n'> <'\t\tgit show HEAD~1 | grep -q auto-committing &&\n'> <'\t\tgit show HEAD | grep -q git-svn-id\n'> <'\t)\n'> ) } ) (command.ShFunction name: delete_first_line body: (BraceGroup children: [ (command.AndOr ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp] children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:file) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_Number '$1'))} spids: [501] ) ] ) (command.Simple words: [{<sed>} {<1d>}] redirects: [ (redir op: <Id.Redir_Less '<'> loc: (redir_loc.Fd fd:0) arg: {(DQ ($ Id.VSub_DollarName '$file'))} ) (redir op: <Id.Redir_Great '>'> loc: (redir_loc.Fd fd:1) arg: {(DQ (${ Id.VSub_Name file) <.tmp>)} ) ] do_fork: T ) (C {<rm>} {(DQ ($ Id.VSub_DollarName '$file'))}) (C {<mv>} {(DQ (${ Id.VSub_Name file) <.tmp>)} {(DQ ($ Id.VSub_DollarName '$file'))}) ] ) ] ) ) (C {<test_expect_success>} {(SQ <'dcommit concurrent non-conflicting change'>)} { (SQ <'\n'> <'\tsetup_hook post-commit 2 &&\n'> <'\tnext_N && git svn clone "$svnrepo" work$N.git &&\n'> <'\t(\n'> <'\t\tcd work$N.git &&\n'> <'\t\tcat file >> auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.1" &&\n'> <'\t\tdelete_first_line auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.2" &&\n'> <'\t\tdelete_first_line auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.3" &&\n'> <'\t\t# should rebase and leave the repository in reasonable state\n'> <'\t\tgit svn dcommit &&\n'> <'\t\tgit update-index --refresh &&\n'> <'\t\tcheck_contents &&\n'> <'\t\tgit show HEAD~3 | grep -q git-svn-id &&\n'> <'\t\tgit show HEAD~2 | grep -q git-svn-id &&\n'> <'\t\tgit show HEAD~1 | grep -q auto-committing &&\n'> <'\t\tgit show HEAD | grep -q git-svn-id\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'dcommit --no-rebase concurrent non-conflicting change'>)} { (SQ <'\n'> <'\tsetup_hook post-commit 2 &&\n'> <'\tnext_N && git svn clone "$svnrepo" work$N.git &&\n'> <'\t(\n'> <'\t\tcd work$N.git &&\n'> <'\t\tcat file >> auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.1" &&\n'> <'\t\tdelete_first_line auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.2" &&\n'> <'\t\tdelete_first_line auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.3" &&\n'> <'\t\t# should fail as rebase is needed\n'> <'\t\ttest_must_fail git svn dcommit --no-rebase &&\n'> <'\t\t# but should leave HEAD unchanged\n'> <'\t\tgit update-index --refresh &&\n'> <'\t\t! git show HEAD~2 | grep -q git-svn-id &&\n'> <'\t\t! git show HEAD~1 | grep -q git-svn-id &&\n'> <'\t\t! git show HEAD | grep -q git-svn-id\n'> <'\t)\n'> ) } ) (C {<test_expect_success>} {(SQ <'dcommit fails on concurrent conflicting change'>)} { (SQ <'\n'> <'\tsetup_hook post-commit 1 &&\n'> <'\tnext_N && git svn clone "$svnrepo" work$N.git &&\n'> <'\t(\n'> <'\t\tcd work$N.git &&\n'> <'\t\techo a >> file &&\n'> <'\t\t\tgit commit -am "commit change $N.1" &&\n'> <'\t\techo b >> auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.2" &&\n'> <'\t\techo c >> auto_updated_file &&\n'> <'\t\t\tgit commit -am "commit change $N.3" &&\n'> <'\t\ttest_must_fail git svn dcommit && # rebase should fail\n'> <'\t\ttest_must_fail git update-index --refresh\n'> <'\t)\n'> ) } ) (C {<test_done>}) ] )