diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 38035aecf4..d90e7a1d81 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -378,6 +378,11 @@ pub mod ffi { basearch: &str, workdir: i32, ) -> Result>; + fn treefile_new_client( + filename: &str, + basearch: &str, + workdir: i32, + ) -> Result>; fn get_workdir(&self) -> i32; fn get_passwd_fd(&mut self) -> i32; diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index 8b7b02610d..b09afd2cd0 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -774,11 +774,6 @@ impl Treefile { } } } - if config.base.repos.is_none() && config.base.lockfile_repos.is_none() { - return Err(anyhow!( - r#"Treefile has neither "repos" nor "lockfile-repos""# - )); - } if let Some(version_suffix) = config.base.automatic_version_suffix.as_ref() { if !(version_suffix.len() == 1 && version_suffix.is_ascii()) { return Err(io::Error::new( @@ -794,6 +789,16 @@ impl Treefile { Ok(()) } + /// Do some upfront semantic checks we can do beyond just the type safety serde provides. + fn validate_base_config(config: &TreeComposeConfig) -> Result<()> { + if config.base.repos.is_none() && config.base.lockfile_repos.is_none() { + return Err(anyhow!( + r#"Treefile has neither "repos" nor "lockfile-repos""# + )); + } + Ok(()) + } + fn serialize_json_string(config: &TreeComposeConfig) -> Result { let output = serde_json::to_string_pretty(config)?; Ok(CUtf8Buf::from_string(output)) @@ -804,6 +809,11 @@ impl Treefile { self.parsed.derive.error_if_nonempty() } + /// Throw an error if any base fields are set. + pub(crate) fn error_if_base(&self) -> Result<()> { + self.parsed.base.error_if_nonempty() + } + /// Pretty-print treefile content as JSON to stdout. pub fn prettyprint_json_stdout(&self) { std::io::stdout() @@ -1395,6 +1405,21 @@ pub(crate) struct DeriveConfigFields { pub(crate) override_commit: Option, } +impl BaseComposeConfigFields { + pub(crate) fn error_if_nonempty(&self) -> Result<()> { + // exemption for `basearch`, which we set to the current arch during parsing + let s = Self { + basearch: self.basearch.clone(), + ..Default::default() + }; + if &s != self { + let j = serde_json::to_string_pretty(self)?; + bail!("the following base fields are not supported:\n{}", j); + } + Ok(()) + } +} + impl DeriveConfigFields { pub(crate) fn error_if_nonempty(&self) -> Result<()> { if &Self::default() != self { @@ -2186,6 +2211,18 @@ pub(crate) fn treefile_new_compose( workdir: i32, ) -> CxxResult> { let r = treefile_new(filename, basearch, workdir)?; + Treefile::validate_base_config(&r.parsed)?; r.error_if_deriving()?; Ok(r) } + +/// Create a new treefile, returning an error if any (currently) compose-side options are set. +pub(crate) fn treefile_new_client( + filename: &str, + basearch: &str, + workdir: i32, +) -> CxxResult> { + let r = treefile_new(filename, basearch, workdir)?; + r.error_if_base()?; + Ok(r) +}