db-functions 12.2 KB
Newer Older
1
#!/hint/bash
2

3
. /usr/share/makepkg/util.sh
4

5
# global shell options for enhanced bash scripting
6
shopt -s extglob globstar nullglob
7
8


9
10
11
# Some PKGBUILDs need CARCH to be set
CARCH="x86_64"

12
# Useful functions
13
14
UMASK=""
set_umask () {
Eli Schwartz's avatar
Eli Schwartz committed
15
	export UMASK="${UMASK:-$(umask)}"
16
17
18
19
	umask 002
}

restore_umask () {
20
	umask "$UMASK" >/dev/null
21
22
}

23
24
25
26
27
28
29
30
# Proxy function to check if a file exists. Using [[ -f ... ]] directly is not
# always wanted because we might want to expand bash globs first. This way we
# can pass unquoted globs to is_globfile() and have them expanded as function
# arguments before being checked.
is_globfile() {
	[[ -f $1 ]]
}

31
32
33
34
35
36
37
38
39
# just like mv -f, but we touch the file and then copy the content so
# default ACLs in the target dir will be applied
mv_acl() {
	rm -f "$2"
	touch "$2"
	cat "$1" >"$2" || return 1
	rm -f "$1"
}

40
# set up general environment
41
WORKDIR=$(mktemp -dt "${0##*/}.XXXXXXXXXX")
42
LOCKS=()
Florian Pritz's avatar
Florian Pritz committed
43
REPO_MODIFIED=0
44
45

script_lock() {
Pierre Schmitz's avatar
Pierre Schmitz committed
46
	local LOCKDIR="$TMPDIR/.scriptlock.${0##*/}"
47
	if ! mkdir "$LOCKDIR" >/dev/null 2>&1 ; then
48
		local _owner="$(/usr/bin/stat -c %U "$LOCKDIR")"
49
		error "Script %s is already locked by %s." "${0##*/}" "$_owner"
50
51
52
53
54
55
56
57
		exit 1
	else
		set_umask
		return 0
	fi
}

script_unlock() {
Pierre Schmitz's avatar
Pierre Schmitz committed
58
	local LOCKDIR="$TMPDIR/.scriptlock.${0##*/}"
Eli Schwartz's avatar
Eli Schwartz committed
59
	if [[ ! -d $LOCKDIR ]]; then
60
		warning "Script %s was not locked!" "${0##*/}"
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
		restore_umask
		return 1
	else
		rmdir "$LOCKDIR"
		restore_umask
		return 0
	fi
}

