aboutsummaryrefslogtreecommitdiff
path: root/libexec/build-fetch-p4
blob: b0af079cbf22108c0e4d3d06c47ef7db1d3b909e (plain)
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
#!/usr/bin/env build

build_fetch_p4()
{
	if ! p4 client -o > /dev/null 2>&1; then
		die 'p4 client not logged in'
	fi

	build_fetch_p4_uri="$(build-url --base "${1}")"
	build_fetch_p4_uri="${build_fetch_p4_uri%%\?*}"
	build_fetch_p4_uri="${build_fetch_p4_uri##p4://}"
	build_fetch_p4_var=
	build_fetch_p4_change=

	# FIXME ignore the server if specified?  The core problem here is that
	# p4 seems to have no way to specify what server you pull from.  It
	# generally assumes that the p4 client only has a single local server.
	# So specifying any such server (usually named 'perforce') is
	# fundementally a waste.
	if test "${build_fetch_p4_uri#/}" = "${build_fetch_p4_uri}"; then
		build_fetch_p4_uri="/${build_fetch_p4_uri#*/}"
	fi

	for arg in $(build-url --arg "${1}"); do
		case "${arg}" in
		(archive=*) build_fetch_p4_var="${arg##*=}";;
		(change=*) build_fetch_p4_change="@${arg##*=}";;
		esac
	done

	if test -z "${build_fetch_p4_var}"; then
		die "do not know how to store source from '${1}'"
	fi

	build_fetch_p4_dir="${build_fetch_p4_var%%.t*}"
	build_fetch_p4_tmp="$(mktemp -d "${BUILDER_TMPDIR}/${build_fetch_p4_dir}.XXXXXX")"
	BUILD_FETCH_CLEAN="${BUILD_FETCH_CLEAN} ${build_fetch_p4_tmp}"

	# We do not really know what sort of directory tree we are getting from
	# Perforce, so put it all into our archive directory and leave the
	# burden of sorting the mess to any Buildrules which pull from p4://
	mkdir -p "${build_fetch_p4_tmp}/${build_fetch_p4_dir}"
	cd "${build_fetch_p4_tmp}/${build_fetch_p4_dir}"
	p4 files "/${build_fetch_p4_uri}/...${build_fetch_p4_change}" | \
			while read build_fetch_p4_line; do
		# Parse the file type off the end of the line
		build_fetch_p4_type="${build_fetch_p4_line##* (}"
		build_fetch_p4_type="${build_fetch_p4_type%)}"
		build_fetch_p4_line="${build_fetch_p4_line%% (*}"

		# Parse the last changeset for the file
		build_fetch_p4_last="${build_fetch_p4_line##*change }"
		build_fetch_p4_line="${build_fetch_p4_line% change *}"

		# add/delete/edit action
		build_fetch_p4_action="${build_fetch_p4_line##* - }"
		build_fetch_p4_line="${build_fetch_p4_line% - *}"

		# File revision
		build_fetch_p4_rev="${build_fetch_p4_line##*#}"
		build_fetch_p4_line="${build_fetch_p4_line%%#*}"

		# File name
		build_fetch_p4_remote="${build_fetch_p4_line}"
		build_fetch_p4_local="${build_fetch_p4_line#//}"

		if test "${build_fetch_p4_remote}" != "//${build_fetch_p4_local}"; then
			die "parsing '${build_fetch_p4_line}'"
		fi

		# Append the @change number, if any
		build_fetch_p4_remote="${build_fetch_p4_remote}${build_fetch_p4_change}"

		# Figure out the mode of the file we should checkout as
		mode='0644'
		case "${build_fetch_p4_type}" in
		(*+x|*+wx|*+xw|xtext|kxtext|xbinary) mode='0755';;
		(text|ktext|text+w);;
		(symlink);;
		(binary|ubinary|apple);;
		(*) die "unknown filetype '${build_fetch_p4_type}'";;
		esac

		# Don't create deleted files
		case "${build_fetch_p4_action}" in
		(delete|move/delete) continue;;
		(add|move/add);;
		(edit|integrate|branch);;
		(*) die "unknown action '${build_fetch_p4_action}'";;
		esac

		if test -f "${build_fetch_p4_local}"; then
			die "${build_fetch_p4_action} existing file '${build_fetch_p4_local}'"
		fi

		mkdir -p "${build_fetch_p4_local%/*}"
		p4 print -q -o "${PWD}/${build_fetch_p4_local}" "${build_fetch_p4_remote}"
		if ! test -f "${build_fetch_p4_local}"; then
			die "failed to ${build_fetch_p4_action} file '${build_fetch_p4_local}'"
		fi
		chmod "${mode}" "${build_fetch_p4_local}"
	done
	unset build_fetch_p4_type
	unset build_fetch_p4_last
	unset build_fetch_p4_action
	unset build_fetch_p4_rev
	unset build_fetch_p4_remote
	unset build_fetch_p4_local
	unset build_fetch_p4_line

	cd "${build_fetch_p4_tmp}"
	tar caf "${build_fetch_p4_var}" "${build_fetch_p4_dir}"

	if test ! -d "${BUILDER_SRCDIR}"; then
		mkdir -p "${BUILDER_SRCDIR}"
	fi

	mv "${build_fetch_p4_var}" "${BUILDER_SRCDIR}/${build_fetch_p4_var}"

	if [ -d "${build_fetch_p4_tmp}" ]; then
		rm -rf "${build_fetch_p4_tmp}"
	fi

	unset build_fetch_p4_tmp
	unset build_fetch_p4_var
	unset build_fetch_p4_dir
	unset build_fetch_p4_uri
}

if test "${BUILDER_CALL_STACK}" = '__main__'; then
	simple_usage 'fetch-p4' '<url>' "$@"
	build_fetch_p4 "${1}"
fi

# vim: filetype=sh