mkimage.sh 6.67 KB
Newer Older
1 2
#!/bin/sh

3 4
# apk add \
#	abuild apk-tools alpine-conf busybox fakeroot syslinux xorriso
5
#	(for efi:) mtools grub-efi
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

# FIXME: clean workdir out of unneeded sections
# FIXME: --release: cp/mv images to REPODIR/$ARCH/releases/
# FIXME: --update-latest: rewrite latest-releases.yaml with this build

set -e

# get abuild configurables
[ -e /usr/share/abuild/functions.sh ] || (echo "abuild not found" ; exit 1)
. /usr/share/abuild/functions.sh

# deduce aports directory
[ -n "$APORTS" ] || APORTS=$(realpath $(dirname $0)/../)
[ -e "$APORTS/main/build-base" ] || die "Unable to deduce aports base checkout"

# 
all_sections=""
all_profiles=""
all_checksums="sha256 sha512"
25
all_arches="aarch64 armhf x86 x86_64"
26 27 28 29 30 31 32
all_dirs=""
build_date="$(date +%y%m%d)"
default_arch="$(apk --print-arch)"
_hostkeys=""
_simulate=""
_checksum=""

33
scriptdir="$(dirname $0)"
34
OUTDIR="$PWD"
35 36
RELEASE="${build_date}"

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

msg() {
	if [ -n "$quiet" ]; then return 0; fi
	local prompt="$GREEN>>>${NORMAL}"
	local name="${BLUE}mkimage${ARCH+-$ARCH}${NORMAL}"
	printf "${prompt} ${name}: %s\n" "$1" >&2
}

list_has() {
	local needle="$1"
	local i
	shift
	for i in $@; do
		[ "$needle" != "$i" ] || return 0
	done
	return 1
}

usage() {
	cat <<EOF

$0	[--tag RELEASE] [--outdir OUTDIR] [--workdir WORKDIR]
		[--arch ARCH] [--profile PROFILE] [--hostkeys] [--simulate]
60
		[--repository REPO] [--extra-repository REPO] [--yaml FILE]
61 62 63
$0	--help

options:
64 65 66 67 68 69 70 71 72 73
--arch			Specify which architecture images to build
			(default: $default_arch)
--hostkeys		Copy system apk signing keys to created images
--outdir		Specify directory for the created images
--profile		Specify which profiles to build
--repository		Package repository to use for the image create
--extra-repository	Add repository to search packages from
--simulate		Don't execute commands
--tag			Build images for tag RELEASE
--workdir		Specify temporary working directory (cache)
74
--yaml
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

known profiles: $(echo $all_profiles | sort -u)

EOF
}

# helpers
load_plugins() {
	local f
	[ -e "$1" ] || return 0
	for f in "$1"/mkimg.*.sh; do
		[ -e "$f" ] || return 0
		break
	done
	all_profiles="$all_profiles $(sed -n -e 's/^profile_\(.*\)() {$/\1/p' $1/mkimg.*.sh)"
	all_sections="$all_sections $(sed -n -e 's/^section_\(.*\)() {$/\1/p' $1/mkimg.*.sh)"
	for f in "$1"/mkimg.*.sh; do
		. $f
	done
}

checksum() {
	sha1sum | cut -f 1 -d ' '
}

build_section() {
	local section="$1"
	local args="$@"
	local _dir="${args//[^a-zA-Z0-9]/_}"
	shift
	local args="$@"

	if [ -z "$_dir" ]; then
		_fail="yes"
		return 1
	fi

	if [ ! -e "$WORKDIR/${_dir}" ]; then
		DESTDIR="$WORKDIR/${_dir}.work"
		msg "--> $section $args"
		if [ -z "$_simulate" ]; then
			rm -rf "$DESTDIR"
			mkdir -p "$DESTDIR"
			if build_${section} "$@"; then
				mv "$DESTDIR" "$WORKDIR/${_dir}"
				_dirty="yes"
			else
				rm -rf "$DESTDIR"
				_fail="yes"
124
				return 1
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
			fi
		fi
	fi
	unset DESTDIR
	all_dirs="$all_dirs $_dir"
	_my_sections="$_my_sections $_dir"
}

