forked from epfl-lasa/control-libraries
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Dockerfile
253 lines (219 loc) · 9.21 KB
/
Dockerfile
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
ARG BASE_TAG=24.04
FROM ubuntu:${BASE_TAG} as base
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
cmake \
g++ \
git \
libgtest-dev \
python3-pip \
ssh \
sudo \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN echo "Set disable_coredump false" >> /etc/sudo.conf
# create the credentials to be able to pull private repos using ssh
RUN mkdir -p /root/.ssh/ && ssh-keyscan github.com | tee -a /root/.ssh/known_hosts
ARG CMAKE_BUILD_TYPE=Release
FROM base as apt-dependencies
COPY apt-packages.tx[t] /
RUN <<HEREDOC
if [ ! -s /apt-packages.txt ]; then
set +e # FIXME: without this, the script fails because of an issue with `clear_console`
exit 0
fi
mkdir -p /tmp/apt
apt-get update
# We then do a dry-run and parse the output of apt to gather the list of packages to be installed
# Example output:
# ```
# #########
# NOTE: This is only a simulation!
# apt-get needs root privileges for real execution.
# Keep also in mind that locking is deactivated,
# so don't depend on the relevance to the real current situation!
# Reading package lists...
# Building dependency tree...
# Reading state information...
# The following additional packages will be installed:
# libavutil56 libblosc1
# The following NEW packages will be installed:
# libavutil56 libblosc1
# 0 upgraded, 5 newly installed, 0 to remove and 28 not upgraded.
# Inst libavutil56 (7:4.4.2-0ubuntu0.22.04.1 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [arm64])
# Inst libblosc1 (1.21.1+ds2-2 Ubuntu:22.04/jammy [arm64])
# Conf libavutil56 (7:4.4.2-0ubuntu0.22.04.1 Ubuntu:22.04/jammy-updates, Ubuntu:22.04/jammy-security [arm64])
# Conf libblosc1 (1.21.1+ds2-2 Ubuntu:22.04/jammy [arm64])
# ```
# Transformed into:
# ```
# libavutil56
# libblosc1
# ```
xargs -a /apt-packages.txt apt-get install --dry-run \
| grep -e '^Inst ' \
| sed -E 's/^Inst (\S+) .*$/\1/' > /tmp/new-packages.txt
# Then we install apt packages like normal
xargs -a /apt-packages.txt apt-get install -y
# Finally we use dpkg to get all files installed by those packages and copy them to a new root
# - get list of files installed by all the packages
# - remove empty lines
# - sort
# - remove duplicates
# - copy files while keeping file hierarchy and preserving links as-is
# - remove "omitting directory" messages (we don't do recursive copy as we only want specific files) for cleaner output
xargs -a /tmp/new-packages.txt dpkg-query -L \
| sed '/^$/d' | sort | uniq \
| xargs -d "\n" cp --parents -dp -t /tmp/apt 2>&1 \
| grep -v 'omitting directory'
# this root can then be copied to / to install everything globally or use LD_LIBRARY_PATH to use it locally
HEREDOC
FROM base as base-dependencies
ARG TARGETPLATFORM
ARG CACHEID
COPY dependencies/base_dependencies.cmake CMakeLists.txt
RUN --mount=type=cache,target=/build,id=cmake-base-deps-${TARGETPLATFORM}-${CACHEID},uid=1000 \
cmake -B build -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} && cmake --build build && cmake --install build --prefix /tmp/deps
FROM base as pinocchio-dependencies
COPY --from=apt-dependencies /tmp/apt /
COPY --from=base-dependencies /tmp/deps /usr
ARG TARGETPLATFORM
ARG CACHEID
ARG PINOCCHIO_TAG=v2.6.20
ARG HPP_FCL_TAG=v2.4.4
# FIXME: it would be nicer to have it all in the root CMakelists.txt but:
# * `pinocchio` doesn't provide an include directory we can easily plug into `target_include_directories` and thus needs to be installed first
# * `pinocchio` uses hacks relying on undocumented CMake quirks which break if you use `FetchContent`
# FIXME: it needs `CMAKE_INSTALL_PREFIX` and `--prefix` because it doesn't install to the right place otherwise
RUN --mount=type=cache,target=/pinocchio,id=cmake-pinocchio-src-${PINOCCHIO_TAG}-${TARGETPLATFORM}-${CACHEID},uid=1000 \
--mount=type=cache,target=/hpp-fcl,id=cmake-hpp-fcl-src-${HPP_FCL_TAG}-${TARGETPLATFORM}-${CACHEID},uid=1000 \
--mount=type=cache,target=/build,id=cmake-pinocchio-${PINOCCHIO_TAG}-${HPP_FCL_TAG}-${TARGETPLATFORM}-${CACHEID},uid=1000 \
<<EOF
set -e
if [ ! -f hpp-fcl/CMakeLists.txt ]; then
rm -rf hpp-fcl/*
git clone --depth 1 -b ${HPP_FCL_TAG} --recursive https://github.com/humanoid-path-planner/hpp-fcl
fi
cmake -B build/hpp-fcl -S hpp-fcl -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBUILD_PYTHON_INTERFACE=OFF -DCMAKE_INSTALL_PREFIX=/tmp/deps
cmake --build build/hpp-fcl --target all install
if [ ! -f pinocchio/CMakeLists.txt ]; then
rm -rf pinocchio/*
git clone --depth 1 -b ${PINOCCHIO_TAG} --recursive https://github.com/stack-of-tasks/pinocchio
fi
cmake -B build/pinocchio -S pinocchio -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBUILD_PYTHON_INTERFACE=OFF -DBUILD_WITH_COLLISION_SUPPORT=ON -DCMAKE_INSTALL_PREFIX=/tmp/deps
cmake --build build/pinocchio --target all install
# FIXME: pinocchio produces non-portable paths
find /tmp/deps -type f -exec sed -i 's#/tmp/deps#/usr#g' '{}' \;
EOF
FROM base as dependencies
ARG TARGETPLATFORM
ARG CACHEID
# Needed to build `osqp-eigen`
COPY --from=apt-dependencies /tmp/apt /
COPY --from=base-dependencies /tmp/deps /usr
COPY dependencies/dependencies.cmake CMakeLists.txt
RUN --mount=type=cache,target=/build,id=cmake-deps-${TARGETPLATFORM}-${CACHEID},uid=1000 \
cmake -B build -Dprotobuf_BUILD_TESTS=OFF -DCPPZMQ_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \
&& cmake --build build && cmake --install build --prefix /tmp/deps
COPY --from=base-dependencies /tmp/deps /tmp/deps
COPY --from=pinocchio-dependencies /tmp/deps /tmp/deps
FROM base as code
COPY --from=apt-dependencies /tmp/apt /
COPY --from=dependencies /tmp/deps /usr
FROM code as development
RUN usermod -a -G dialout ubuntu
RUN echo "ubuntu ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/99_aptget
RUN chmod 0440 /etc/sudoers.d/99_aptget && chown root:root /etc/sudoers.d/99_aptget
# Configure sshd server settings
RUN ( \
echo 'LogLevel DEBUG2'; \
echo 'PubkeyAuthentication yes'; \
echo 'Subsystem sftp /usr/lib/openssh/sftp-server'; \
) > /etc/ssh/sshd_config_development \
&& mkdir /run/sshd
# Configure sshd entrypoint to authorise the new user for ssh access and
# optionally update UID and GID when invoking the container with the entrypoint script
COPY ./docker/sshd_entrypoint.sh /sshd_entrypoint.sh
RUN chmod 744 /sshd_entrypoint.sh
RUN mkdir /guidelines && cd /guidelines \
&& wget https://raw.githubusercontent.com/aica-technology/.github/v0.9.0/guidelines/.clang-format
USER ${USER}
WORKDIR /src
COPY --chown=${USER}:${USER} . .
FROM code as build
ARG TARGETPLATFORM
ARG CACHEID
COPY licenses licenses
COPY protocol protocol
COPY source source
COPY CMakeLists.txt CMakeLists.txt
RUN --mount=type=cache,target=/build,id=cmake-build-${TARGETPLATFORM}-${CACHEID},uid=1000 \
cmake -B build -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} && cmake --build build
FROM build as cpp-test
ARG TARGETPLATFORM
ARG CACHEID
RUN --mount=type=cache,target=/build,id=cmake-build-${TARGETPLATFORM}-${CACHEID},uid=1000 \
cmake -B build -DBUILD_TESTING=ON && make -C build && CTEST_OUTPUT_ON_FAILURE=1 make -C build test
FROM build as install
ARG TARGETPLATFORM
ARG CACHEID
RUN --mount=type=cache,target=/build,id=cmake-build-${TARGETPLATFORM}-${CACHEID},uid=1000 \
cmake --install build --prefix /tmp/cl
FROM code as python
ARG TARGETPLATFORM
ARG CACHEID
COPY --from=install /tmp/cl /usr
COPY ./python/include /python/include
COPY ./python/source /python/source
COPY ./python/pyproject.toml ./python/setup.py /python/
RUN --mount=type=cache,target=/.cache,id=pip-${TARGETPLATFORM}-${CACHEID},uid=1000 \
python3 -m pip install --prefix=/tmp/python /python
RUN mv /tmp/python/local /tmp/python-usr
FROM cpp-test as python-test
RUN pip install pytest --break-system-packages
COPY --from=install /tmp/cl /usr
COPY --from=python /tmp/python-usr /usr
COPY ./python/test /test
RUN pytest /test
FROM code as python-stubs
ARG TARGETPLATFORM
ARG CACHEID
COPY --from=install /tmp/cl /usr
COPY --from=python /tmp/python-usr /usr
RUN pip install pybind11-stubgen --break-system-packages
RUN --mount=type=cache,target=/.cache,id=pip-${TARGETPLATFORM}-${CACHEID},uid=1000 \
<<HEREDOC
for PKG in state_representation dynamical_systems robot_model controllers clproto; do
python3 -c "import ${PKG}"
if [ $? -eq 0 ]; then
pybind11-stubgen $PKG -o ./stubs
mkdir -p ./stubs-package/$PKG-stubs && find ./stubs -type f -name "*.pyi" -exec mv {} ./stubs-package/$PKG-stubs \;
cat << EoF > ./stubs-package/setup.py
from distutils.core import setup
import $PKG
setup(
name="$PKG-stubs",
author="Dominic Reber",
author_email="[email protected]",
version=$PKG.__version__,
package_data={"$PKG-stubs": ["*.pyi"]},
packages=["$PKG-stubs"]
)
EoF
python3 -m pip install --prefix=/tmp/python ./stubs-package || exit 1
rm -r ./stubs*
fi
done
HEREDOC
RUN mv /tmp/python/local /tmp/python-usr
FROM scratch as production
COPY --from=apt-dependencies /tmp/apt /
COPY --from=dependencies /tmp/deps /usr
COPY --from=install /tmp/cl /usr
COPY --from=python /tmp/python-usr /usr
COPY --from=python-stubs /tmp/python-usr /usr
ARG VERSION
LABEL org.opencontainers.image.title="AICA control-libraries"
LABEL org.opencontainers.image.description="AICA control libraries"
LABEL org.opencontainers.image.version="${VERSION}"
LABEL tech.aica.image.metadata='{"type":"lib"}'