makepkg.sh.in 40.4 KB
Newer Older
1
#!/bin/bash
2
#
Francois Charette's avatar
Francois Charette committed
3
#   makepkg - make packages compatible for use with pacman
4
#
Allan McRae's avatar
Allan McRae committed
5
#   Copyright (c) 2006-2019 Pacman Development Team <pacman-dev@archlinux.org>
6
#   Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7
#   Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
Aaron Griffin's avatar
Aaron Griffin committed
8
#   Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
9
10
11
#   Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
#   Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk>
#   Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org>
12
#
Judd Vinet's avatar
Judd Vinet committed
13
14
15
16
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
17
#
Judd Vinet's avatar
Judd Vinet committed
18
19
20
21
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
22
#
Judd Vinet's avatar
Judd Vinet committed
23
#   You should have received a copy of the GNU General Public License
24
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
Judd Vinet's avatar
Judd Vinet committed
25
26
#

27
28
# makepkg uses quite a few external programs during its execution. You
# need to have at least the following installed for makepkg to function:
29
#   awk, bsdtar (libarchive), bzip2, coreutils, fakeroot, file, find (findutils),
30
#   gettext, gpg, grep, gzip, sed, tput (ncurses), xz
31

Giovanni Scafora's avatar
Giovanni Scafora committed
32
# gettext initialization
33
export TEXTDOMAIN='pacman-scripts'
34
export TEXTDOMAINDIR='@localedir@'
Giovanni Scafora's avatar
Giovanni Scafora committed
35

36
37
# file -i does not work on Mac OSX unless legacy mode is set
export COMMAND_MODE='legacy'
38
39
# Ensure CDPATH doesn't screw with our cd calls
unset CDPATH
Andrew Gregory's avatar
Andrew Gregory committed
40
41
# Ensure GREP_OPTIONS doesn't screw with our grep calls
unset GREP_OPTIONS
42

Allan McRae's avatar
Allan McRae committed
43
declare -r makepkg_version='@PACKAGE_VERSION@'
44
45
declare -r confdir='@sysconfdir@'
declare -r BUILDSCRIPT='@BUILDSCRIPT@'
46
declare -r startdir="$(pwd -P)"
47

Allan McRae's avatar
Allan McRae committed
48
49
LIBRARY=${LIBRARY:-'@libmakepkgdir@'}

50
# Options
51
ASDEPS=0
52
BUILDFUNC=0
53
BUILDPKG=1
54
55
CHECKFUNC=0
CLEANBUILD=0
56
57
58
CLEANUP=0
DEP_BIN=0
FORCE=0
59
GENINTEG=0
60
HOLDVER=0
61
62
IGNOREARCH=0
INFAKEROOT=0
63
INSTALL=0
64
65
LOGGING=0
NEEDED=0
66
NOARCHIVE=0
67
68
69
NOBUILD=0
NODEPS=0
NOEXTRACT=0
70
PKGFUNC=0
71
72
73
PKGVERFUNC=0
PREPAREFUNC=0
REPKG=0
74
REPRODUCIBLE=0
75
76
77
RMDEPS=0
SKIPCHECKSUMS=0
SKIPPGPCHECK=0
78
SIGNPKG=''
79
80
81
SPLITPKG=0
SOURCEONLY=0
VERIFYSOURCE=0
82

83
84
85
86
87
88
if [[ -n $SOURCE_DATE_EPOCH ]]; then
	REPRODUCIBLE=1
else
	SOURCE_DATE_EPOCH=$(date +%s)
fi
export SOURCE_DATE_EPOCH
89

Xyne's avatar
Xyne committed
90
PACMAN_OPTS=()
Aurelien Foret's avatar
Aurelien Foret committed
91

92
93
shopt -s extglob

Judd Vinet's avatar
Judd Vinet committed
94
95
### SUBROUTINES ###

