Repository navigation
Expand file tree
/
Copy pathDockerfile.layer2
More file actions
405 lines (365 loc) · 17.4 KB
/
Copy pathDockerfile.layer2
File metadata and controls
405 lines (365 loc) · 17.4 KB
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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# syntax=docker/dockerfile:1.7
# Version: 1.0.10
# Layer 2: Flutter Bench Image
# Extends Layer 1 (dev-bench-base) with Flutter-specific tools
# Includes: Flutter SDK, Android SDK, Dart tools, mobile dev tools
ARG BASE_IMAGE=dev-bench-base:latest
FROM ${BASE_IMAGE}
# Container version labels
LABEL layer="2"
LABEL layer.name="flutter-bench"
LABEL layer.version="1.0.10"
LABEL layer.description="Flutter and mobile development tools"
LABEL bench.type="flutter"
# Everything runs as root — user personalization happens in Layer 3
USER root
# Keep CLI tooling on a UTF-8 locale so Ruby/Fastlane/CocoaPods behave cleanly.
ENV LANG=C.UTF-8
ENV LANGUAGE=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV PUB_CACHE=/opt/dart-pub-cache
# ========================================
# FLUTTER/ANDROID PREREQUISITES
# ========================================
# Install Flutter/Android prerequisites
RUN apt-get update && apt-get install -y \
libglu1-mesa \
android-tools-adb \
android-tools-fastboot \
clang \
cmake \
ninja-build \
libgtk-3-dev \
mesa-utils \
&& rm -rf /var/lib/apt/lists/*
# ========================================
# JAVA JDK (FOR ANDROID DEVELOPMENT)
# ========================================
RUN apt-get update && apt-get install -y \
openjdk-17-jdk \
&& rm -rf /var/lib/apt/lists/*
# ========================================
# ANDROID SDK INSTALLATION
# ========================================
RUN mkdir -p /opt/android-sdk \
&& wget -q https://dl.google.com/android/repository/commandlinetools-linux-14742923_latest.zip -O /tmp/cmdtools.zip \
&& unzip -q /tmp/cmdtools.zip -d /opt/android-sdk \
&& rm /tmp/cmdtools.zip \
&& mv /opt/android-sdk/cmdline-tools /opt/android-sdk/cmdline-tools-temp \
&& mkdir -p /opt/android-sdk/cmdline-tools/latest \
&& mv /opt/android-sdk/cmdline-tools-temp/* /opt/android-sdk/cmdline-tools/latest/ \
&& rmdir /opt/android-sdk/cmdline-tools-temp \
&& chown -R root:root /opt/android-sdk \
&& chmod -R 775 /opt/android-sdk
# Set Android SDK environment variables
ENV ANDROID_HOME="/opt/android-sdk"
ENV ANDROID_SDK_ROOT="/opt/android-sdk"
ENV PATH="/opt/android-sdk/platform-tools:/opt/android-sdk/emulator:/opt/android-sdk/cmdline-tools/latest/bin:${PATH}"
# Install current Android platform-tools directly. The full sdkmanager package
# set is installed by default, with per-package timeouts to bound slow or
# unavailable Google package downloads.
ARG ANDROID_PLATFORM_TOOLS_VERSION=37.0.0
RUN --mount=type=cache,target=/var/cache/android-sdk-downloads,sharing=locked set -eux; \
archive="/var/cache/android-sdk-downloads/platform-tools_r${ANDROID_PLATFORM_TOOLS_VERSION}-linux.zip"; \
downloaded=false; \
for attempt in 1 2 3 4 5; do \
if curl -fL --retry 2 --connect-timeout 30 --max-time 900 -C - \
-o "$archive" \
"https://dl.google.com/android/repository/platform-tools_r${ANDROID_PLATFORM_TOOLS_VERSION}-linux.zip"; then \
downloaded=true; \
break; \
fi; \
sleep 5; \
done; \
[ "$downloaded" = true ] || { echo "Failed to download Android platform-tools after 5 attempts" >&2; exit 1; }; \
unzip -q -o "$archive" -d /opt/android-sdk; \
chmod -R 775 /opt/android-sdk
ARG INSTALL_ANDROID_SDK_PACKAGES=true
ARG ANDROID_SDK_PACKAGE_INSTALL_TIMEOUT=3600
ARG ANDROID_SDK_PACKAGE_INSTALL_ATTEMPTS=2
RUN if [ "$INSTALL_ANDROID_SDK_PACKAGES" = "true" ]; then \
set -eux; \
yes | /opt/android-sdk/cmdline-tools/latest/bin/sdkmanager --licenses; \
for package in \
"emulator" \
"cmake;3.22.1" \
"ndk;27.0.12077973" \
"build-tools;33.0.0" \
"build-tools;34.0.0" \
"build-tools;36.0.0" \
"platforms;android-30" \
"platforms;android-31" \
"platforms;android-32" \
"platforms;android-33" \
"platforms;android-34" \
"platforms;android-35" \
"platforms;android-36" \
"system-images;android-34;google_apis;x86_64"; do \
installed=false; \
for attempt in $(seq 1 "$ANDROID_SDK_PACKAGE_INSTALL_ATTEMPTS"); do \
if timeout "$ANDROID_SDK_PACKAGE_INSTALL_TIMEOUT" \
/opt/android-sdk/cmdline-tools/latest/bin/sdkmanager "$package"; then \
installed=true; \
break; \
fi; \
if [ "$attempt" -lt "$ANDROID_SDK_PACKAGE_INSTALL_ATTEMPTS" ]; then \
echo "Android SDK package ${package} failed on attempt ${attempt}; retrying." >&2; \
sleep 5; \
fi; \
done; \
[ "$installed" = true ] || { echo "Android SDK package ${package} failed after ${ANDROID_SDK_PACKAGE_INSTALL_ATTEMPTS} attempts." >&2; exit 1; }; \
done; \
chmod -R 775 /opt/android-sdk; \
else \
echo "Skipping heavyweight Android SDK package preloads; set INSTALL_ANDROID_SDK_PACKAGES=true to include them."; \
fi
# ========================================
# FLUTTER ECOSYSTEM
# ========================================
RUN apt-get update && apt-get install -y --no-install-recommends aria2 \
&& rm -rf /var/lib/apt/lists/*
# Install Flutter SDKs
ENV FLUTTER_HOME="/opt/flutter"
ENV FLUTTER_LTS_327_HOME="/opt/flutter-3.27.0"
ENV PATH="$PUB_CACHE/bin:$FLUTTER_HOME/bin:$FLUTTER_HOME/bin/cache/dart-sdk/bin:$PATH"
# Install the versioned Flutter SDK directly. The git clone path can hang for a
# long time inside Docker Desktop without producing progress output.
ARG FLUTTER_VERSION=3.44.4
RUN --mount=type=cache,target=/var/cache/flutter-downloads,sharing=locked set -eux; \
mkdir -p /var/cache/flutter-downloads; \
download_archive() { \
url="$1"; \
output="$2"; \
if aria2c --allow-overwrite=true --auto-file-renaming=false --continue=true \
--max-connection-per-server=8 --split=8 --min-split-size=16M \
--max-tries=10 --retry-wait=5 --connect-timeout=30 --timeout=120 \
--summary-interval=30 --console-log-level=warn \
-d "$(dirname "$output")" -o "$(basename "$output")" "$url"; then \
return 0; \
fi; \
for attempt in 1 2 3 4 5 6 7 8; do \
curl -fL --retry 3 --connect-timeout 30 --max-time 1800 -C - \
--user-agent "Mozilla/5.0" -o "$output" "$url" && return 0; \
sleep 5; \
done; \
return 1; \
}; \
archive_path="/var/cache/flutter-downloads/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz"; \
download_archive \
"https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \
"$archive_path"; \
tmp_root="$(mktemp -d)"; \
tar -xJf "$archive_path" -C "$tmp_root"; \
rm -rf "$FLUTTER_HOME"; \
mv "$tmp_root/flutter" "$FLUTTER_HOME"; \
rm -rf "$tmp_root"; \
git config --system --add safe.directory "$FLUTTER_HOME"; \
"$FLUTTER_HOME/bin/flutter" config --no-analytics
# Install the long-term supported Flutter 3.27 SDK alongside the shared stable
# toolchain so pinned repos can avoid first-run downloads inside the bench.
ARG FLUTTER_LTS_327_VERSION=3.27.0
RUN --mount=type=cache,target=/var/cache/flutter-downloads,sharing=locked set -eux; \
mkdir -p /var/cache/flutter-downloads; \
download_archive() { \
url="$1"; \
output="$2"; \
if aria2c --allow-overwrite=true --auto-file-renaming=false --continue=true \
--max-connection-per-server=8 --split=8 --min-split-size=16M \
--max-tries=10 --retry-wait=5 --connect-timeout=30 --timeout=120 \
--summary-interval=30 --console-log-level=warn \
-d "$(dirname "$output")" -o "$(basename "$output")" "$url"; then \
return 0; \
fi; \
for attempt in 1 2 3 4 5 6 7 8; do \
curl -fL --retry 3 --connect-timeout 30 --max-time 1800 -C - \
--user-agent "Mozilla/5.0" -o "$output" "$url" && return 0; \
sleep 5; \
done; \
return 1; \
}; \
archive_path="/var/cache/flutter-downloads/flutter_linux_${FLUTTER_LTS_327_VERSION}-stable.tar.xz"; \
download_archive \
"https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_LTS_327_VERSION}-stable.tar.xz" \
"$archive_path"; \
tmp_root="$(mktemp -d)"; \
tar -xJf "$archive_path" -C "$tmp_root"; \
rm -rf "$FLUTTER_LTS_327_HOME"; \
mv "$tmp_root/flutter" "$FLUTTER_LTS_327_HOME"; \
rm -rf "$tmp_root"; \
git config --system --add safe.directory "$FLUTTER_LTS_327_HOME"
# Install shared Dart global tools into a system cache, then expose them via
# /usr/local/bin so Layer 3 users can run them without inheriting root's home.
ARG DART_PUB_ACTIVATE_TIMEOUT=600
RUN set -eux; \
mkdir -p "$PUB_CACHE"; \
for package in \
coverage \
fvm \
very_good_cli \
mason_cli \
flutterfire_cli \
dart_code_metrics \
build_runner \
flutter_gen \
flutter_launcher_icons \
flutter_native_splash \
intl_utils \
rename \
get_cli \
patrol_cli \
melos; do \
echo "Activating Dart package: ${package}"; \
timeout "$DART_PUB_ACTIVATE_TIMEOUT" "$FLUTTER_HOME/bin/dart" pub global activate "$package" || \
echo "Dart package ${package} installation failed or timed out, skipping..."; \
done; \
if [ -d "$PUB_CACHE/bin" ]; then \
find "$PUB_CACHE/bin" -maxdepth 1 -type f -exec chmod a+rx {} +; \
find "$PUB_CACHE/bin" -maxdepth 1 -type f -printf '%f\n' | \
while read -r tool; do \
ln -sf "$PUB_CACHE/bin/$tool" "/usr/local/bin/$tool"; \
done; \
fi
# Provide stable command names for globally activated Flutter tools that do not
# emit their own PATH wrapper or whose package name differs from the binary.
RUN set -eux; \
ln -sf /usr/local/bin/metrics /usr/local/bin/dart_code_metrics; \
ln -sf /usr/local/bin/fluttergen /usr/local/bin/flutter_gen; \
printf '%s\n' \
'#!/usr/bin/env sh' \
'set -eu' \
"snapshot=\$(find /opt/dart-pub-cache/global_packages/build_runner/bin -maxdepth 1 -name 'build_runner.dart-*.snapshot' | head -n1)" \
'exec dart "$snapshot" "$@"' \
> /usr/local/bin/build_runner; \
chmod +x /usr/local/bin/build_runner; \
printf '%s\n' \
'#!/usr/bin/env sh' \
'set -eu' \
"snapshot=\$(find /opt/dart-pub-cache/global_packages/flutter_launcher_icons/bin -maxdepth 1 -name 'flutter_launcher_icons.dart-*.snapshot' | head -n1)" \
'exec dart "$snapshot" "$@"' \
> /usr/local/bin/flutter_launcher_icons; \
chmod +x /usr/local/bin/flutter_launcher_icons; \
printf '%s\n' \
'#!/usr/bin/env sh' \
'set -eu' \
'subcommand="${1:-create}"' \
'case "$subcommand" in' \
' create|remove)' \
' shift || true' \
' ;;' \
' *)' \
' subcommand="create"' \
' ;;' \
'esac' \
"snapshot=\$(find /opt/dart-pub-cache/global_packages/flutter_native_splash/bin -maxdepth 1 -name \"\${subcommand}.dart-*.snapshot\" | head -n1)" \
'exec dart "$snapshot" "$@"' \
> /usr/local/bin/flutter_native_splash; \
chmod +x /usr/local/bin/flutter_native_splash; \
printf '%s\n' \
'#!/usr/bin/env sh' \
'set -eu' \
'subcommand="${1:-generate}"' \
'case "$subcommand" in' \
' generate|localizely_download|localizely_upload_main)' \
' shift || true' \
' ;;' \
' *)' \
' subcommand="generate"' \
' ;;' \
'esac' \
"snapshot=\$(find /opt/dart-pub-cache/global_packages/intl_utils/bin -maxdepth 1 -name \"\${subcommand}.dart-*.snapshot\" | head -n1)" \
'exec dart "$snapshot" "$@"' \
> /usr/local/bin/intl_utils; \
chmod +x /usr/local/bin/intl_utils
COPY files/sonarcloud-dart-flutter /usr/local/bin/sonarcloud-dart-flutter
RUN chmod +x /usr/local/bin/sonarcloud-dart-flutter
# ========================================
# MOBILE DEVELOPMENT TOOLS
# ========================================
# Install Firebase CLI
RUN npm install -g firebase-tools \
|| echo "❌ Firebase CLI installation failed completely, skipping..."
# Install additional mobile development tools
RUN apt-get update && apt-get install -y \
gradle \
ruby-full \
&& rm -rf /var/lib/apt/lists/*
# Install Google Chrome so Flutter web tooling works without extra setup.
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -O /tmp/google-chrome.deb \
&& apt-get update \
&& apt-get install -y /tmp/google-chrome.deb \
&& rm /tmp/google-chrome.deb \
&& ln -sf /usr/bin/google-chrome-stable /usr/local/bin/google-chrome \
&& rm -rf /var/lib/apt/lists/*
# Install Fastlane (mobile deployment automation) with fallback
RUN (gem install fastlane --no-document --force) || \
echo "❌ Fastlane installation failed, skipping..."
# Install CocoaPods for iOS development with fallback
RUN (gem install cocoapods --no-document) || \
echo "❌ CocoaPods installation failed, skipping..."
# Install Sentry CLI for error tracking with fallback
RUN (curl -fsSL --retry 3 --user-agent "Mozilla/5.0" \
https://sentry.io/get-cli/ | bash) || \
(echo "⚠️ Sentry CLI script failed, using npm fallback..." && \
npm install -g @sentry/cli) || \
echo "❌ Sentry CLI installation failed completely, skipping..."
# Install Shorebird for code push updates with fallback
ARG SHOREBIRD_INSTALL_TIMEOUT=600
RUN timeout "$SHOREBIRD_INSTALL_TIMEOUT" bash -lc 'curl -fsSL --retry 3 --connect-timeout 30 --max-time 300 --user-agent "Mozilla/5.0" \
https://raw.githubusercontent.com/shorebirdtech/install/main/install.sh | bash' || \
echo "❌ Shorebird installation failed or timed out, skipping..."
# Make Shorebird available to Layer 3 users without relying on root's home directory.
RUN if [ -d /root/.shorebird ]; then \
rm -rf /opt/shorebird && \
cp -a /root/.shorebird /opt/shorebird && \
chmod -R a+rX /opt/shorebird && \
git config --system --add safe.directory /opt/shorebird && \
git config --system --add safe.directory "/opt/shorebird/bin/cache/flutter/$(cat /opt/shorebird/bin/internal/flutter.version)" && \
ln -sf /opt/shorebird/bin/shorebird /usr/local/bin/shorebird; \
fi
# Install Figma CLI for design workflow with fallback
RUN (npm install -g @figma/code-connect) || \
echo "❌ Figma CLI installation failed, skipping..."
# ========================================
# ENVIRONMENT & SHELL CONFIGURATION (into /etc/skel)
# ========================================
# Set Java home
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
# Ensure Flutter SDKs are group-writable (Layer 3 adds user to root group for write access)
RUN chown -R root:root $FLUTTER_HOME $FLUTTER_LTS_327_HOME && \
chmod -R 775 $FLUTTER_HOME $FLUTTER_LTS_327_HOME
# Allow non-root Layer 3 users to run Flutter git-backed commands safely.
RUN git config --system --add safe.directory /opt/flutter && \
git config --system --add safe.directory /opt/flutter-3.27.0
# Expose the pinned 3.27 toolchain as real commands so it works even when
# devcontainer shell dotfiles are bind-mounted from the host.
RUN ln -sf "$FLUTTER_LTS_327_HOME/bin/flutter" /usr/local/bin/flutter327 && \
ln -sf "$FLUTTER_LTS_327_HOME/bin/dart" /usr/local/bin/dart327
# Add Flutter and Android environment to /etc/skel shell configs
RUN echo '' >> /etc/skel/.zshrc && \
echo '# Flutter/Android environment' >> /etc/skel/.zshrc && \
echo 'export FLUTTER_HOME="/opt/flutter"' >> /etc/skel/.zshrc && \
echo 'export FLUTTER_LTS_327_HOME="/opt/flutter-3.27.0"' >> /etc/skel/.zshrc && \
echo 'export ANDROID_HOME="/opt/android-sdk"' >> /etc/skel/.zshrc && \
echo 'export ANDROID_SDK_ROOT="/opt/android-sdk"' >> /etc/skel/.zshrc && \
echo 'export PUB_CACHE="/opt/dart-pub-cache"' >> /etc/skel/.zshrc && \
echo 'export PATH="$PUB_CACHE/bin:$FLUTTER_HOME/bin:$FLUTTER_HOME/bin/cache/dart-sdk/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH:$HOME/.pub-cache/bin"' >> /etc/skel/.zshrc && \
echo 'export ADB_SERVER_SOCKET=tcp:host.docker.internal:5037' >> /etc/skel/.zshrc && \
echo 'alias flutter327="$FLUTTER_LTS_327_HOME/bin/flutter"' >> /etc/skel/.zshrc && \
echo 'alias dart327="$FLUTTER_LTS_327_HOME/bin/dart"' >> /etc/skel/.zshrc && \
echo 'alias flutter-sonar-coverage="sonarcloud-dart-flutter"' >> /etc/skel/.zshrc && \
echo 'alias dart-sonar-coverage="sonarcloud-dart-flutter"' >> /etc/skel/.zshrc
# Pre-download Flutter dependencies and accept Android licenses
RUN timeout 5m bash -lc 'yes | flutter doctor --android-licenses' || true \
&& flutter precache || true \
&& timeout 20m "$FLUTTER_LTS_327_HOME/bin/flutter" precache || true
# Root prewarming creates new cache files; restore group-write only where later
# Layer 3 users actually need it. The Android SDK tree is already normalized
# immediately after installation above, so re-walking it here just burns time.
RUN for shared_dir in "$FLUTTER_HOME/bin/cache" "$FLUTTER_LTS_327_HOME/bin/cache" /opt/dart-pub-cache /opt/shorebird; do \
if [ -d "$shared_dir" ]; then \
chmod -R g+rwX "$shared_dir"; \
find "$shared_dir" -type d -exec chmod g+s {} +; \
fi; \
done
# Default command
CMD ["sleep", "infinity"]