Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework how packages describe how they contain the components of an embedded package #744

Merged
merged 20 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .clippy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,13 @@
max-fn-params-bools = 1

# default is 7
too-many-arguments-threshold = 5
too-many-arguments-threshold = 5

ignore-interior-mutability = [
# Bytes is the default value for this setting.
"bytes::Bytes",
# FileMatcher contains a Gitignore field which has interior mutability,
# but FileMatcher has a custom hash implementation that skips that field.
"spk_schema_foundation::spec_ops::file_matcher::FileMatcher",
]

1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/spk-schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ indexmap = { workspace = true }
is_default_derive_macro = { workspace = true }
itertools = { workspace = true }
nom = { workspace = true }
nom-supreme = { workspace = true }
regex = { workspace = true }
relative-path = { workspace = true }
ring = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ mod ident;
mod request;

pub use ident::{ident_parts, ident_parts_with_components, IdentParts, IdentPartsBuf};
pub use request::range_ident_pkg_name;
pub use request::{range_ident_pkg_name, request_pkg_name_and_version};

pub static KNOWN_REPOSITORY_NAMES: Lazy<HashSet<&'static str>> = Lazy::new(|| {
let mut known_repositories = HashSet::from(["local"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::collections::BTreeSet;

use nom::character::complete::char;
use nom::combinator::{cut, map, opt};
use nom::error::{ContextError, ParseError};
use nom::error::{ContextError, FromExternalError, ParseError};
use nom::sequence::{pair, preceded};
use nom::IResult;
use nom_supreme::tag::TagError;
Expand All @@ -15,6 +15,8 @@ use crate::ident_component::parsing::components;
use crate::ident_component::Component;
use crate::name::parsing::package_name;
use crate::name::PkgName;
use crate::version::parsing::version;
use crate::version::Version;

/// Parse a package name in the context of a range identity.
///
Expand All @@ -39,3 +41,40 @@ where
),
)(input)
}

/// Parse a package name with optional components and optional version.
///
/// The package name must either be followed by a `/` and a version, or the end
/// of input.
///
/// Examples:
/// - `"package-name"`
/// - `"package-name/"`
/// - `"package-name/1.0.0"`
/// - `"package-name:comp"`
/// - `"package-name:{comp1,comp2}/"`
/// - `"package-name:{comp1,comp2}/1.0.0"`
pub fn request_pkg_name_and_version<'a, E>(
input: &'a str,
) -> IResult<&'a str, (&PkgName, BTreeSet<Component>, Option<Version>), E>
where
E: ParseError<&'a str>
+ ContextError<&'a str>
+ FromExternalError<&'a str, std::num::ParseIntError>
+ FromExternalError<&'a str, crate::version::Error>
+ TagError<&'a str, &'static str>,
{
map(
pair(
package_name,
pair(
map(
opt(preceded(char(':'), cut(components))),
|opt_components| opt_components.unwrap_or_default(),
),
opt(preceded(char('/'), cut(version))),
),
),
|(pkg_name, (components, opt_version))| (pkg_name, components, opt_version),
)(input)
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,15 @@ pub enum ComponentsMissingProblem {
needed: CommaSeparated<BTreeSet<String>>,
have: CommaSeparated<BTreeSet<String>>,
},
#[strum(
to_string = "package {embedder} embeds {embedded} but does not provide all required components: needed {needed}; have {have}"
)]
EmbeddedComponentsNotProvided {
embedder: PkgNameBuf,
embedded: PkgNameBuf,
needed: CommaSeparated<BTreeSet<String>>,
have: CommaSeparated<BTreeSet<String>>,
},
}

impl IsSameReasonAs for ComponentsMissingProblem {
Expand Down
106 changes: 106 additions & 0 deletions crates/spk-schema/crates/ident/src/ident_optversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) Sony Pictures Imageworks, et al.
// SPDX-License-Identifier: Apache-2.0
// https://github.com/imageworks/spk

use std::fmt::Write;
use std::str::FromStr;

use spk_schema_foundation::name::{PkgName, PkgNameBuf};
use spk_schema_foundation::version::Version;

use crate::{parsing, Ident, Result, VersionIdent};

/// Identifies a package name and number version.
pub type OptVersionIdent = Ident<PkgNameBuf, Option<Version>>;

impl OptVersionIdent {
/// Create a new identifier for the named package and no version.
pub fn new_none<N: Into<PkgNameBuf>>(name: N) -> Self {
Self {
base: name.into(),
target: Default::default(),
}
}

/// Copy this identifier and add the given version.
pub fn to_version(&self, version: Version) -> VersionIdent {
VersionIdent {
base: self.base.clone(),
target: version,
}
}

/// Turn this identifier into one for the given version.
pub fn into_version(self, version: Version) -> VersionIdent {
VersionIdent {
base: self.base,
target: version,
}
}
}

macro_rules! opt_version_ident_methods {
($Ident:ty $(, .$($access:ident).+)?) => {
impl $Ident {
/// The name of the identified package
pub fn name(&self) -> &PkgName {
self$(.$($access).+)?.base().as_ref()
}

/// Set the package name of this package identifier
pub fn set_name<T: Into<PkgNameBuf>>(&mut self, name: T) {
self$(.$($access).+)?.base = name.into();
}

/// Return a copy of this identifier with the given name instead
pub fn with_name<T: Into<PkgNameBuf>>(&self, name: T) -> Self {
let mut new = self.clone();
new$(.$($access).+)?.set_name(name);
new
}
}

impl spk_schema_foundation::spec_ops::Named for $Ident {
fn name(&self) -> &PkgName {
self.name()
}
}
};
}

