antlir2 depgraph
antlir2 ships with an image-aware dependency graph that sits alongside the
buck2 dependency graph. When put together, they enable antlir2 to
intelligently cache image layers and even phases within a single layer.
Build Phases
A porcelain image.layer target is internally represented as one or more
image.layers chained together with parent_layer, depending on the features
that are being used.
Each BuildPhase results in a single antlir2 build operation that produces
exactly one of these internal layers at a time. Within that build, the antlir2
depgraph is used for ordering features.
Every feature type corresponds to a default BuildPhase, used to run
unpredictable features (where antlir2 cannot determine what files that feature
requires or produces) in a well-defined order.
build_phase.bzl has a complete list of the BuildPhases that antlir2 uses,
but it generally operates in this order:
- Install packages
- Run arbitrary genrules
- Removals with
feature.remove - Well behaved features (everything else)
- Build info stamping
In this page, the term "layer" generally refers to one of these internal layers
for each phase, rather than the porcelain image.layer target.
buck2 target graph
The buck2 dependency graph is the top-level mechanism that causes antlir2 rebuilds.
If the input to a feature changes (for example, a source file changed that causes a binary to be rebuilt, and that binary is installed in an image), everything downstream of that feature must be rebuilt.
If the input to a layer changes (for example, a feature changed, or its
parent_layer changed), that layer and everything downstream of it must be
rebuilt.
antlir2 depgraph
The antlir2 depgraph is used only for correctness, not cache invalidation
(buck2 simply does not invoke antlir2 if nothing has changed).
"Correctness" has a few key components:
- Ordering features so they compile safely - examples:
- Parent directories need to exist before installing files
- User must exist before extending their group membership
- Entities satisfy certain requirements - examples:
- User homedir must exist and be a directory
- Symlink targets need to exist
- Running a command requires argv[0] to exist and be executable
- Failing on any conflicts - examples:
- Install both 'a' and 'b' to '/c'
- Overwrite file installed by an rpm
- Create same user twice with different settings
Requires / Provides
Requires and Provides are the mechanisms by which antlir2 can provide the
correctness properties described above.
Every feature must declare what entities (files, users, etc) it creates, and any that it requires (either before or concurrently to) building.
When this information is exhaustive - as it is for well-behaved features (not
rpms or genrules) - this is enough for antlir2 to detect conflicts, any
missing dependencies and lastly topologically sort features to be executed in
the correct order)