Skip to content

Commit

Permalink
refactor: introduce custom type for build string in recipe
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Aug 16, 2024
1 parent e04d897 commit 920e032
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ pub fn vars(output: &Output, build_state: &str) -> HashMap<String, String> {
.recipe
.build()
.string()
.map(|s| s.to_string())
.unwrap_or_else(|| hash.to_string())
.resolve(&hash, output.recipe.build().number)
.into_owned()
);
insert!(vars, "PKG_HASH", hash);

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ pub async fn get_build_output(
build_string: recipe
.build()
.string()
.map(ToString::to_string)
.unwrap_or_else(|| format!("{}_{}", hash, recipe.build().number())),
.resolve(&hash, recipe.build().number())
.into_owned(),
},
);

Expand Down
13 changes: 4 additions & 9 deletions src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,10 @@ impl Output {
/// The build string is either the build string from the recipe or computed
/// from the hash and build number.
pub fn build_string(&self) -> Cow<'_, str> {
if let Some(build) = self.recipe.build().string() {
build.into()
} else {
format!(
"{}_{}",
&self.build_configuration.hash, self.recipe.build.number
)
.into()
}
self.recipe
.build()
.string
.resolve(&self.build_configuration.hash, self.recipe.build().number)
}

/// The channels to use when resolving dependencies
Expand Down
3 changes: 2 additions & 1 deletion src/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use url::Url;

/// Application subcommands.
#[derive(Parser)]
#[allow(clippy::large_enum_variant)]
pub enum SubCommands {
/// Build a package from a recipe
Build(BuildOpts),
Expand Down Expand Up @@ -358,7 +359,7 @@ fn is_dir(dir: &str) -> Result<PathBuf, String> {
/// Parse a single key-value pair
fn parse_key_val(s: &str) -> Result<(String, Value), Box<dyn Error + Send + Sync + 'static>> {
let (key, value) = s
.split_once("=")
.split_once('=')
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
Ok((key.to_string(), json!(value)))
}
Expand Down
86 changes: 81 additions & 5 deletions src/recipe/parser/build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::str::FromStr;

use rattler_conda_types::{package::EntryPoint, NoArchType};
Expand All @@ -9,6 +10,7 @@ use crate::recipe::custom_yaml::RenderedSequenceNode;
use crate::recipe::parser::script::Script;
use crate::recipe::parser::skip::Skip;

use crate::hash::HashInfo;
use crate::validate_keys;
use crate::{
_partialerror,
Expand Down Expand Up @@ -72,8 +74,8 @@ pub struct Build {
pub number: u64,
/// The build string is usually set automatically as the hash of the variant configuration.
/// It's possible to override this by setting it manually, but not recommended.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub string: Option<String>,
#[serde(default, skip_serializing_if = "BuildString::is_derived")]
pub string: BuildString,
/// List of conditions under which to skip the build of the package.
#[serde(default, skip)]
pub skip: Skip,
Expand Down Expand Up @@ -113,6 +115,80 @@ pub struct Build {
pub files: GlobVec,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(from = "Option<String>", into = "Option<String>")]
pub enum BuildString {
/// The build string is explicitly set by the user.
UserSpecified(String),

/// The build string should be derived from the variants
#[default]
Derived,
}

impl From<Option<String>> for BuildString {
fn from(value: Option<String>) -> Self {
value.map_or_else(|| BuildString::Derived, BuildString::UserSpecified)
}
}

impl From<BuildString> for Option<String> {
fn from(value: BuildString) -> Self {
match value {
BuildString::UserSpecified(s) => Some(s),
BuildString::Derived => None,
}
}
}

impl From<String> for BuildString {
fn from(value: String) -> Self {
BuildString::UserSpecified(value)
}
}

impl BuildString {
/// Returns true if the build string should be derived from the variants.
pub fn is_derived(&self) -> bool {
matches!(self, BuildString::Derived)
}

/// Returns the user specified build string.
pub fn as_deref(&self) -> Option<&str> {
match self {
BuildString::UserSpecified(s) => Some(s),
BuildString::Derived => None,
}
}

/// Returns the final build string, either based on the user defined value or by computing the derived value.
pub fn resolve(&self, hash: &HashInfo, build_number: u64) -> Cow<'_, str> {
match self {
BuildString::UserSpecified(s) => s.as_str().into(),
BuildString::Derived => Self::compute(hash, build_number).into(),
}
}

/// Compute the build string based on the hash and build number
pub fn compute(hash: &HashInfo, build_number: u64) -> String {
format!("{}_{}", hash, build_number)
}
}

impl TryConvertNode<BuildString> for RenderedNode {
fn try_convert(&self, name: &str) -> Result<BuildString, Vec<PartialParsingError>> {
self.as_scalar()
.ok_or_else(|| vec![_partialerror!(*self.span(), ErrorKind::ExpectedScalar)])
.and_then(|m| m.try_convert(name))
}
}

impl TryConvertNode<BuildString> for RenderedScalarNode {
fn try_convert(&self, _name: &str) -> Result<BuildString, Vec<PartialParsingError>> {
Ok(BuildString::UserSpecified(self.as_str().to_owned()))
}
}

/// Post process operations for regex based replacements
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostProcess {
Expand All @@ -138,8 +214,8 @@ impl Build {
}

/// Get the build string.
pub fn string(&self) -> Option<&str> {
self.string.as_deref()
pub fn string(&self) -> &BuildString {
&self.string
}

/// Get the skip conditions.
Expand Down Expand Up @@ -476,7 +552,7 @@ impl RunExports {
}

/// Get all run exports from all configurations
pub fn all(&self) -> impl Iterator<Item = &Dependency> {
pub fn all(&self) -> impl Iterator<Item=&Dependency> {
self.noarch
.iter()
.chain(self.strong.iter())
Expand Down
11 changes: 7 additions & 4 deletions src/variant_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,8 +715,8 @@ impl VariantConfig {
let build_string = parsed_recipe
.build()
.string()
.unwrap_or(&hash.to_string())
.to_string();
.resolve(&hash, parsed_recipe.build().number)
.into_owned();

other_recipes.insert(
parsed_recipe.package().name().as_normalized().to_string(),
Expand All @@ -725,8 +725,11 @@ impl VariantConfig {
parsed_recipe
.build()
.string()
.unwrap_or(&hash.to_string())
.to_string(),
.resolve(
&hash,
parsed_recipe.build().number,
)
.into_owned(),
used_filtered.clone(),
),
);
Expand Down

0 comments on commit 920e032

Please sign in to comment.