96
97
98
99
# Import libmakepkg
for lib in "$LIBRARY"/*.sh; do
	source "$lib"
done
100
101
102
103
104
105

##
# Special exit call for traps, Don't print any error messages when inside,
# the fakeroot call, the error message will be printed by the main call.
##
trap_exit() {
106
107
	local signal=$1; shift

108
	if (( ! INFAKEROOT )); then
109
110
111
		echo
		error "$@"
	fi
112
	[[ -n $srclinks ]] && rm -rf "$srclinks"
113
114
115
116

	# unset the trap for this signal, and then call the default handler
	trap -- "$signal"
	kill "-$signal" "$$"
117
118
119
120
121
122
123
124
125
}


##
# Clean up function. Called automatically when the script exits.
##
clean_up() {
	local EXIT_CODE=$?

126
	if (( INFAKEROOT )); then
127
		# Don't clean up when leaving fakeroot, we're not done yet.
128
		return 0
129
130
	fi

131
132
133
134
	if [[ -p $logpipe ]]; then
		rm "$logpipe"
	fi

135
	if (( (EXIT_CODE == E_OK || EXIT_CODE == E_INSTALL_FAILED) && BUILDPKG && CLEANUP )); then
Andres P's avatar
Andres P committed
136
137
		local pkg file

138
139
		# If it's a clean exit and -c/--clean has been passed...
		msg "$(gettext "Cleaning up...")"
140
		rm -rf "$pkgdirbase" "$srcdir"
141
		if [[ -n $pkgbase ]]; then
142
			local fullver=$(get_full_version)
143
			# Can't do this unless the BUILDSCRIPT has been sourced.
144
145
146
147
148
149
			if (( PKGVERFUNC )); then
				rm -f "${pkgbase}-${fullver}-${CARCH}-pkgver.log"*
			fi
			if (( PREPAREFUNC )); then
				rm -f "${pkgbase}-${fullver}-${CARCH}-prepare.log"*
			fi
150
			if (( BUILDFUNC )); then
151
				rm -f "${pkgbase}-${fullver}-${CARCH}-build.log"*
152
			fi
153
			if (( CHECKFUNC )); then
154
				rm -f "${pkgbase}-${fullver}-${CARCH}-check.log"*
155
			fi
156
			if (( PKGFUNC )); then
157
				rm -f "${pkgbase}-${fullver}-${CARCH}-package.log"*
158
			elif (( SPLITPKG )); then
159
				for pkg in ${pkgname[@]}; do
160
					rm -f "${pkgbase}-${fullver}-${CARCH}-package_${pkg}.log"*
161
162
				done
			fi
163
164
165

			# clean up dangling symlinks to packages
			for pkg in ${pkgname[@]}; do
166
				for file in ${pkg}-*-*-*{${PKGEXT},${SRCEXT}}; do
167
					if [[ -h $file && ! -e $file ]]; then
168
						rm -f "$file"
169
170
171
					fi
				done
			done
172
173
174
		fi
	fi

175
176
177
178
179
	if ! remove_deps && (( EXIT_CODE == E_OK )); then
	    exit $E_REMOVE_DEPS_FAILED
	else
	    exit $EXIT_CODE
	fi
180
181
}

182
enter_fakeroot() {
183
	msg "$(gettext "Entering %s environment...")" "fakeroot"
184
	fakeroot -- bash -$- "${BASH_SOURCE[0]}" -F "${ARGLIST[@]}" || exit $?
185
186
}

187
188
189
# Automatically update pkgver variable if a pkgver() function is provided
# Re-sources the PKGBUILD afterwards to allow for other variables that use $pkgver
update_pkgver() {
190
	msg "$(gettext "Starting %s()...")" "pkgver"
191
	newpkgver=$(run_function_safe pkgver)
192
193
194
	if (( $? != 0 )); then
		error_function pkgver
	fi
195
	if ! check_pkgver "$newpkgver"; then
196
		error "$(gettext "pkgver() generated an invalid version: %s")" "$newpkgver"
Ivy Foster's avatar
Ivy Foster committed
197
		exit $E_PKGBUILD_ERROR
198
	fi
199
200

	if [[ -n $newpkgver && $newpkgver != "$pkgver" ]]; then
201
202
203
204
205
		if [[ -w $BUILDFILE ]]; then
			mapfile -t buildfile < "$BUILDFILE"
			buildfile=("${buildfile[@]/#pkgver=*([^ ])/pkgver=$newpkgver}")
			buildfile=("${buildfile[@]/#pkgrel=*([^ ])/pkgrel=1}")
			if ! printf '%s\n' "${buildfile[@]}" > "$BUILDFILE"; then
206
207
				error "$(gettext "Failed to update %s from %s to %s")" \
						"pkgver" "$pkgver" "$newpkgver"
Ivy Foster's avatar
Ivy Foster committed
208
				exit $E_PKGBUILD_ERROR
209
			fi
210
			source_safe "$BUILDFILE"
211
212
			local fullver=$(get_full_version)
			msg "$(gettext "Updated version: %s")" "$pkgbase $fullver"
213
214
215
216
217
218
219
		else
			warning "$(gettext "%s is not writeable -- pkgver will not be updated")" \
					"$BUILDFILE"
		fi
	fi
}

220
221
222
223
# Print 'source not found' error message and exit makepkg
missing_source_file() {
	error "$(gettext "Unable to find source file %s.")" "$(get_filename "$1")"
	plain "$(gettext "Aborting...")"
Ivy Foster's avatar
Ivy Foster committed
224
	exit $E_MISSING_FILE
225
226
}

227
run_pacman() {
228
	local cmd
229
	if [[ $1 = -@(T|Q)*([[:alpha:]]) ]]; then
230
		cmd=("$PACMAN_PATH" "$@")
231
232
	else
		cmd=("$PACMAN_PATH" "${PACMAN_OPTS[@]}" "$@")
233
		if type -p sudo >/dev/null; then
234
			cmd=(sudo "${cmd[@]}")
235
		else
236
			cmd=(su root -c "$(printf '%q ' "${cmd[@]}")")
237
		fi
238
239
240
241
242
243
244
245
246
		local lockfile="$(pacman-conf DBPath)/db.lck"
		while [[ -f $lockfile ]]; do
			local timer=0
			msg "$(gettext "Pacman is currently in use, please wait...")"
			while [[ -f $lockfile ]] && (( timer < 10 )); do
				(( ++timer ))
				sleep 3
			done
		done
247
	fi
248
	"${cmd[@]}"
249
250
}

251
check_deps() {
252
	(( $# > 0 )) || return 0
Judd Vinet's avatar
Judd Vinet committed
253

254
	local ret=0
Andres P's avatar
Andres P committed
255
	local pmout
256
257
	pmout=$(run_pacman -T "$@")
	ret=$?
258

259
	if (( ret == 127 )); then #unresolved deps
260
		printf "%s\n" "$pmout"
261
	elif (( ret )); then
262
		error "$(gettext "'%s' returned a fatal error (%i): %s")" "$PACMAN" "$ret" "$pmout"
263
		return "$ret"
Judd Vinet's avatar
Judd Vinet committed
264
265
266
	fi
}

267
handle_deps() {
268
269
270
	local R_DEPS_SATISFIED=0
	local R_DEPS_MISSING=1

271
	(( $# == 0 )) && return $R_DEPS_SATISFIED
Judd Vinet's avatar
Judd Vinet committed
272

273
	local deplist=("$@")
274

275
	if (( ! DEP_BIN )); then
276
277
278
		return $R_DEPS_MISSING
	fi

279
	if (( DEP_BIN )); then
280
281
282
		# install missing deps from binary packages (using pacman -S)
		msg "$(gettext "Installing missing dependencies...")"

283
		if ! run_pacman -S --asdeps "${deplist[@]}"; then
284
			error "$(gettext "'%s' failed to install missing dependencies.")" "$PACMAN"
285
			return $R_DEPS_MISSING
286
		fi
Judd Vinet's avatar
Judd Vinet committed
287
	fi
288

Xavier Chantry's avatar
Xavier Chantry committed
289
	# we might need the new system environment
290
	# save our shell options and turn off extglob
291
	local shellopts=$(shopt -p extglob)
292
	shopt -u extglob
Xavier Chantry's avatar
Xavier Chantry committed
293
	source /etc/profile &>/dev/null
294
	eval "$shellopts"
295

296
297
298
299
	# umask might have been changed in /etc/profile
	# ensure that sane default is set again
	umask 0022

300
	return $R_DEPS_SATISFIED
Judd Vinet's avatar
Judd Vinet committed
301
302
}

303
resolve_deps() {
304
	local R_DEPS_SATISFIED=0
Andrew Fyfe's avatar
Andrew Fyfe committed
305
	local R_DEPS_MISSING=1
306

307
308
309
	# deplist cannot be declared like this: local deplist=$(foo)
	# Otherwise, the return value will depend on the assignment.
	local deplist
Ivy Foster's avatar
Ivy Foster committed
310
	deplist=($(check_deps "$@")) || exit $E_INSTALL_DEPS_FAILED
311
	[[ -z $deplist ]] && return $R_DEPS_SATISFIED
312

313
	if handle_deps "${deplist[@]}"; then
314
		# check deps again to make sure they were resolved
315
		deplist=$(check_deps "$@")
316
		[[ -z $deplist ]] && return $R_DEPS_SATISFIED
317
318
	fi

Jason St. John's avatar
Jason St. John committed
319
	msg "$(gettext "Missing dependencies:")"
320
	local dep
321
	for dep in ${deplist[@]}; do
322
323
324
325
		msg2 "$dep"
	done

	return $R_DEPS_MISSING
326
327
}

328
remove_deps() {
329
	(( ! RMDEPS )) && return 0
330

331
332
	# check for packages removed during dependency install (e.g. due to conflicts)
	# removing all installed packages is risky in this case
333
	if [[ -n $(grep -xvFf <(printf '%s\n' "${current_pkglist[@]}") \
334
			<(printf '%s\n' "${original_pkglist[@]}")) ]]; then
335
		warning "$(gettext "Failed to remove installed dependencies.")"
Ivy Foster's avatar
Ivy Foster committed
336
		return $E_REMOVE_DEPS_FAILED
337
	fi
338

339
	local deplist
340
	deplist=($(grep -xvFf <(printf "%s\n" "${original_pkglist[@]}") \
341
			<(printf "%s\n" "${current_pkglist[@]}")))
342
	if [[ -z $deplist ]]; then
343
		return 0
344
	fi
345

346
	msg "Removing installed dependencies..."
347
	# exit cleanly on failure to remove deps as package has been built successfully
348
	if ! run_pacman -Rnu ${deplist[@]}; then
349
		warning "$(gettext "Failed to remove installed dependencies.")"
Ivy Foster's avatar
Ivy Foster committed
350
		return $E_REMOVE_DEPS_FAILED
351
352
353
	fi
}

354
error_function() {
355
	# first exit all subshells, then print the error
356
	if (( ! BASH_SUBSHELL )); then
357
		error "$(gettext "A failure occurred in %s().")" "$1"
358
		plain "$(gettext "Aborting...")"
359
	fi
Ivy Foster's avatar
Ivy Foster committed
360
	exit $E_USER_FUNCTION_FAILED
361
362
}

363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
merge_arch_attrs() {
	local attr supported_attrs=(
		provides conflicts depends replaces optdepends
		makedepends checkdepends)

	for attr in "${supported_attrs[@]}"; do
		eval "$attr+=(\"\${${attr}_$CARCH[@]}\")"
	done

	# ensure that calling this function is idempotent.
	unset -v "${supported_attrs[@]/%/_$CARCH}"
}

source_buildfile() {
	source_safe "$@"
}

380
run_function_safe() {
381
	local restoretrap restoreshopt
382

383
384
385
386
	# we don't set any special shopts of our own, but we don't want the user to
	# muck with our environment.
	restoreshopt=$(shopt -p)

387
388
	# localize 'set' shell options to this function - this does not work for shopt
	local -
389
	shopt -o -s errexit errtrace
390
391

	restoretrap=$(trap -p ERR)
392
	trap "error_function '$1'" ERR
393
394
395

	run_function "$1"

396
	trap - ERR
397
398
	eval "$restoretrap"
	eval "$restoreshopt"
399
400
}

401
run_function() {
402
	if [[ -z $1 ]]; then
403
		return 1
404
	fi
Andres P's avatar
Andres P committed
405
	local pkgfunc="$1"
406

407
408
409
	if (( ! BASH_SUBSHELL )); then
		msg "$(gettext "Starting %s()...")" "$pkgfunc"
	fi
410
	cd_safe "$srcdir"
411
412

	local ret=0
413
	if (( LOGGING )); then
414
		local fullver=$(get_full_version)
William Giokas's avatar
William Giokas committed
415
		local BUILDLOG="$LOGDEST/${pkgbase}-${fullver}-${CARCH}-$pkgfunc.log"
416
		if [[ -f $BUILDLOG ]]; then
417
418
			local i=1
			while true; do
419
				if [[ -f $BUILDLOG.$i ]]; then
420
421
422
423
424
425
426
427
					i=$(($i +1))
				else
					break
				fi
			done
			mv "$BUILDLOG" "$BUILDLOG.$i"
		fi

Francois Charette's avatar
Francois Charette committed
428
		# ensure overridden package variables survive tee with split packages
Allan McRae's avatar
Allan McRae committed
429
		logpipe=$(mktemp -u "$LOGDEST/logpipe.XXXXXXXX")
430
		mkfifo "$logpipe"
431
		tee "$BUILDLOG" < "$logpipe" &
432
433
434
435
		local teepid=$!

		$pkgfunc &>"$logpipe"

436
		wait -f $teepid
437
		rm "$logpipe"
438
	else
439
		"$pkgfunc"
440
	fi
441
442
}

443
444
445
446
run_prepare() {
	run_function_safe "prepare"
}

447
run_build() {
448
	run_function_safe "build"
449
450
}

451
run_check() {
452
	run_function_safe "check"
453
454
}

455
run_package() {
456
	run_function_safe "package${1:+_$1}"
457
458
}

459
find_libdepends() {
460
	local d sodepends
Allan McRae's avatar
Allan McRae committed
461

462
	sodepends=0
Allan McRae's avatar
Allan McRae committed
463
464
	for d in "${depends[@]}"; do
		if [[ $d = *.so ]]; then
465
466
			sodepends=1
			break
Allan McRae's avatar
Allan McRae committed
467
468
469
470
		fi
	done

	if (( sodepends == 0 )); then
471
		(( ${#depends[@]} )) && printf '%s\n' "${depends[@]}"
472
		return 0
Allan McRae's avatar
Allan McRae committed
473
474
	fi

475
476
	local libdeps filename soarch sofile soname soversion
	declare -A libdeps
Allan McRae's avatar
Allan McRae committed
477

478
	while IFS= read -rd '' filename; do
479
480
		# get architecture of the file; if soarch is empty it's not an ELF binary
		soarch=$(LC_ALL=C readelf -h "$filename" 2>/dev/null | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p')
Allan McRae's avatar
Allan McRae committed
481
482
		[[ -n "$soarch" ]] || continue

483
484
485
486
		# process all libraries needed by the binary
		for sofile in $(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -nr 's/.*Shared library: \[(.*)\].*/\1/p')
		do
			# extract the library name: libfoo.so
