Download gtk from cache #129

Closed
opened 2026-05-20 12:44:59 +00:00 by guettli · 3 comments
guettli commented 2026-05-20 12:44:59 +00:00 (Migrated from codeberg.org)

Implement:

flutter precache --linux in toolchain()

like explained in below comment.

Implement: flutter precache --linux in toolchain() like explained in below comment.
guettlibot commented 2026-05-21 05:00:31 +00:00 (Migrated from codeberg.org)

Plan: Cache flutter-gtk Tool Downloads

Root cause

When any Flutter command runs on Linux (including flutter test for unit tests that use Flutter's test runner), Flutter checks its internal artifact cache at $FLUTTER_ROOT/bin/cache/artifacts/engine/ and downloads missing platform tools on demand. The three variants — linux-x64-debug, linux-x64-profile, linux-x64-release — add ~18 seconds of downloads on every cold start.

The ghcr.io/cirruslabs/flutter:3.41.6 image does not pre-bundle these Linux engine artifacts, so they are downloaded the first time any Flutter command triggers them in the container.

These downloads happen inside the containers created by toolchain(), before any Dagger execution cache can intercept them. Because toolchain() currently has no step that downloads the artifacts, the download falls outside the cached layer.


Recommended fix: flutter precache --linux in toolchain()

Add a flutter precache step to the toolchain() function in ci/main.go:

func (m *Ci) toolchain() *dagger.Container {
    return dag.Container().
        From("ghcr.io/cirruslabs/flutter:3.41.6").
        WithExec([]string{"apt-get", "update"}).
        WithExec([]string{"apt-get", "install", "-y", "clang", "cmake", ...}).
        WithEnvVariable("PUB_CACHE", "/root/.pub-cache").
        WithExec([]string{"/bin/sh", "-c", `yes | sdkmanager ...`}).
        WithExec([]string{"flutter", "precache", "--linux", "--no-android", "--no-ios"})  // ← add this
}

flutter precache --linux downloads exactly the three GTK artifact variants (debug, profile, release) into Flutter's bin/cache and exits. The artifacts are baked into the container layer.

Why this works well:

  • toolchain() already has stable execution caching (no mutable cache volume mounts). Dagger's execution cache captures the entire toolchain() chain including the pre-downloaded artifacts.
  • After the first build, subsequent toolchain() calls reuse the cached layer — no downloads.
  • This is the same pattern already used for Android SDK components (sdkmanager is also baked into the layer).
  • The cache is invalidated only when the Flutter image version changes (3.41.63.42.x), which is the correct granularity.

One-time cost: ~18s of downloads on the first run after a Flutter version bump. Zero cost on every subsequent run.


Alternative considered: WithMountedCache for Flutter's bin/cache

Mount a Dagger cache volume at $FLUTTER_ROOT/bin/cache. The GTK artifacts are downloaded once and reused via the volume.

Problem: Same issue as the old flutter-pub-cache volume — a mutable WithMountedCache makes the container's execution cache key unstable. Every subsequent container that mounts the volume sees an unpredictable hash, causing execution cache misses for dart format, dart analyze, and unit tests.

Not recommended for the same reason we removed the pub-cache volume from pubGetLayer().


Summary

flutter precache in toolchain() WithMountedCache for bin/cache
GTK downloads after first run 0 0
Execution cache stability ✓ stable ✗ unstable (causes cascade misses)
Implementation complexity 1 line 1 line + risk of cache instability

Recommended: add WithExec([]string{"flutter", "precache", "--linux", "--no-android", "--no-ios"}) to toolchain(), placed after the sdkmanager step.

## Plan: Cache flutter-gtk Tool Downloads ### Root cause When any Flutter command runs on Linux (including `flutter test` for unit tests that use Flutter's test runner), Flutter checks its internal artifact cache at `$FLUTTER_ROOT/bin/cache/artifacts/engine/` and downloads missing platform tools on demand. The three variants — `linux-x64-debug`, `linux-x64-profile`, `linux-x64-release` — add ~18 seconds of downloads on every cold start. The `ghcr.io/cirruslabs/flutter:3.41.6` image does not pre-bundle these Linux engine artifacts, so they are downloaded the first time any Flutter command triggers them in the container. These downloads happen inside the containers created by `toolchain()`, before any Dagger execution cache can intercept them. Because `toolchain()` currently has no step that downloads the artifacts, the download falls outside the cached layer. --- ### Recommended fix: `flutter precache --linux` in `toolchain()` Add a `flutter precache` step to the `toolchain()` function in `ci/main.go`: ```go func (m *Ci) toolchain() *dagger.Container { return dag.Container(). From("ghcr.io/cirruslabs/flutter:3.41.6"). WithExec([]string{"apt-get", "update"}). WithExec([]string{"apt-get", "install", "-y", "clang", "cmake", ...}). WithEnvVariable("PUB_CACHE", "/root/.pub-cache"). WithExec([]string{"/bin/sh", "-c", `yes | sdkmanager ...`}). WithExec([]string{"flutter", "precache", "--linux", "--no-android", "--no-ios"}) // ← add this } ``` `flutter precache --linux` downloads exactly the three GTK artifact variants (debug, profile, release) into Flutter's bin/cache and exits. The artifacts are baked into the container layer. **Why this works well:** - `toolchain()` already has stable execution caching (no mutable cache volume mounts). Dagger's execution cache captures the entire `toolchain()` chain including the pre-downloaded artifacts. - After the first build, subsequent `toolchain()` calls reuse the cached layer — no downloads. - This is the same pattern already used for Android SDK components (`sdkmanager` is also baked into the layer). - The cache is invalidated only when the Flutter image version changes (`3.41.6` → `3.42.x`), which is the correct granularity. **One-time cost:** ~18s of downloads on the first run after a Flutter version bump. Zero cost on every subsequent run. --- ### Alternative considered: `WithMountedCache` for Flutter's bin/cache Mount a Dagger cache volume at `$FLUTTER_ROOT/bin/cache`. The GTK artifacts are downloaded once and reused via the volume. **Problem:** Same issue as the old `flutter-pub-cache` volume — a mutable `WithMountedCache` makes the container's execution cache key unstable. Every subsequent container that mounts the volume sees an unpredictable hash, causing execution cache misses for `dart format`, `dart analyze`, and unit tests. Not recommended for the same reason we removed the pub-cache volume from `pubGetLayer()`. --- ### Summary | | `flutter precache` in `toolchain()` | `WithMountedCache` for bin/cache | |---|---|---| | GTK downloads after first run | 0 | 0 | | Execution cache stability | ✓ stable | ✗ unstable (causes cascade misses) | | Implementation complexity | 1 line | 1 line + risk of cache instability | **Recommended:** add `WithExec([]string{"flutter", "precache", "--linux", "--no-android", "--no-ios"})` to `toolchain()`, placed after the `sdkmanager` step.
guettli commented 2026-05-21 08:20:40 +00:00 (Migrated from codeberg.org)

done

done
guettlibot commented 2026-05-23 08:30:07 +00:00 (Migrated from codeberg.org)

The agent exited without pushing any changes (no new CI run was triggered). This usually means the agent hit a rate limit or crashed at startup. The issue has been set to State/Question — please review the agent log and retry.

The agent exited without pushing any changes (no new CI run was triggered). This usually means the agent hit a rate limit or crashed at startup. The issue has been set to State/Question — please review the agent log and retry.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: guettli/sharedinbox#129