cleanup() {
	local l
	local repo
	local arch

	trap - EXIT INT QUIT TERM
76
	for l in "${LOCKS[@]}"; do
77
78
		repo=${l%.*}
		arch=${l#*.}
Eli Schwartz's avatar
Eli Schwartz committed
79
		if [[ -d $TMPDIR/.repolock.$repo.$arch ]]; then
80
			msg "Removing left over lock from [%s] (%s)" "$repo" "$arch"
81
			repo_unlock "$repo" "$arch"
82
83
		fi
	done
Eli Schwartz's avatar
Eli Schwartz committed
84
	if [[ -d $TMPDIR/.scriptlock.${0##*/} ]]; then
85
		msg "Removing left over lock from %s" "${0##*/}"
86
87
88
		script_unlock
	fi
	rm -rf "$WORKDIR"
Florian Pritz's avatar
Florian Pritz committed
89
90
91
92
93

	if (( REPO_MODIFIED )); then
		date +%s > "${FTP_BASE}/lastupdate"
	fi

94
	[[ -n $1 ]] && exit "$1"
95
96
97
}

abort() {
98
	msg 'Aborting...'
99
100
101
102
	cleanup 0
}

die() {
103
	error "$@"
104
105
106
	cleanup 1
}

107
trap abort INT QUIT TERM HUP
108
109
110
trap cleanup EXIT


Pierre Schmitz's avatar
Pierre Schmitz committed
111
#repo_lock <repo-name> <arch> [timeout]
112
113
114
115
116
117
118
119
repo_lock() {
	local repo base=${1}; shift
	for repo in ${base} ${base}-debug; do
		_repo_lock ${repo} "${@}"
	done
}

_repo_lock () {
120
	local LOCKDIR="$TMPDIR/.repolock.$1.$2"
121
	local DBLOCKFILE="${FTP_BASE}/${1}/os/${2}/${1}${DBEXT}.lck"
122
123
124
125
126
127
	local _count
	local _trial
	local _timeout
	local _lockblock
	local _owner

128
	# This is the lock file used by repo-add and repo-remove
Eli Schwartz's avatar
Eli Schwartz committed
129
	if [[ -f ${DBLOCKFILE} ]]; then
130
		error "Repo [%s] (%s) is already locked by repo-{add,remove} process %s" "$1" "$2" "$(cat "$DBLOCKFILE")"
131
132
		return 1
	fi
133

Eli Schwartz's avatar
Eli Schwartz committed
134
	if (( $# == 2 )); then
Pierre Schmitz's avatar
Pierre Schmitz committed
135
136
		_lockblock=true
		_trial=0
Eli Schwartz's avatar
Eli Schwartz committed
137
	elif (( $# == 3 )); then
Pierre Schmitz's avatar
Pierre Schmitz committed
138
139
140
		_lockblock=false
		_timeout=$3
		let _trial=$_timeout/$LOCK_DELAY
141
	fi
142
143

	_count=0
144
	while (( _count <= _trial )) || [[ $_lockblock = true ]]; do
Pierre Schmitz's avatar
Pierre Schmitz committed
145
		if ! mkdir "$LOCKDIR" >/dev/null 2>&1 ; then
146
			_owner="$(/usr/bin/stat -c %U "$LOCKDIR")"
147
148
			warning "Repo [%s] (%s) is already locked by %s." "$1" "$2" "$_owner"
			msg2 "Retrying in %s seconds..." "$LOCK_DELAY"
Pierre Schmitz's avatar
Pierre Schmitz committed
149
		else
150
			LOCKS+=("$1.$2")
Pierre Schmitz's avatar
Pierre Schmitz committed
151
152
153
			set_umask
			return 0
		fi
154
		sleep "$LOCK_DELAY"
Pierre Schmitz's avatar
Pierre Schmitz committed
155
		let _count=$_count+1
156
	done
157

158
	error "Repo [%s] (%s) is already locked by %s. Giving up!" "$1" "$2" "$_owner"
159
	return 1
160
161
}

162
163
164
165
166
167
168
169
170
#repo_unlock <repo-name> <arch>
repo_unlock () {
	local repo base=${1}; shift
	for repo in ${base} ${base}-debug; do
		_repo_unlock ${repo} "${@}"
	done
}

_repo_unlock () {
171
	local LOCKDIR="$TMPDIR/.repolock.$1.$2"
Eli Schwartz's avatar
Eli Schwartz committed
172
	if [[ ! -d $LOCKDIR ]]; then
173
		warning "Repo lock [%s] (%s) was not locked!" "$1" "$2"
174
175
		restore_umask
		return 1
176
	else
177
		rmdir "$LOCKDIR"
178
179
		restore_umask
		return 0
180
181
182
	fi
}

183
184
185
186
187
188
189
190
191
# usage: _grep_all_info pkgfile infofile key
_grep_all_info() {
	local _ret=()

	mapfile -t _ret < <(/usr/bin/bsdtar -xOqf "$1" "${2}" | grep "^${3} = ")

	printf '%s\n' "${_ret[@]#${3} = }"
}

192
193
# usage: _grep_pkginfo pkgfile pattern
_grep_pkginfo() {
194
	_grep_all_info "${1}" .PKGINFO "${2}" | tail -1
195
196
}

197
198
# usage: _grep_buildinfo pkgfile pattern
_grep_buildinfo() {
199
	_grep_all_info "${1}" .BUILDINFO "${2}" | tail -1
200
}
201

202
# Get the package base or name as fallback
203
204
205
getpkgbase() {
	local _base

206
	_base="$(_grep_pkginfo "$1" "pkgbase")"
Eli Schwartz's avatar
Eli Schwartz committed
207
	if [[ -z $_base ]]; then
208
		getpkgname "$1"
209
210
	else
		echo "$_base"
211
	fi
212
}
213
214

# Get the package name
215
getpkgname() {
216
	local _name
217

218
	_name="$(_grep_pkginfo "$1" "pkgname")"
Eli Schwartz's avatar
Eli Schwartz committed
219
	if [[ -z $_name ]]; then
220
		error "Package '%s' has no pkgname in the PKGINFO. Fail!" "$1"
221
222
223
224
		exit 1
	fi

	echo "$_name"
225
226
}

227
228
# Get the pkgver-pkgrel of this package
getpkgver() {
229
230
	local _ver

231
	_ver="$(_grep_pkginfo "$1" "pkgver")"
Eli Schwartz's avatar
Eli Schwartz committed
232
	if [[ -z $_ver ]]; then
233
		error "Package '%s' has no pkgver in the PKGINFO. Fail!" "$1"
234
235
		exit 1
	fi
236

237
	echo "$_ver"
238
239
}

Pierre Schmitz's avatar
Pierre Schmitz committed
240
241
242
getpkgarch() {
	local _ver

243
	_ver="$(_grep_pkginfo "$1" "arch")"
Eli Schwartz's avatar
Eli Schwartz committed
244
	if [[ -z $_ver ]]; then
245
		error "Package '%s' has no arch in the PKGINFO. Fail!" "$1"
Pierre Schmitz's avatar
Pierre Schmitz committed
246
247
248
249
250
251
		exit 1
	fi

	echo "$_ver"
}

252
253
254
255
256
257
258
259
is_debug_package() {
	local pkgfile=${1}
	local pkgbase="$(getpkgbase "${pkgfile}")"
	local pkgname="$(getpkgname "${pkgfile}")"

	[[ ${pkgbase}-debug = ${pkgname} ]]
}

260
261
262
263
check_packager() {
	local _packager

	_packager=$(_grep_pkginfo "$1" "packager")
Eli Schwartz's avatar
Eli Schwartz committed
264
	[[ -n $_packager && $_packager != 'Unknown Packager' ]]
265
266
}

267
check_buildinfo() {
268
	/usr/bin/bsdtar -tqf "$1" .BUILDINFO >/dev/null 2>&1
269
270
271
272
273
274
}

check_builddir() {
	local _builddir

	_builddir=$(_grep_buildinfo "$1" "builddir")
Eli Schwartz's avatar
Eli Schwartz committed
275
	[[ -n $_builddir && $_builddir = '/build' ]]
276
277
}

278
getpkgfile() {
Eli Schwartz's avatar
Eli Schwartz committed
279
	if  (( $# != 1 )); then
280
		error 'No canonical package found!'
281
		exit 1
Eli Schwartz's avatar
Eli Schwartz committed
282
	elif [[ ! -f ${1} ]]; then
283
		error "Package %s not found!" "$1"
284
		exit 1
Eli Schwartz's avatar
Eli Schwartz committed
285
	elif [[ ! -f ${1}.sig ]]; then
286
		error "Package signature %s not found!" "$1.sig"
287
		exit 1
288
289
	fi

290
	echo "${1}"
291
292
293
}

getpkgfiles() {
Eli Schwartz's avatar
Eli Schwartz committed
294
	local f files
Luke Shumaker's avatar
Luke Shumaker committed
295
	if ! printf '%s\n' "${@%\.*}" | awk 'a[$0]++{exit 1}'; then
296
		error 'Duplicate packages found!'
297
298
299
		exit 1
	fi

300
301
	for f in "$@"; do
		files+=("$(getpkgfile "$f")") || exit 1
302
303
	done

304
	echo "${files[@]}"
305
306
}

Pierre Schmitz's avatar
Pierre Schmitz committed
307
308
check_pkgfile() {
	local pkgfile=$1
309

310
311
312
	local pkgname="$(getpkgname "${pkgfile}")" || return 1
	local pkgver="$(getpkgver "${pkgfile}")" || return 1
	local pkgarch="$(getpkgarch "${pkgfile}")" || return 1
Pierre Schmitz's avatar
Pierre Schmitz committed
313

314
	in_array "${pkgarch}" "${ARCHES[@]}" 'any' || return 1
315

316
	[[ ${pkgfile##*/} = "${pkgname}-${pkgver}-${pkgarch}"* ]]
Pierre Schmitz's avatar
Pierre Schmitz committed
317
318
}

319
320
# Check that the package file is consistent with the PKGBUILD in version control
check_pkgvcs() {
Pierre Schmitz's avatar
Pierre Schmitz committed
321
	local pkgfile="${1}"
322
	local repo="${2}"
323
324
325
326
	local _pkgbase="$(getpkgbase "${pkgfile}")" || return 1
	local _pkgname="$(getpkgname "${pkgfile}")" || return 1
	local _pkgver="$(getpkgver "${pkgfile}")" || return 1
	local _pkgarch="$(getpkgarch "${pkgfile}")" || return 1
Pierre Schmitz's avatar
Pierre Schmitz committed
327

328
	in_array "${repo}" "${PKGREPOS[@]}" || return 1
329

330
331
332
333
	local vcsver vcsnames=()
	read -rd'\n' vcsver vcsnames < <(source_pkgbuild "${_pkgbase}" "repos/${repo}-${_pkgarch}"; \
	                                 get_full_version; echo "${pkgname[@]}")
	read -ra vcsnames <<<"${vcsnames}"
Pierre Schmitz's avatar
Pierre Schmitz committed
334

335
	[[ "${vcsver}" = "${_pkgver}" ]] || return 1
336
	in_array "${_pkgname}" "${vcsnames[@]}" "${_pkgbase}-debug" || return 1
337
338

	return 0
339
340
}

341
342
343
check_splitpkgs() {
	local repo="${1}"
	shift
344
	local pkgfiles=("${@}")
345
346
	local pkgfile
	local pkgdir
347
	local vcsname
348
349
350
351

	mkdir -p "${WORKDIR}/check_splitpkgs/"
	pushd "${WORKDIR}/check_splitpkgs" >/dev/null

352
353
354
355
	for pkgfile in "${pkgfiles[@]}"; do
		local _pkgbase="$(getpkgbase "${pkgfile}")"
		local _pkgname="$(getpkgname "${pkgfile}")"
		local _pkgarch="$(getpkgarch "${pkgfile}")"
356
357
358
359
		local vcsnames=($(source_pkgbuild "${_pkgbase}" "repos/${repo}-${_pkgarch}"; echo "${pkgname[@]}"))

		# not a split package
		(( ${#vcsnames[@]} > 1 )) || continue
360
		[[ ${_pkgbase}-debug = ${_pkgname} ]] && continue
361

362
363
		mkdir -p "${repo}/${_pkgarch}/${_pkgbase}"
		echo "${_pkgname}" >> "${repo}/${_pkgarch}/${_pkgbase}/staging"
364
		printf '%s\n' "${vcsnames[@]}" >> "${repo}/${_pkgarch}/${_pkgbase}/vcs"
365
366
367
368
	done
	popd >/dev/null

	for pkgdir in "${WORKDIR}/check_splitpkgs/${repo}"/*/*; do
Eli Schwartz's avatar
Eli Schwartz committed
369
		[[ ! -d ${pkgdir} ]] && continue
370
		sort -u "${pkgdir}/staging" -o "${pkgdir}/staging"
371
372
		sort -u "${pkgdir}/vcs" -o "${pkgdir}/vcs"
		if [[ ! -z "$(comm -13 "${pkgdir}/staging" "${pkgdir}/vcs")" ]]; then
373
374
375
376
377
378
379
			return 1
		fi
	done

	return 0
}

380
381
382
check_pkgrepos() {
	local pkgfile=$1

383
384
385
	local pkgname="$(getpkgname "${pkgfile}")" || return 1
	local pkgver="$(getpkgver "${pkgfile}")" || return 1
	local pkgarch="$(getpkgarch "${pkgfile}")" || return 1
386

387
388
	is_globfile "${FTP_BASE}/${PKGPOOL}/${pkgname}-${pkgver}-${pkgarch}"${PKGEXTS} && return 1
	is_globfile "${FTP_BASE}/${PKGPOOL}/${pkgname}-${pkgver}-${pkgarch}"${PKGEXTS}.sig && return 1
Eli Schwartz's avatar
Eli Schwartz committed
389
390
	[[ -f ${FTP_BASE}/${PKGPOOL}/${pkgfile##*/} ]] && return 1
	[[ -f ${FTP_BASE}/${PKGPOOL}/${pkgfile##*/}.sig ]] && return 1
391
392
393
394

	return 0
}

395
396
397
check_stagingrepos() {
	local pkgfile=${1}
	local pkgrepo=${2}
398
	local pkgbase=$(getpkgbase "${pkgfile}")
399
400
401
402
403
	local pkgname=$(getpkgname "${pkgfile}")
	local pkgarch=$(getpkgarch "${pkgfile}")
	local candidate candidates=()

	if in_array "${pkgrepo}" "${STABLE_REPOS[@]}"; then
404
		candidates+=($(find_repo_for_package "${pkgbase}" "${pkgarch}" "${TESTING_REPOS[@]}"))
405
406
	fi
	if in_array "${pkgrepo}" "${STABLE_REPOS[@]}" "${TESTING_REPOS[@]}"; then
407
		candidates+=($(find_repo_for_package "${pkgbase}" "${pkgarch}" "${STAGING_REPOS[@]}"))
408
409
410
411
412
413
414
415
416
417
418
419
420
	fi
	(( ${#candidates[@]} == 0 )) && return 0

	printf '%s\n' "${candidates[@]%-*}"
	for candidate in "${candidates[@]}"; do
		for candidate in "${STAGING}/${candidate%-*}"/*${PKGEXTS}; do
			[[ ${pkgname} = $(getpkgname "${candidate}" 2>/dev/null) ]] && return 0
		done
	done

	return 1
}

421
422
#usage: chk_license ${license[@]}"
chk_license() {
Pierre Schmitz's avatar
Pierre Schmitz committed
423
	local l
424
	for l in "${@}"; do
425
		in_array "${l}" "${ALLOWED_LICENSES[@]}" && return 0
Pierre Schmitz's avatar
Pierre Schmitz committed
426
427
428
	done

	return 1
429
430
}

431
432
433
434
435
436
437
438
439
check_repo_configured() {
	local repo=$1

	local count=$(printf '%s\n' "${PKGREPOS[@]}" | grep --count --line-regexp "$repo")
	[[ $count -gt 0 ]] && return 0

	return 1
}

440
441
442
check_repo_permission() {
	local repo=$1

Eli Schwartz's avatar
Eli Schwartz committed
443
444
	(( ${#PKGREPOS[@]} == 0 )) && return 1
	[[ -z "${PKGPOOL}" ]] && return 1
445

446
	in_array "${repo}" "${PKGREPOS[@]}" "${DEBUGREPOS[@]}" || return 1
447

Eli Schwartz's avatar
Eli Schwartz committed
448
	[[ -w $FTP_BASE/${PKGPOOL} ]] || return 1
449
450

	local arch
451
	for arch in "${ARCHES[@]}"; do
Pierre Schmitz's avatar
Pierre Schmitz committed
452
		local dir="${FTP_BASE}/${repo}/os/${arch}/"
Eli Schwartz's avatar
Eli Schwartz committed
453
454
455
		[[ -w ${dir} ]] || return 1
		[[ -f ${dir}${repo}${DBEXT} && ! -w ${dir}${repo}${DBEXT} ]] && return 1
		[[ -f ${dir}${repo}${FILESEXT} && ! -w ${dir}${repo}${FILESEXT} ]] && return 1
456
457
458
459
	done

	return 0
}
460
461

set_repo_permission() {
Eli Schwartz's avatar
Eli Schwartz committed
462
	local -; set -x
463
464
465
	local repo=$1
	local arch=$2
	local dbfile="${FTP_BASE}/${repo}/os/${arch}/${repo}${DBEXT}"
466
	local filesfile="${FTP_BASE}/${repo}/os/${arch}/${repo}${FILESEXT}"
467

Eli Schwartz's avatar
Eli Schwartz committed
468
	if [[ -w ${dbfile} ]]; then
469
		local group=$(/usr/bin/stat --printf='%G' "$(dirname "${dbfile}")")
Luke Shumaker's avatar
Luke Shumaker committed
470
471
472
		chgrp "$group" "${dbfile}"    || error "Could not change group of %s to %s" "$dbfile" "$group"
		chgrp "$group" "${filesfile}" || error "Could not change group of %s to %s" "$filesfile" "$group"
		chmod g+w "${dbfile}"    || error "Could not set write permission for group %s to %s" "$group" "$dbfile"
473
		chmod g+w "${filesfile}" || error "Could not set write permission for group %s to %s" "$group" "$filesfile"
474
	else
475
		error "You don't have permission to change %s" "$dbfile"
476
477
	fi
}
478

479
arch_repo_modify() {
Eli Schwartz's avatar
Eli Schwartz committed
480
	echo "call: arch_repo_modify ${@@Q}"
481
482
483
484
	local action=$1
	local repo=$2
	local arch=$3
	local pkgs=("${@:4}")
485
	local dbfile="${FTP_BASE}/${repo}/os/${arch}/${repo}${DBEXT}"
Eli Schwartz's avatar
Eli Schwartz committed
486
	tree "${FTP_BASE}"
487

488
	if [[ ${action} = remove && ! -f ${dbfile} ]]; then
489
		error "No database found at '%s'" "$dbfile"
490
491
		return 1
	fi
492
493
494

	# package files for repo-add might be relative to repo dir
	pushd "${dbfile%/*}" >/dev/null
Eli Schwartz's avatar
Eli Schwartz committed
495
	ls
496
	/usr/bin/"repo-${action}" -q "${dbfile}" "${pkgs[@]}" \
497
		|| error '%s' "repo-${action} ${dbfile@Q} ${pkgs[*]@Q}"
498
	set_repo_permission "${repo}" "${arch}"
499
	popd >/dev/null
Florian Pritz's avatar
Florian Pritz committed
500
501

	REPO_MODIFIED=1
502
}
503

504
505
506
507
508
509
510
511
512
# Verify the existence of dependent packages needed by a given pkgfile
# usage: check_reproducible pkgfile
check_reproducible() {
	local pkg dir pkgs=() pkgfile pkgfiles=()

	mapfile -t pkgs < <(_grep_all_info "${1}" .BUILDINFO installed)

	for pkg in "${pkgs[@]}"; do
		local pkgname=${pkg%-*-*-*}
513
		for dir in "${FTP_BASE}"/pool/* "${ARCHIVE_BASE}/packages/${pkgname:0:1}/${pkgname}" "${STAGING}"/**/; do
514
515
516
517
518
519
520
521
522
523
			if pkgfile="$(getpkgfile "${dir}/${pkg}"${PKGEXTS} 2>/dev/null)"; then
				pkgfiles+=("${pkgfile}")
				continue 2
			fi
		done
		error "could not find existing or staged package for dependency %s" "${pkg}"
		return 1
	done
}

524
. "$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")/db-functions-${VCS}"