487
			soname="${sofile%.so?(+(.+([0-9])))}".so
488
489
			# extract the major version: 1
			soversion="${sofile##*\.so\.}"
Allan McRae's avatar
Allan McRae committed
490
491
492
493

			if [[ ${libdeps[$soname]} ]]; then
				if [[ ${libdeps[$soname]} != *${soversion}-${soarch}* ]]; then
					libdeps[$soname]+=" ${soversion}-${soarch}"
494
				fi
Allan McRae's avatar
Allan McRae committed
495
496
			else
				libdeps[$soname]="${soversion}-${soarch}"
497
498
			fi
		done
499
	done < <(find "$pkgdir" -type f -perm -u+x -print0)
Allan McRae's avatar
Allan McRae committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

	local libdepends v
	for d in "${depends[@]}"; do
		case "$d" in
			*.so)
				if [[ ${libdeps[$d]} ]]; then
					for v in ${libdeps[$d]}; do
						libdepends+=("$d=$v")
					done
				else
					warning "$(gettext "Library listed in %s is not required by any files: %s")" "'depends'" "$d"
					libdepends+=("$d")
				fi
				;;
			*)
				libdepends+=("$d")
				;;
		esac
518
	done
Allan McRae's avatar
Allan McRae committed
519

520
	(( ${#libdepends[@]} )) && printf '%s\n' "${libdepends[@]}"
521
522
}

Allan McRae's avatar
Allan McRae committed
523

524
find_libprovides() {
Allan McRae's avatar
Allan McRae committed
525
	local p libprovides missing
526
	for p in "${provides[@]}"; do
Allan McRae's avatar
Allan McRae committed
527
528
529
		missing=0
		case "$p" in
			*.so)
530
				mapfile -t filename < <(find "$pkgdir" -type f -name $p\*)
Allan McRae's avatar
Allan McRae committed
531
532
				if [[ $filename ]]; then
					# packages may provide multiple versions of the same library
533
					for fn in "${filename[@]}"; do
Allan McRae's avatar
Allan McRae committed
534
535
536
537
538
539
						# check if we really have a shared object
						if LC_ALL=C readelf -h "$fn" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then
							# get the string binaries link to (e.g. libfoo.so.1.2 -> libfoo.so.1)
							local sofile=$(LC_ALL=C readelf -d "$fn" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p')
							if [[ -z "$sofile" ]]; then
								warning "$(gettext "Library listed in %s is not versioned: %s")" "'provides'" "$p"
540
								libprovides+=("$p")
Allan McRae's avatar
Allan McRae committed
541
542
543
544
545
546
547
548
549
								continue
							fi

							# get the library architecture (32 or 64 bit)
							local soarch=$(LC_ALL=C readelf -h "$fn" | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p')

							# extract the library major version
							local soversion="${sofile##*\.so\.}"

550
							libprovides+=("${p}=${soversion}-${soarch}")
Allan McRae's avatar
Allan McRae committed
551
552
						else
							warning "$(gettext "Library listed in %s is not a shared object: %s")" "'provides'" "$p"
553
							libprovides+=("$p")
Allan McRae's avatar
Allan McRae committed
554
555
556
						fi
					done
				else
557
					libprovides+=("$p")
Allan McRae's avatar
Allan McRae committed
558
					missing=1
559
				fi
Allan McRae's avatar
Allan McRae committed
560
561
				;;
			*)
562
				libprovides+=("$p")
Allan McRae's avatar
Allan McRae committed
563
564
565
566
				;;
		esac

		if (( missing )); then
Jason St. John's avatar
Jason St. John committed
567
			warning "$(gettext "Cannot find library listed in %s: %s")" "'provides'" "$p"
Allan McRae's avatar
Allan McRae committed
568
		fi
569
	done
Allan McRae's avatar
Allan McRae committed
570

571
	(( ${#libprovides[@]} )) && printf '%s\n' "${libprovides[@]}"
572
573
}

574
575
576
577
578
579
580
write_kv_pair() {
	local key="$1"
	shift

	for val in "$@"; do
		if [[ $val = *$'\n'* ]]; then
			error "$(gettext "Invalid value for %s: %s")" "$key" "$val"
Ivy Foster's avatar
Ivy Foster committed
581
			exit $E_PKGBUILD_ERROR
582
583
584
585
586
		fi
		printf "%s = %s\n" "$key" "$val"
	done
}

587
write_pkginfo() {
588
	local size=$(dirsize)
589

590
591
	merge_arch_attrs

592
	printf "# Generated by makepkg %s\n" "$makepkg_version"
Allan McRae's avatar
Allan McRae committed
593
	printf "# using %s\n" "$(fakeroot -v)"
594

595
	write_kv_pair "pkgname" "$pkgname"
Allan McRae's avatar
Allan McRae committed
596
	write_kv_pair "pkgbase" "$pkgbase"
597
598

	local fullver=$(get_full_version)
599
	write_kv_pair "pkgver" "$fullver"
600

601
602
603
604
605
	# TODO: all fields should have this treatment
	local spd="${pkgdesc//+([[:space:]])/ }"
	spd=("${spd[@]#[[:space:]]}")
	spd=("${spd[@]%[[:space:]]}")

606
607
	write_kv_pair "pkgdesc" "$spd"
	write_kv_pair "url" "$url"
608
	write_kv_pair "builddate" "$SOURCE_DATE_EPOCH"
609
	write_kv_pair "packager" "$PACKAGER"
610
611
	write_kv_pair "size" "$size"
	write_kv_pair "arch" "$pkgarch"
612

613
	mapfile -t provides < <(find_libprovides)
Allan McRae's avatar
Allan McRae committed
614
615
	mapfile -t depends < <(find_libdepends)

616
617
618
619
620
621
622
623
624
625
	write_kv_pair "license"     "${license[@]}"
	write_kv_pair "replaces"    "${replaces[@]}"
	write_kv_pair "group"       "${groups[@]}"
	write_kv_pair "conflict"    "${conflicts[@]}"
	write_kv_pair "provides"    "${provides[@]}"
	write_kv_pair "backup"      "${backup[@]}"
	write_kv_pair "depend"      "${depends[@]}"
	write_kv_pair "optdepend"   "${optdepends[@]//+([[:space:]])/ }"
	write_kv_pair "makedepend"  "${makedepends[@]}"
	write_kv_pair "checkdepend" "${checkdepends[@]}"
626
}
627

628
write_buildinfo() {
629
	write_kv_pair "format" "2"
630
631
632
633
634
635

	write_kv_pair "pkgname" "$pkgname"
	write_kv_pair "pkgbase" "$pkgbase"

	local fullver=$(get_full_version)
	write_kv_pair "pkgver" "$fullver"
636

Robin Broda's avatar
Robin Broda committed
637
638
	write_kv_pair "pkgarch" "$pkgarch"

639
640
	local sum="$(sha256sum "${BUILDFILE}")"
	sum=${sum%% *}
641
	write_kv_pair "pkgbuild_sha256sum" $sum
642

643
644
645
	write_kv_pair "packager" "${PACKAGER}"
	write_kv_pair "builddate" "${SOURCE_DATE_EPOCH}"
	write_kv_pair "builddir"  "${BUILDDIR}"
646
	write_kv_pair "startdir"  "${startdir}"
647
648
	write_kv_pair "buildenv" "${BUILDENV[@]}"
	write_kv_pair "options" "${OPTIONS[@]}"
649

650
651
652
	local pkginfos_parsed=($(LC_ALL=C run_pacman -Qi | awk -F': ' '\
		/^Name .*/ {printf "%s", $2} \
		/^Version .*/ {printf "-%s", $2} \
653
		/^Architecture .*/ {print "-"$2} \
654
		'))
655
656

	write_kv_pair "installed" "${pkginfos_parsed[@]}"
657
658
}

659
660
661
662
663
# build a sorted NUL-separated list of the full contents of the current
# directory suitable for passing to `bsdtar --files-from`
# database files are placed at the beginning of the package regardless of
# sorting
list_package_files() {
664
665
666
	(
		export LC_COLLATE=C
		shopt -s dotglob globstar
667
668
		# bash 5.0 only works with combo directory + file globs
		printf '%s\0' **/*
669
	)
670
671
}

672
create_package() {
673
	(( NOARCHIVE )) && return 0
674

675
	if [[ ! -d $pkgdir ]]; then
676
		error "$(gettext "Missing %s directory.")" "\$pkgdir/"
677
		plain "$(gettext "Aborting...")"
Ivy Foster's avatar
Ivy Foster committed
678
		exit $E_MISSING_PKGDIR
679
680
	fi

681
	cd_safe "$pkgdir"
682
	msg "$(gettext "Creating package \"%s\"...")" "$pkgname"
683

684
	pkgarch=$(get_pkg_arch)
685
	msg2 "$(gettext "Generating %s file...")" ".PKGINFO"
686
	write_pkginfo > .PKGINFO
687
	msg2 "$(gettext "Generating %s file...")" ".BUILDINFO"
688
	write_buildinfo > .BUILDINFO
689

690
	# check for changelog/install files
691
	for i in 'changelog/.CHANGELOG' 'install/.INSTALL'; do
692
		IFS='/' read -r orig dest < <(printf '%s\n' "$i")
693

694
695
		if [[ -n ${!orig} ]]; then
			msg2 "$(gettext "Adding %s file...")" "$orig"
696
697
			if ! cp "$startdir/${!orig}" "$dest"; then
				error "$(gettext "Failed to add %s file to package.")" "$orig"
Ivy Foster's avatar
Ivy Foster committed
698
				exit $E_MISSING_FILE
699
			fi
700
701
702
			chmod 644 "$dest"
		fi
	done
703
704

	# tar it up
705
	local fullver=$(get_full_version)
706
	local pkg_file="$PKGDEST/${pkgname}-${fullver}-${pkgarch}${PKGEXT}"
707
	local ret=0
708

709
710
711
	[[ -f $pkg_file ]] && rm -f "$pkg_file"
	[[ -f $pkg_file.sig ]] && rm -f "$pkg_file.sig"

712
713
714
	# ensure all elements of the package have the same mtime
	find . -exec touch -h -d @$SOURCE_DATE_EPOCH {} +

715
	msg2 "$(gettext "Generating .MTREE file...")"
716
	list_package_files | LANG=C bsdtar -cnf - --format=mtree \
717
		--options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \
718
719
		--null --files-from - --exclude .MTREE | gzip -c -f -n > .MTREE
	touch -d @$SOURCE_DATE_EPOCH .MTREE
720
721

	msg2 "$(gettext "Compressing package...")"
722
723
	# TODO: Maybe this can be set globally for robustness
	shopt -s -o pipefail
724
	list_package_files | LANG=C bsdtar --no-fflags -cnf - --null --files-from - |
725
		compress_as "$PKGEXT" > "${pkg_file}" || ret=$?
726

727
	shopt -u -o pipefail
728

729
	if (( ret )); then
730
		error "$(gettext "Failed to create package file.")"
Ivy Foster's avatar
Ivy Foster committed
731
		exit $E_PACKAGE_FAILED
732
	fi
733
734
}

735
736
737
create_debug_package() {
	# check if a debug package was requested
	if ! check_option "debug" "y" || ! check_option "strip" "y"; then
738
		return 0
739
740
	fi

741
	local pkgdir="$pkgdirbase/$pkgbase-@DEBUGSUFFIX@"
742
743
744

	# check if we have any debug symbols to package
	if dir_is_empty "$pkgdir/usr/lib/debug"; then
745
		return 0
746
747
	fi

748
749
750
751
752
753
754
755
	unset groups depends optdepends provides conflicts replaces backup install changelog

	local pkg
	for pkg in ${pkgname[@]}; do
		if [[ $pkg != $pkgbase ]]; then
			provides+=("$pkg-@DEBUGSUFFIX@")
		fi
	done
756

757
758
	pkgdesc="Detached debugging symbols for $pkgname"
	pkgname=$pkgbase-@DEBUGSUFFIX@
759
760
761
762

	create_package
}

763
create_srcpackage() {
764
	local ret=0
765
	msg "$(gettext "Creating source package...")"
Allan McRae's avatar
Allan McRae committed
766
	local srclinks="$(mktemp -d "$startdir"/srclinks.XXXXXXXXX)"
Allan McRae's avatar
Allan McRae committed
767
	mkdir "${srclinks}"/${pkgbase}
Allan McRae's avatar
Allan McRae committed
768

769
	msg2 "$(gettext "Adding %s...")" "$BUILDSCRIPT"
770
	ln -s "${BUILDFILE}" "${srclinks}/${pkgbase}/${BUILDSCRIPT}"
771

772
773
774
	msg2 "$(gettext "Generating %s file...")" .SRCINFO
	write_srcinfo > "$srclinks/$pkgbase"/.SRCINFO

775
776
777
778
	local file all_sources

	get_all_sources 'all_sources'
	for file in "${all_sources[@]}"; do
779
		if [[ "$file" = "$(get_filename "$file")" ]] || (( SOURCEONLY == 2 )); then
780
781
			local absfile
			absfile=$(get_filepath "$file") || missing_source_file "$file"
782
783
			msg2 "$(gettext "Adding %s...")" "${absfile##*/}"
			ln -s "$absfile" "$srclinks/$pkgbase"
784
785
786
		fi
	done

787
788
789
790
	# set pkgname the same way we do for running package(), this way we get
	# the right value in extract_function_variable
	local pkgname_backup=(${pkgname[@]})
	local i pkgname
791
	for i in 'changelog' 'install'; do
792
793
		local file files

794
		[[ ${!i} ]] && files+=("${!i}")
795
796
		for pkgname in "${pkgname_backup[@]}"; do
			if extract_function_variable "package_$pkgname" "$i" 0 file; then
797
798
799
800
801
				files+=("$file")
			fi
		done

		for file in "${files[@]}"; do
802
			if [[ $file && ! -f "${srclinks}/${pkgbase}/$file" ]]; then
Allan McRae's avatar
Allan McRae committed
803
				msg2 "$(gettext "Adding %s file (%s)...")" "$i" "${file}"
804
805
				ln -s "${startdir}/$file" "${srclinks}/${pkgbase}/"
			fi
806
		done
807
	done
808
	pkgname=(${pkgname_backup[@]})
809

810
	local fullver=$(get_full_version)
811
	local pkg_file="$SRCPKGDEST/${pkgbase}-${fullver}${SRCEXT}"
812
813
814

	# tar it up
	msg2 "$(gettext "Compressing source package...")"
815
	cd_safe "${srclinks}"
816
817
818

	# TODO: Maybe this can be set globally for robustness
	shopt -s -o pipefail
819
	LANG=C bsdtar --no-fflags -cLf - ${pkgbase} | compress_as "$SRCEXT" > "${pkg_file}" || ret=$?
820
821
822
823

	shopt -u -o pipefail

	if (( ret )); then
824
		error "$(gettext "Failed to create source package file.")"
Ivy Foster's avatar
Ivy Foster committed
825
		exit $E_PACKAGE_FAILED
826
	fi
827

828
	cd_safe "${startdir}"
829
	rm -rf "${srclinks}"
830
831
}

832
install_package() {