2023-01-16 15:24:02 +01:00
|
|
|
use crate::{derivation::Derivation, write::DOT_FILE_EXT, ValidateDerivationError};
|
2023-01-06 16:56:38 +01:00
|
|
|
use tvix_store::store_path::StorePath;
|
2023-01-04 13:38:28 +01:00
|
|
|
|
|
|
|
impl Derivation {
|
|
|
|
/// validate ensures a Derivation struct is properly populated,
|
2023-01-16 15:24:02 +01:00
|
|
|
/// and returns a [ValidateDerivationError] if not.
|
|
|
|
pub fn validate(&self) -> Result<(), ValidateDerivationError> {
|
2023-01-04 13:38:28 +01:00
|
|
|
// Ensure the number of outputs is > 1
|
|
|
|
if self.outputs.is_empty() {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::NoOutputs());
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validate all outputs
|
|
|
|
for (output_name, output) in &self.outputs {
|
2023-01-17 11:56:23 +01:00
|
|
|
// empty output names are invalid.
|
|
|
|
//
|
|
|
|
// `drv` is an invalid output name too, as this would cause
|
|
|
|
// a `builtins.derivation` call to return an attrset with a
|
|
|
|
// `drvPath` key (which already exists) and has a different
|
|
|
|
// meaning.
|
|
|
|
//
|
|
|
|
// Other output names that don't match the name restrictions from
|
|
|
|
// [StorePath] will fail output path calculation.
|
|
|
|
if output_name.is_empty() || output_name == "drv" {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidOutputName(
|
|
|
|
output_name.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if output.is_fixed() {
|
|
|
|
if self.outputs.len() != 1 {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::MoreThanOneOutputButFixed());
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
if output_name != "out" {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidOutputNameForFixed(
|
|
|
|
output_name.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-01-16 15:24:02 +01:00
|
|
|
if let Err(e) = output.validate() {
|
|
|
|
return Err(ValidateDerivationError::InvalidOutputPath(
|
|
|
|
output_name.to_string(),
|
|
|
|
e,
|
|
|
|
));
|
|
|
|
};
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validate all input_derivations
|
|
|
|
for (input_derivation_path, output_names) in &self.input_derivations {
|
|
|
|
// Validate input_derivation_path
|
2023-01-16 15:24:02 +01:00
|
|
|
if let Err(e) = StorePath::from_absolute_path(input_derivation_path) {
|
|
|
|
return Err(ValidateDerivationError::InvalidInputDerivationPath(
|
|
|
|
input_derivation_path.to_string(),
|
|
|
|
e,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2023-01-04 13:38:28 +01:00
|
|
|
if !input_derivation_path.ends_with(DOT_FILE_EXT) {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidInputDerivationPrefix(
|
|
|
|
input_derivation_path.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if output_names.is_empty() {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::EmptyInputDerivationOutputNames(
|
|
|
|
input_derivation_path.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
2023-01-13 18:19:48 +01:00
|
|
|
for output_name in output_names.iter() {
|
2023-01-17 11:56:23 +01:00
|
|
|
// empty output names are invalid.
|
|
|
|
//
|
|
|
|
// `drv` is an invalid output name too, as this would cause
|
|
|
|
// a `builtins.derivation` call to return an attrset with a
|
|
|
|
// `drvPath` key (which already exists) and has a different
|
|
|
|
// meaning.
|
|
|
|
//
|
|
|
|
// Other output names that don't match the name restrictions
|
|
|
|
// from [StorePath] can't be constructed with this library, but
|
|
|
|
// are not explicitly checked here (yet).
|
|
|
|
if output_name.is_empty() || output_name == "drv" {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidInputDerivationOutputName(
|
|
|
|
input_derivation_path.to_string(),
|
|
|
|
output_name.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate all input_sources
|
2023-01-16 15:25:08 +01:00
|
|
|
for input_source in self.input_sources.iter() {
|
2023-01-16 15:24:02 +01:00
|
|
|
if let Err(e) = StorePath::from_absolute_path(input_source) {
|
|
|
|
return Err(ValidateDerivationError::InvalidInputSourcesPath(
|
|
|
|
input_source.to_string(),
|
|
|
|
e,
|
|
|
|
));
|
|
|
|
}
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// validate platform
|
|
|
|
if self.system.is_empty() {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidPlatform(
|
|
|
|
self.system.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// validate builder
|
|
|
|
if self.builder.is_empty() {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidBuilder(
|
|
|
|
self.builder.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// validate env, none of the keys may be empty.
|
|
|
|
// We skip the `name` validation seen in go-nix.
|
|
|
|
for k in self.environment.keys() {
|
|
|
|
if k.is_empty() {
|
2023-01-16 15:24:02 +01:00
|
|
|
return Err(ValidateDerivationError::InvalidEnvironmentKey(
|
|
|
|
k.to_string(),
|
|
|
|
));
|
2023-01-04 13:38:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|