build_profile() {
	local _id _dir _spec
	_my_sections=""
	_dirty="no"
	_fail="no"

	profile_$PROFILE
	list_has $ARCH $arch || return 0

	msg "Building $PROFILE"

	# Collect list of needed sections, and make sure they are built
	for SECTION in $all_sections; do
146
		section_$SECTION || return 1
147 148 149 150 151 152
	done
	[ "$_fail" = "no" ] || return 1

	# Defaults
	[ -n "$image_name" ] || image_name="alpine-${PROFILE}"
	[ -n "$output_filename" ] || output_filename="${image_name}-${RELEASE}-${ARCH}.${image_ext}"
153
	local output_file="${OUTDIR:-.}/$output_filename"
154 155 156 157

	# Construct final image
	local _imgid=$(echo -n $_my_sections | sort | checksum)
	DESTDIR=$WORKDIR/image-$_imgid-$ARCH-$PROFILE
158
	if [ "$_dirty" = "yes" -o ! -e "$DESTDIR" ]; then
159 160 161 162 163 164 165 166 167 168 169 170 171 172
		msg "Creating $output_filename"
		if [ -z "$_simulate" ]; then
			# Merge sections
			rm -rf "$DESTDIR"
			mkdir -p "$DESTDIR"
			for _dir in $_my_sections; do
				for _fn in $WORKDIR/$_dir/*; do
					[ ! -e "$_fn" ] || cp -Lrs $_fn $DESTDIR/
				done
			done
			echo "${image_name}-${RELEASE} ${build_date}" > "$DESTDIR"/.alpine-release
		fi
	fi

173
	if [ "$_dirty" = "yes" -o ! -e "$output_file" ]; then
174
		# Create image
175
		[ -n "$output_format" ] || output_format="${image_ext//[:\.]/}"
176
		create_image_${output_format} || { _fail="yes"; false; }
177 178 179

		if [ "$_checksum" = "yes" ]; then
			for _c in $all_checksums; do
180
				echo "$(${_c}sum "$output_file" | cut -d' '  -f1)  ${output_filename}" > "${output_file}.${_c}"
181 182
			done
		fi
183 184 185

		if [ -n "$_yaml_out" ]; then
			$mkimage_yaml --release $RELEASE \
186 187
				--title "$title" \
				--desc "$desc" \
188 189
				"$output_file" >> "$_yaml_out"
		fi
190 191 192 193
	fi
}

# load plugins
194
load_plugins "$scriptdir"
195 196
[ -z "$HOME" ] || load_plugins "$HOME/.mkimage"

197 198
mkimage_yaml="$(dirname $0)"/mkimage-yaml.sh

199 200 201 202 203
# parse parameters
while [ $# -gt 0 ]; do
	opt="$1"
	shift
	case "$opt" in
204 205 206 207 208 209 210
	--repository)
		if [ -z "$REPOS" ]; then
			REPOS="$1"
		else
			REPOS=$(printf '%s\n%s' "$REPOS" "$1");
		fi
		shift ;;
211
	--extra-repository) EXTRAREPOS="$EXTRAREPOS $1"; shift ;;
212 213 214 215 216 217 218 219
	--workdir) WORKDIR="$1"; shift ;;
	--outdir) OUTDIR="$1"; shift ;;
	--tag) RELEASE="$1"; shift ;;
	--arch) req_arch="$1"; shift ;;
	--profile) req_profiles="$1"; shift ;;
	--hostkeys) _hostkeys="--hostkeys";;
	--simulate) _simulate="yes";;
	--checksum) _checksum="yes";;
220
	--yaml) _yaml="yes";;
221 222 223 224 225
	--) break ;;
	-*) usage; exit 1;;
	esac
done

226 227 228 229 230 231 232 233 234
if [ -z "$RELEASE" ]; then
	if git describe --exact-match >/dev/null 2>&1; then
		RELEASE=$(git describe --always)
		RELEASE=${RELEASE#v}
	else
		RELEASE="${build_date}"
	fi
fi

235 236 237 238 239 240 241 242 243 244 245
# setup defaults
if [ -z "$WORKDIR" ]; then
	WORKDIR="$(mktemp -d -t mkimage.XXXXXX)"
	trap 'rm -rf $WORKDIR' INT
	mkdir -p "$WORKDIR"
fi
req_profiles=${req_profiles:-${all_profiles}}
req_arch=${req_arch:-${default_arch}}
[ "$req_arch" != "all" ] || req_arch="${all_arch}"
[ "$req_profiles" != "all" ] || req_profiles="${all_profiles}"

246 247
mkdir -p "$OUTDIR"

248 249 250 251 252 253 254 255
# get abuild pubkey used to sign the apkindex
# we need inject this to the initramfs or we will not be able to use the
# boot repository
if [ -z "$_hostkeys" ]; then
	_pub=${PACKAGER_PRIVKEY:+${PACKAGER_PRIVKEY}.pub}
	_abuild_pubkey="${PACKAGER_PUBKEY:-$_pub}"
fi

256 257 258 259 260 261 262 263 264
# create images
for ARCH in $req_arch; do
	APKROOT="$WORKDIR/apkroot-$ARCH"
	if [ ! -e "$APKROOT" ]; then
		# create root for caching packages
		mkdir -p "$APKROOT/etc/apk/cache"
		cp -Pr /etc/apk/keys "$APKROOT/etc/apk/"
		abuild-apk --arch "$ARCH" --root "$APKROOT" add --initdb

265
		if [ -z "$REPOS" ]; then
266 267
			warning "no repository set"
		fi
268
		echo "$REPOS" > "$APKROOT/etc/apk/repositories"
269 270 271
		for repo in $EXTRAREPOS; do
			echo "$repo" >> "$APKROOT/etc/apk/repositories"
		done
272 273 274
	fi
	abuild-apk update --root "$APKROOT"

275
	if [ "$_yaml" = "yes" ]; then
276
		_yaml_out=${OUTDIR:-.}/latest-releases.yaml
277 278
		echo "---" > "$_yaml_out"
	fi
279
	for PROFILE in $req_profiles; do
280
		(build_profile) || exit 1
281 282
	done
done
283
echo "Images generated in $OUTDIR"