1
0
Fork 0
devscripts/scripts/deb2docker.sh
Daniel Baumann b543f2e88d
Adding upstream version 2.25.15.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 11:04:07 +02:00

349 lines
9.9 KiB
Bash
Executable file

#! /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 " "