pub(crate) use opt_version_ident_methods;

opt_version_ident_methods!(OptVersionIdent);

impl std::fmt::Display for OptVersionIdent {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.base.fmt(f)?;
if let Some(version) = &self.target {
f.write_char('/')?;
version.fmt(f)
} else {
Ok(())
}
}
}

impl FromStr for OptVersionIdent {
type Err = crate::Error;

/// Parse the given identifier string into this instance.
fn from_str(source: &str) -> Result<Self> {
use nom::combinator::all_consuming;

all_consuming(parsing::opt_version_ident::<nom_supreme::error::ErrorTree<_>>)(source)
.map(|(_, ident)| ident)
.map_err(|err| match err {
nom::Err::Error(e) | nom::Err::Failure(e) => crate::Error::String(e.to_string()),
nom::Err::Incomplete(_) => unreachable!(),
})
}
}

/// Parse a package identifier string.
pub fn parse_optversion_ident<S: AsRef<str>>(source: S) -> Result<OptVersionIdent> {
Ident::from_str(source.as_ref())
}
25 changes: 2 additions & 23 deletions crates/spk-schema/crates/ident/src/ident_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,41 +66,20 @@ impl AsVersionIdent for VersionIdent {

macro_rules! version_ident_methods {
($Ident:ty $(, .$($access:ident).+)?) => {
impl $Ident {
/// The name of the identified package
pub fn name(&self) -> &PkgName {
self$(.$($access).+)?.base().as_ref()
}
$crate::ident_optversion::opt_version_ident_methods!($Ident $(, .$($access).+)?);

impl $Ident {
/// The version number identified for this package
pub fn version(&self) -> &Version {
self$(.$($access).+)?.target()
}

/// Set the package name of this package identifier
pub fn set_name<T: Into<PkgNameBuf>>(&mut self, name: T) {
self$(.$($access).+)?.base = name.into();
}

/// Return a copy of this identifier with the given name instead
pub fn with_name<T: Into<PkgNameBuf>>(&self, name: T) -> Self {
let mut new = self.clone();
new$(.$($access).+)?.set_name(name);
new
}

/// Set the version number of this package identifier
pub fn set_version(&mut self, version: Version) {
self$(.$($access).+)?.target = version;
}
}

impl spk_schema_foundation::spec_ops::Named for $Ident {
fn name(&self) -> &PkgName {
self.name()
}
}

impl spk_schema_foundation::spec_ops::HasVersion for $Ident {
fn version(&self) -> &Version {
self.version()
Expand Down
2 changes: 2 additions & 0 deletions crates/spk-schema/crates/ident/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod ident;
mod ident_any;
mod ident_build;
mod ident_located;
mod ident_optversion;
mod ident_version;
pub mod parsing;
mod range_ident;
Expand All @@ -19,6 +20,7 @@ pub use ident::{AsVersionIdent, Ident};
pub use ident_any::{parse_ident, AnyIdent, ToAnyIdentWithoutBuild};
pub use ident_build::{parse_build_ident, BuildIdent};
pub use ident_located::{LocatedBuildIdent, LocatedVersionIdent};
pub use ident_optversion::{parse_optversion_ident, OptVersionIdent};
pub use ident_version::{parse_version_ident, VersionIdent};
pub use range_ident::{parse_ident_range, parse_ident_range_list, RangeIdent};
pub use request::{
Expand Down
22 changes: 21 additions & 1 deletion crates/spk-schema/crates/ident/src/parsing/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use spk_schema_foundation::ident_ops::parsing::{version_and_build, version_and_r
use spk_schema_foundation::name::parsing::package_name;
use spk_schema_foundation::version::parsing::version;

use crate::{AnyIdent, BuildIdent, VersionIdent};
use crate::{AnyIdent, BuildIdent, OptVersionIdent, VersionIdent};

/// Parse a package identity into an [`AnyIdent`].
///
Expand Down Expand Up @@ -43,6 +43,26 @@ where
}
}

/// Parse a package identity into a [`OptVersionIdent`].
///
/// Examples:
/// - `"pkg-name"`
/// - `"pkg-name/1.0"`
pub fn opt_version_ident<'b, E>(input: &'b str) -> IResult<&'b str, OptVersionIdent, E>
where
E: ParseError<&'b str>
+ ContextError<&'b str>
+ FromExternalError<&'b str, crate::error::Error>
+ FromExternalError<&'b str, spk_schema_foundation::ident_build::Error>
+ FromExternalError<&'b str, spk_schema_foundation::version::Error>
+ FromExternalError<&'b str, std::num::ParseIntError>
+ TagError<&'b str, &'static str>,
{
let (input, ident) = package_ident(input)?;
let (input, v) = opt(preceded(char('/'), version))(input)?;
Ok((input, OptVersionIdent::new(ident.base, v)))
}

/// Parse a package identity into a [`VersionIdent`].
///
/// Examples:
Expand Down
2 changes: 1 addition & 1 deletion crates/spk-schema/crates/ident/src/parsing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod request;
#[path = "./parsing_test.rs"]
mod parsing_test;

pub use ident::{build_ident, ident, version_ident};
pub use ident::{build_ident, ident, opt_version_ident, version_ident};
pub use request::{
range_ident,
range_ident_comma_separated_list,
Expand Down
Loading
Loading