snix_build/buildservice/build_request.rs
1use std::collections::{BTreeMap, BTreeSet, HashSet};
2use std::path::PathBuf;
3
4use bytes::Bytes;
5use snix_castore::{Node, PathComponent};
6/// A BuildRequest describes the request of something to be run on the builder.
7/// It is distinct from an actual \[Build\] that has already happened, or might be
8/// currently ongoing.
9///
10/// A BuildRequest can be seen as a more normalized version of a Derivation
11/// (parsed from A-Term), "writing out" some of the Nix-internal details about
12/// how e.g. environment variables in the build are set.
13///
14/// Nix has some impurities when building a Derivation, for example the --cores option
15/// ends up as an environment variable in the build, that's not part of the ATerm.
16///
17/// As of now, we serialize this into the BuildRequest, so builders can stay dumb.
18/// This might change in the future.
19///
20/// There's also a big difference when it comes to how inputs are modelled:
21///
22/// * Nix only uses store path (strings) to describe the inputs.
23/// As store paths can be input-addressed, a certain store path can contain
24/// different contents (as not all store paths are binary reproducible).
25/// This requires that for every input-addressed input, the builder has access
26/// to either the input's deriver (and needs to build it) or else a trusted
27/// source for the built input.
28/// to upload input-addressed paths, requiring the trusted users concept.
29/// * snix-build records a list of snix.castore.v1.Node as inputs.
30/// These map from the store path base name to their contents, relieving the
31/// builder from having to "trust" any input-addressed paths, contrary to Nix.
32///
33/// While this approach gives a better hermeticity, it has one downside:
34/// A BuildRequest can only be sent once the contents of all its inputs are known.
35///
36/// As of now, we're okay to accept this, but it prevents uploading an
37/// entirely-non-IFD subgraph of BuildRequests eagerly.
38#[derive(Default, Debug, Clone, PartialEq)]
39pub struct BuildRequest {
40 /// The list of all root nodes that should be visible in `inputs_dir` at the
41 /// time of the build.
42 /// As all references are content-addressed, no additional signatures are
43 /// needed to substitute / make these available in the build environment.
44 pub inputs: BTreeMap<PathComponent, Node>,
45 /// The command (and its args) executed as the build script.
46 /// In the case of a Nix derivation, this is usually
47 /// \["/path/to/some-bash/bin/bash", "-e", "/path/to/some/builder.sh"\].
48 pub command_args: Vec<String>,
49 /// The working dir of the command, relative to the build root.
50 /// "build", in the case of Nix.
51 /// This MUST be a clean relative path, without any ".", "..", or superfluous
52 /// slashes.
53 pub working_dir: PathBuf,
54 /// A list of "scratch" paths, relative to the build root.
55 /// These will be write-able during the build.
56 /// \[build, nix/store\] in the case of Nix.
57 /// These MUST be clean relative paths, without any ".", "..", or superfluous
58 /// slashes, and sorted.
59 pub scratch_paths: Vec<PathBuf>,
60 /// The path where the castore input nodes will be located at,
61 /// "nix/store" in case of Nix.
62 /// Builds might also write into here (Nix builds do that).
63 /// This MUST be a clean relative path, without any ".", "..", or superfluous
64 /// slashes.
65 pub inputs_dir: PathBuf,
66 /// The list of output paths the build is expected to produce,
67 /// relative to the root.
68 /// If the path is not produced, the build is considered to have failed.
69 /// These MUST be clean relative paths, without any ".", "..", or superfluous
70 /// slashes, and sorted.
71 pub outputs: Vec<PathBuf>,
72 /// The list of environment variables and their values that should be set
73 /// inside the build environment.
74 /// This includes both environment vars set inside the derivation, as well as
75 /// more "ephemeral" ones like NIX_BUILD_CORES, controlled by the `--cores`
76 /// CLI option of `nix-build`.
77 /// For now, we consume this as an option when turning a Derivation into a BuildRequest,
78 /// similar to how Nix has a `--cores` option.
79 /// We don't want to bleed these very nix-specific sandbox impl details into
80 /// (dumber) builders if we don't have to.
81 /// Environment variables are sorted by their keys.
82 pub environment_vars: Vec<EnvVar>,
83 /// A set of constraints that need to be satisfied on a build host before a
84 /// Build can be started.
85 pub constraints: HashSet<BuildConstraints>,
86 /// Additional (small) files and their contents that should be placed into the
87 /// build environment, but outside inputs_dir.
88 /// Used for passAsFile and structuredAttrs in Nix.
89 pub additional_files: Vec<AdditionalFile>,
90 /// If this is an non-empty list, all paths in `outputs` are scanned for these.
91 /// For Nix, `refscan_needles` would be populated with the nixbase32 hash parts of
92 /// every input store path and output store path. The latter is necessary to scan
93 /// for references between multi-output derivations.
94 pub refscan_needles: Vec<String>,
95}
96
97#[derive(Debug, Clone, PartialEq)]
98pub struct EnvVar {
99 /// name of the environment variable. Must not contain =.
100 pub key: String,
101 pub value: Bytes,
102}
103/// BuildConstraints represents certain conditions that must be fulfilled
104/// inside the build environment to be able to build this.
105/// Constraints can be things like required architecture and minimum amount of memory.
106/// The required input paths are *not* represented in here, because it
107/// wouldn't be hermetic enough - see the comment around inputs too.
108#[derive(Debug, Clone, PartialEq, Eq, Hash)]
109pub enum BuildConstraints {
110 /// The system that's needed to execute the build.
111 /// Must not be empty.
112 System(String),
113 /// The amount of memory required to be available for the build, in bytes.
114 MinMemory(u64),
115 /// An absolute path that need to be available in the build
116 /// environment, like `/dev/kvm`.
117 /// This is distinct from the castore nodes in inputs.
118 /// These MUST be clean absolute paths, without any ".", "..", or superfluous
119 /// slashes, and sorted.
120 AvailableReadOnlyPath(PathBuf),
121 /// Whether the build should be able to access the network.
122 NetworkAccess,
123 /// Whether to provide a /bin/sh inside the build environment, usually a static bash.
124 ProvideBinSh,
125}
126
127#[derive(Debug, Clone, PartialEq)]
128pub struct AdditionalFile {
129 pub path: PathBuf,
130 pub contents: Bytes,
131}
132
133/// Describes the result of a [BuildRequest].
134#[derive(Debug, Clone, PartialEq)]
135pub struct BuildResult {
136 /// The outputs that were produced after successfully building.
137 // They are sorted by the order specified in the build request.
138 pub outputs: Vec<BuildOutput>,
139}
140
141/// Specific information about an individual output in [BuildResult].
142#[derive(Debug, Clone, PartialEq)]
143pub struct BuildOutput {
144 /// The castore node describing the contents.
145 pub node: Node,
146 /// Indexes into the found [BuildRequest::refscan_needles] in that output.
147 pub output_needles: BTreeSet<u64>,
148}