CI: Cache archives downloaded by apt (#8159)

Belt-and-braces in case GitHub apt mirrors start acting up again: On any
successful apt install, cache the deb files downloaded/needed for the
step, so on next run the mirrors need not be consulted. (That is: trade
apt mirror access with GitHub cache access, which is more reliable)
This commit is contained in:
Geza Lore
2026-08-20 11:16:17 +02:00
committed by GitHub
parent e717c513e9
commit 38ae4e617d
7 changed files with 130 additions and 10 deletions
+109
View File
@@ -0,0 +1,109 @@
---
# DESCRIPTION: Github actions composite action
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
name: Install dependencies
description: >-
Install the dependencies of a CI stage with 'ci/ci-install.bash', caching the
'.deb' files apt downloads for that stage, so a package is fetched from the
network at most once per runner image. On hosts that do not use apt this is
just the install, there is nothing to cache.
inputs:
repo:
description: "Verilator checkout holding the ci/ scripts"
required: false
default: repo
stage:
description: "CI stage to install the dependencies of, e.g. 'build'"
required: true
runs:
using: composite
steps:
- name: Compute apt cache key
id: cachekey
if: ${{ runner.os == 'Linux' }}
shell: bash
working-directory: ${{ inputs.repo }}
env:
STAGE: ${{ inputs.stage }}
run: |
source ci/ci-common.bash
host="${DISTRO_ID:-$HOST_OS}${DISTRO_VERSION:+-$DISTRO_VERSION}"
echo "key=apt-${host}-${STAGE}" >> "$GITHUB_OUTPUT"
- name: Restore apt downloads
if: ${{ runner.os == 'Linux' }}
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
with:
path: ${{ runner.temp }}/apt-cache
key: ${{ steps.cachekey.outputs.key }}
restore-keys: |
${{ steps.cachekey.outputs.key }}-
- name: Seed apt archive from cache
if: ${{ runner.os == 'Linux' }}
shell: bash
env:
APT_CACHE_DIR: ${{ runner.temp }}/apt-cache
run: |
set -euo pipefail
# Ask apt where it keeps its downloads, rather than assume
eval "$(apt-config shell ARCHIVES Dir::Cache::archives/d)"
ARCHIVES=${ARCHIVES%/} # '/d' yields a trailing slash
# Wipe the archive first, so that whatever the runner image left behind is not stored
sudo apt-get -o DPkg::Lock::Timeout=60 clean
# The directory is absent when nothing was restored, e.g. on a cold start
if [ -d "$APT_CACHE_DIR" ] &&
[ -n "$(find "$APT_CACHE_DIR" -maxdepth 1 -name '*.deb' -print -quit)" ]; then
sudo cp "$APT_CACHE_DIR"/*.deb "$ARCHIVES"
fi
- name: Install dependencies
shell: bash
working-directory: ${{ inputs.repo }}
env:
STAGE: ${{ inputs.stage }}
run: ./ci/ci-install.bash "$STAGE"
- name: Collect apt downloads
id: collect
if: ${{ runner.os == 'Linux' }}
shell: bash
env:
APT_CACHE_DIR: ${{ runner.temp }}/apt-cache
run: |
set -euo pipefail
# Ask apt where it keeps its downloads, rather than assume
eval "$(apt-config shell ARCHIVES Dir::Cache::archives/d)"
ARCHIVES=${ARCHIVES%/} # '/d' yields a trailing slash
# Sorted names of the '.deb' files in a directory, empty if it has none
list-debs() {
[ -d "$1" ] || return 0
find "$1" -maxdepth 1 -name '*.deb' -printf '%f\n' | sort
}
# Superseded downloads can no longer be fetched, so drop them
sudo apt-get -o DPkg::Lock::Timeout=60 autoclean
downloaded=$(list-debs "$ARCHIVES")
if [ -z "$downloaded" ]; then
echo "Apt kept no '.deb' files, nothing to cache"
exit 0
fi
if [ "$downloaded" = "$(list-debs "$APT_CACHE_DIR")" ]; then
echo "Downloads unchanged, keeping the restored cache entry"
exit 0
fi
# Mirror the archive, rather than add to it, so that the cache cannot
# grow without bound as package versions churn
mkdir -p "$APT_CACHE_DIR"
rm -f "$APT_CACHE_DIR"/*.deb
sudo cp "$ARCHIVES"/*.deb "$APT_CACHE_DIR"
echo "changed=true" >> "$GITHUB_OUTPUT"
- name: Save apt downloads
if: ${{ steps.collect.outputs.changed == 'true' }}
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
with:
path: ${{ runner.temp }}/apt-cache
key: ${{ steps.cachekey.outputs.key }}-${{ github.run_id }}
+3 -2
View File
@@ -116,8 +116,9 @@ jobs:
ls -lsha
- name: Install dependencies
working-directory: repo
run: ./ci/ci-install.bash coverage
uses: ./repo/.github/actions/install-deps
with:
stage: coverage
- name: Download code coverage data
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
+3 -1
View File
@@ -27,7 +27,9 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install packages for build
run: ./ci/ci-install.bash format
uses: ./repo/.github/actions/install-deps
with:
stage: format
- name: Configure git identity
run: |
+3 -1
View File
@@ -90,7 +90,9 @@ jobs:
${{ env.CACHE_KEY }}
- name: Install packages for build
run: ./ci/ci-install.bash build
uses: ./repo/.github/actions/install-deps
with:
stage: build
- name: Build
run: |
+3 -1
View File
@@ -24,7 +24,9 @@ jobs:
path: repo
- name: Install dependencies
run: ./ci/ci-install.bash lint-py
uses: ./repo/.github/actions/install-deps
with:
stage: lint-py
- name: Configure
run: |
+6 -3
View File
@@ -66,11 +66,14 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
path: repo
sparse-checkout: ci
sparse-checkout: |
.github/actions
ci
- name: Install dependencies
working-directory: repo
run: ./ci/ci-install.bash rtlmeter-run
uses: ./repo/.github/actions/install-deps
with:
stage: rtlmeter-run
- name: Checkout RTLMeter
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
+3 -2
View File
@@ -85,8 +85,9 @@ jobs:
key: ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.suite }}
- name: Install test dependencies
run: |
./ci/ci-install.bash test
uses: ./repo/.github/actions/install-deps
with:
stage: test
- name: Set up Python venv
uses: ./repo/.github/actions/setup-venv