summaryrefslogtreecommitdiff
path: root/image-package.write
blob: 15ceadcfdeb5dbf5833cb02f5a57512c251577fd (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
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
#!/bin/sh
# Copyright (C) 2014  Codethink Limited
#
# 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# =*= License: GPL-2 =*=
#
#
# This is a write extension for making a package that can be used to
# install the produced system. Ideally we'd instead have Baserock
# everywhere to do the deployment, but we need to support this workflow
# until that is possible.
#
# This write extension produces a tarball, which contains:
#    - a tarball of the configured system root file system
#    - any supporting files listed in BOOTLOADER_BLOBS
#    - any supporting scripts, generated from templates listed in
#      INCLUDE_SCRIPTS
#
# The extension requires the following environment variables to be set:
#
#   * BOOTLOADER_BLOBS: files to include besides rootfs tarball,
#                       paths are relative to the root of the built rootfs
#                       works on any kind of file in the rootfs, named
#                       BOOTLOADER_BLOBS since that's the common use-case
#                       :-separated by default
#   * INCLUDE_SCRIPTS:  script templates that are included in the package
#                       after being filled out
#                       file paths are relative to the definitions repository
#                       :-separated by default
#
# The script templates may contain any of the following strings, which
# will be replaced with a string which will expand to the appropriate
# value as a shell word:
#    - @@SCRIPT_DIR@@:      the path the script files are installed to
#    - @@IMAGE_DIR@@:       the path BOOTLOADER_BLOBS are installed to
#    - @@ROOTFS_TAR_PATH@@: path to the rootfs tarball
#
# The interpolated strings may run commands dependant on the current
# working directory, so if `cd` is required, bind these values to a
# variable beforehand.
#
# The following optional variables can be set as well:
#
#   * INCLUDE_SCRIPTS_SEPARATOR: character to separate INCLUDE_SCRIPTS with (default: :)
#   * BOOTLOADER_BLOBS_SEPARATOR: character to separate BOOTLOADER_BLOBS with (default: :)
#   * SCRIPT_SUBDIR: where in the package processed scripts are installed to (default: tools)
#   * IMAGE_SUBDIR:  where in the package BOOTLOADER_BLOBS are copied to (default: image_files)
#   * ROOTFS_TAR:    name to call the rootfs tarball inside IMAGE_SUBDIR (default: rootfs.tar)
#   * OUTPUT_COMPRESS: compression used for output tarball (default: none)
#   * ROOTFS_COMPRESS: compression used for rootfs (default: none)

set -eu

die(){
    echo "$@" >&2
    exit 1
}

warn(){
    echo "$@" >&2
}

info(){
    echo "$@" >&2
}

shellescape(){
    echo "'$(echo "$1" | sed -e "s/'/'\\''/g")'"
}

sedescape(){
    # Escape the passed in string so it can be safely interpolated into
    # a sed expression as a literal value.
    echo "$1" | sed -e 's/[\/&]/\\&/g'
}

ROOTDIR="$1"
OUTPUT_TAR="$2"
td="$(mktemp -d)"
IMAGE_SUBDIR="${IMAGE_SUBDIR-image_files}"
SCRIPT_SUBDIR="${SCRIPT_SUBDIR-tools}"
ROOTFS_TAR="${ROOTFS_TAR-rootfs.tar}"

# Generate shell snippets that will expand to paths to various resources
# needed by the scripts.
# They expand to a single shell word, so constructs like the following work
#     SCRIPT_DIR=@@SCRIPT_DIR@@
#     dd if="$SCRIPT_DIR/mbr" of="$disk" count=1
#     tar -C "$mountpoint" -xf @@ROOTFS_TAR_PATH@@ .
find_script_dir='"$(readlink -f "$(dirname "$0")")"'
image_dir="$find_script_dir/../$(shellescape "$IMAGE_SUBDIR")"
rootfs_tar_path="$image_dir/$(shellescape "$ROOTFS_TAR")"

install_script(){
    local source_file="$1"
    local output_dir="$2"
    local target_file="$output_dir/$SCRIPT_SUBDIR/$(basename "$source_file" .in)"
    sed -e "s/@@SCRIPT_DIR@@/$(sedescape "$find_script_dir")/g" \
        -e "s/@@IMAGE_DIR@@/$(sedescape "$image_dir")/g" \
        -e "s/@@ROOTFS_TAR_PATH@@/$(sedescape "$rootfs_tar_path")/g" \
        "$source_file" \
    |   install -D -m 755 /proc/self/fd/0 "$target_file"
}

install_scripts(){
    local output_dir="$1"
    (
        IFS="${INCLUDE_SCRIPTS_SEPARATOR-:}"
        for script in $INCLUDE_SCRIPTS; do
            local script_path="$(pwd)/$script"
            if [ ! -e "$script_path" ]; then
                warn Script "$script" not found, ignoring
                continue
            fi
            install_script "$script" "$output_dir"
        done
    )
}

install_bootloader_blobs(){
    local output_dir="$1"
    local image_dir="$output_dir/$IMAGE_SUBDIR"
    (
        IFS="${BOOTLOADER_BLOBS_SEPARATOR-:}"
        for blob in $BOOTLOADER_BLOBS; do
            local blob_path="$ROOTDIR/$blob"
            if [ ! -e "$blob_path" ]; then
                warn Bootloader blob "$blob" not found, ignoring
                continue
            fi
            install -D -m644 "$blob_path" "$image_dir/$(basename "$blob_path")"
        done
    )
}

# Determine a basename for our directory as the same as our tarball with
# extensions removed. This is needed, since tarball packages usually
# have a base directory of its contents, rather then extracting into the
# current directory.
output_dir="$(basename "$OUTPUT_TAR")"
for ext in .xz .bz2 .gzip .gz .tgz .tar; do
    output_dir="${output_dir%$ext}"
done

info Installing scripts
install_scripts "$td/$output_dir"

info Installing bootloader blobs
install_bootloader_blobs "$td/$output_dir"

info Writing rootfs tar to "$IMAGE_SUBDIR/$ROOTFS_TAR"
tar -C "$ROOTDIR" -c . \
| sh -c "${ROOTFS_COMPRESS-cat}" >"$td/$output_dir/$IMAGE_SUBDIR/$ROOTFS_TAR"

info Writing image package tar to "$OUTPUT_TAR"
tar -C "$td" -c "$output_dir" | sh -c "${OUTPUT_COMPRESS-cat}" >"$OUTPUT_TAR"