Skip to content

Commit

Permalink
feat: refactor manifest into more generic approach (prefix-dev#2015)
Browse files Browse the repository at this point in the history
Co-authored-by: Hofer-Julian <[email protected]>
  • Loading branch information
nichmor and Hofer-Julian authored Sep 10, 2024
1 parent 78850aa commit c8b4849
Show file tree
Hide file tree
Showing 24 changed files with 350 additions and 204 deletions.
2 changes: 1 addition & 1 deletion crates/pixi_manifest/src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ mod tests {
use assert_matches::assert_matches;

use super::*;
use crate::manifest::Manifest;
use crate::manifests::manifest::Manifest;

#[test]
fn test_dependencies_borrowed() {
Expand Down
5 changes: 2 additions & 3 deletions crates/pixi_manifest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
mod activation;
pub(crate) mod channel;
mod dependencies;
mod document;
mod environment;
mod environments;
mod error;
mod feature;
mod features_ext;
mod has_features_iter;
mod has_manifest_ref;
mod manifest;
mod manifests;
mod metadata;
mod parsed_manifest;
pub mod pypi;
Expand All @@ -24,7 +23,7 @@ mod validation;

pub use dependencies::{CondaDependencies, Dependencies, PyPiDependencies};

pub use manifest::{Manifest, ManifestKind};
pub use manifests::manifest::{Manifest, ManifestKind};

pub use crate::environments::Environments;
pub use crate::parsed_manifest::ParsedManifest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use toml_edit::DocumentMut;

use crate::{
consts,
document::ManifestSource,
error::{DependencyError, TomlError, UnknownFeature},
manifests::{ManifestSource, TomlManifest},
pypi::PyPiPackageName,
pyproject::PyProjectManifest,
to_options, DependencyOverwriteBehavior, Environment, EnvironmentName, Feature, FeatureName,
Expand Down Expand Up @@ -122,8 +122,8 @@ impl Manifest {
manifest.validate(NamedSource::new(file_name, contents.to_owned()), root)?;

let source = match manifest_kind {
ManifestKind::Pixi => ManifestSource::PixiToml(document),
ManifestKind::Pyproject => ManifestSource::PyProjectToml(document),
ManifestKind::Pixi => ManifestSource::PixiToml(TomlManifest::new(document)),
ManifestKind::Pyproject => ManifestSource::PyProjectToml(TomlManifest::new(document)),
};

Ok(Self {
Expand Down Expand Up @@ -707,7 +707,7 @@ mod tests {
use tempfile::tempdir;

use super::*;
use crate::{channel::PrioritizedChannel, manifest::Manifest};
use crate::channel::PrioritizedChannel;
use glob::glob;

const PROJECT_BOILERPLATE: &str = r#"
Expand Down
77 changes: 77 additions & 0 deletions crates/pixi_manifest/src/manifests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use toml_edit::{self, Array, Item, Table, Value};

pub mod project;

pub mod manifest;

pub use project::ManifestSource;

use crate::error::TomlError;

/// Represents a wrapper around a TOML document.
/// This struct is exposed to other crates
/// to allow for easy manipulation of the TOML document.
#[derive(Debug, Clone, Default)]
pub struct TomlManifest(toml_edit::DocumentMut);

impl TomlManifest {
/// Create a new `TomlManifest` from a `toml_edit::DocumentMut` document.
pub fn new(document: toml_edit::DocumentMut) -> Self {
Self(document)
}

/// Retrieve a mutable reference to a target table `table_name`
/// in dotted form (e.g. `table1.table2`) from the root of the document.
/// If the table is not found, it is inserted into the document.
fn get_or_insert_nested_table<'a>(
&'a mut self,
table_name: &str,
) -> Result<&'a mut Table, TomlError> {
let parts: Vec<&str> = table_name.split('.').collect();

let mut current_table = self.0.as_table_mut();

for part in parts {
let entry = current_table.entry(part);
let item = entry.or_insert(Item::Table(Table::new()));
current_table = item
.as_table_mut()
.ok_or_else(|| TomlError::table_error(part, table_name))?;
// Avoid creating empty tables
current_table.set_implicit(true);
}
Ok(current_table)
}

/// Retrieves a mutable reference to a target array `array_name`
/// in table `table_name` in dotted form (e.g. `table1.table2.array`).
///
/// If the array is not found, it is inserted into the document.
pub fn get_or_insert_toml_array<'a>(
&'a mut self,
table_name: &str,
array_name: &str,
) -> Result<&'a mut Array, TomlError> {
self.get_or_insert_nested_table(table_name)?
.entry(array_name)
.or_insert(Item::Value(Value::Array(Array::new())))
.as_array_mut()
.ok_or_else(|| TomlError::array_error(array_name, table_name.to_string().as_str()))
}

/// Retrieves a mutable reference to a target array `array_name`
/// in table `table_name` in dotted form (e.g. `table1.table2.array`).
///
/// If the array is not found, returns None.
pub fn get_toml_array<'a>(
&'a mut self,
table_name: &str,
array_name: &str,
) -> Result<Option<&'a mut Array>, TomlError> {
let array = self
.get_or_insert_nested_table(table_name)?
.get_mut(array_name)
.and_then(|a| a.as_array_mut());
Ok(array)
}
}
Loading

0 comments on commit c8b4849

Please sign in to comment.