zephyr provider
A zephyr stage manages a West
workspace (Zephyr RTOS).
[my-zephyr-stage]
provider = "zephyr"
(provider:/description:/disabled:/ci:/depends-on:/scripts:/env:/env-prepend:/env-append: are generic keys every stage has —
see “Generic stage keys” in Configuration. Everything below is specific to zephyr.)
Requires
west must be installed wherever this stage runs — denver never
installs it. In practice an earlier uv stage provides it, by listing
west in its requirements:.
Key reference
topdir—WEST_TOPDIR(a zephyr concept, not a denver built-in), set explicitly. Wins outright over everything else, and is exported asWEST_TOPDIR(overwriting an already-exported value) so every${WEST_TOPDIR}substitution elsewhere in this env agrees with it. Without it,WEST_TOPDIRfalls back to an already-exportedWEST_TOPDIRenv var (e.g. set by the user, or by an outer denver run before re-invoking inside docker), else discovery: walking up from the env dir for the nearest enclosing.west, or failing that, the outermost enclosing.git.exe(default:"west") — thewestexecutable, resolved onPATH.west-yml(default:<WEST_TOPDIR>/west.yml) — the manifest.base(default:${WEST_TOPDIR}/zephyr-rtos) —ZEPHYR_BASE. Thezephyr.basewest configentry itself is set separately, afterwest updateand project patches are applied, fromwest list zephyr -f {path}— i.e. wherever the manifest’s ownzephyrproject actually landed. Left untouched if the manifest has no project namedzephyr.west-config— extra/overridingwest configkey/value pairs, e.g.{zephyr.base-prefer: env}.blobs-cache— a path to an auto-generated list of west blobs to pre-cache.blobs-fetch-args(default["--auto-accept"]) — extrawest blobs fetchargs.skip-blobs-fetch(defaultfalse) — skipwest blobs fetchentirely.blobs-fetch-allow-failure(defaultfalse) — don’t fail the stage ifwest blobs fetchexits non-zero (e.g. a flaky blob host). Ignored ifskip-blobs-fetch:is set.patch-committer-name/patch-committer-email/patch-committer-date— the identity used when applying project patches viawest patches(GIT_COMMITTER_NAME/_EMAIL/_DATE), defaulting todenver/denver@denver/2000-01-01T00:00:00(a fixed value, so applying the same patches twice never produces a different commit).update-args— extrawest updateargs.skip-update(defaultfalse) — skipwest updateentirely (patch application,zephyr.base, and blobs fetch/cache still run).skip-patch-apply(defaultfalse) — skip applying projects’patches.yml(seepatches-yml-path:) viawest patches.patches-yml-path(default["zephyr/patches.yml"]) — a list of paths, each relative to a west project’s own directory, checked for apatches.ymlto apply viawest patch --patch-yml. Every listed path that exists in a given project is applied (all of them, not just the first match), in the order listed.
WEST_CONFIG_SYSTEM (west’s own base-config env var, e.g. the
remotes/defaults denver ships) is not a denver.yml key — set it
directly via env:/hooks.env like any other real environment variable;
west reads it itself, no provider-specific handling needed.
Design notes
west packages pipis a separate concern. Installing the Python packages a workspace’s own modules declare (west packages pip) isn’t this provider’s job — give a separateuvstage arequirements: [$(west packages pip)]entry instead (seeuv.md), with its ownoverrides:/freeze-to:for pinning them. It has to run after this stage, since until the workspace is updated there’s no way to know what those packages even are.Broken
update.auto-cacheentries are removed beforewest update. With west’supdate.auto-cacheset, an interruptedgit clone --mirror(Ctrl+C, a cancelled CI job, a dropped network) leaves an empty bare repo with no refs in the cache. west never repairs an existing entry, so every laterwest updatefails withupload-pack: not our ref. Right before eachwest update, this stage therefore removes every<auto-cache>/<project>/<hash>/entry that has no refs at all (one info line each), and west recreates it. A mirror that is merely out of date is kept. Nothing happens ifupdate.auto-cacheis unset or the dir does not exist, or whenwest updateitself doesn’t run (skip-update:,--fast, or nothing changed since the last run).--cialways adds a fixed shallow-clone strategy (--narrow -o=--depth=1) towest update, on top of whateverupdate-args:already configures.west updatechecks out with parallel workers. It runs with git’scheckout.workers=0(git >= 2.32, one worker per CPU), passed viaGIT_CONFIG_COUNT/GIT_CONFIG_KEY_<n>/GIT_CONFIG_VALUE_<n>(appended to any the environment already has), so no git config file is changed.Patches of different modules are applied in parallel.
west patchapplies one patch after the other and has no jobs option of its own. So for apatches.ymlwhose patches name amodule:, there is onewest patch --dst-module <module> applyper destination module, run in parallel throughxargs -P <CPUs>; the patches of one module stay in order. Apatches.ymlwithout anymodule:is applied in one go, as before.--fastonly checks the workspace is already configured — dies with a clear message if it isn’t, rather than runningwest update.--forcealways rerunswest update(even if this stage’s own drift check found nothing new) and recreates the workspace setup steps’ own on-disk state unconditionally.--dry-runprints thewestcommands instead of running them, and writes neither.west/config, the drift fingerprint, norblobs-cache:, nor removes any broken auto-cache entry (it is reported asrm -rinstead). The read-only queries this stage branches on (west config -l,west config update.auto-cache,west manifest --resolve,west list,git rev-parse,git for-each-ref) do still run: they are what decide whichwest configkeys differ, whetherwest updatewould be skipped as unchanged, which projects carry apatches.yml, and which auto-cache entries are broken.