about summary refs log tree commit diff
path: root/t/lib-git-p4.sh
blob: 5aff2abe8b5490156e7745beb5ad01d9cacc0d58 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#
# Library code for git p4 tests
#

# p4 tests never use the top-level repo; always build/clone into
# a subdirectory called "$git"
TEST_NO_CREATE_REPO=NoThanks

# Some operations require multiple attempts to be successful. Define
# here the maximal retry timeout in seconds.
RETRY_TIMEOUT=60

# Sometimes p4d seems to hang. Terminate the p4d process automatically after
# the defined timeout in seconds.
P4D_TIMEOUT=300

. ./test-lib.sh

if ! test_have_prereq PYTHON
then
	skip_all='skipping git p4 tests; python not available'
	test_done
fi
( p4 -h && p4d -h ) >/dev/null 2>&1 || {
	skip_all='skipping git p4 tests; no p4 or p4d'
	test_done
}

# On cygwin, the NT version of Perforce can be used.  When giving
# it paths, either on the command-line or in client specifications,
# be sure to use the native windows form.
#
# Older versions of perforce were available compiled natively for
# cygwin.  Those do not accept native windows paths, so make sure
# not to convert for them.
native_path () {
	path="$1" &&
	if test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN
	then
		path=$(cygpath --windows "$path")
	else
		path=$(test-tool path-utils real_path "$path")
	fi &&
	echo "$path"
}

test_set_port P4DPORT

P4PORT=localhost:$P4DPORT
P4CLIENT=client
P4USER=author
P4EDITOR=true
unset P4CHARSET
export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET

db="$TRASH_DIRECTORY/db"
cli="$TRASH_DIRECTORY/cli"
git="$TRASH_DIRECTORY/git"
pidfile="$TRASH_DIRECTORY/p4d.pid"

stop_p4d_and_watchdog () {
	kill -9 $p4d_pid $watchdog_pid
}

# git p4 submit generates a temp file, which will
# not get cleaned up if the submission fails.  Don't
# clutter up /tmp on the test machine.
TMPDIR="$TRASH_DIRECTORY"
export TMPDIR

registered_stop_p4d_atexit_handler=
start_p4d () {
	# One of the test scripts stops and then re-starts p4d.
	# Don't register and then run the same atexit handlers several times.
	if test -z "$registered_stop_p4d_atexit_handler"
	then
		test_atexit 'stop_p4d_and_watchdog'
		registered_stop_p4d_atexit_handler=AlreadyDone
	fi

	mkdir -p "$db" "$cli" "$git" &&
	rm -f "$pidfile" &&
	(
		cd "$db" &&
		{
			p4d -q -p $P4DPORT "$@" &
			echo $! >"$pidfile"
		}
	) &&
	p4d_pid=$(cat "$pidfile")

	# This gives p4d a long time to start up, as it can be
	# quite slow depending on the machine.  Set this environment
	# variable to something smaller to fail faster in, say,
	# an automated test setup.  If the p4d process dies, that
	# will be caught with the "kill -0" check below.
	i=${P4D_START_PATIENCE:-300}

	nr_tries_left=$P4D_TIMEOUT
	while true
	do
		if test $nr_tries_left -eq 0
		then
			kill -9 $p4d_pid
			exit 1
		fi
		sleep 1
		nr_tries_left=$(($nr_tries_left - 1))
	done 2>/dev/null 4>&2 &
	watchdog_pid=$!

	ready=
	while test $i -gt 0
	do
		# succeed when p4 client commands start to work
		if p4 info >/dev/null 2>&1
		then
			ready=true
			break
		fi
		# fail if p4d died
		kill -0 $p4d_pid 2>/dev/null || break
		echo waiting for p4d to start
		sleep 1
		i=$(( $i - 1 ))
	done

	if test -z "$ready"
	then
		# p4d failed to start
		return 1
	fi

	# build a p4 user so author@example.com has an entry
	p4_add_user author

	# build a client
	client_view "//depot/... //client/..." &&

	return 0
}

p4_add_user () {
	name=$1 &&
	p4 user -f -i <<-EOF
	User: $name
	Email: $name@example.com
	FullName: Dr. $name
	EOF
}

p4_add_job () {
	p4 job -f -i <<-EOF
	Job: $1
	Status: open
	User: dummy
	Description:
	EOF
}

retry_until_success () {
	nr_tries_left=$RETRY_TIMEOUT
	until "$@" 2>/dev/null || test $nr_tries_left -eq 0
	do
		sleep 1
		nr_tries_left=$(($nr_tries_left - 1))
	done
}

stop_and_cleanup_p4d () {
	kill -9 $p4d_pid $watchdog_pid
	wait $p4d_pid
	rm -rf "$db" "$cli" "$pidfile"
}

cleanup_git () {
	retry_until_success rm -r "$git"
	test_path_is_missing "$git" &&
	retry_until_success mkdir "$git"
}

marshal_dump () {
	what=$1 &&
	line=${2:-1} &&
	cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF &&
	import marshal
	import sys
	instream = getattr(sys.stdin, 'buffer', sys.stdin)
	for i in range($line):
	    d = marshal.load(instream)
	print(d[b'$what'].decode('utf-8'))
	EOF
	"$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
}

#
# Construct a client with this list of View lines
#
client_view () {
	(
		cat <<-EOF &&
		Client: $P4CLIENT
		Description: $P4CLIENT
		Root: $cli
		AltRoots: $(native_path "$cli")
		LineEnd: unix
		View:
		EOF
		printf "\t%s\n" "$@"
	) | p4 client -i
}

is_cli_file_writeable () {
	# cygwin version of p4 does not set read-only attr,
	# will be marked 444 but -w is true
	file="$1" &&
	if test_have_prereq CYGWIN && p4 -V | grep -q CYGWIN
	then
		stat=$(stat --format=%a "$file") &&
		test $stat = 644
	else
		test -w "$file"
	fi
}