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
| | #!/bin/sh
# -*- mode: shell-script; sh-basic-offset: 8; tab-width: 8 -*-
case ${BASH_VERSION-} in *.*) PATH=/ shopt -s xpg_echo; esac
case ${ZSH_VERSION-} in *.*) PATH=/ emulate ksh; esac
set -u # expanding unset variable makes non-interactive shell exit immediately
set -f # disable pathname expansion by default -- makes e.g. eval more robust
set -e # exit on error -- know potential false negatives and positives !
#et -x # s/#/s/ may help debugging (or run /bin/sh -x ... on command line)
LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8; export LANG LC_ALL
#PATH='/sbin:/usr/sbin:/bin:/usr/bin'; export PATH
# XXX If bash finds *this* script by searching PATH...
case $0 in */*) ;; *)
echo "'$0' does not contain '/'s. try './$0'" >&2; exit 1
esac
saved_IFS=$IFS; readonly saved_IFS
warn () { for l; do echo "$l"; done; } >&2
die () { for l; do echo "$l"; done; exit 1; } >&2
x () { echo + "$@" >&2; "$@"; }
x_env () { echo + "$@" >&2; env "$@"; }
x_eval () { echo + "$*" >&2; eval "$*"; }
x_exec () { echo + "$@" >&2; exec "$@"; die "exec '$*' failed"; }
test $# -gt 0 || {
exec >&2; echo
echo Usage: $0 '(debian8|ubuntu1604)'
echo
echo After everything set up a user shell to the given container
echo is started "(cwd='$HOME'; X11 should work)."
echo
echo If container is already running, new shell is started.
echo If container exists but is not running it is restarted.
echo If image exists but no container, new container is created.
echo If image does not exist. It is built.
echo Build files are stored in /root/.docker-setup/ in the container.
echo
exit 1
}
case $1
in debian|debian8)
shift; set debian8 "$@"
name='debian8-notmuch'
;; ubuntu|ubuntu16|ubuntu1604)
shift; set ubuntu1604 "$@"
name='ubuntu1604-notmuch'
;; *)
die "'$1': unsupported container name"
esac
if status=`exec docker inspect -f '{{.State.Status}}' $name 2>&1`
then
if test "$status" = running
then x_exec docker exec -it "$name" /bin/bash --login
else x_exec docker start -i "$name"
fi
fi
run ()
{
test -d /tmp/.X11-unix &&
xv='-v /tmp/.X11-unix:/tmp/.X11-unix:ro' || xv=
x_exec docker run -it -e DISPLAY -e _USER="$USER" --name "$name" \
-h "$name" -v $HOME:/home/$USER ${v:+-v "$v"} --ipc=host "$name"
}
case $status in *parsing*error*.State.Status*) run; esac
# Here if above docker inspect -f '{{.State.Status}}' did not match above, but
# Error: No such image or container: ...
case $1
in debian8)
FROM_HASH=1b01529cc499d51767c62f9fc8083043610546b4e050898809ec54e00dbb1a34
FROM_REF=debian:8.5
;; ubuntu1604)
FROM_HASH=42118e3df429f09ca581a9deb3df274601930e428e452f7e4e9f1833c56a100a
FROM_REF=ubuntu:16.04
esac
TRUNC_HASH=${FROM_HASH%????????????????????????????????????????????????????}
rmtmps () { rm -rf _docker_wip; trap - 0; }
rmtmps
mkdir _docker_wip
# outcomment next line when debugging build
trap rmtmps 0 INT HUP TERM
exec 3>&1 > _docker_wip/Dockerfile.gen
cat <<EOF
# Ensure that FROM_REF & FROM_HASH are in sync; hash wins if not...
#FROM $FROM_REF (is $TRUNC_HASH...)
FROM $FROM_HASH
# Note: The result of docker build with this Dockerfile is not entirely
# reproducable as packages installed from remote sources may get
# updated...
ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
EOF
case $1 in debian*|ubuntu*)
cat <<'EOF'
# Set locale in a way that is both ubuntu and debian compatible
RUN set -xeu \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get update && apt-get install -y -q locales \
&& if test -f /etc/locale.gen; then \
sed -i '/en_US.UTF-8/ s/^. *//' /etc/locale.gen; fi \
&& locale-gen en_US.UTF-8 \
&& echo 'LANG="en_US.UTF-8"' > /etc/default/locale \
&& apt-get install -y -q build-essential git libxapian-dev libgmime-2.6-dev libtalloc-dev zlib1g-dev \
&& apt-get -y autoremove && apt-get -y clean # rm -rf /var/lib/apt/lists/
EOF
esac
# all containers (more may be added...)
cat <<'EOF'
RUN set -xeu \
&& chmod 755 /root \
&& exec 3>&1 >>/root/.bash_profile && echo \
&& echo 'test ! -f /root/.docker-setup/bash-as-user.sh ||' \
&& echo ' . /root/.docker-setup/bash-as-user.sh' \
&& exec >>/etc/bash.bashrc && echo \
&& echo '# emulate zsh printexitvalue (written from Dockerfile)' \
&& echo 'trap '\''echo -n bash: exit $? \\ \\ ; fc -nl -1 -1'\'' ERR' \
&& exec 1>&3 3>&- \
&& umask 077 \
&& mkdir -p /etc/sudoers.d \
&& echo '%root ALL= NOPASSWD: ALL' >/etc/sudoers.d/55-wheel-allmighty
ADD bash-as-user.sh Dockerfile.gen /root/.docker-setup/
CMD ["/bin/bash", "--login" ]
EOF
exec >&3 3>&-
cat >_docker_wip/bash-as-user.sh <<'EOF'
# This file is supposed to be loaded from /root/.bash_profile
# when bash is started as login shell (-l or --login).
user=${_USER-}
unset _USER
if test "$user" && test -d /home/"$user"
then
case $user in *[!-a-z0-9_]*) exit 1; esac
grep -q "^$user:" /etc/passwd || {
duid=`exec stat -c %u /home/"$user"`
useradd -d /home/"$user" -M -u $duid -U -G 0 -s /bin/bash \
-c "user $user" "$user" 2>/dev/null || :
}
fi
# Simple change user which may work as well as gosu(1) if not (better).
test -z "$user" || exec perl -e '
my @user = getpwnam $ARGV[0];
chdir $user[7];
$ENV{HOME} = $user[7];
$ENV{USER} = $ARGV[0];
$( = $) = "$user[3] $user[3] 0";
$< = $> = $user[2]; die "setting uids: $!\n" if $!;
exec qw"/bin/bash --login";' "$user"
unset user
EOF
( cd _docker_wip
# TIME is used by (GNU) /usr/bin/time (TIMEFORMAT by bash builtin)
export TIME='%Us user, %Ss system, %P cpu, %E total (max resident mem %Mk)'
export SHELL=/bin/sh
x command time docker build -f Dockerfile.gen -t $name .
x_exec docker history $name )
rmtmps
# run() does exec; auto-eliminating traps
run
|