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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
#!/usr/bin/env bash
set -euE
# libremakepkg
# Copyright (C) 2010-2012 Nicolás Reynolds <fauno@parabola.nu>
# Copyright (C) 2010-2012 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com>
# Copyright (C) 2012 Michał Masłowski <mtjm@mtjm.eu>
# Copyright (C) 2012-2014 Luke Shumaker <lukeshu@sbcglobal.net>
#
# License: GNU GPLv2+
#
# This file is part of Parabola.
#
# Parabola 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.
#
# Parabola 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.
#
# You should have received a copy of the GNU General Public License
# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
. "$(librelib conf)"
. "$(librelib messages)"
. "$(librelib chroot/makechrootpkg.sh)"
set -o pipefail
shopt -s nullglob
umask 0022
# Global variables:
readonly _indent="$(librelib chroot/indent)"
readonly INCHROOT=$([[ -f /.arch-chroot ]] && echo true || echo false)
NONET=true # can be changed with the -N flag
# {PKG,SRC,SRCPKG,LOG}DEST set at runtime by makepkg.conf
# MAKEFLAGS, PACKAGER set at runtime by makepkg.conf
# LIBREUSER, LIBREHOME are set by conf.sh
librechroot_flags=()
# Hooks ########################################################################
hook_pre_build=(:)
hook_post_build=(:)
hook_check_pkgbuild=(:)
hook_check_pkg=(:)
. "$(librelib chroot/hooks-chcleanup.sh)"
. "$(librelib chroot/hooks-check.sh)"
. "$(librelib chroot/hooks-distcc.sh)"
# Boring/mundane functions #####################################################
indent() {
"$_indent" ' | '
}
# Usage: _check_perms_dir $directory
# Make sure that $directory is readable and executable (searchable) by 'nobody'
check_directory_permissions() (
local dir=$1
# `cd` to the directory, then test `.`; that way if parent
# directories aren't readable, we aren't testing for that. We
# only need the last element in `$dir`.
cd "$dir"
if ! sudo -u nobody test -r . -a -x .; then
error "Directory '%s' must be readable by user 'nobody'" "$dir"
return 1
fi
return 0
)
# Usage: exit_copy $copydir $src_owner
# End immediately, but copy log files out
exit_copy() {
local copydir=$1
local src_owner=$2
if ! $INCHROOT; then
msg "Copying log and package files out of the chroot..."
move_products "$copydir" "$src_owner"
fi
}
# Usage; run_hook $hookname $args...
run_hook() {
local hookname=$1; shift
local hookvar="hook_${hookname}[@]"
local fails=()
for hook in "${!hookvar}"; do
"$hook" "$@" || fails+=("$hook")
done |& indent
if [[ ${#fails[@]} -gt 0 ]]; then
error "Failure(s) in %s: %s" "$hookname" "${fails[*]}"
return 1
else
return 0
fi
}
# Usage: add_to_local_repo $copydir $pkgfiles...
add_to_local_repo() {
local copydir=$1; shift
mkdir -p "$copydir/repo"
local pkgfile
for pkgfile in "$@"; do
cp "$pkgfile" "$copydir/repo"
pushd "$copydir/repo" >/dev/null
repo-add repo.db.tar.gz "${pkgfile##*/}"
popd >/dev/null
done
}
hook_post_build+=('cleanup')
cleanup() {
local copydir=$1
rm -f -- "$copydir"/chroot{prepare,build}
}
build() (
local copydir=$1; shift
local repack=$1; shift
local run_ynet=()
local run_nnet=()
if $INCHROOT; then
run_ynet=(unshare)
run_nnet=(unshare -n)
else
run_ynet=(librechroot "${librechroot_flags[@]}" run)
run_nnet=(librechroot "${librechroot_flags[@]}" -N run)
fi
$NONET || run_nnet=("${run_ynet[@]}")
prepare_chroot "$copydir" "$LIBREHOME" "$repack" false
"${run_ynet[@]}" /chrootprepare false "$@" |& indent
run_hook pre_build "$copydir"
trap "run_hook post_build '$copydir'" EXIT
"${run_nnet[@]}" /chrootbuild false "$@" |& indent
)
# The main program #############################################################
usage() {
print "Usage: %s [options] [-- makepkg args]" "${0##*/}"
print 'This program will build your package.'
echo
prose 'If run from outside of a chroot, command will make the following
configuration changes in the chroot:'
bullet 'whatever changes `librechroot` makes.'
bullet 'set `{PKG,SRC,SRCPKG,LOG}DEST` in `/etc/makepkg.conf`'
bullet 'set `PACKAGER` in `/etc/makepkg.conf` to reflect the value
outside of the chroot.'
bullet '(maybe) delete `/build/.makepkg.conf`'
bullet '(maybe) delete `/build/.ssh/config`'
prose 'If run from inside of a chroot, this command will:'
bullet '(maybe) delete `~/.makepkg.conf`'
bullet '(maybe) delete `~/.ssh/config`'
prose 'The above "maybe"s happen as part of the workarounds to make
distcc work in a network-less environment. They will happen if
both `socat` and `distcc` are installed in the chroot.'
echo
prose 'The `-n` and `-l` options behave identically to librechroot, see
the documentation there.'
echo
print 'Options:'
print ' %s options:' librechroot
flag "-n <$(_ CHROOT)>" 'Name of the chroot to use'
flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use'
flag "-w <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read/write'
flag "-r <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read-only'
print ' %s options:' libremakepkg
flag '-N' "Don't disable networking during build() and
package(). PLEASE don't use this unless you
have a special reason, its use is a violation
of Parabola policy."
flag '-R' 'Repackage contents of the package without rebuilding'
flag '-h' 'Show this message'
}
# Convenience method for use in option parsing
err_chflag() {
local flag=$1
error 'The -%s flag does not make sense inside of a chroot' "$flag"
return 1
}
main() {
# Initial variable values ##############################################
local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER")
local makepkg_args=(-s --noconfirm -L)
local repack=false
local chroot=''
# Parse command line options ###########################################
while getopts 'n:l:w:r:NRh' flag ; do
case "${flag}" in
n) if $INCHROOT; then err_chflag "$flag"; else
chroot=$OPTARG; fi;;
l) if $INCHROOT; then err_chflag "$flag"; else
copy=$OPTARG; fi;;
w|r) if $INCHROOT; then err_chflag "$flag"; else
librechroot_flags+=(-$flag "$OPTARG"); fi;;
N) NONET=false;;
R) repack=true; makepkg_args+=(-R);;
h) usage; return 0;;
*) usage >&2; return 1;;
esac
done
shift $(($OPTIND - 1))
# Pass all arguments after -- right to makepkg
makepkg_args+=("$@")
# Resolve the chroot path ##############################################
local copydir
if $INCHROOT; then
copydir='/'
else
load_files chroot
check_vars chroot CHROOTDIR CHROOT
[[ -z ${chroot} ]] || CHROOT=$chroot
if [[ ${copy:0:1} = / ]]; then
copydir=$copy
else
copydir="${CHROOTDIR}/${CHROOT}/${copy}"
fi
unset CHROOTDIR CHROOTEXTRAPKG
fi
unset chroot
# Load makepkg configuration ###########################################
# Note that all of these are globals
PKGDEST="$(get_var makepkg PKGDEST "$PWD")"
SRCDEST="$(get_var makepkg SRCDEST "$PWD")"
SRCPKGDEST="$(get_var makepkg SRCPKGDEST "$PWD")"
LOGDEST="$(get_var makepkg LOGDEST "$PWD")"
MAKEFLAGS="$(get_var makepkg MAKEFLAGS '')"
PACKAGER="$(get_var makepkg PACKAGER '')"
# Quick sanity check ###################################################
if (( EUID )); then
error "This program must be run as root"
exit 1
fi
if [[ ! -f PKGBUILD ]]; then
# This is the message used by makepkg
error "PKGBUILD does not exist."
exit 1
fi
# Make sure that the various *DEST directories exist
mkdir -p -- "$PKGDEST" "$SRCDEST" "$SRCPKGDEST" "$LOGDEST"
# Check the permissions for $startdir and $SRCDEST
(
declare -i ret=0
check_directory_permissions "$PWD" || ret=1
if ! [[ "$PWD" -ef "$SRCDEST" ]]; then
check_directory_permissions "$SRCDEST" || ret=1
fi
exit $ret
)
# OK, we are starting now ##############################################
if $INCHROOT; then
lock 9 "/build/.lock" \
"Waiting for existing lock on build directory to be released"
else
librechroot_flags+=(
-r "$PWD:/startdir_host"
-r "$SRCDEST:/srcdest_host"
-n "$CHROOT"
-l "$copy"
)
# Obtain a lock on the chroot
lock 9 "$copydir.lock" \
"Waiting for existing lock on chroot copy to be released: [%s]" "$copy"
# Create the chroot if it does not exist
msg 'Initializing the chroot...'
librechroot "${librechroot_flags[@]}" make |& indent
fi
# Set target CARCH
# note that we waited until after locking/creating the chroot to do this
export CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)"
# Pre-build
msg 'Starting pre-build activities...'
run_hook check_pkgbuild
msg 'Downloading sources...'
download_sources "$copydir" "$LIBREUSER" |& indent
# Build
msg 'Starting to build the package...'
trap "exit_copy '$copydir' '$LIBREUSER'" EXIT
build "$copydir" "$repack" "${makepkg_args[@]}"
# Post-build
msg 'Starting post-build activities...'
run_hook check_pkg
add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* |& indent
}
main "$@"
|