use std::collections::{BTreeMap, HashSet};
use std::path::PathBuf;
use bytes::Bytes;
use tvix_castore::{Node, PathComponent};
/// A BuildRequest describes the request of something to be run on the builder.
/// It is distinct from an actual \[Build\] that has already happened, or might be
/// currently ongoing.
///
/// A BuildRequest can be seen as a more normalized version of a Derivation
/// (parsed from A-Term), "writing out" some of the Nix-internal details about
/// how e.g. environment variables in the build are set.
///
/// Nix has some impurities when building a Derivation, for example the --cores option
/// ends up as an environment variable in the build, that's not part of the ATerm.
///
/// As of now, we serialize this into the BuildRequest, so builders can stay dumb.
/// This might change in the future.
///
/// There's also a big difference when it comes to how inputs are modelled:
///
/// * Nix only uses store path (strings) to describe the inputs.
/// As store paths can be input-addressed, a certain store path can contain
/// different contents (as not all store paths are binary reproducible).
/// This requires that for every input-addressed input, the builder has access
/// to either the input's deriver (and needs to build it) or else a trusted
/// source for the built input.
/// to upload input-addressed paths, requiring the trusted users concept.
/// * tvix-build records a list of tvix.castore.v1.Node as inputs.
/// These map from the store path base name to their contents, relieving the
/// builder from having to "trust" any input-addressed paths, contrary to Nix.
///
/// While this approach gives a better hermeticity, it has one downside:
/// A BuildRequest can only be sent once the contents of all its inputs are known.
///
/// As of now, we're okay to accept this, but it prevents uploading an
/// entirely-non-IFD subgraph of BuildRequests eagerly.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct BuildRequest {
/// The list of all root nodes that should be visible in `inputs_dir` at the
/// time of the build.
/// As all references are content-addressed, no additional signatures are
/// needed to substitute / make these available in the build environment.
pub inputs: BTreeMap<PathComponent, Node>,
/// The command (and its args) executed as the build script.
/// In the case of a Nix derivation, this is usually
/// \["/path/to/some-bash/bin/bash", "-e", "/path/to/some/builder.sh"\].
pub command_args: Vec<String>,
/// The working dir of the command, relative to the build root.
/// "build", in the case of Nix.
/// This MUST be a clean relative path, without any ".", "..", or superfluous
/// slashes.
pub working_dir: PathBuf,
/// A list of "scratch" paths, relative to the build root.
/// These will be write-able during the build.
/// \[build, nix/store\] in the case of Nix.
/// These MUST be clean relative paths, without any ".", "..", or superfluous
/// slashes, and sorted.
pub scratch_paths: Vec<PathBuf>,
/// The path where the castore input nodes will be located at,
/// "nix/store" in case of Nix.
/// Builds might also write into here (Nix builds do that).
/// This MUST be a clean relative path, without any ".", "..", or superfluous
/// slashes.
pub inputs_dir: PathBuf,
/// The list of output paths the build is expected to produce,
/// relative to the root.
/// If the path is not produced, the build is considered to have failed.
/// These MUST be clean relative paths, without any ".", "..", or superfluous
/// slashes, and sorted.
pub outputs: Vec<PathBuf>,
/// The list of environment variables and their values that should be set
/// inside the build environment.
/// This includes both environment vars set inside the derivation, as well as
/// more "ephemeral" ones like NIX_BUILD_CORES, controlled by the `--cores`
/// CLI option of `nix-build`.
/// For now, we consume this as an option when turning a Derivation into a BuildRequest,
/// similar to how Nix has a `--cores` option.
/// We don't want to bleed these very nix-specific sandbox impl details into
/// (dumber) builders if we don't have to.
/// Environment variables are sorted by their keys.
pub environment_vars: Vec<EnvVar>,
/// A set of constraints that need to be satisfied on a build host before a
/// Build can be started.
pub constraints: HashSet<BuildConstraints>,
/// Additional (small) files and their contents that should be placed into the
/// build environment, but outside inputs_dir.
/// Used for passAsFile and structuredAttrs in Nix.
pub additional_files: Vec<AdditionalFile>,
/// If this is an non-empty list, all paths in `outputs` are scanned for these.
/// For Nix, `refscan_needles` would be populated with the nixbase32 hash parts of
/// every input store path and output store path. The latter is necessary to scan
/// for references between multi-output derivations.
pub refscan_needles: Vec<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EnvVar {
/// name of the environment variable. Must not contain =.
pub key: String,
pub value: Bytes,
}
/// BuildConstraints represents certain conditions that must be fulfilled
/// inside the build environment to be able to build this.
/// Constraints can be things like required architecture and minimum amount of memory.
/// The required input paths are *not* represented in here, because it
/// wouldn't be hermetic enough - see the comment around inputs too.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum BuildConstraints {
/// The system that's needed to execute the build.
/// Must not be empty.
System(String),
/// The amount of memory required to be available for the build, in bytes.
MinMemory(u64),
/// An absolute path that need to be available in the build
/// environment, like `/dev/kvm`.
/// This is distinct from the castore nodes in inputs.
/// These MUST be clean absolute paths, without any ".", "..", or superfluous
/// slashes, and sorted.
AvailableReadOnlyPath(PathBuf),
/// Whether the build should be able to access the network.
NetworkAccess,
/// Whether to provide a /bin/sh inside the build environment, usually a static bash.
ProvideBinSh,
}
#[derive(Debug, Clone, PartialEq)]
pub struct AdditionalFile {
pub path: PathBuf,
pub contents: Bytes,
}