aboutsummaryrefslogtreecommitdiffhomepage
path: root/packaging/run-in-container
blob: bc27bfe46d89f83db5059310ff1ec1b394d0fee4 (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
#!/bin/sh

set -eu

this="$(readlink -e "${0}")"

# assign defaults
project_dir="$(dirname "$(dirname "${this}")")"
debian_tag="${DEBIAN_TAG:-sid}"

usage() {
    cat << EOF
Usage: $(basename "${this}") [OPTION]... [ACTION]
Run tests or create package in a podman (or docker) container

Options:
    -h                print this usage and exit
    -C PROJECT_DIR    change to PROJECT_DIR (default: ${project_dir})
    -t DEBIAN_TAG     debian release tag (default: ${debian_tag})
    -c CONTAINER_CMD  container runner command (default: podman)

Actions:
    help       print this usage and exit
    package    create debian package artifacts
    test       run tests (default)

Example:
    $(basename "${this}") -C ~/code/git-buildpackage -t stretch package
EOF
}

die() { { echo "ERROR: ${*}"; usage; } >&2; exit 1; }

# convenience wrapper
# shellcheck disable=SC2068  # re-splitting command arguments intentional
container_build() {
    ${container_cmd} build \
        --force-rm="${DOCKER_BUILD_FORCE_RM:-false}" \
        --no-cache="${DOCKER_BUILD_NO_CACHE:-false}" \
        ${@}
}

# take path to project dir; build docker image for base
base_build() {
    (
        cd "${project_dir}"
        [ -f .gitignore ] && cat .gitignore
        [ -f .gitmodules ] && sed -nr 's|\s+path = (.+)|\1|gp' .gitmodules
        cat <<EOF
${this##"${PWD}"/}
*.buildinfo
*.changes
*.deb
*.dsc
*.tar.xz
.dockerignore
.git*
EOF
    ) > "${project_dir}/.dockerignore"
    container_build \
        --pull="${DOCKER_BUILD_PULL:-false}" \
        --build-arg="FROM_IMAGE=debian:${debian_tag}" \
        -t "gbp-base:${debian_tag}" -f- "${project_dir}" <<'EOF'
ARG FROM_IMAGE
FROM ${FROM_IMAGE}
ENV DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
WORKDIR /workdir/project
RUN set -euvx \
&& apt-get update -y \
&& apt-get -y --no-install-recommends install \
build-essential devscripts equivs
COPY debian debian
RUN mk-build-deps -r -i debian/control -t 'apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends'
# To avoid constantly invalidating previous container layers, run the slow
# dependency installation early and copy files (along with any changed files)
# later
COPY . .
RUN groupadd luser && useradd -g luser luser && chown -R luser:luser ..
USER luser
EOF
    rm -vf "${project_dir}/.dockerignore"
}


# run tests
gbp_test() {
    base_build
    for L in C.UTF-8 C; do
        ${container_cmd} run --rm -ie"TEST_LOCALE=${L}" \
        "gbp-base:${debian_tag}" sh <<'EOF'
set -euvx
make all+net
make -C docs
EOF
    done
}

# create debian package artifacts, copy to host
gbp_package() {
    base_build
    container_build \
        --build-arg="FROM_IMAGE=gbp-base:${debian_tag}" \
        -t "gbp-package:${debian_tag}" -f- "${project_dir}" <<'EOF'
ARG FROM_IMAGE
FROM ${FROM_IMAGE}
RUN dpkg-buildpackage -j$(nproc) -sa -us -uc
EOF
    ${container_cmd} run --rm -iu0:0 \
        --mount="type=bind,source=${PWD},target=/mnt/host-volume" \
        "gbp-package:${debian_tag}" sh <<EOF
set -euvx
find .. -maxdepth 1 -mindepth 1 -type f \
    -exec chown -v $(id -u):$(id -g) {} + \
    -a -exec cp -vat /mnt/host-volume {} +
EOF
}

while getopts ":hC:t:c:" opt; do
    case $opt in
        h) usage; exit 0;;
        C) project_dir="$(readlink -e "${OPTARG}")"
            [ -d "${project_dir}" ] || die "bad project dir ${OPTARG}";;
        t) debian_tag="${OPTARG}";;
        c) container_cmd="${OPTARG}";;
        :) die "missing argument: -${OPTARG}";;
        \?) die "bad option: -${OPTARG}";;
    esac
done

# Set default container command
container_cmd="${container_cmd:-podman}"

# Set default container command value if none set
case "${container_cmd}" in
    docker|podman) ;;
    *) die "container command is expected to be one of 'docker' or 'podman'" ;;
esac

shift $((OPTIND - 1))
case "${1:-test}" in
    'help') usage; exit 0;;
    'test') gbp_test; exit ${?};;
    'package') gbp_package; exit ${?};;
    *) die "bad action: ${1}";;
esac