blob: c68aac8c25a27e5e783e182bf87f209106e2c15b (
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
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
|
#! /bin/bash
# Purpose: install Debian packages in a Docker image
#
# Usage: deb2docker [options] packages
# -B do NOT build the image (default is to build)
# -c CMD command to run in the container (default to '/bin/bash')
# -f FROM indicate which distribution is to be used (default to debian:stable)
# -h show this help
# -n NAME name of the image (default to package list)
# -o DIR use given directory for the build (default in /tmp)
# -p PRE execute the given script during the container build (before packages install)
# -s POST execute the given script during the container build (after packages install)
# -v show package version
# The package list can be any Debian package, as well as local .deb
#
# Example: 'deb2docker -o /tmp/xeyes x11-apps' then '/tmp/xeyes/start xeyes'
# build: docker build --rm Dockerfile
# run: docker run --rm -it NAME
# clean: docker rmi NAME
# clean ALL: docker system prune -a
# (c) E. Farhi - Synchrotron SOLEIL - GPL3
# requires:
# bash
# docker.io
# requires: docker privileges:
# sudo usermod -aG docker $USER
set -e
# default settings -------------------------------------------------------------
FROM=debian:stable
BUILD=1
NAME=
SETNAME=0
CMD="/bin/bash"
WORK_DIR=
SCRIPT=
PRE=
VERSION=1.0.8
ARGS="$@"
# handle input arguments -------------------------------------------------------
while getopts vhBf:n:c:o:d:p:s: flag
do
case "${flag}" in
h) # display help
echo "Usage: $0 [-hB][-c CMD][-f FROM][-n NAME][-o DIR][-s SCRIPT] packages..."
echo " Build a Docker image with given Debian packages."
echo " Options:"
echo " -B do NOT build the image (default is to build)"
echo " -c EXEC command to run in the container (default to $CMD)"
echo " -f FROM indicate which distribution is to be used (default to $FROM)"
echo " -h show this help"
echo " -n NAME name of the image (default to package list)"
echo " -o DIR use given directory for the build (default is in /tmp)"
echo " -p PRE execute script PRE before packages install"
echo " -s POST execute script POST after packages install"
echo " -v show package version"
echo " The package list can be any Debian package, as well as local .deb"
echo " "
echo "Example: '$0 -o /tmp/xeyes x11-apps' then '/tmp/xeyes/start xeyes'"
exit 0;
;;
B) # do not build the image
BUILD=0
;;
f) # set FROM image
FROM=${OPTARG}
;;
n) # set image name
NAME=${OPTARG}
;;
c) # command to execute
CMD=${OPTARG}
;;
o|d) # output directory
WORK_DIR=${OPTARG}
;;
p) # PRE SCRIPT
PRE=${OPTARG}
;;
s) # SCRIPT (POST)
SCRIPT=${OPTARG}
;;
v) # VERSION
echo "$0 version $VERSION"
exit 0;
;;
*)
echo "ERROR: Invalid option. Use -h for help."
exit 1;
;;
esac
done
shift $((OPTIND-1))
# check that docker is installed
if ! command -v docker > /dev/null
then
echo "ERROR: docker could not be found. Install it with: apt install docker.io"
exit 1
fi
# set name when not set
if [ "x$NAME" = "x" ]; then
SETNAME=1
fi
# create a temporary directory to work in --------------------------------------
if [ "x$WORK_DIR" = "x" ]; then
N=`basename $0`
WORK_DIR=`mktemp -p /tmp -d $N-XXXXXXXX`
else
mkdir -p $WORK_DIR || echo "ERROR: Invalid directory $WORK_DIR"
fi
PW=$PWD
# search for executable commands -----------------
DEB=
# get a local copy of packages and find bin and desktop files
mkdir -p $WORK_DIR/apt || exit # hold deb pkg copies for analysis
echo "$0: creating image $NAME in $WORK_DIR"
echo "Getting Debian packages..."
for i in $@; do
echo " $i"
if [ -f "$i" ]; then
cp $i $WORK_DIR/apt/
n=`basename $i`
DEB="$DEB /opt/install/$n"
else
DEB="$DEB $i"
cd $WORK_DIR/apt
apt download $i
cd $PW
fi
done
echo " " >> $WORK_DIR/README
echo "Created with $0" >> $WORK_DIR/README
echo "$ARGS" >> $WORK_DIR/README
echo " " >> $WORK_DIR/file_list.txt
for i in $WORK_DIR/apt/*.deb; do
echo "Analyzing $i"
N=$(dpkg-deb -f $i Package) || continue
# set the container name if needed
if [ "x$SETNAME" = "x2" ]; then
NAME="$NAME-$N"
fi
if [ "x$SETNAME" = "x1" ]; then
SETNAME=2
NAME=$N
fi
echo "Package $N ------------------------------------------" >> $WORK_DIR/README
dpkg-deb -I $i >> $WORK_DIR/README
F=`dpkg -c $i`
echo "$F" >> $WORK_DIR/file_list.txt
echo " " >> $WORK_DIR/README
done
# the base command to start the containers from image
cmd="docker run -it --net=host --env=DISPLAY --env='QT_X11_NO_MITSHM=1' --volume=\$HOME/.Xauthority:/home/user/.Xauthority:rw $NAME"
# prepare the Dockerfile -------------------------------------------------------
FILE="$WORK_DIR/Dockerfile"
DATE=`date`
if [ -f "$PRE" ]; then
cp $PRE $WORK_DIR/
N=`basename $PRE`
PRE="RUN chmod a+x /opt/install/$N && sh -c \"/opt/install/$N\""
PRE_FILE="ADD $N /opt/install/"
else
PRE_FILE=
fi
if [ -f "$SCRIPT" ]; then
cp $SCRIPT $WORK_DIR/
N=`basename $SCRIPT`
SCRIPT="RUN chmod a+x /opt/install/$N && sh -c \"/opt/install/$N\""
SCRIPT_FILE="ADD $N /opt/install/"
else
SCRIPT_FILE=
fi
echo "Creating Dockerfile $NAME into $FILE"
dd status=none of=${FILE} << EOF
# created by $0 on $DATE
# $ARGS
#
# Docker image $NAME
#
# build: docker build --rm Dockerfile
# run: docker run --rm -it $NAME
# clean: docker rmi $NAME
# clean ALL: docker system prune -a
FROM $FROM
# copy required packages
ADD apt/ /opt/install/
ADD README /opt/install/
ADD file_list.txt /opt/install/
ADD Dockerfile /opt/install/
$PRE_FILE
$SCRIPT_FILE
# execute/install
$PRE
RUN apt-get update -y
RUN apt-get install -y --no-install-recommends bash xauth $DEB
$SCRIPT
RUN rm /opt/install/*.deb || echo " "
# start the container (interactive/terminal)
RUN useradd -ms /bin/bash user
ENV DISPLAY :0
USER user
CMD ["$CMD"]
EOF
# build docker -----------------------------------------------------------------
FILE=$WORK_DIR/build
dd status=none of=${FILE} << EOF
#!/bin/bash
# created by $0 on $DATE
# $ARGS
#
# build image $NAME
#
# Usage: build
docker build --rm -t $NAME .
# handle of Desktop launchers
mkdir -p launchers/
mkdir -p icons/
# get .desktop files ----------------------------------------------------------
D=\$(grep '\.desktop' file_list.txt) || echo "WARNING: No desktop files found."
# get the desktop files
D=\$(echo "\$D" | awk '{ print \$6 }')
# we need to copy them back, as well as their icons, and change the Exec lines
# create a container from image to access the files
id=\$(docker create $NAME)
for i in \$D; do
docker cp \$id:\$i launchers/ || echo "WARNING: Failed to get desktop launcher \$i"
done
# get icon files --------------------------------------------------------------
D=\$(grep 'icon' file_list.txt) || echo "WARNING: No icon files found."
# get the icon files
D=\$(echo "\$D" | awk '{ print \$6 }')
# we need to copy them back, as well as their icons, and change the Exec lines
# create a container from image to access the files
id=\$(docker create $NAME)
for i in \$D; do
docker cp \$id:\$i icons/ &> /dev/null|| echo "WARNING: Failed to get icon \$i"
done
# cleanup
docker rm -v \$id
# adapt the Desktop launchers to insert 'run', set Icons=
for i in launchers/*; do
if [ ! -f "\$i" ]; then continue; fi
I=\$(grep 'Icon=' \$i | cut -d = -f 2) || I=
if [ ! -z "\$I" ]; then
n=\`basename \$I\`
if [ ! -f "icons/\$n" ]; then
# get closest file that match Icon name when initial name is not present as a file
n1=( icons/\$n* ) || n1=
if [ ! -z "\$n1" ]; then
n=\`basename \${n1[0]}\`
fi
fi
sed -i "s|Icon=.*|Icon=icons/\$n|g" \$i || echo " "
fi
I=\$(grep 'Exec=' \$i | cut -d = -f 2-) || I=
sed -i "s|Exec=.*|Exec=sh -c \"echo '$NAME'; $cmd \$I\"|g" \$i || echo " "
# make sure terminal is set (else 'docker -it' fails)
I=\$(grep 'Terminal=' \$i | cut -d = -f 2) || I=
if [ ! -z "\$I" ]; then
sed -i 's|Terminal=.*|Terminal=true|g' \$i || echo " "
else
echo "Terminal=true" >> \$i
fi
chmod a+x \$i || echo " "
done
# create a Terminal launcher
echo "[Desktop Entry]" > launchers/$NAME-terminal.desktop
echo "Type=Application" >> launchers/$NAME-terminal.desktop
echo "Name=$NAME Terminal" >> launchers/$NAME-terminal.desktop
echo "Terminal=true" >> launchers/$NAME-terminal.desktop
echo "Exec=sh -c \"echo '$NAME'; $cmd\"" >> launchers/$NAME-terminal.desktop
chmod a+x launchers/$NAME-terminal.desktop
EOF
chmod a+x $WORK_DIR/build
if [ "x$BUILD" = "x1" ]; then
# build the image
(cd $WORK_DIR && ./build)
else
echo "INFO: To build this image, use: cd $WORK_DIR; ./build"
echo " "
cat $WORK_DIR/build
fi
# ------------------------------------------------------------------------------
# get executables and Desktop launchers (from the Docker)
echo "------------------------------------------------------" >> $WORK_DIR/README
B=$(grep '\.desktop' $WORK_DIR/file_list.txt) || echo " "
echo "$B" >> $WORK_DIR/README
FILE=$WORK_DIR/start
dd status=none of=${FILE} << EOF
#!/bin/bash
# created by $0 on $DATE
#
# start a container from image $NAME
#
# Usage: start [CMD]
# default CMD is $CMD
$cmd \$@
EOF
chmod a+x $WORK_DIR/start
# display final message
echo "--------------------------------------------"
echo "The image $NAME has been prepared in $WORK_DIR"
echo " Desktop launchers are available in $WORK_DIR/launchers"
echo "To start $NAME, use:"
echo " cd $WORK_DIR; ./start [cmd]"
echo " "
|