v0.1.3-pre.007

This commit is contained in:
2026-08-15 20:57:13 +02:00
parent b7323fe961
commit 96753e4ba1
17 changed files with 1647 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/src/registry.rs
// version: 1
// version: 2
/// Bootstrap argument used to replace a known Config filename mapping.
pub const ARG_FILE_MAP: &str = "--filemap";
@@ -43,12 +43,13 @@ pub enum ConfigFileKind {
Schema,
}
/// Logical descriptor associating a stable file identifier with its physical filename and root category.
/// Logical descriptor associating a stable file identifier with its physical filename, root category and optional validation schema.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigFileDescriptor {
file_id: ConfigFileId,
kind: ConfigFileKind,
filename: std::path::PathBuf,
schema_file_id: std::option::Option<ConfigFileId>,
}
impl ConfigFileDescriptor {
@@ -70,7 +71,18 @@ impl ConfigFileDescriptor {
return self.filename.as_path();
}
fn new(file_id: &'static str, kind: ConfigFileKind, filename: &'static str) -> ksp_core_lib::Result<Self> {
/// Returns the logical schema identifier associated with this Config document when one is declared.
#[must_use]
pub fn schema_file_id(&self) -> std::option::Option<&ConfigFileId> {
return self.schema_file_id.as_ref();
}
fn new(
file_id: &'static str,
kind: ConfigFileKind,
filename: &'static str,
schema_file_id: std::option::Option<&'static str>,
) -> ksp_core_lib::Result<Self> {
let file_id = ConfigFileId::new(file_id);
let file_id = match file_id {
std::result::Result::Ok(value) => value,
@@ -82,8 +94,13 @@ impl ConfigFileDescriptor {
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
let filename = validate_relative_filename(&file_id, std::path::PathBuf::from(filename));
return match filename {
std::result::Result::Ok(value) => std::result::Result::Ok(Self { file_id, kind, filename: value }),
let filename = match filename {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let schema_file_id = parse_schema_file_id(&file_id, kind, schema_file_id);
return match schema_file_id {
std::result::Result::Ok(value) => std::result::Result::Ok(Self { file_id, kind, filename, schema_file_id: value }),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
@@ -98,12 +115,18 @@ pub struct ConfigFileRegistry {
impl ConfigFileRegistry {
/// Creates the registry containing the KSP default file mappings known in the current release.
pub fn defaults() -> ksp_core_lib::Result<Self> {
let logging = ConfigFileDescriptor::new(FILE_ID_STD_LOGGING, ConfigFileKind::Config, DEFAULT_STD_LOGGING_FILENAME);
let logging = ConfigFileDescriptor::new(
FILE_ID_STD_LOGGING,
ConfigFileKind::Config,
DEFAULT_STD_LOGGING_FILENAME,
std::option::Option::Some(FILE_ID_SCHEMA_STD_LOGGING),
);
let logging = match logging {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let logging_schema = ConfigFileDescriptor::new(FILE_ID_SCHEMA_STD_LOGGING, ConfigFileKind::Schema, DEFAULT_STD_LOGGING_SCHEMA_FILENAME);
let logging_schema =
ConfigFileDescriptor::new(FILE_ID_SCHEMA_STD_LOGGING, ConfigFileKind::Schema, DEFAULT_STD_LOGGING_SCHEMA_FILENAME, std::option::Option::None);
let logging_schema = match logging_schema {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -154,7 +177,7 @@ impl ConfigFileRegistry {
return std::result::Result::Ok(root.join(descriptor.filename()));
}
/// Replaces the physical filename of one known logical identifier while preserving its kind and logical identity.
/// Replaces the physical filename of one known logical identifier while preserving its kind, schema association and logical identity.
pub fn with_filename_override(mut self, file_id: &ConfigFileId, filename: impl std::convert::Into<std::path::PathBuf>) -> ksp_core_lib::Result<Self> {
let update = self.set_filename_override(file_id, filename.into());
return match update {
@@ -174,7 +197,12 @@ impl ConfigFileRegistry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let updated = ConfigFileDescriptor { file_id: descriptor.file_id.clone(), kind: descriptor.kind, filename };
let updated = ConfigFileDescriptor {
file_id: descriptor.file_id.clone(),
kind: descriptor.kind,
filename,
schema_file_id: descriptor.schema_file_id.clone(),
};
self.descriptors.insert(file_id.clone(), updated);
return std::result::Result::Ok(());
}
@@ -190,7 +218,68 @@ fn build_registry<const N: usize>(descriptors: [ConfigFileDescriptor; N]) -> ksp
return std::result::Result::Err(duplicate_file_id_error(duplicate_id.as_str()));
}
}
return std::result::Result::Ok(registry);
let associations = validate_schema_associations(&registry);
return match associations {
std::result::Result::Ok(()) => std::result::Result::Ok(registry),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
fn parse_schema_file_id(
file_id: &ConfigFileId,
kind: ConfigFileKind,
schema_file_id: std::option::Option<&'static str>,
) -> ksp_core_lib::Result<std::option::Option<ConfigFileId>> {
return match (kind, schema_file_id) {
(ConfigFileKind::Schema, std::option::Option::Some(_)) => {
std::result::Result::Err(invalid_file_mapping_with_id_error(file_id.as_str(), "schema descriptors cannot declare another validation schema"))
},
(ConfigFileKind::Schema, std::option::Option::None) | (ConfigFileKind::Config, std::option::Option::None) => {
std::result::Result::Ok(std::option::Option::None)
},
(ConfigFileKind::Config, std::option::Option::Some(value)) => {
let schema_id = ConfigFileId::new(value);
match schema_id {
std::result::Result::Ok(schema_id) => {
if schema_id.as_str().starts_with("schema.") {
std::result::Result::Ok(std::option::Option::Some(schema_id))
} else {
std::result::Result::Err(invalid_file_mapping_with_id_error(
file_id.as_str(),
"validation schema file_id must use the schema namespace",
))
}
},
std::result::Result::Err(error) => std::result::Result::Err(error),
}
},
};
}
fn validate_schema_associations(registry: &ConfigFileRegistry) -> ksp_core_lib::Result<()> {
for descriptor in registry.descriptors.values() {
let schema_file_id = match descriptor.schema_file_id() {
std::option::Option::Some(value) => value,
std::option::Option::None => continue,
};
let schema = registry.descriptors.get(schema_file_id);
let schema = match schema {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(invalid_file_mapping_with_id_error(
descriptor.file_id().as_str(),
"validation schema file_id is not registered",
));
},
};
if schema.kind() != ConfigFileKind::Schema {
return std::result::Result::Err(invalid_file_mapping_with_id_error(
descriptor.file_id().as_str(),
"validation schema descriptor must have schema kind",
));
}
}
return std::result::Result::Ok(());
}
fn apply_file_map_argument(registry: &mut ConfigFileRegistry, argument: &std::ffi::OsStr) -> ksp_core_lib::Result<()> {