From af27b7a39bf339a9bf457841ebe22cddd262d456 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sun, 25 May 2025 16:31:54 -0400 Subject: [PATCH 01/62] Update package version to 2.0.0 and refactor package structure --- Cargo.toml | 4 +- src/extensions/mod.rs | 3 +- src/extensions/package_metadata.rs | 97 +-------------- src/extensions/serde_utils.rs | 13 ++ src/gen-schema.rs | 10 +- src/models/backend.rs | 15 --- src/models/extra.rs | 130 -------------------- src/models/mod.rs | 8 +- src/models/package.rs | 186 +++++++++++++++++------------ src/models/qpackages.rs | 25 ++++ src/models/qpkg.rs | 20 ++++ src/models/shared_package.rs | 50 ++++++++ src/models/version_req.rs | 2 +- 13 files changed, 237 insertions(+), 326 deletions(-) create mode 100644 src/extensions/serde_utils.rs delete mode 100644 src/models/backend.rs create mode 100644 src/models/qpackages.rs create mode 100644 src/models/qpkg.rs create mode 100644 src/models/shared_package.rs diff --git a/Cargo.toml b/Cargo.toml index e58deed..809cf99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "qpm_package" -version = "0.4.0" -edition = "2021" +version = "2.0.0" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs index 879f73f..a823a51 100644 --- a/src/extensions/mod.rs +++ b/src/extensions/mod.rs @@ -1,2 +1,3 @@ pub mod package_metadata; -pub mod workspace; \ No newline at end of file +pub mod workspace; +pub mod serde_utils; \ No newline at end of file diff --git a/src/extensions/package_metadata.rs b/src/extensions/package_metadata.rs index f4bcaf2..9100c34 100644 --- a/src/extensions/package_metadata.rs +++ b/src/extensions/package_metadata.rs @@ -1,99 +1,8 @@ use std::path::PathBuf; -use crate::models::{dependency::SharedDependency, package::PackageMetadata}; +use crate::models::{package::Package, shared_package::SharedPackage}; -pub trait PackageMetadataExtensions { - #[deprecated = "Use get_so_name2 instead"] - fn get_so_name(&self) -> PathBuf; - fn get_so_name2(&self) -> PathBuf; +pub trait PackageMetadataExtensions {} - #[deprecated = "Use get_static_name2 instead"] - fn get_static_name(&self) -> PathBuf; - fn get_static_name2(&self) -> PathBuf; +impl PackageMetadataExtensions for Package {} - fn get_module_id(&self) -> String { - let fixed_name = self - .get_so_name2() - .with_extension("") - .to_str() - .unwrap() - .to_string(); - fixed_name[3..fixed_name.len()].to_string() - } -} - -impl PackageMetadataExtensions for PackageMetadata { - fn get_so_name(&self) -> PathBuf { - self.get_so_name2() - } - fn get_static_name(&self) -> PathBuf { - self.get_static_name2() - } - - fn get_so_name2(&self) -> PathBuf { - self.additional_data - .override_so_name - .clone() - .unwrap_or_else(|| { - format!( - "lib{}_{}.so", - self.id, - self.version.to_string().replace('.', "_"), - ) - }) - .into() - } - - fn get_static_name2(&self) -> PathBuf { - self.additional_data - .override_static_name - .clone() - .unwrap_or_else(|| { - format!( - "lib{}_{}.a", - self.id, - self.version.to_string().replace('.', "_"), - ) - }) - .into() - } -} - -impl PackageMetadataExtensions for SharedDependency { - fn get_so_name(&self) -> PathBuf { - self.dependency - .additional_data - .override_so_name - .clone() - .unwrap_or_else(|| { - format!( - "lib{}_{}.so", - self.dependency.id, - self.version.to_string().replace('.', "_"), - ) - }) - .into() - } - fn get_static_name(&self) -> PathBuf { - self.dependency - .additional_data - .override_static_name - .clone() - .unwrap_or_else(|| { - format!( - "lib{}_{}.a", - self.dependency.id, - self.version.to_string().replace('.', "_"), - ) - }) - .into() - } - - fn get_so_name2(&self) -> PathBuf { - todo!() - } - - fn get_static_name2(&self) -> PathBuf { - todo!() - } -} diff --git a/src/extensions/serde_utils.rs b/src/extensions/serde_utils.rs new file mode 100644 index 0000000..838c9ef --- /dev/null +++ b/src/extensions/serde_utils.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Deserializer}; + +/// +/// This function is used to deserialize a value from JSON, and if the value is `null`, it will return the default value of the type `T`. +/// +pub fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result +where + T: Default + Deserialize<'de>, + D: Deserializer<'de>, +{ + let opt = Option::deserialize(deserializer)?; + Ok(opt.unwrap_or_default()) +} diff --git a/src/gen-schema.rs b/src/gen-schema.rs index 9c8fa7f..2971051 100644 --- a/src/gen-schema.rs +++ b/src/gen-schema.rs @@ -1,13 +1,15 @@ -mod models; -use std::env; +pub mod models; +pub mod extensions; + +use models::{package::Package, shared_package::SharedPackage}; fn main() { - let shared_schema_json = schemars::schema_for!(models::dependency::SharedPackageConfig); + let shared_schema_json = schemars::schema_for!(SharedPackage); let shared_schema = serde_json::to_string_pretty(&shared_schema_json).unwrap(); std::fs::write("qpm.shared.schema.json", shared_schema).expect("Failed to write shared schema"); - let schema_json = schemars::schema_for!(models::package::PackageConfig); + let schema_json = schemars::schema_for!(Package); let schema = serde_json::to_string_pretty(&schema_json).unwrap(); std::fs::write("qpm.schema.json", schema).expect("Failed to write schema"); } diff --git a/src/models/backend.rs b/src/models/backend.rs deleted file mode 100644 index 563fa97..0000000 --- a/src/models/backend.rs +++ /dev/null @@ -1,15 +0,0 @@ -use schemars::JsonSchema; -use semver::Version; -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, PartialEq, Eq)] -#[allow(non_snake_case)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "The package version")] -pub struct PackageVersion { - #[schemars(description = "The unique identifier of the package.")] - pub id: String, - - #[schemars(description = "The version of the package.")] - pub version: Version, -} diff --git a/src/models/extra.rs b/src/models/extra.rs index 635aabb..fcb47eb 100644 --- a/src/models/extra.rs +++ b/src/models/extra.rs @@ -3,77 +3,6 @@ use std::path::PathBuf; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq, Default)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "Additional metadata for the package.")] -pub struct AdditionalPackageMetadata { - /// Whether or not the package is header only - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Whether or not the package is header only")] - pub headers_only: Option, - - /// Whether or not the package is statically linked - /// DEPRECATED - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(since="0.2.0", note="Use static_link instead")] - #[schemars(description = "Whether the package is statically linked. Deprecated, use staticLink instead.")] - pub static_linking: Option, - - /// the link to the so file - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The link to the shared object file.")] - pub so_link: Option, - - /// the link to the so file - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The link to the static library file.")] - pub static_link: Option, - - /// the link to the debug .so file - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The link to the debug shared object file.")] - pub debug_so_link: Option, - - /// the overridden so file name - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The override name for the shared object file.")] - pub override_so_name: Option, - - /// the overridden static file name - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The override name for the static library file.")] - pub override_static_name: Option, - - /// the link to the qmod - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The link to the qmod file.")] - pub mod_link: Option, - - /// Branch name of a Github repo. Only used when a valid github url is provided - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The branch name of a GitHub repository. Only used when a valid GitHub URL is provided.")] - pub branch_name: Option, - - /// Additional Compile options to be used with this package - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Additional compile options for the package.")] - pub compile_options: Option, - - /// Sub folder to use from the downloaded repo / zip, so one repo can contain multiple packages - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Sub-folder to use from the downloaded repository or zip, so one repository can contain multiple packages.")] - pub sub_folder: Option, - - /// Whether to generate the cmake files on restore - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Whether to generate CMake files on restore.")] - pub cmake: Option, - - /// Whether to generate the a toolchain JSON file [CompileOptions] describing the project setup configuration - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Path to generate a toolchain JSON file describing the project setup configuration.")] - pub toolchain_out: Option -} /// - compileOptions (QPM.Commands.SupportedPropertiesCommand+CompileOptionsProperty): Additional options for compilation and edits to compilation related files. - Supported in: package /// Type: QPM.Commands.SupportedPropertiesCommand+CompileOptionsProperty @@ -113,62 +42,3 @@ pub struct CompileOptions { pub c_flags: Option>, } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "Describes the dependency type.")] -pub enum DependencyLibType { - #[schemars(description = "Shared library")] - Shared, // shared - - #[schemars(description = "Static library")] - Static, // statically link - - #[schemars(description = "Header only")] - HeaderOnly // Only restore headers, don't link -} - -// Modifies how a package should be restored in qpm.json -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq, Default)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "Modifies how a dependency should be restored.")] -pub struct PackageDependencyModifier { - /// Copy a dependency from a location that is local to this root path instead of from a remote url - /// Technically just a dependency field - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Copy a dependency from a location that is local to this root path instead of from a remote URL.")] - pub local_path: Option, - - /// By default if empty, true - /// If false, this mod dependency will NOT be included in the generated mod.json - /// Technically just a dependency field - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "If the mod dependency should be included in the generated mod.json. Defaults to true.")] - pub include_qmod: Option, - - /// Specify any additional files to be downloaded - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Additional files to be downloaded.")] - pub extra_files: Option>, - - /// Whether or not the dependency is private and should be used in restore - /// Technically just a dependency field - #[serde( - skip_serializing_if = "Option::is_none", - rename(serialize = "private", deserialize = "private") - )] - #[schemars(description = "Whether or not the dependency is private and should be used in restore.")] - pub is_private: Option, - - /// Specifies how to restore this dependency - #[serde( - skip_serializing_if = "Option::is_none", - )] - #[schemars(description = "Specifies how to restore this dependency.")] - pub lib_type: Option, - - /// whether the mod is optional or required. If omitted, assume Some(True) - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(rename = "required")] - #[schemars(description = "Whether the mod is optional or required. If omitted, assume true.")] - pub required: Option, -} diff --git a/src/models/mod.rs b/src/models/mod.rs index 9a405fc..53bafc1 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,6 +1,10 @@ pub mod package; -pub mod dependency; +pub mod shared_package; pub mod extra; -pub mod backend; + +pub mod qpackages; + +pub mod qpkg; + pub mod workspace; mod version_req; \ No newline at end of file diff --git a/src/models/package.rs b/src/models/package.rs index 9cc02d0..06490e0 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -4,16 +4,14 @@ use schemars::JsonSchema; use semver::{Version, VersionReq}; use serde::{Deserialize, Deserializer, Serialize}; -use super::{ - extra::{AdditionalPackageMetadata, PackageDependencyModifier}, - workspace::WorkspaceConfig, -}; - use crate::models::version_req::make_version_req_schema; +use crate::extensions::serde_utils::deserialize_null_default; + +use super::extra::CompileOptions; #[inline] fn default_ver() -> Version { - Version::new(0, 4, 0) + Version::new(2, 0, 0) } /// latest version @@ -28,90 +26,124 @@ pub fn package_target_version() -> Version { #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] #[schemars(description = "Configuration for a package.")] -pub struct PackageConfig { +pub struct Package { + /// Package ID + pub id: String, + /// Package version + pub version: String, + /// Directory where dependencies are restored + pub dependencies_directory: String, + /// Directories shared by the package + pub shared_directories: Vec, + /// Workspace configuration + #[serde(default)] + pub workspace: PackageWorkspace, + /// Additional package metadata + #[serde(default)] + pub additional_data: PackageAdditionalData, + /// Package triplet configurations + pub triplet: PackageTripletConfig, + /// Config version, defaults to 2.0.0 #[serde(default = "default_ver")] - #[schemars(description = "The version of the package configuration.")] - pub version: Version, - - #[schemars(description = "The directory where shared files are stored.")] - pub shared_dir: PathBuf, - - #[schemars(description = "The directory where dependencies are stored.")] - pub dependencies_dir: PathBuf, + pub config_version: Version, + + /// Whether to generate the cmake files on restore + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "Whether to generate CMake files on restore.")] + pub cmake: Option, + + /// Whether to generate the a toolchain JSON file [CompileOptions] describing the project setup configuration + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars( + description = "Path to generate a toolchain JSON file describing the project setup configuration." + )] + pub toolchain_out: Option, +} - #[schemars(description = "The package metadata.")] - pub info: PackageMetadata, - // allow workspace to be null +#[derive( + Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct PackageWorkspace { + /// Scripts to run at different stages + #[serde(default)] + pub scripts: PackageWorkspaceScripts, + /// Directories to search for qmod files + #[serde(default)] + pub qmod_search_dirs: Vec, + /// Files to include in the qmod + #[serde(default)] + pub qmod_include_files: Vec, + /// Output directory for the qmod #[serde(default, deserialize_with = "deserialize_null_default")] - #[schemars(description = "The workspace configuration.")] - pub workspace: WorkspaceConfig, - - #[schemars(description = "The dependencies of the package.")] - pub dependencies: Vec, + pub qmod_output: Option, } -impl Default for PackageConfig { - fn default() -> Self { - Self { - version: default_ver(), - dependencies: Default::default(), - dependencies_dir: Default::default(), - info: PackageMetadata { - name: Default::default(), - id: Default::default(), - version: Version::new(1, 0, 0), - url: Default::default(), - additional_data: Default::default(), - }, - shared_dir: Default::default(), - workspace: Default::default(), - } - } +#[derive( + Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct PackageWorkspaceScripts { + /// Scripts to run before building + #[serde(default)] + pub build: Vec, } -// qpm.json::info -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "Metadata information about the package.")] -pub struct PackageMetadata { - #[schemars(description = "The name of the package.")] - pub name: String, - - #[schemars(description = "The unique identifier of the package.")] - pub id: String, +#[derive( + Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, +)] +pub struct PackageAdditionalData { + /// Package description + #[serde(default)] + pub description: String, + /// Package author + #[serde(default)] + pub author: String, + /// Package license + #[serde(default)] + pub license: String, +} - #[schemars(description = "The version of the package.")] - pub version: Version, +pub type TripletDependencyMap = std::collections::HashMap; - #[schemars(description = "The website for the package.")] - pub url: Option, +pub type TripletEnvironmentMap = std::collections::HashMap; - #[schemars(description = "Additional metadata for the package.")] - pub additional_data: AdditionalPackageMetadata, +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +pub struct PackageTripletConfig { + /// Default configuration for all triplets. All triplets will inherit from this. + pub default: PackageTripletSettings, + /// Configuration for specific triplets + #[serde(flatten)] + pub specific_triplets: std::collections::HashMap, } -// qpm.json::dependencies[] -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "A dependency of the package.")] -pub struct PackageDependency { - #[schemars(description = "The unique identifier of the dependency")] - pub id: String, +/// Triplet settings for a package +#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] +pub struct PackageTripletSettings { + /// Dependencies for this triplet + #[serde(default)] + pub dependencies: TripletDependencyMap, + + /// Environment variables for this triplet. + #[serde(default)] + pub env: TripletEnvironmentMap, + + /// Additional Compile options to be used with this package + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "Additional compile options for the package.")] + pub compile_options: Option, +} - #[serde(deserialize_with = "cursed_semver_parser::deserialize")] - #[schemars(description = "The version range of the dependency")] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +pub struct PackageTripletDependency { + /// Version range requirement + #[serde(rename = "versionRange")] #[schemars(schema_with = "make_version_req_schema")] pub version_range: VersionReq, - - #[schemars(description = "Additional metadata for the dependency")] - pub additional_data: PackageDependencyModifier, -} - -fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result -where - T: Default + Deserialize<'de>, - D: Deserializer<'de>, -{ - let opt = Option::deserialize(deserializer)?; - Ok(opt.unwrap_or_default()) + /// Target triplet + pub triplet: String, + /// Whether to export this dependency to consumers + #[serde(default)] + pub export: bool, + /// Whether to include this dependency in the qmod + #[serde(default)] + pub qmod_export: bool, } diff --git a/src/models/qpackages.rs b/src/models/qpackages.rs new file mode 100644 index 0000000..fd2247f --- /dev/null +++ b/src/models/qpackages.rs @@ -0,0 +1,25 @@ +use schemars::JsonSchema; +use semver::Version; +use serde::{Serialize, Deserialize}; + +use super::{package::Package, shared_package::SharedPackage}; + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "The package version")] +pub struct QPackagesPackage { + /// Package Configuration + #[schemars(description = "Package Configuration")] + #[serde(rename = "config")] + pub config: Package, + + + /// Checksum of the qpkg + #[schemars(description = "Checksum of the qpkg")] + pub qpkg_checksum: Option, + + /// URL of the qpkg + #[schemars(description = "URL of the qpkg")] + pub qpkg_url: String, +} diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs new file mode 100644 index 0000000..52e49c1 --- /dev/null +++ b/src/models/qpkg.rs @@ -0,0 +1,20 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "QPKG package. Distributes a package with all triplet binaries and their headers.")] +pub struct QPkg { + /// Triplet map + pub triplets: HashMap, + + pub header_file: String, +} + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +pub struct TripletInfo { + /// Paths to the binary files + pub files: Vec, +} diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs new file mode 100644 index 0000000..0f24881 --- /dev/null +++ b/src/models/shared_package.rs @@ -0,0 +1,50 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use super::package::Package; + +pub type SharedLockedTripletMap = HashMap; + +// qpm.shared.json +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Configuration for a shared package.")] +pub struct SharedPackage { + /// Package name + #[schemars(description = "Package name")] + pub config: Package, + /// Triplet map + #[schemars(description = "Triplet map")] + pub locked_triplet: SharedLockedTripletMap, +} + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Configuration for a shared triplet.")] +pub struct SharedTriplet { + /// Triplet map + #[schemars(description = "Triplet map")] + pub restored_dependencies: HashMap, + // default should not appear here. All triplets should be listed + // TODO: Include checksums here? + // TODO: Include qpkg urls here? +} + +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Dependency information for a shared triplet.")] +pub struct SharedTripletDependencyInfo { + /// Version of the dependency + #[schemars(description = "Version of the dependency.")] + pub restored_version: Option, + /// Version range requirement + #[schemars(description = "Version range requirement.")] + pub version_range: String, + /// Triplet of the dependency + #[schemars(description = "Triplet of the dependency.")] + pub triplet: String, +} diff --git a/src/models/version_req.rs b/src/models/version_req.rs index bcb7d04..4f39899 100644 --- a/src/models/version_req.rs +++ b/src/models/version_req.rs @@ -1,4 +1,4 @@ -use schemars::{gen::SchemaGenerator, schema::Schema, schema_for, JsonSchema}; +use schemars::{r#gen::SchemaGenerator, schema::Schema, schema_for, JsonSchema}; pub fn make_version_req_schema(generator: &mut SchemaGenerator) -> Schema { let schema = String::json_schema(generator); From 2c1a2cbe714ae88c61b4fa4d9d7bff2728a8008e Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 13:14:40 -0400 Subject: [PATCH 02/62] Add qmod_url field to PackageTripletSettings and rename TripletInfo to QPkgTripletInfo --- src/models/package.rs | 5 +++++ src/models/qpkg.rs | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index 06490e0..63ff018 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -130,6 +130,11 @@ pub struct PackageTripletSettings { #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "Additional compile options for the package.")] pub compile_options: Option, + + /// QMod URL for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod URL for this triplet.")] + pub qmod_url: Option, } #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 52e49c1..fe94f36 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -8,13 +8,13 @@ use std::collections::HashMap; #[schemars(description = "QPKG package. Distributes a package with all triplet binaries and their headers.")] pub struct QPkg { /// Triplet map - pub triplets: HashMap, + pub triplets: HashMap, pub header_file: String, } #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] -pub struct TripletInfo { +pub struct QPkgTripletInfo { /// Paths to the binary files pub files: Vec, } From 3fb993b447e1d9d21c5d5b9dfb8ecd6f65dca2db Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 19:21:24 -0400 Subject: [PATCH 03/62] Change package version field type from String to Version --- src/models/package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/package.rs b/src/models/package.rs index 63ff018..c051713 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -30,7 +30,7 @@ pub struct Package { /// Package ID pub id: String, /// Package version - pub version: String, + pub version: Version, /// Directory where dependencies are restored pub dependencies_directory: String, /// Directories shared by the package From fe5bab53ba6e911abd33f0399176c6574a9d8c5c Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 19:22:53 -0400 Subject: [PATCH 04/62] Implement default method for Package struct --- src/models/package.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/models/package.rs b/src/models/package.rs index c051713..c787ca4 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -60,6 +60,23 @@ pub struct Package { pub toolchain_out: Option, } +impl Default for Package { + fn default() -> Self { + Self { + id: String::new(), + version: default_ver(), + dependencies_directory: "dependencies".to_string(), + shared_directories: Vec::new(), + workspace: PackageWorkspace::default(), + additional_data: PackageAdditionalData::default(), + triplet: PackageTripletConfig::default(), + config_version: default_ver(), + cmake: None, + toolchain_out: None, + } + } +} + #[derive( Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, )] From 08427c079325c1e50ab4ed62e661197a11a6f6bf Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 19:23:47 -0400 Subject: [PATCH 05/62] Change default value of dependencies_directory from "dependencies" to "extern" --- src/models/package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/package.rs b/src/models/package.rs index c787ca4..9d27b59 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -65,7 +65,7 @@ impl Default for Package { Self { id: String::new(), version: default_ver(), - dependencies_directory: "dependencies".to_string(), + dependencies_directory: "extern".to_string(), shared_directories: Vec::new(), workspace: PackageWorkspace::default(), additional_data: PackageAdditionalData::default(), From 803791f7983401b5b759634e8d2732f36b4bfa9f Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 19:26:14 -0400 Subject: [PATCH 06/62] rename Package to PackageConfig and SharedPackage to SharedPackageConfig, updating related implementations and usages. --- src/extensions/package_metadata.rs | 5 ++--- src/models/package.rs | 6 +++--- src/models/qpackages.rs | 7 +++---- src/models/shared_package.rs | 6 +++--- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/extensions/package_metadata.rs b/src/extensions/package_metadata.rs index 9100c34..fc2a371 100644 --- a/src/extensions/package_metadata.rs +++ b/src/extensions/package_metadata.rs @@ -1,8 +1,7 @@ use std::path::PathBuf; -use crate::models::{package::Package, shared_package::SharedPackage}; +use crate::models::{package::PackageConfig, shared_package::SharedPackageConfig}; pub trait PackageMetadataExtensions {} -impl PackageMetadataExtensions for Package {} - +impl PackageMetadataExtensions for PackageConfig {} diff --git a/src/models/package.rs b/src/models/package.rs index 9d27b59..2e5f427 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -4,8 +4,8 @@ use schemars::JsonSchema; use semver::{Version, VersionReq}; use serde::{Deserialize, Deserializer, Serialize}; -use crate::models::version_req::make_version_req_schema; use crate::extensions::serde_utils::deserialize_null_default; +use crate::models::version_req::make_version_req_schema; use super::extra::CompileOptions; @@ -26,7 +26,7 @@ pub fn package_target_version() -> Version { #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] #[schemars(description = "Configuration for a package.")] -pub struct Package { +pub struct PackageConfig { /// Package ID pub id: String, /// Package version @@ -60,7 +60,7 @@ pub struct Package { pub toolchain_out: Option, } -impl Default for Package { +impl Default for PackageConfig { fn default() -> Self { Self { id: String::new(), diff --git a/src/models/qpackages.rs b/src/models/qpackages.rs index fd2247f..7844058 100644 --- a/src/models/qpackages.rs +++ b/src/models/qpackages.rs @@ -1,8 +1,8 @@ use schemars::JsonSchema; use semver::Version; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; -use super::{package::Package, shared_package::SharedPackage}; +use super::{package::PackageConfig, shared_package::SharedPackageConfig}; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] @@ -12,8 +12,7 @@ pub struct QPackagesPackage { /// Package Configuration #[schemars(description = "Package Configuration")] #[serde(rename = "config")] - pub config: Package, - + pub config: PackageConfig, /// Checksum of the qpkg #[schemars(description = "Checksum of the qpkg")] diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 0f24881..edc2f91 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use super::package::Package; +use super::package::PackageConfig; pub type SharedLockedTripletMap = HashMap; @@ -11,10 +11,10 @@ pub type SharedLockedTripletMap = HashMap; #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] #[schemars(description = "Configuration for a shared package.")] -pub struct SharedPackage { +pub struct SharedPackageConfig { /// Package name #[schemars(description = "Package name")] - pub config: Package, + pub config: PackageConfig, /// Triplet map #[schemars(description = "Triplet map")] pub locked_triplet: SharedLockedTripletMap, From 558f5d2767d90e4a0c2ad6d6537f6add9ec874d0 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 28 May 2025 20:16:59 -0400 Subject: [PATCH 07/62] Refactor package metadata and shared package structures: remove unused dependencies, update imports, and rename triplet configurations for consistency. --- src/extensions/package_metadata.rs | 3 +- src/gen-schema.rs | 8 +++-- src/models/dependency.rs | 49 ------------------------------ src/models/extra.rs | 1 - src/models/package.rs | 24 ++++++++++----- src/models/qpackages.rs | 3 +- src/models/shared_package.rs | 18 ++++++----- 7 files changed, 34 insertions(+), 72 deletions(-) delete mode 100644 src/models/dependency.rs diff --git a/src/extensions/package_metadata.rs b/src/extensions/package_metadata.rs index fc2a371..d3887fa 100644 --- a/src/extensions/package_metadata.rs +++ b/src/extensions/package_metadata.rs @@ -1,6 +1,5 @@ -use std::path::PathBuf; -use crate::models::{package::PackageConfig, shared_package::SharedPackageConfig}; +use crate::models::package::PackageConfig; pub trait PackageMetadataExtensions {} diff --git a/src/gen-schema.rs b/src/gen-schema.rs index 2971051..212ae09 100644 --- a/src/gen-schema.rs +++ b/src/gen-schema.rs @@ -1,15 +1,17 @@ +use models::{package::PackageConfig, shared_package::SharedPackageConfig}; + pub mod models; pub mod extensions; -use models::{package::Package, shared_package::SharedPackage}; + fn main() { - let shared_schema_json = schemars::schema_for!(SharedPackage); + let shared_schema_json = schemars::schema_for!(SharedPackageConfig); let shared_schema = serde_json::to_string_pretty(&shared_schema_json).unwrap(); std::fs::write("qpm.shared.schema.json", shared_schema).expect("Failed to write shared schema"); - let schema_json = schemars::schema_for!(Package); + let schema_json = schemars::schema_for!(PackageConfig); let schema = serde_json::to_string_pretty(&schema_json).unwrap(); std::fs::write("qpm.schema.json", schema).expect("Failed to write schema"); } diff --git a/src/models/dependency.rs b/src/models/dependency.rs deleted file mode 100644 index f9fe62e..0000000 --- a/src/models/dependency.rs +++ /dev/null @@ -1,49 +0,0 @@ -use schemars::JsonSchema; -use semver::{Version, VersionReq}; -use serde::{Deserialize, Serialize}; - -use super::{extra::AdditionalPackageMetadata, package::PackageConfig}; - -use crate::models::version_req::make_version_req_schema; - - -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "A dependency of the package.")] -pub struct Dependency { - pub id: String, - #[serde(deserialize_with = "cursed_semver_parser::deserialize")] - #[schemars(description = "The version range of the dependency")] - #[schemars(schema_with = "make_version_req_schema")] - pub version_range: VersionReq, - - // Should've been PackageDependencyModifier but oh well - #[deprecated = "Use PackageConfig additional_data instead"] - #[schemars(description = "Additional metadata for the dependency. Deprecated, use packageConfig.additionalData instead.")] - pub additional_data: AdditionalPackageMetadata, -} - -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Hash, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "A resolved dependency of the package.")] -pub struct SharedDependency { - #[schemars(description = "The resolved dependency")] - pub dependency: Dependency, - - #[schemars(description = "The resolved version of the dependency")] - pub version: Version, -} - -/// qpm.shared.json -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] -#[allow(non_snake_case)] -#[serde(rename_all = "camelCase")] -#[schemars(description = "Shared package configuration.")] -pub struct SharedPackageConfig { - /// The package config that is stored in qpm.json, copied - #[schemars(description = "A copy of the package configuration stored in qpm.json for convenience.")] - pub config: PackageConfig, - /// The dependencies as given by self.config.resolve() - #[schemars(description = "The resolved dependencies of the package.")] - pub restored_dependencies: Vec, -} diff --git a/src/models/extra.rs b/src/models/extra.rs index fcb47eb..cfdf3ce 100644 --- a/src/models/extra.rs +++ b/src/models/extra.rs @@ -1,4 +1,3 @@ -use std::path::PathBuf; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src/models/package.rs b/src/models/package.rs index 2e5f427..a905264 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -1,8 +1,9 @@ +use std::collections::HashMap; use std::path::PathBuf; use schemars::JsonSchema; use semver::{Version, VersionReq}; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use crate::extensions::serde_utils::deserialize_null_default; use crate::models::version_req::make_version_req_schema; @@ -42,7 +43,7 @@ pub struct PackageConfig { #[serde(default)] pub additional_data: PackageAdditionalData, /// Package triplet configurations - pub triplet: PackageTripletConfig, + pub triplet: PackageTripletsConfig, /// Config version, defaults to 2.0.0 #[serde(default = "default_ver")] pub config_version: Version, @@ -69,7 +70,7 @@ impl Default for PackageConfig { shared_directories: Vec::new(), workspace: PackageWorkspace::default(), additional_data: PackageAdditionalData::default(), - triplet: PackageTripletConfig::default(), + triplet: PackageTripletsConfig::default(), config_version: default_ver(), cmake: None, toolchain_out: None, @@ -119,17 +120,24 @@ pub struct PackageAdditionalData { pub license: String, } -pub type TripletDependencyMap = std::collections::HashMap; +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +pub struct TripletId(String); -pub type TripletEnvironmentMap = std::collections::HashMap; +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +pub struct DependencyId(String); + +// Dependency ID -> Dependency +pub type TripletDependencyMap = HashMap; +// ENV -> VALUE +pub type TripletEnvironmentMap = HashMap; #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] -pub struct PackageTripletConfig { +pub struct PackageTripletsConfig { /// Default configuration for all triplets. All triplets will inherit from this. pub default: PackageTripletSettings, /// Configuration for specific triplets #[serde(flatten)] - pub specific_triplets: std::collections::HashMap, + pub specific_triplets: HashMap, } /// Triplet settings for a package @@ -161,7 +169,7 @@ pub struct PackageTripletDependency { #[schemars(schema_with = "make_version_req_schema")] pub version_range: VersionReq, /// Target triplet - pub triplet: String, + pub triplet: TripletId, /// Whether to export this dependency to consumers #[serde(default)] pub export: bool, diff --git a/src/models/qpackages.rs b/src/models/qpackages.rs index 7844058..c1fe259 100644 --- a/src/models/qpackages.rs +++ b/src/models/qpackages.rs @@ -1,8 +1,7 @@ use schemars::JsonSchema; -use semver::Version; use serde::{Deserialize, Serialize}; -use super::{package::PackageConfig, shared_package::SharedPackageConfig}; +use super::package::PackageConfig; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index edc2f91..d5e0feb 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -1,10 +1,13 @@ use schemars::JsonSchema; +use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use super::package::PackageConfig; +use super::package::{DependencyId, PackageConfig, TripletId}; + +pub type SharedLockedTripletMap = HashMap; +use crate::models::version_req::make_version_req_schema; -pub type SharedLockedTripletMap = HashMap; // qpm.shared.json #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] @@ -27,7 +30,7 @@ pub struct SharedPackageConfig { pub struct SharedTriplet { /// Triplet map #[schemars(description = "Triplet map")] - pub restored_dependencies: HashMap, + pub restored_dependencies: HashMap, // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? @@ -40,11 +43,12 @@ pub struct SharedTriplet { pub struct SharedTripletDependencyInfo { /// Version of the dependency #[schemars(description = "Version of the dependency.")] - pub restored_version: Option, + pub restored_version: Option, /// Version range requirement - #[schemars(description = "Version range requirement.")] - pub version_range: String, + #[serde(rename = "versionRange")] + #[schemars(schema_with = "make_version_req_schema")] + pub version_range: VersionReq, /// Triplet of the dependency #[schemars(description = "Triplet of the dependency.")] - pub triplet: String, + pub triplet: TripletId, } From dea292e54b27c6d4c804b9b54c6c93c260d7889a Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 11:36:44 -0400 Subject: [PATCH 08/62] Refactor PackageConfig struct: change id type to DependencyId, update dependencies_directory and shared_directories types to PathBuf, and modify default implementation accordingly. --- src/models/package.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index a905264..5b5858e 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -29,13 +29,13 @@ pub fn package_target_version() -> Version { #[schemars(description = "Configuration for a package.")] pub struct PackageConfig { /// Package ID - pub id: String, + pub id: DependencyId, /// Package version pub version: Version, /// Directory where dependencies are restored - pub dependencies_directory: String, + pub dependencies_directory: PathBuf, /// Directories shared by the package - pub shared_directories: Vec, + pub shared_directories: Vec, /// Workspace configuration #[serde(default)] pub workspace: PackageWorkspace, @@ -64,9 +64,9 @@ pub struct PackageConfig { impl Default for PackageConfig { fn default() -> Self { Self { - id: String::new(), + id: DependencyId::default(), version: default_ver(), - dependencies_directory: "extern".to_string(), + dependencies_directory: "extern".into(), shared_directories: Vec::new(), workspace: PackageWorkspace::default(), additional_data: PackageAdditionalData::default(), @@ -87,13 +87,13 @@ pub struct PackageWorkspace { pub scripts: PackageWorkspaceScripts, /// Directories to search for qmod files #[serde(default)] - pub qmod_search_dirs: Vec, + pub qmod_search_dirs: Vec, /// Files to include in the qmod #[serde(default)] - pub qmod_include_files: Vec, + pub qmod_include_files: Vec, /// Output directory for the qmod #[serde(default, deserialize_with = "deserialize_null_default")] - pub qmod_output: Option, + pub qmod_output: Option, } #[derive( From 9034786468b0d86e931baad075a778bb2df54194 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 11:39:44 -0400 Subject: [PATCH 09/62] publicize --- src/models/package.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index 5b5858e..fafe065 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -121,10 +121,10 @@ pub struct PackageAdditionalData { } #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] -pub struct TripletId(String); +pub struct TripletId(pub String); #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] -pub struct DependencyId(String); +pub struct DependencyId(pub String); // Dependency ID -> Dependency pub type TripletDependencyMap = HashMap; From 1a166a736c8d4dde7a3a28c60becb4e2a3d4117c Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 11:43:34 -0400 Subject: [PATCH 10/62] Update restored_version in SharedTripletDependencyInfo to require a Version instead of Option --- src/models/shared_package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index d5e0feb..136c8ac 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -43,7 +43,7 @@ pub struct SharedTriplet { pub struct SharedTripletDependencyInfo { /// Version of the dependency #[schemars(description = "Version of the dependency.")] - pub restored_version: Option, + pub restored_version: Version, /// Version range requirement #[serde(rename = "versionRange")] #[schemars(schema_with = "make_version_req_schema")] From 4c7ca6bbeced4c1f564599a1cc22e3f055ef54f0 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 12:32:50 -0400 Subject: [PATCH 11/62] Remove version range requirement from SharedTripletDependencyInfo --- src/models/shared_package.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 136c8ac..a0c8d68 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -44,10 +44,6 @@ pub struct SharedTripletDependencyInfo { /// Version of the dependency #[schemars(description = "Version of the dependency.")] pub restored_version: Version, - /// Version range requirement - #[serde(rename = "versionRange")] - #[schemars(schema_with = "make_version_req_schema")] - pub version_range: VersionReq, /// Triplet of the dependency #[schemars(description = "Triplet of the dependency.")] pub triplet: TripletId, From 769c12629c3cef467f691a23ce2f4e2a14ae6335 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 15:37:52 -0400 Subject: [PATCH 12/62] Implement get_triplet_settings method in PackageTripletsConfig and add merge method in CompileOptions for enhanced triplet configuration management. --- src/models/package.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/models/package.rs b/src/models/package.rs index fafe065..25227b1 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -140,6 +140,47 @@ pub struct PackageTripletsConfig { pub specific_triplets: HashMap, } +impl PackageTripletsConfig { + /// Retrieves the settings for a specific triplet, merging with default settings. + /// + /// This function looks up settings for the specified triplet and combines them with + /// the default settings to create a complete configuration. The merging strategy is: + /// + /// - Dependencies: Both specific and default dependencies are included + /// - Environment variables: Both specific and default variables are included, with specific ones taking precedence + /// - Compile options: Merged with default options if present + /// - QMod URL: Uses the specific URL if available, otherwise falls back to the default + /// + /// # Parameters + /// * `triplet` - The triplet identifier to look up settings for + /// + /// # Returns + /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration + /// * `None` if the triplet is not found in the specific_triplets map + pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { + let found = self.specific_triplets.get(triplet)?; + + let default = &self.default; + let mut dependencies = found.dependencies.clone(); + dependencies.extend(default.dependencies.clone()); + + let mut env = found.env.clone(); + env.extend(default.env.clone()); + + let compile_options = found + .compile_options + .clone() + .map(|a| a.merge(self.default.compile_options.clone().unwrap_or_default())); + + Some(PackageTripletSettings { + dependencies, + env, + compile_options, + qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), + }) + } +} + /// Triplet settings for a package #[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] pub struct PackageTripletSettings { @@ -162,6 +203,18 @@ pub struct PackageTripletSettings { pub qmod_url: Option, } +impl CompileOptions { + pub fn merge(self, other: CompileOptions) -> Self { + Self { + c_flags: self.c_flags.or(other.c_flags), + cpp_features: self.cpp_features.or(other.cpp_features), + cpp_flags: self.cpp_flags.or(other.cpp_flags), + include_paths: self.include_paths.or(other.include_paths), + system_includes: self.system_includes.or(other.system_includes), + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] pub struct PackageTripletDependency { /// Version range requirement From cb9cdb08c7a2dc906874f708dc49f80ceb7fdd25 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 16:05:19 -0400 Subject: [PATCH 13/62] Use WorkspaceConfig and remove PackageWorkspace struct; update qmod_output in WorkspaceConfig to skip serialization if None. --- src/models/package.rs | 23 +++-------------------- src/models/workspace.rs | 1 + 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index 25227b1..a969518 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -9,6 +9,7 @@ use crate::extensions::serde_utils::deserialize_null_default; use crate::models::version_req::make_version_req_schema; use super::extra::CompileOptions; +use super::workspace::WorkspaceConfig; #[inline] fn default_ver() -> Version { @@ -38,7 +39,7 @@ pub struct PackageConfig { pub shared_directories: Vec, /// Workspace configuration #[serde(default)] - pub workspace: PackageWorkspace, + pub workspace: WorkspaceConfig, /// Additional package metadata #[serde(default)] pub additional_data: PackageAdditionalData, @@ -68,7 +69,7 @@ impl Default for PackageConfig { version: default_ver(), dependencies_directory: "extern".into(), shared_directories: Vec::new(), - workspace: PackageWorkspace::default(), + workspace: Default::default(), additional_data: PackageAdditionalData::default(), triplet: PackageTripletsConfig::default(), config_version: default_ver(), @@ -78,24 +79,6 @@ impl Default for PackageConfig { } } -#[derive( - Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, -)] -pub struct PackageWorkspace { - /// Scripts to run at different stages - #[serde(default)] - pub scripts: PackageWorkspaceScripts, - /// Directories to search for qmod files - #[serde(default)] - pub qmod_search_dirs: Vec, - /// Files to include in the qmod - #[serde(default)] - pub qmod_include_files: Vec, - /// Output directory for the qmod - #[serde(default, deserialize_with = "deserialize_null_default")] - pub qmod_output: Option, -} - #[derive( Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, )] diff --git a/src/models/workspace.rs b/src/models/workspace.rs index 9b16a14..1ca2cd8 100644 --- a/src/models/workspace.rs +++ b/src/models/workspace.rs @@ -34,5 +34,6 @@ pub struct WorkspaceConfig { #[serde(default)] #[schemars(description = "Output path for the qmod.")] + #[serde(skip_serializing_if = "Option::is_none")] pub qmod_output: Option, } From aca1b31ca177a7170b3329486902fba5f9cfa7da Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 29 May 2025 16:09:58 -0400 Subject: [PATCH 14/62] Refactor PackageConfig default implementation and add Display trait for DependencyId and TripletId --- src/models/package.rs | 48 +++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index a969518..0c730dc 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; +use std::fmt::Display; use std::path::PathBuf; use schemars::JsonSchema; use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; -use crate::extensions::serde_utils::deserialize_null_default; use crate::models::version_req::make_version_req_schema; use super::extra::CompileOptions; @@ -62,23 +62,6 @@ pub struct PackageConfig { pub toolchain_out: Option, } -impl Default for PackageConfig { - fn default() -> Self { - Self { - id: DependencyId::default(), - version: default_ver(), - dependencies_directory: "extern".into(), - shared_directories: Vec::new(), - workspace: Default::default(), - additional_data: PackageAdditionalData::default(), - triplet: PackageTripletsConfig::default(), - config_version: default_ver(), - cmake: None, - toolchain_out: None, - } - } -} - #[derive( Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq, PartialOrd, Ord, )] @@ -213,3 +196,32 @@ pub struct PackageTripletDependency { #[serde(default)] pub qmod_export: bool, } + +impl Default for PackageConfig { + fn default() -> Self { + Self { + id: DependencyId::default(), + version: default_ver(), + dependencies_directory: "extern".into(), + shared_directories: Vec::new(), + workspace: Default::default(), + additional_data: PackageAdditionalData::default(), + triplet: PackageTripletsConfig::default(), + config_version: default_ver(), + cmake: None, + toolchain_out: None, + } + } +} + +impl Display for DependencyId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Display for TripletId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} From f23a543bbe71cdb1c26cac0cc77b05f88672f2be Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 19 Jul 2025 12:43:46 -0400 Subject: [PATCH 15/62] Remove unused import and fix typo in SharedPackageConfig struct --- src/models/shared_package.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index a0c8d68..ba0ee8a 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -6,7 +6,6 @@ use std::collections::HashMap; use super::package::{DependencyId, PackageConfig, TripletId}; pub type SharedLockedTripletMap = HashMap; -use crate::models::version_req::make_version_req_schema; // qpm.shared.json @@ -18,6 +17,9 @@ pub struct SharedPackageConfig { /// Package name #[schemars(description = "Package name")] pub config: PackageConfig, + + pub restored_tripelt: TripletId, + /// Triplet map #[schemars(description = "Triplet map")] pub locked_triplet: SharedLockedTripletMap, From 9466e5d674928cb60d6b306d64f7c5351b431098 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 19 Jul 2025 12:46:37 -0400 Subject: [PATCH 16/62] Fix typo --- src/models/shared_package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index ba0ee8a..32dc5fc 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -18,7 +18,7 @@ pub struct SharedPackageConfig { #[schemars(description = "Package name")] pub config: PackageConfig, - pub restored_tripelt: TripletId, + pub restored_triplet: TripletId, /// Triplet map #[schemars(description = "Triplet map")] From bf42facb637a53d95674c663c6026a2afbeb49c4 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:42:28 -0400 Subject: [PATCH 17/62] Refactor package configuration: rename CompileOptions to PackageTripletCompileOptions, update related structures, and implement triplet settings management --- src/extensions/mod.rs | 2 +- src/extensions/package_metadata.rs | 1 - src/extensions/serde_utils.rs | 4 +- src/extensions/workspace.rs | 2 +- src/gen-schema.rs | 5 +- src/lib.rs | 2 +- src/models/extra.rs | 45 +++++++--- src/models/mod.rs | 8 +- src/models/package.rs | 130 ++--------------------------- src/models/qpkg.rs | 4 +- src/models/shared_package.rs | 12 +-- src/models/triplet.rs | 115 +++++++++++++++++++++++++ src/models/version_req.rs | 2 +- 13 files changed, 177 insertions(+), 155 deletions(-) create mode 100644 src/models/triplet.rs diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs index a823a51..883df56 100644 --- a/src/extensions/mod.rs +++ b/src/extensions/mod.rs @@ -1,3 +1,3 @@ pub mod package_metadata; +pub mod serde_utils; pub mod workspace; -pub mod serde_utils; \ No newline at end of file diff --git a/src/extensions/package_metadata.rs b/src/extensions/package_metadata.rs index d3887fa..382888f 100644 --- a/src/extensions/package_metadata.rs +++ b/src/extensions/package_metadata.rs @@ -1,4 +1,3 @@ - use crate::models::package::PackageConfig; pub trait PackageMetadataExtensions {} diff --git a/src/extensions/serde_utils.rs b/src/extensions/serde_utils.rs index 838c9ef..30a006d 100644 --- a/src/extensions/serde_utils.rs +++ b/src/extensions/serde_utils.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Deserializer}; -/// +/// /// This function is used to deserialize a value from JSON, and if the value is `null`, it will return the default value of the type `T`. -/// +/// pub fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result where T: Default + Deserialize<'de>, diff --git a/src/extensions/workspace.rs b/src/extensions/workspace.rs index 75963d9..beebeb4 100644 --- a/src/extensions/workspace.rs +++ b/src/extensions/workspace.rs @@ -1,4 +1,4 @@ -use std::collections::{btree_map::Entry, BTreeMap}; +use std::collections::{BTreeMap, btree_map::Entry}; use crate::models::workspace::{WorkspaceConfig, WorkspaceScript}; diff --git a/src/gen-schema.rs b/src/gen-schema.rs index 212ae09..5f58ba0 100644 --- a/src/gen-schema.rs +++ b/src/gen-schema.rs @@ -1,10 +1,7 @@ use models::{package::PackageConfig, shared_package::SharedPackageConfig}; -pub mod models; pub mod extensions; - - - +pub mod models; fn main() { let shared_schema_json = schemars::schema_for!(SharedPackageConfig); diff --git a/src/lib.rs b/src/lib.rs index 882551e..26fd133 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,2 @@ +pub mod extensions; pub mod models; -pub mod extensions; \ No newline at end of file diff --git a/src/models/extra.rs b/src/models/extra.rs index cfdf3ce..c846f05 100644 --- a/src/models/extra.rs +++ b/src/models/extra.rs @@ -1,8 +1,6 @@ - use schemars::JsonSchema; use serde::{Deserialize, Serialize}; - /// - compileOptions (QPM.Commands.SupportedPropertiesCommand+CompileOptionsProperty): Additional options for compilation and edits to compilation related files. - Supported in: package /// Type: QPM.Commands.SupportedPropertiesCommand+CompileOptionsProperty /// - includePaths - OPTIONAL (System.String[]): Additional include paths to add, relative to the extern directory. @@ -12,8 +10,10 @@ use serde::{Deserialize, Serialize}; /// - cFlags - OPTIONAL (System.String[]): Additional C flags to add. #[derive(Serialize, Deserialize, JsonSchema, Default, Clone, Debug, Hash, Eq, PartialEq)] #[serde(rename_all = "camelCase")] -#[schemars(description = "Additional options for compilation and edits to compilation related files.")] -pub struct CompileOptions { +#[schemars( + description = "Additional options for compilation and edits to compilation related files." +)] +pub struct PackageTripletCompileOptions { /// Additional include paths to add, relative to the extern directory. #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "Additional include paths to add, relative to the extern directory.")] @@ -21,15 +21,11 @@ pub struct CompileOptions { /// Additional system include paths to add, relative to the extern directory. #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Additional system include paths to add, relative to the extern directory.")] + #[schemars( + description = "Additional system include paths to add, relative to the extern directory." + )] pub system_includes: Option>, - /// Additional C++ features to add. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(since="0.2.1", note="Unused and exclusive to CMake")] - #[schemars(description = "Additional C++ features to add. Deprecated, unused and exclusive to CMake.")] - pub cpp_features: Option>, - /// Additional C++ flags to add. #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "Additional C++ flags to add.")] @@ -41,3 +37,30 @@ pub struct CompileOptions { pub c_flags: Option>, } +impl PackageTripletCompileOptions { + pub fn merge(self, other: PackageTripletCompileOptions) -> Self { + Self { + c_flags: self.c_flags.or(other.c_flags), + cpp_flags: self.cpp_flags.or(other.cpp_flags), + include_paths: self.include_paths.or(other.include_paths), + system_includes: self.system_includes.or(other.system_includes), + } + } +} + +// #[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] +// pub struct PackageTripletSettings { +// /// Environment variables for this triplet. +// #[serde(default)] +// pub env: TripletEnvironmentMap, + +// /// Additional Compile options to be used with this package +// #[serde(skip_serializing_if = "Option::is_none")] +// #[schemars(description = "Additional compile options for the package.")] +// pub compile_options: Option, + +// /// QMod URL for this triplet +// #[serde(skip_serializing_if = "Option::is_none")] +// #[schemars(description = "QMod URL for this triplet.")] +// pub qmod_url: Option, +// } diff --git a/src/models/mod.rs b/src/models/mod.rs index 53bafc1..850c73e 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,10 +1,12 @@ pub mod package; -pub mod shared_package; +pub mod triplet; +pub mod workspace; + pub mod extra; +pub mod shared_package; pub mod qpackages; pub mod qpkg; -pub mod workspace; -mod version_req; \ No newline at end of file +mod version_req; diff --git a/src/models/package.rs b/src/models/package.rs index 0c730dc..ded65c7 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -1,14 +1,12 @@ -use std::collections::HashMap; use std::fmt::Display; use std::path::PathBuf; use schemars::JsonSchema; -use semver::{Version, VersionReq}; +use semver::Version; use serde::{Deserialize, Serialize}; -use crate::models::version_req::make_version_req_schema; +use crate::models::triplet::PackageTripletsConfig; -use super::extra::CompileOptions; use super::workspace::WorkspaceConfig; #[inline] @@ -23,6 +21,9 @@ pub fn package_target_version() -> Version { Version::parse(env!("CARGO_PKG_VERSION")).unwrap() } +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +pub struct DependencyId(pub String); + // qpm.json #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] @@ -44,7 +45,7 @@ pub struct PackageConfig { #[serde(default)] pub additional_data: PackageAdditionalData, /// Package triplet configurations - pub triplet: PackageTripletsConfig, + pub triplets: PackageTripletsConfig, /// Config version, defaults to 2.0.0 #[serde(default = "default_ver")] pub config_version: Version, @@ -86,117 +87,6 @@ pub struct PackageAdditionalData { pub license: String, } -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] -pub struct TripletId(pub String); - -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] -pub struct DependencyId(pub String); - -// Dependency ID -> Dependency -pub type TripletDependencyMap = HashMap; -// ENV -> VALUE -pub type TripletEnvironmentMap = HashMap; - -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] -pub struct PackageTripletsConfig { - /// Default configuration for all triplets. All triplets will inherit from this. - pub default: PackageTripletSettings, - /// Configuration for specific triplets - #[serde(flatten)] - pub specific_triplets: HashMap, -} - -impl PackageTripletsConfig { - /// Retrieves the settings for a specific triplet, merging with default settings. - /// - /// This function looks up settings for the specified triplet and combines them with - /// the default settings to create a complete configuration. The merging strategy is: - /// - /// - Dependencies: Both specific and default dependencies are included - /// - Environment variables: Both specific and default variables are included, with specific ones taking precedence - /// - Compile options: Merged with default options if present - /// - QMod URL: Uses the specific URL if available, otherwise falls back to the default - /// - /// # Parameters - /// * `triplet` - The triplet identifier to look up settings for - /// - /// # Returns - /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration - /// * `None` if the triplet is not found in the specific_triplets map - pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { - let found = self.specific_triplets.get(triplet)?; - - let default = &self.default; - let mut dependencies = found.dependencies.clone(); - dependencies.extend(default.dependencies.clone()); - - let mut env = found.env.clone(); - env.extend(default.env.clone()); - - let compile_options = found - .compile_options - .clone() - .map(|a| a.merge(self.default.compile_options.clone().unwrap_or_default())); - - Some(PackageTripletSettings { - dependencies, - env, - compile_options, - qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), - }) - } -} - -/// Triplet settings for a package -#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] -pub struct PackageTripletSettings { - /// Dependencies for this triplet - #[serde(default)] - pub dependencies: TripletDependencyMap, - - /// Environment variables for this triplet. - #[serde(default)] - pub env: TripletEnvironmentMap, - - /// Additional Compile options to be used with this package - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Additional compile options for the package.")] - pub compile_options: Option, - - /// QMod URL for this triplet - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "QMod URL for this triplet.")] - pub qmod_url: Option, -} - -impl CompileOptions { - pub fn merge(self, other: CompileOptions) -> Self { - Self { - c_flags: self.c_flags.or(other.c_flags), - cpp_features: self.cpp_features.or(other.cpp_features), - cpp_flags: self.cpp_flags.or(other.cpp_flags), - include_paths: self.include_paths.or(other.include_paths), - system_includes: self.system_includes.or(other.system_includes), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] -pub struct PackageTripletDependency { - /// Version range requirement - #[serde(rename = "versionRange")] - #[schemars(schema_with = "make_version_req_schema")] - pub version_range: VersionReq, - /// Target triplet - pub triplet: TripletId, - /// Whether to export this dependency to consumers - #[serde(default)] - pub export: bool, - /// Whether to include this dependency in the qmod - #[serde(default)] - pub qmod_export: bool, -} - impl Default for PackageConfig { fn default() -> Self { Self { @@ -206,7 +96,7 @@ impl Default for PackageConfig { shared_directories: Vec::new(), workspace: Default::default(), additional_data: PackageAdditionalData::default(), - triplet: PackageTripletsConfig::default(), + triplets: PackageTripletsConfig::default(), config_version: default_ver(), cmake: None, toolchain_out: None, @@ -219,9 +109,3 @@ impl Display for DependencyId { write!(f, "{}", self.0) } } - -impl Display for TripletId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index fe94f36..05cddd4 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -5,7 +5,9 @@ use std::collections::HashMap; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] -#[schemars(description = "QPKG package. Distributes a package with all triplet binaries and their headers.")] +#[schemars( + description = "QPKG package. Distributes a package with all triplet binaries and their headers." +)] pub struct QPkg { /// Triplet map pub triplets: HashMap, diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 32dc5fc..fcb9af9 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -1,12 +1,13 @@ use schemars::JsonSchema; -use semver::{Version, VersionReq}; +use semver::Version; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use super::package::{DependencyId, PackageConfig, TripletId}; +use crate::models::triplet::{PackageTripletDependency, TripletId}; -pub type SharedLockedTripletMap = HashMap; +use super::package::{DependencyId, PackageConfig}; +pub type SharedLockedTripletMap = HashMap; // qpm.shared.json #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] @@ -46,7 +47,6 @@ pub struct SharedTripletDependencyInfo { /// Version of the dependency #[schemars(description = "Version of the dependency.")] pub restored_version: Version, - /// Triplet of the dependency - #[schemars(description = "Triplet of the dependency.")] - pub triplet: TripletId, + /// Original triplet data + pub triplet: PackageTripletDependency, } diff --git a/src/models/triplet.rs b/src/models/triplet.rs new file mode 100644 index 0000000..596bbb5 --- /dev/null +++ b/src/models/triplet.rs @@ -0,0 +1,115 @@ +use std::{collections::HashMap, fmt::Display}; + +use schemars::JsonSchema; +use semver::VersionReq; +use serde::{Deserialize, Serialize}; + +use super::version_req::make_version_req_schema; + +use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; + +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +pub struct TripletId(pub String); + +/// Dependency ID -> Dependency +pub type TripletDependencyMap = HashMap; + +/// ENV -> VALUE +pub type TripletEnvironmentMap = HashMap; + +/// Package triplet configuration +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +pub struct PackageTripletsConfig { + /// Default configuration for all triplets. All triplets will inherit from this. + #[serde(default)] + pub default: PackageTriplet, + /// Configuration for specific triplets + #[serde(flatten)] + pub specific_triplets: HashMap, +} + +impl PackageTripletsConfig { + /// Retrieves the settings for a specific triplet, merging with default settings. + /// + /// This function looks up settings for the specified triplet and combines them with + /// the default settings to create a complete configuration. The merging strategy is: + /// + /// - Dependencies: Both specific and default dependencies are included + /// - Environment variables: Both specific and default variables are included, with specific ones taking precedence + /// - Compile options: Merged with default options if present + /// - QMod URL: Uses the specific URL if available, otherwise falls back to the default + /// + /// # Parameters + /// * `triplet` - The triplet identifier to look up settings for + /// + /// # Returns + /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration + /// * `None` if the triplet is not found in the specific_triplets map + pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { + let found = self.specific_triplets.get(triplet)?; + + let default = &self.default; + let mut dependencies = found.dependencies.clone(); + dependencies.extend(default.dependencies.clone()); + + let mut env = found.env.clone(); + env.extend(default.env.clone()); + + let compile_options = found + .compile_options + .clone() + .map(|a| a.merge(self.default.compile_options.clone().unwrap_or_default())); + + Some(PackageTriplet { + dependencies, + env, + compile_options, + qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), + }) + } +} + +/// Triplet +#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] +pub struct PackageTriplet { + /// Dependencies for this triplet + #[serde(default)] + pub dependencies: TripletDependencyMap, + + // TODO: use PackageTripletSettings + /// Environment variables for this triplet. + #[serde(default)] + pub env: TripletEnvironmentMap, + + /// Additional Compile options to be used with this package + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "Additional compile options for the package.")] + pub compile_options: Option, + + /// QMod URL for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod URL for this triplet.")] + pub qmod_url: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +pub struct PackageTripletDependency { + /// Version range requirement + #[serde(rename = "versionRange")] + #[schemars(schema_with = "make_version_req_schema")] + pub version_range: VersionReq, + /// Target triplet + pub triplet: TripletId, + /// Whether to export this dependency to consumers + #[serde(default)] + pub export: bool, + /// Whether to include this dependency in the qmod + #[serde(default)] + pub qmod_export: bool, +} + +impl Display for TripletId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/models/version_req.rs b/src/models/version_req.rs index 4f39899..8af69eb 100644 --- a/src/models/version_req.rs +++ b/src/models/version_req.rs @@ -1,4 +1,4 @@ -use schemars::{r#gen::SchemaGenerator, schema::Schema, schema_for, JsonSchema}; +use schemars::{JsonSchema, r#gen::SchemaGenerator, schema::Schema, schema_for}; pub fn make_version_req_schema(generator: &mut SchemaGenerator) -> Schema { let schema = String::json_schema(generator); From 30afc82170baf93b995583d6bfc0b33231d709bf Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:10:26 -0400 Subject: [PATCH 18/62] Refactor QPkg and QPkgTripletInfo structs: add header_file field to QPkg, update files field type to PathBuf, and adjust headers field in QPkgTripletInfo --- src/models/qpkg.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 05cddd4..87943f1 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -1,6 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] @@ -11,12 +11,13 @@ use std::collections::HashMap; pub struct QPkg { /// Triplet map pub triplets: HashMap, - - pub header_file: String, } #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] pub struct QPkgTripletInfo { + pub headers: Vec, + /// Paths to the binary files - pub files: Vec, + /// relative to the qpkg root + pub files: Vec, } From 5235bb1b5fe9a2e3cf1d43c0e1313753676b3b09 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:28:38 -0400 Subject: [PATCH 19/62] Refactor QPkgTripletInfo struct: rename headers field to shared_dir and update documentation --- src/models/qpkg.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 87943f1..06e93a6 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -15,7 +15,8 @@ pub struct QPkg { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] pub struct QPkgTripletInfo { - pub headers: Vec, + /// The directory where the headers are located + pub shared_dir: PathBuf, /// Paths to the binary files /// relative to the qpkg root From 546b77f5fb407e9e3901a41cbf3ed4094e8e9d83 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:34:28 -0400 Subject: [PATCH 20/62] Add dev dependencies array --- src/models/triplet.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 596bbb5..4d01bae 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -52,6 +52,10 @@ impl PackageTripletsConfig { let mut dependencies = found.dependencies.clone(); dependencies.extend(default.dependencies.clone()); + + let mut dev_dependencies = found.dependencies.clone(); + dev_dependencies.extend(default.dev_dependencies.clone()); + let mut env = found.env.clone(); env.extend(default.env.clone()); @@ -62,6 +66,7 @@ impl PackageTripletsConfig { Some(PackageTriplet { dependencies, + dev_dependencies, env, compile_options, qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), @@ -76,6 +81,10 @@ pub struct PackageTriplet { #[serde(default)] pub dependencies: TripletDependencyMap, + /// Dependencies for this triplet + #[serde(default)] + pub dev_dependencies: TripletDependencyMap, + // TODO: use PackageTripletSettings /// Environment variables for this triplet. #[serde(default)] From d2c9cbf754ac60ff6509e3699ac4865820e70860 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:49:53 -0400 Subject: [PATCH 21/62] Add constants --- src/models/package.rs | 2 ++ src/models/qpkg.rs | 2 ++ src/models/shared_package.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/models/package.rs b/src/models/package.rs index ded65c7..dcaffc6 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -21,6 +21,8 @@ pub fn package_target_version() -> Version { Version::parse(env!("CARGO_PKG_VERSION")).unwrap() } +pub const QPM_JSON: &str = "qpm2.json"; + #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] pub struct DependencyId(pub String); diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 06e93a6..95753c2 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -2,6 +2,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; +pub const QPKG_JSON: &str = "qpm2.qpkg.json"; + #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index fcb9af9..3014323 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -9,6 +9,8 @@ use super::package::{DependencyId, PackageConfig}; pub type SharedLockedTripletMap = HashMap; +pub const QPM_SHARED_JSON: &str = "qpm2.shared.json"; + // qpm.shared.json #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] From 8aff519e8dda4af43bc7b26703e990525f38d0d9 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:57:29 -0400 Subject: [PATCH 22/62] Refactor SharedTripletDependencyInfo struct: rename triplet field to restored_triplet for clarity --- src/models/shared_package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 3014323..8450cea 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -50,5 +50,5 @@ pub struct SharedTripletDependencyInfo { #[schemars(description = "Version of the dependency.")] pub restored_version: Version, /// Original triplet data - pub triplet: PackageTripletDependency, + pub restored_triplet: TripletId, } From a7a75ce7cb3cd7ba82c9835b1544376b17038348 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:07:38 -0400 Subject: [PATCH 23/62] Refactor QPkg struct: move shared_dir field to QPkgTripletInfo and update documentation --- src/models/qpkg.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 95753c2..37cad9e 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -11,15 +11,15 @@ pub const QPKG_JSON: &str = "qpm2.qpkg.json"; description = "QPKG package. Distributes a package with all triplet binaries and their headers." )] pub struct QPkg { + /// The directory where the headers are located + pub shared_dir: PathBuf, + /// Triplet map pub triplets: HashMap, } #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] pub struct QPkgTripletInfo { - /// The directory where the headers are located - pub shared_dir: PathBuf, - /// Paths to the binary files /// relative to the qpkg root pub files: Vec, From 0e7bf3493ed49fc0fb833fa814104a2998956aca Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:16:06 -0400 Subject: [PATCH 24/62] Refactor SharedTripletDependencyInfo and PackageTriplet structs: add version_range field and update documentation --- src/models/shared_package.rs | 9 +++++++-- src/models/triplet.rs | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 8450cea..b409336 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -1,9 +1,10 @@ +use super::version_req::make_version_req_schema; use schemars::JsonSchema; -use semver::Version; +use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::models::triplet::{PackageTripletDependency, TripletId}; +use crate::models::triplet::TripletId; use super::package::{DependencyId, PackageConfig}; @@ -49,6 +50,10 @@ pub struct SharedTripletDependencyInfo { /// Version of the dependency #[schemars(description = "Version of the dependency.")] pub restored_version: Version, + + #[schemars(schema_with = "make_version_req_schema")] + pub version_range: VersionReq, + /// Original triplet data pub restored_triplet: TripletId, } diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 4d01bae..de938b6 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -19,6 +19,9 @@ pub type TripletEnvironmentMap = HashMap; /// Package triplet configuration #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Configuration for a package's triplets map")] pub struct PackageTripletsConfig { /// Default configuration for all triplets. All triplets will inherit from this. #[serde(default)] @@ -76,6 +79,9 @@ impl PackageTripletsConfig { /// Triplet #[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Configuration for a package triplet.")] pub struct PackageTriplet { /// Dependencies for this triplet #[serde(default)] @@ -102,6 +108,9 @@ pub struct PackageTriplet { } #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] +#[allow(non_snake_case)] +#[serde(rename_all = "camelCase")] +#[schemars(description = "Dependency information for a package triplet.")] pub struct PackageTripletDependency { /// Version range requirement #[serde(rename = "versionRange")] From aa1e4c39f455fa2e77feb2b7d0f04c8e5b689a2f Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:24:02 -0400 Subject: [PATCH 25/62] Refactor QPkg struct: change triplets field type from HashMap to HashMap --- src/models/qpkg.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 37cad9e..4e65af5 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -2,6 +2,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; +use crate::models::triplet::TripletId; + pub const QPKG_JSON: &str = "qpm2.qpkg.json"; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] @@ -15,7 +17,7 @@ pub struct QPkg { pub shared_dir: PathBuf, /// Triplet map - pub triplets: HashMap, + pub triplets: HashMap, } #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] From d998ceed4345864562e78fd6b18981f55fb695bc Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 00:55:00 -0400 Subject: [PATCH 26/62] Remove `export`, superseded by `devDependencies` --- src/models/triplet.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index de938b6..60214be 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -118,9 +118,6 @@ pub struct PackageTripletDependency { pub version_range: VersionReq, /// Target triplet pub triplet: TripletId, - /// Whether to export this dependency to consumers - #[serde(default)] - pub export: bool, /// Whether to include this dependency in the qmod #[serde(default)] pub qmod_export: bool, From 14a28cb4ceb509dbaaba9f9b5543d4191d575aa7 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 11:28:32 -0400 Subject: [PATCH 27/62] Comment out version_range field in SharedTripletDependencyInfo struct --- src/models/shared_package.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index b409336..b9543d3 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -51,8 +51,8 @@ pub struct SharedTripletDependencyInfo { #[schemars(description = "Version of the dependency.")] pub restored_version: Version, - #[schemars(schema_with = "make_version_req_schema")] - pub version_range: VersionReq, + // #[schemars(schema_with = "make_version_req_schema")] + // pub version_range: VersionReq, /// Original triplet data pub restored_triplet: TripletId, From a4eb5b753e8d01bd096779d039cdbe18a4af7698 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:05:59 -0400 Subject: [PATCH 28/62] Add method to retrieve dependencies from PackageTriplet --- src/models/triplet.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 60214be..a44de02 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -107,6 +107,17 @@ pub struct PackageTriplet { pub qmod_url: Option, } +impl PackageTriplet { + + pub fn get_dependency(&self, dep_id: &DependencyId) -> Option<&PackageTripletDependency> { + self.dependencies.get(dep_id).or_else(|| { + self.dev_dependencies.get(dep_id) + }) + } + + +} + #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] From d084f8f5d6be4fb6c9adf28781508487d5b2daab Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:07:53 -0400 Subject: [PATCH 29/62] Refactor PackageTripletsConfig and PackageTriplet: streamline dependency retrieval and add combined dependencies iterator --- src/models/triplet.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index a44de02..c46216d 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -55,7 +55,6 @@ impl PackageTripletsConfig { let mut dependencies = found.dependencies.clone(); dependencies.extend(default.dependencies.clone()); - let mut dev_dependencies = found.dependencies.clone(); dev_dependencies.extend(default.dev_dependencies.clone()); @@ -108,14 +107,17 @@ pub struct PackageTriplet { } impl PackageTriplet { - pub fn get_dependency(&self, dep_id: &DependencyId) -> Option<&PackageTripletDependency> { - self.dependencies.get(dep_id).or_else(|| { - self.dev_dependencies.get(dep_id) - }) + self.dependencies + .get(dep_id) + .or_else(|| self.dev_dependencies.get(dep_id)) } - + pub fn get_dependencies_combined( + &self, + ) -> impl Iterator { + self.dependencies.iter().chain(self.dev_dependencies.iter()) + } } #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] From b5dda429ec86382fbbe69034f4f355134eb5484b Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:00:37 -0400 Subject: [PATCH 30/62] Add qmod_id field to PackageTriplet and update retrieval logic in PackageTripletsConfig --- src/models/triplet.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index c46216d..e91d405 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -72,6 +72,7 @@ impl PackageTripletsConfig { env, compile_options, qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), + qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), }) } } @@ -104,6 +105,11 @@ pub struct PackageTriplet { #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod URL for this triplet.")] pub qmod_url: Option, + + /// QMod URL for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod ID for this triplet.")] + pub qmod_id: Option, } impl PackageTriplet { From 5edcba9b0fdab2edef7a395b55b62b2215fa983d Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 18:37:12 -0400 Subject: [PATCH 31/62] Add qmod_required field to PackageTriplet and update retrieval logic in PackageTripletsConfig --- src/models/triplet.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index e91d405..2852bff 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -73,6 +73,7 @@ impl PackageTripletsConfig { compile_options, qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), + qmod_required: found.qmod_required.or(default.qmod_required), }) } } @@ -110,6 +111,11 @@ pub struct PackageTriplet { #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod ID for this triplet.")] pub qmod_id: Option, + + /// QMod URL for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod required for this triplet.")] + pub qmod_required: Option, } impl PackageTriplet { From fcfaffbddf46a5cfb3c168c04bb14adf3743b22e Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 18:39:22 -0400 Subject: [PATCH 32/62] Move qmod_required field to PackageTripletDependency and update related logic in PackageTripletsConfig --- src/models/triplet.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 2852bff..b1f7882 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -73,7 +73,6 @@ impl PackageTripletsConfig { compile_options, qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), - qmod_required: found.qmod_required.or(default.qmod_required), }) } } @@ -111,11 +110,6 @@ pub struct PackageTriplet { #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod ID for this triplet.")] pub qmod_id: Option, - - /// QMod URL for this triplet - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "QMod required for this triplet.")] - pub qmod_required: Option, } impl PackageTriplet { @@ -146,6 +140,11 @@ pub struct PackageTripletDependency { /// Whether to include this dependency in the qmod #[serde(default)] pub qmod_export: bool, + + /// QMod URL for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod required for this triplet.")] + pub qmod_required: Option, } impl Display for TripletId { From 31a095bef2436dfe7424a5ad90f937e8630268c1 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:10:43 -0400 Subject: [PATCH 33/62] Update shared_directories field in PackageConfig to use PathBuf instead of Vec --- src/models/package.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index dcaffc6..7f7736e 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -39,7 +39,7 @@ pub struct PackageConfig { /// Directory where dependencies are restored pub dependencies_directory: PathBuf, /// Directories shared by the package - pub shared_directories: Vec, + pub shared_directories: PathBuf, /// Workspace configuration #[serde(default)] pub workspace: WorkspaceConfig, @@ -95,7 +95,7 @@ impl Default for PackageConfig { id: DependencyId::default(), version: default_ver(), dependencies_directory: "extern".into(), - shared_directories: Vec::new(), + shared_directories: "shared".into(), workspace: Default::default(), additional_data: PackageAdditionalData::default(), triplets: PackageTripletsConfig::default(), From 2337dda3e68b243233cb47547e64070134002ac9 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:11:16 -0400 Subject: [PATCH 34/62] Rename shared_directories field to shared_directory in PackageConfig for consistency --- src/models/package.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index 7f7736e..8346cbb 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -39,7 +39,7 @@ pub struct PackageConfig { /// Directory where dependencies are restored pub dependencies_directory: PathBuf, /// Directories shared by the package - pub shared_directories: PathBuf, + pub shared_directory: PathBuf, /// Workspace configuration #[serde(default)] pub workspace: WorkspaceConfig, @@ -95,7 +95,7 @@ impl Default for PackageConfig { id: DependencyId::default(), version: default_ver(), dependencies_directory: "extern".into(), - shared_directories: "shared".into(), + shared_directory: "shared".into(), workspace: Default::default(), additional_data: PackageAdditionalData::default(), triplets: PackageTripletsConfig::default(), From b99e8044a313468956198527afef08b2295b14fd Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:55:37 -0400 Subject: [PATCH 35/62] Add binaries field to SharedTripletDependencyInfo for triplet binaries --- src/models/shared_package.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index b9543d3..f950e41 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -2,7 +2,7 @@ use super::version_req::make_version_req_schema; use schemars::JsonSchema; use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; use crate::models::triplet::TripletId; @@ -55,5 +55,11 @@ pub struct SharedTripletDependencyInfo { // pub version_range: VersionReq, /// Original triplet data + /// This is the triplet ID of the original triplet that this dependency was restored from. + #[schemars(description = "Restored triplet ID of the dependency.")] pub restored_triplet: TripletId, + + /// Binaries for this triplet + #[schemars(description = "Binaries for this triplet.")] + pub binaries: Vec } From 39657ac34e482e00d49b1d4fc6b243776c09e68a Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:26:13 -0400 Subject: [PATCH 36/62] Specify output binaries in triplet config --- src/models/qpkg.rs | 2 ++ src/models/shared_package.rs | 4 ++-- src/models/triplet.rs | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index 4e65af5..d27a213 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -6,6 +6,8 @@ use crate::models::triplet::TripletId; pub const QPKG_JSON: &str = "qpm2.qpkg.json"; +/// QPKG package configuration +/// Distributes a package with all triplet binaries and their headers. #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index f950e41..5f16550 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -59,7 +59,7 @@ pub struct SharedTripletDependencyInfo { #[schemars(description = "Restored triplet ID of the dependency.")] pub restored_triplet: TripletId, - /// Binaries for this triplet + /// Binaries restored for this triplet #[schemars(description = "Binaries for this triplet.")] - pub binaries: Vec + pub restored_binaries: Vec } diff --git a/src/models/triplet.rs b/src/models/triplet.rs index b1f7882..1ae7630 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::Display}; +use std::{collections::HashMap, fmt::Display, path::PathBuf}; use schemars::JsonSchema; use semver::VersionReq; @@ -71,6 +71,7 @@ impl PackageTripletsConfig { dev_dependencies, env, compile_options, + out_binaries: found.out_binaries.clone().or(default.out_binaries.clone()), qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), }) @@ -110,6 +111,11 @@ pub struct PackageTriplet { #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod ID for this triplet.")] pub qmod_id: Option, + + /// Output binaries for this triplet + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "Output binaries for this triplet.")] + pub out_binaries: Option>, } impl PackageTriplet { From e38d016b671ea804579171107f4b5c7a7eb6e3c8 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 11:34:24 -0400 Subject: [PATCH 37/62] Add iteration methods for triplets in PackageTripletsConfig --- src/models/triplet.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 1ae7630..02d976d 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::Display, path::PathBuf}; +use std::{borrow::Cow, collections::HashMap, fmt::Display, path::PathBuf}; use schemars::JsonSchema; use semver::VersionReq; @@ -76,6 +76,29 @@ impl PackageTripletsConfig { qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), }) } + + /// Iterates over all triplets, including the default one. + pub fn iter_triplets(&self) -> impl Iterator)> { + let other = self.specific_triplets.keys().map(|k| { + let package_triplet = self.get_triplet_settings(k).unwrap(); + + (k.clone(), Cow::Owned(package_triplet)) + }); + + let value = ( + TripletId("default".to_string()), + Cow::Borrowed(&self.default), + ); + + std::iter::once(value).chain(other) + } + + pub fn iter_non_default_triplets(&self) -> impl Iterator { + self.specific_triplets.keys().map(|k| { + let package_triplet = self.get_triplet_settings(k).unwrap(); + (k, package_triplet) + }) + } } /// Triplet From 98cf91ea1589ede2c579dfef66a4ac13916ed75b Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 18:40:28 -0400 Subject: [PATCH 38/62] Add default_triplet_id function and update get_triplet_settings logic --- src/models/triplet.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 02d976d..6354358 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -17,6 +17,10 @@ pub type TripletDependencyMap = HashMap; /// ENV -> VALUE pub type TripletEnvironmentMap = HashMap; +pub fn default_triplet_id() -> TripletId { + TripletId("default".to_owned()) +} + /// Package triplet configuration #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq)] #[allow(non_snake_case)] @@ -49,6 +53,10 @@ impl PackageTripletsConfig { /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration /// * `None` if the triplet is not found in the specific_triplets map pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { + if triplet == &default_triplet_id() { + return Some(self.default.clone()); + } + let found = self.specific_triplets.get(triplet)?; let default = &self.default; @@ -86,7 +94,7 @@ impl PackageTripletsConfig { }); let value = ( - TripletId("default".to_string()), + default_triplet_id(), Cow::Borrowed(&self.default), ); From d69c2d30a0a25d0db342ae7dedea47ff4425a507 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 18:48:18 -0400 Subject: [PATCH 39/62] Enhance DependencyId and TripletId structs with PartialOrd and Ord traits for improved sorting capabilities --- src/models/package.rs | 2 +- src/models/triplet.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/package.rs b/src/models/package.rs index 8346cbb..3c4eae6 100644 --- a/src/models/package.rs +++ b/src/models/package.rs @@ -23,7 +23,7 @@ pub fn package_target_version() -> Version { pub const QPM_JSON: &str = "qpm2.json"; -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct DependencyId(pub String); // qpm.json diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 6354358..6bd9f47 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -8,7 +8,7 @@ use super::version_req::make_version_req_schema; use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct TripletId(pub String); /// Dependency ID -> Dependency From 84ea1270f2d5bd6ad95093153dc2876362da6b7a Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 19:02:14 -0400 Subject: [PATCH 40/62] Add environment variables to SharedTriplet and SharedTripletDependencyInfo structs --- src/models/shared_package.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 5f16550..05c6402 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -37,6 +37,9 @@ pub struct SharedTriplet { /// Triplet map #[schemars(description = "Triplet map")] pub restored_dependencies: HashMap, + + #[schemars(description = "Environment variables for the triplet.")] + pub env: HashMap, // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? @@ -61,5 +64,9 @@ pub struct SharedTripletDependencyInfo { /// Binaries restored for this triplet #[schemars(description = "Binaries for this triplet.")] - pub restored_binaries: Vec + pub restored_binaries: Vec, + + /// Restored environment variables for the triplet + #[schemars(description = "Restored environment variables for the triplet.")] + pub restored_env: HashMap, } From 40a94f7977a1817b41566d63d26fd3e14f665367 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 19:30:01 -0400 Subject: [PATCH 41/62] Refactor SharedTriplet and SharedTripletDependencyInfo to use TripletEnvironmentMap for environment variables --- src/models/shared_package.rs | 7 ++++--- src/models/triplet.rs | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 05c6402..4810f2c 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -4,7 +4,7 @@ use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; -use crate::models::triplet::TripletId; +use crate::models::triplet::{TripletEnvironmentMap, TripletId}; use super::package::{DependencyId, PackageConfig}; @@ -29,6 +29,7 @@ pub struct SharedPackageConfig { pub locked_triplet: SharedLockedTripletMap, } + #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] @@ -39,7 +40,7 @@ pub struct SharedTriplet { pub restored_dependencies: HashMap, #[schemars(description = "Environment variables for the triplet.")] - pub env: HashMap, + pub env: TripletEnvironmentMap, // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? @@ -68,5 +69,5 @@ pub struct SharedTripletDependencyInfo { /// Restored environment variables for the triplet #[schemars(description = "Restored environment variables for the triplet.")] - pub restored_env: HashMap, + pub restored_env: TripletEnvironmentMap, } diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 6bd9f47..8b375c8 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -17,6 +17,11 @@ pub type TripletDependencyMap = HashMap; /// ENV -> VALUE pub type TripletEnvironmentMap = HashMap; +/// Represents the game id for a QMOD package. +pub const QPM_ENV_GAME_ID: &str = "QMOD_GAME_ID"; +/// Represents the game version for a QMOD package. +pub const QPM_ENV_GAME_VERSION: &str = "QMOD_GAME_VERSION"; + pub fn default_triplet_id() -> TripletId { TripletId("default".to_owned()) } From ad9cef9bf96dd913e42d3330ad486f86d694afbb Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 26 Jul 2025 19:33:25 -0400 Subject: [PATCH 42/62] Add output binaries field to SharedTriplet struct --- src/models/shared_package.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index 4810f2c..e6075af 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -41,6 +41,10 @@ pub struct SharedTriplet { #[schemars(description = "Environment variables for the triplet.")] pub env: TripletEnvironmentMap, + + /// Output binaries for this triplet + #[schemars(description = "Output binaries for this triplet.")] + pub out_binaries: Vec, // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? From 780c3a1bc08bb51a19fefb16fa69b81ba8978ae9 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sun, 27 Jul 2025 14:21:43 -0400 Subject: [PATCH 43/62] Remove commented-out output binaries field from SharedTriplet struct --- src/models/shared_package.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index e6075af..aeed8e7 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -42,9 +42,10 @@ pub struct SharedTriplet { #[schemars(description = "Environment variables for the triplet.")] pub env: TripletEnvironmentMap, - /// Output binaries for this triplet - #[schemars(description = "Output binaries for this triplet.")] - pub out_binaries: Vec, + // /// Output binaries for this triplet + // #[schemars(description = "Output binaries for this triplet.")] + // pub out_binaries: Vec, + // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? From c6326babd6c260f674dd7e6975f6d71b867945b9 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sun, 27 Jul 2025 14:30:36 -0400 Subject: [PATCH 44/62] Add methods to retrieve triplets from PackageTripletsConfig --- src/models/triplet.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 8b375c8..afb305b 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -90,6 +90,21 @@ impl PackageTripletsConfig { }) } + pub fn get_triplet(&self, triplet: &TripletId) -> Option<&PackageTriplet> { + if triplet == &default_triplet_id() { + return Some(&self.default); + } + + self.specific_triplets.get(triplet) + } + pub fn get_triplet_mut(&mut self, triplet: &TripletId) -> Option<&mut PackageTriplet> { + if triplet == &default_triplet_id() { + return Some(&mut self.default); + } + + self.specific_triplets.get_mut(triplet) + } + /// Iterates over all triplets, including the default one. pub fn iter_triplets(&self) -> impl Iterator)> { let other = self.specific_triplets.keys().map(|k| { From bb902df2b44ee7d5877105ae7f2dad9c94705e14 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:41:28 -0400 Subject: [PATCH 45/62] Add qmod_template key for specifying mod.json path --- src/models/shared_package.rs | 8 ++------ src/models/triplet.rs | 39 ++++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/models/shared_package.rs b/src/models/shared_package.rs index aeed8e7..20484f5 100644 --- a/src/models/shared_package.rs +++ b/src/models/shared_package.rs @@ -1,6 +1,5 @@ -use super::version_req::make_version_req_schema; use schemars::JsonSchema; -use semver::{Version, VersionReq}; +use semver::Version; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; @@ -29,7 +28,6 @@ pub struct SharedPackageConfig { pub locked_triplet: SharedLockedTripletMap, } - #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] @@ -41,11 +39,10 @@ pub struct SharedTriplet { #[schemars(description = "Environment variables for the triplet.")] pub env: TripletEnvironmentMap, - // /// Output binaries for this triplet // #[schemars(description = "Output binaries for this triplet.")] // pub out_binaries: Vec, - + // default should not appear here. All triplets should be listed // TODO: Include checksums here? // TODO: Include qpkg urls here? @@ -62,7 +59,6 @@ pub struct SharedTripletDependencyInfo { // #[schemars(schema_with = "make_version_req_schema")] // pub version_range: VersionReq, - /// Original triplet data /// This is the triplet ID of the original triplet that this dependency was restored from. #[schemars(description = "Restored triplet ID of the dependency.")] diff --git a/src/models/triplet.rs b/src/models/triplet.rs index afb305b..02817a0 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -8,7 +8,9 @@ use super::version_req::make_version_req_schema; use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; -#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive( + Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash, PartialOrd, Ord, +)] pub struct TripletId(pub String); /// Dependency ID -> Dependency @@ -62,31 +64,32 @@ impl PackageTripletsConfig { return Some(self.default.clone()); } - let found = self.specific_triplets.get(triplet)?; + let found = self.specific_triplets.get(triplet)?.clone(); + let default = self.default.clone(); - let default = &self.default; - let mut dependencies = found.dependencies.clone(); - dependencies.extend(default.dependencies.clone()); + let mut dependencies = found.dependencies; + dependencies.extend(default.dependencies); - let mut dev_dependencies = found.dependencies.clone(); - dev_dependencies.extend(default.dev_dependencies.clone()); + let mut dev_dependencies = found.dev_dependencies; + dev_dependencies.extend(default.dev_dependencies); - let mut env = found.env.clone(); - env.extend(default.env.clone()); + let mut env = found.env; + env.extend(default.env); let compile_options = found .compile_options .clone() - .map(|a| a.merge(self.default.compile_options.clone().unwrap_or_default())); + .map(|a| a.merge(default.compile_options.unwrap_or_default())); Some(PackageTriplet { dependencies, dev_dependencies, env, compile_options, - out_binaries: found.out_binaries.clone().or(default.out_binaries.clone()), - qmod_url: found.qmod_url.clone().or(default.qmod_url.clone()), - qmod_id: found.qmod_id.clone().or(default.qmod_id.clone()), + out_binaries: found.out_binaries.clone().or(default.out_binaries), + qmod_url: found.qmod_url.clone().or(default.qmod_url), + qmod_id: found.qmod_id.clone().or(default.qmod_id), + qmod_template: found.qmod_template.clone().or(default.qmod_template), }) } @@ -113,10 +116,7 @@ impl PackageTripletsConfig { (k.clone(), Cow::Owned(package_triplet)) }); - let value = ( - default_triplet_id(), - Cow::Borrowed(&self.default), - ); + let value = (default_triplet_id(), Cow::Borrowed(&self.default)); std::iter::once(value).chain(other) } @@ -163,6 +163,11 @@ pub struct PackageTriplet { #[schemars(description = "QMod ID for this triplet.")] pub qmod_id: Option, + /// QMod template path for this triplet e.g mod.template.json + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "QMod template for this triplet.")] + pub qmod_template: Option, + /// Output binaries for this triplet #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "Output binaries for this triplet.")] From 9fa5ba5e3eb06f15531c8e5b7c7b7b6d5c68f023 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:16:06 -0400 Subject: [PATCH 46/62] Refactor QPkg struct to include PackageConfig and update schemars descriptions --- src/models/qpkg.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/models/qpkg.rs b/src/models/qpkg.rs index d27a213..3d8a4df 100644 --- a/src/models/qpkg.rs +++ b/src/models/qpkg.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; -use crate::models::triplet::TripletId; +use crate::models::{package::PackageConfig, triplet::TripletId}; pub const QPKG_JSON: &str = "qpm2.qpkg.json"; @@ -15,10 +15,16 @@ pub const QPKG_JSON: &str = "qpm2.qpkg.json"; description = "QPKG package. Distributes a package with all triplet binaries and their headers." )] pub struct QPkg { + /// Package configuration + #[schemars(description = "Package configuration")] + pub config: PackageConfig, + /// The directory where the headers are located + #[schemars(description = "The directory where the headers are located")] pub shared_dir: PathBuf, /// Triplet map + #[schemars(description = "Triplet map")] pub triplets: HashMap, } From b8f8b1c5d2bde7998f128c5f0883e55304e0a899 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:33:54 -0400 Subject: [PATCH 47/62] Fix TripletId default and make triplet optional --- src/models/triplet.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 02817a0..18723fc 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -9,10 +9,11 @@ use super::version_req::make_version_req_schema; use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; #[derive( - Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq, Hash, PartialOrd, Ord, + Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord, )] pub struct TripletId(pub String); + /// Dependency ID -> Dependency pub type TripletDependencyMap = HashMap; @@ -25,7 +26,7 @@ pub const QPM_ENV_GAME_ID: &str = "QMOD_GAME_ID"; pub const QPM_ENV_GAME_VERSION: &str = "QMOD_GAME_VERSION"; pub fn default_triplet_id() -> TripletId { - TripletId("default".to_owned()) + TripletId::default() } /// Package triplet configuration @@ -197,8 +198,11 @@ pub struct PackageTripletDependency { #[serde(rename = "versionRange")] #[schemars(schema_with = "make_version_req_schema")] pub version_range: VersionReq, + /// Target triplet - pub triplet: TripletId, + #[schemars(description = "Target triplet for this dependency.")] + pub triplet: Option, + /// Whether to include this dependency in the qmod #[serde(default)] pub qmod_export: bool, @@ -214,3 +218,9 @@ impl Display for TripletId { write!(f, "{}", self.0) } } + +impl Default for TripletId { + fn default() -> Self { + TripletId("default".to_owned()) + } +} \ No newline at end of file From c17f052b3f7a9dae561ef7bf841184bf36ef4121 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:41:19 -0400 Subject: [PATCH 48/62] Don't serialize if null --- src/models/triplet.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 18723fc..c26f535 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -199,10 +199,11 @@ pub struct PackageTripletDependency { #[schemars(schema_with = "make_version_req_schema")] pub version_range: VersionReq, - /// Target triplet + /// Target triplet. `default` if null #[schemars(description = "Target triplet for this dependency.")] + #[serde(skip_serializing_if = "Option::is_none")] pub triplet: Option, - + /// Whether to include this dependency in the qmod #[serde(default)] pub qmod_export: bool, From 8d43a1a2103499e231e008856042a07ef421e439 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:49:10 -0400 Subject: [PATCH 49/62] Update qmod_required field description in PackageTripletDependency --- src/models/triplet.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index c26f535..969d8f2 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -208,9 +208,10 @@ pub struct PackageTripletDependency { #[serde(default)] pub qmod_export: bool, - /// QMod URL for this triplet + /// Whether this is required/optional in the qmod + /// QMod required field for this dependency #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "QMod required for this triplet.")] + #[schemars(description = "QMod required field for this dependency.")] pub qmod_required: Option, } From 678866cf4b720247654eee76c437ad02e114e915 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 2 Aug 2025 11:37:03 -0400 Subject: [PATCH 50/62] Move ndk, qmod_include_dirs, qmod_include_files, and qmod_output from workspace to triplet --- src/models/triplet.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/models/workspace.rs | 18 ------------------ 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 969d8f2..a2c8c0c 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -13,7 +13,6 @@ use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; )] pub struct TripletId(pub String); - /// Dependency ID -> Dependency pub type TripletDependencyMap = HashMap; @@ -82,15 +81,32 @@ impl PackageTripletsConfig { .clone() .map(|a| a.merge(default.compile_options.unwrap_or_default())); + let qmod_include_files = found + .qmod_include_files + .into_iter() + .chain(default.qmod_include_files) + .collect(); + + let qmod_include_dirs = found + .qmod_include_dirs + .into_iter() + .chain(default.qmod_include_dirs) + .collect(); + Some(PackageTriplet { dependencies, dev_dependencies, env, compile_options, + qmod_include_dirs, + qmod_include_files, + out_binaries: found.out_binaries.clone().or(default.out_binaries), qmod_url: found.qmod_url.clone().or(default.qmod_url), qmod_id: found.qmod_id.clone().or(default.qmod_id), qmod_template: found.qmod_template.clone().or(default.qmod_template), + qmod_output: found.qmod_output.clone().or(default.qmod_output), + ndk: found.ndk.clone().or(default.ndk), }) } @@ -159,16 +175,35 @@ pub struct PackageTriplet { #[schemars(description = "QMod URL for this triplet.")] pub qmod_url: Option, - /// QMod URL for this triplet + /// QMod ID for this triplet #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod ID for this triplet.")] pub qmod_id: Option, + #[serde(default)] + #[schemars(description = "List of directories to search during qmod creation.")] + pub qmod_include_dirs: Vec, + + #[serde(default)] + #[schemars(description = "List of files to include in the resulting qmod.")] + pub qmod_include_files: Vec, + + #[serde(default)] + #[schemars(description = "Output path for the qmod.")] + #[serde(skip_serializing_if = "Option::is_none")] + pub qmod_output: Option, + /// QMod template path for this triplet e.g mod.template.json #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "QMod template for this triplet.")] pub qmod_template: Option, + /// NDK Version Range + #[serde(skip_serializing_if = "Option::is_none")] + #[schemars(description = "The NDK version range.")] + #[schemars(schema_with = "make_version_req_schema")] + pub ndk: Option, + /// Output binaries for this triplet #[serde(skip_serializing_if = "Option::is_none")] #[schemars(description = "Output binaries for this triplet.")] @@ -225,4 +260,4 @@ impl Default for TripletId { fn default() -> Self { TripletId("default".to_owned()) } -} \ No newline at end of file +} diff --git a/src/models/workspace.rs b/src/models/workspace.rs index 1ca2cd8..c1c6e9d 100644 --- a/src/models/workspace.rs +++ b/src/models/workspace.rs @@ -18,22 +18,4 @@ pub struct WorkspaceConfig { #[schemars(description = "Scripts associated with the workspace.")] pub scripts: BTreeMap, - /// NDK Version Range - #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "The NDK version range.")] - #[schemars(schema_with = "make_version_req_schema")] - pub ndk: Option, - - #[serde(default)] - #[schemars(description = "List of directories to search during qmod creation.")] - pub qmod_include_dirs: Vec, - - #[serde(default)] - #[schemars(description = "List of files to include in the resulting qmod.")] - pub qmod_include_files: Vec, - - #[serde(default)] - #[schemars(description = "Output path for the qmod.")] - #[serde(skip_serializing_if = "Option::is_none")] - pub qmod_output: Option, } From 318d85f1f2ffe70b877c65fa35e92f348c4353e1 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 2 Aug 2025 11:48:41 -0400 Subject: [PATCH 51/62] Refactor triplet retrieval methods to provide standalone access without merging defaults --- src/models/triplet.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index a2c8c0c..0003a39 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -86,7 +86,7 @@ impl PackageTripletsConfig { .into_iter() .chain(default.qmod_include_files) .collect(); - + let qmod_include_dirs = found .qmod_include_dirs .into_iter() @@ -110,14 +110,16 @@ impl PackageTripletsConfig { }) } - pub fn get_triplet(&self, triplet: &TripletId) -> Option<&PackageTriplet> { + /// Retrieves the settings for a specific triplet without merging with default settings. + pub fn get_triplet_standalone(&self, triplet: &TripletId) -> Option<&PackageTriplet> { if triplet == &default_triplet_id() { return Some(&self.default); } self.specific_triplets.get(triplet) } - pub fn get_triplet_mut(&mut self, triplet: &TripletId) -> Option<&mut PackageTriplet> { + /// Retrieves the settings for a specific triplet, allowing mutable access. + pub fn get_triplet_standalone_mut(&mut self, triplet: &TripletId) -> Option<&mut PackageTriplet> { if triplet == &default_triplet_id() { return Some(&mut self.default); } From 4d66d7cf4c60864aa7baa315c696ce77a1a81e56 Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 2 Aug 2025 23:14:54 -0400 Subject: [PATCH 52/62] Add QPackagesVersion struct to represent package version details --- src/models/qpackages.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/qpackages.rs b/src/models/qpackages.rs index c1fe259..716765f 100644 --- a/src/models/qpackages.rs +++ b/src/models/qpackages.rs @@ -1,8 +1,14 @@ use schemars::JsonSchema; +use semver::Version; use serde::{Deserialize, Serialize}; use super::package::PackageConfig; +pub struct QPackagesVersion { + pub id: String, + pub version: Version, +} + #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] #[allow(non_snake_case)] #[serde(rename_all = "camelCase")] From 1e3cc0a45218d384f946ec22af6404d80c0c706b Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 2 Aug 2025 23:19:06 -0400 Subject: [PATCH 53/62] Add serde to QPackagesVersion --- src/models/qpackages.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/models/qpackages.rs b/src/models/qpackages.rs index 716765f..201bdde 100644 --- a/src/models/qpackages.rs +++ b/src/models/qpackages.rs @@ -2,10 +2,13 @@ use schemars::JsonSchema; use semver::Version; use serde::{Deserialize, Serialize}; +use crate::models::package::DependencyId; + use super::package::PackageConfig; +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq, Eq)] pub struct QPackagesVersion { - pub id: String, + pub id: DependencyId, pub version: Version, } From 45f5b33748a6958161e6b58b766711e9c1510a4a Mon Sep 17 00:00:00 2001 From: FernTheDev <15272073+Fernthedev@users.noreply.github.com> Date: Thu, 7 Aug 2025 15:57:34 -0400 Subject: [PATCH 54/62] Fix schema --- qpm.schema.json | 432 +++++++++++++------------------ qpm.shared.schema.json | 570 ++++++++++++++++++----------------------- 2 files changed, 428 insertions(+), 574 deletions(-) diff --git a/qpm.schema.json b/qpm.schema.json index cb75fbc..8ed7096 100644 --- a/qpm.schema.json +++ b/qpm.schema.json @@ -4,47 +4,78 @@ "description": "Configuration for a package.", "type": "object", "required": [ - "dependencies", - "dependenciesDir", - "info", - "sharedDir" + "dependenciesDirectory", + "id", + "sharedDirectory", + "triplets", + "version" ], "properties": { - "dependencies": { - "description": "The dependencies of the package.", - "type": "array", - "items": { - "$ref": "#/definitions/PackageDependency" - } + "additionalData": { + "description": "Additional package metadata", + "default": { + "author": "", + "description": "", + "license": "" + }, + "allOf": [ + { + "$ref": "#/definitions/PackageAdditionalData" + } + ] }, - "dependenciesDir": { - "description": "The directory where dependencies are stored.", + "cmake": { + "description": "Whether to generate CMake files on restore.", + "type": [ + "boolean", + "null" + ] + }, + "configVersion": { + "description": "Config version, defaults to 2.0.0", + "default": "2.0.0", + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "dependenciesDirectory": { + "description": "Directory where dependencies are restored", "type": "string" }, - "info": { - "description": "The package metadata.", + "id": { + "description": "Package ID", "allOf": [ { - "$ref": "#/definitions/PackageMetadata" + "$ref": "#/definitions/DependencyId" } ] }, - "sharedDir": { - "description": "The directory where shared files are stored.", + "sharedDirectory": { + "description": "Directories shared by the package", "type": "string" }, + "toolchainOut": { + "description": "Path to generate a toolchain JSON file describing the project setup configuration.", + "type": [ + "string", + "null" + ] + }, + "triplets": { + "description": "Package triplet configurations", + "allOf": [ + { + "$ref": "#/definitions/PackageTripletsConfig" + } + ] + }, "version": { - "description": "The version of the package configuration.", - "default": "0.4.0", + "description": "Package version", "type": "string", "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }, "workspace": { - "description": "The workspace configuration.", + "description": "Workspace configuration", "default": { - "qmodIncludeDirs": [], - "qmodIncludeFiles": [], - "qmodOutput": null, "scripts": {} }, "allOf": [ @@ -55,101 +86,130 @@ } }, "definitions": { - "AdditionalPackageMetadata": { - "description": "Additional metadata for the package.", + "DependencyId": { + "type": "string" + }, + "PackageAdditionalData": { "type": "object", "properties": { - "branchName": { - "description": "The branch name of a GitHub repository. Only used when a valid GitHub URL is provided.", - "type": [ - "string", - "null" - ] + "author": { + "description": "Package author", + "default": "", + "type": "string" }, - "cmake": { - "description": "Whether to generate CMake files on restore.", - "type": [ - "boolean", - "null" - ] + "description": { + "description": "Package description", + "default": "", + "type": "string" }, + "license": { + "description": "Package license", + "default": "", + "type": "string" + } + } + }, + "PackageTriplet": { + "description": "Configuration for a package triplet.", + "type": "object", + "required": [ + "ndk" + ], + "properties": { "compileOptions": { "description": "Additional compile options for the package.", "anyOf": [ { - "$ref": "#/definitions/CompileOptions" + "$ref": "#/definitions/PackageTripletCompileOptions" }, { "type": "null" } ] }, - "debugSoLink": { - "description": "The link to the debug shared object file.", - "type": [ - "string", - "null" - ] + "dependencies": { + "description": "Dependencies for this triplet", + "default": {}, + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PackageTripletDependency" + } }, - "headersOnly": { - "description": "Whether or not the package is header only", - "type": [ - "boolean", - "null" - ] + "devDependencies": { + "description": "Dependencies for this triplet", + "default": {}, + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PackageTripletDependency" + } }, - "modLink": { - "description": "The link to the qmod file.", - "type": [ - "string", - "null" - ] + "env": { + "description": "Environment variables for this triplet.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "overrideSoName": { - "description": "The override name for the shared object file.", - "type": [ - "string", - "null" - ] + "ndk": { + "description": "The NDK version range.", + "type": "string", + "properties": { + "format": { + "title": "String", + "type": "string" + } + } }, - "overrideStaticName": { - "description": "The override name for the static library file.", + "outBinaries": { + "description": "Output binaries for this triplet.", "type": [ - "string", + "array", "null" - ] + ], + "items": { + "type": "string" + } }, - "soLink": { - "description": "The link to the shared object file.", + "qmodId": { + "description": "QMod ID for this triplet.", "type": [ "string", "null" ] }, - "staticLink": { - "description": "The link to the static library file.", - "type": [ - "string", - "null" - ] + "qmodIncludeDirs": { + "description": "List of directories to search during qmod creation.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "qmodIncludeFiles": { + "description": "List of files to include in the resulting qmod.", + "default": [], + "type": "array", + "items": { + "type": "string" + } }, - "staticLinking": { - "description": "Whether the package is statically linked. Deprecated, use staticLink instead.", - "deprecated": true, + "qmodOutput": { + "description": "Output path for the qmod.", "type": [ - "boolean", + "string", "null" ] }, - "subFolder": { - "description": "Sub-folder to use from the downloaded repository or zip, so one repository can contain multiple packages.", + "qmodTemplate": { + "description": "QMod template for this triplet.", "type": [ "string", "null" ] }, - "toolchainOut": { - "description": "Path to generate a toolchain JSON file describing the project setup configuration.", + "qmodUrl": { + "description": "QMod URL for this triplet.", "type": [ "string", "null" @@ -157,7 +217,7 @@ } } }, - "CompileOptions": { + "PackageTripletCompileOptions": { "description": "Additional options for compilation and edits to compilation related files.", "type": "object", "properties": { @@ -171,17 +231,6 @@ "type": "string" } }, - "cppFeatures": { - "description": "Additional C++ features to add. Deprecated, unused and exclusive to CMake.", - "deprecated": true, - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } - }, "cppFlags": { "description": "Additional C++ flags to add.", "type": [ @@ -214,201 +263,76 @@ } } }, - "DependencyLibType": { - "description": "Describes the dependency type.", - "oneOf": [ - { - "description": "Shared library", - "type": "string", - "enum": [ - "shared" - ] - }, - { - "description": "Static library", - "type": "string", - "enum": [ - "static" - ] - }, - { - "description": "Header only", - "type": "string", - "enum": [ - "headerOnly" - ] - } - ] - }, - "PackageDependency": { - "description": "A dependency of the package.", + "PackageTripletDependency": { + "description": "Dependency information for a package triplet.", "type": "object", "required": [ - "additionalData", - "id", "versionRange" ], "properties": { - "additionalData": { - "description": "Additional metadata for the dependency", - "allOf": [ - { - "$ref": "#/definitions/PackageDependencyModifier" - } - ] - }, - "id": { - "description": "The unique identifier of the dependency", - "type": "string" - }, - "versionRange": { - "description": "The version range of the dependency", - "type": "string", - "properties": { - "format": { - "title": "String", - "type": "string" - } - } - } - } - }, - "PackageDependencyModifier": { - "description": "Modifies how a dependency should be restored.", - "type": "object", - "properties": { - "extraFiles": { - "description": "Additional files to be downloaded.", - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } + "qmodExport": { + "description": "Whether to include this dependency in the qmod", + "default": false, + "type": "boolean" }, - "includeQmod": { - "description": "If the mod dependency should be included in the generated mod.json. Defaults to true.", + "qmodRequired": { + "description": "QMod required field for this dependency.", "type": [ "boolean", "null" ] }, - "libType": { - "description": "Specifies how to restore this dependency.", + "triplet": { + "description": "Target triplet for this dependency.", "anyOf": [ { - "$ref": "#/definitions/DependencyLibType" + "$ref": "#/definitions/TripletId" }, { "type": "null" } ] }, - "localPath": { - "description": "Copy a dependency from a location that is local to this root path instead of from a remote URL.", - "type": [ - "string", - "null" - ] - }, - "private": { - "description": "Whether or not the dependency is private and should be used in restore.", - "type": [ - "boolean", - "null" - ] - }, - "required": { - "description": "Whether the mod is optional or required. If omitted, assume true.", - "type": [ - "boolean", - "null" - ] + "versionRange": { + "description": "Version range requirement", + "type": "string", + "properties": { + "format": { + "title": "String", + "type": "string" + } + } } } }, - "PackageMetadata": { - "description": "Metadata information about the package.", + "PackageTripletsConfig": { + "description": "Configuration for a package's triplets map", "type": "object", - "required": [ - "additionalData", - "id", - "name", - "version" - ], "properties": { - "additionalData": { - "description": "Additional metadata for the package.", + "default": { + "description": "Default configuration for all triplets. All triplets will inherit from this.", + "default": { + "dependencies": {}, + "devDependencies": {}, + "env": {}, + "qmodIncludeDirs": [], + "qmodIncludeFiles": [] + }, "allOf": [ { - "$ref": "#/definitions/AdditionalPackageMetadata" + "$ref": "#/definitions/PackageTriplet" } ] - }, - "id": { - "description": "The unique identifier of the package.", - "type": "string" - }, - "name": { - "description": "The name of the package.", - "type": "string" - }, - "url": { - "description": "The website for the package.", - "type": [ - "string", - "null" - ] - }, - "version": { - "description": "The version of the package.", - "type": "string", - "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" } } }, + "TripletId": { + "type": "string" + }, "WorkspaceConfig": { "description": "Configuration for the workspace.", "type": "object", - "required": [ - "ndk" - ], "properties": { - "ndk": { - "description": "The NDK version range.", - "type": "string", - "properties": { - "format": { - "title": "String", - "type": "string" - } - } - }, - "qmodIncludeDirs": { - "description": "List of directories to search during qmod creation.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "qmodIncludeFiles": { - "description": "List of files to include in the resulting qmod.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "qmodOutput": { - "description": "Output path for the qmod.", - "default": null, - "type": [ - "string", - "null" - ] - }, "scripts": { "description": "Scripts associated with the workspace.", "default": {}, diff --git a/qpm.shared.schema.json b/qpm.shared.schema.json index 25c4df7..23fa9d9 100644 --- a/qpm.shared.schema.json +++ b/qpm.shared.schema.json @@ -1,39 +1,79 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SharedPackageConfig", - "description": "Shared package configuration.", + "description": "Configuration for a shared package.", "type": "object", "required": [ "config", - "restoredDependencies" + "lockedTriplet", + "restoredTriplet" ], "properties": { "config": { - "description": "A copy of the package configuration stored in qpm.json for convenience.", + "description": "Package name", "allOf": [ { "$ref": "#/definitions/PackageConfig" } ] }, - "restoredDependencies": { - "description": "The resolved dependencies of the package.", - "type": "array", - "items": { - "$ref": "#/definitions/SharedDependency" + "lockedTriplet": { + "description": "Triplet map", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/SharedTriplet" } + }, + "restoredTriplet": { + "$ref": "#/definitions/TripletId" } }, "definitions": { - "AdditionalPackageMetadata": { - "description": "Additional metadata for the package.", + "DependencyId": { + "type": "string" + }, + "PackageAdditionalData": { "type": "object", "properties": { - "branchName": { - "description": "The branch name of a GitHub repository. Only used when a valid GitHub URL is provided.", - "type": [ - "string", - "null" + "author": { + "description": "Package author", + "default": "", + "type": "string" + }, + "description": { + "description": "Package description", + "default": "", + "type": "string" + }, + "license": { + "description": "Package license", + "default": "", + "type": "string" + } + } + }, + "PackageConfig": { + "description": "Configuration for a package.", + "type": "object", + "required": [ + "dependenciesDirectory", + "id", + "sharedDirectory", + "triplets", + "version" + ], + "properties": { + "additionalData": { + "description": "Additional package metadata", + "default": { + "author": "", + "description": "", + "license": "" + }, + "allOf": [ + { + "$ref": "#/definitions/PackageAdditionalData" + } ] }, "cmake": { @@ -43,83 +83,162 @@ "null" ] }, - "compileOptions": { - "description": "Additional compile options for the package.", - "anyOf": [ - { - "$ref": "#/definitions/CompileOptions" - }, + "configVersion": { + "description": "Config version, defaults to 2.0.0", + "default": "2.0.0", + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "dependenciesDirectory": { + "description": "Directory where dependencies are restored", + "type": "string" + }, + "id": { + "description": "Package ID", + "allOf": [ { - "type": "null" + "$ref": "#/definitions/DependencyId" } ] }, - "debugSoLink": { - "description": "The link to the debug shared object file.", + "sharedDirectory": { + "description": "Directories shared by the package", + "type": "string" + }, + "toolchainOut": { + "description": "Path to generate a toolchain JSON file describing the project setup configuration.", "type": [ "string", "null" ] }, - "headersOnly": { - "description": "Whether or not the package is header only", - "type": [ - "boolean", - "null" + "triplets": { + "description": "Package triplet configurations", + "allOf": [ + { + "$ref": "#/definitions/PackageTripletsConfig" + } ] }, - "modLink": { - "description": "The link to the qmod file.", - "type": [ - "string", - "null" - ] + "version": { + "description": "Package version", + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }, - "overrideSoName": { - "description": "The override name for the shared object file.", - "type": [ - "string", - "null" + "workspace": { + "description": "Workspace configuration", + "default": { + "scripts": {} + }, + "allOf": [ + { + "$ref": "#/definitions/WorkspaceConfig" + } ] - }, - "overrideStaticName": { - "description": "The override name for the static library file.", - "type": [ - "string", - "null" + } + } + }, + "PackageTriplet": { + "description": "Configuration for a package triplet.", + "type": "object", + "required": [ + "ndk" + ], + "properties": { + "compileOptions": { + "description": "Additional compile options for the package.", + "anyOf": [ + { + "$ref": "#/definitions/PackageTripletCompileOptions" + }, + { + "type": "null" + } ] }, - "soLink": { - "description": "The link to the shared object file.", + "dependencies": { + "description": "Dependencies for this triplet", + "default": {}, + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PackageTripletDependency" + } + }, + "devDependencies": { + "description": "Dependencies for this triplet", + "default": {}, + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PackageTripletDependency" + } + }, + "env": { + "description": "Environment variables for this triplet.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ndk": { + "description": "The NDK version range.", + "type": "string", + "properties": { + "format": { + "title": "String", + "type": "string" + } + } + }, + "outBinaries": { + "description": "Output binaries for this triplet.", "type": [ - "string", + "array", "null" - ] + ], + "items": { + "type": "string" + } }, - "staticLink": { - "description": "The link to the static library file.", + "qmodId": { + "description": "QMod ID for this triplet.", "type": [ "string", "null" ] }, - "staticLinking": { - "description": "Whether the package is statically linked. Deprecated, use staticLink instead.", - "deprecated": true, + "qmodIncludeDirs": { + "description": "List of directories to search during qmod creation.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "qmodIncludeFiles": { + "description": "List of files to include in the resulting qmod.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "qmodOutput": { + "description": "Output path for the qmod.", "type": [ - "boolean", + "string", "null" ] }, - "subFolder": { - "description": "Sub-folder to use from the downloaded repository or zip, so one repository can contain multiple packages.", + "qmodTemplate": { + "description": "QMod template for this triplet.", "type": [ "string", "null" ] }, - "toolchainOut": { - "description": "Path to generate a toolchain JSON file describing the project setup configuration.", + "qmodUrl": { + "description": "QMod URL for this triplet.", "type": [ "string", "null" @@ -127,7 +246,7 @@ } } }, - "CompileOptions": { + "PackageTripletCompileOptions": { "description": "Additional options for compilation and edits to compilation related files.", "type": "object", "properties": { @@ -141,17 +260,6 @@ "type": "string" } }, - "cppFeatures": { - "description": "Additional C++ features to add. Deprecated, unused and exclusive to CMake.", - "deprecated": true, - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - } - }, "cppFlags": { "description": "Additional C++ flags to add.", "type": [ @@ -184,29 +292,38 @@ } } }, - "Dependency": { - "description": "A dependency of the package.", + "PackageTripletDependency": { + "description": "Dependency information for a package triplet.", "type": "object", "required": [ - "additionalData", - "id", "versionRange" ], "properties": { - "additionalData": { - "description": "Additional metadata for the dependency. Deprecated, use packageConfig.additionalData instead.", - "deprecated": true, - "allOf": [ + "qmodExport": { + "description": "Whether to include this dependency in the qmod", + "default": false, + "type": "boolean" + }, + "qmodRequired": { + "description": "QMod required field for this dependency.", + "type": [ + "boolean", + "null" + ] + }, + "triplet": { + "description": "Target triplet for this dependency.", + "anyOf": [ { - "$ref": "#/definitions/AdditionalPackageMetadata" + "$ref": "#/definitions/TripletId" + }, + { + "type": "null" } ] }, - "id": { - "type": "string" - }, "versionRange": { - "description": "The version range of the dependency", + "description": "Version range requirement", "type": "string", "properties": { "format": { @@ -217,284 +334,97 @@ } } }, - "DependencyLibType": { - "description": "Describes the dependency type.", - "oneOf": [ - { - "description": "Shared library", - "type": "string", - "enum": [ - "shared" - ] - }, - { - "description": "Static library", - "type": "string", - "enum": [ - "static" - ] - }, - { - "description": "Header only", - "type": "string", - "enum": [ - "headerOnly" - ] - } - ] - }, - "PackageConfig": { - "description": "Configuration for a package.", + "PackageTripletsConfig": { + "description": "Configuration for a package's triplets map", "type": "object", - "required": [ - "dependencies", - "dependenciesDir", - "info", - "sharedDir" - ], "properties": { - "dependencies": { - "description": "The dependencies of the package.", - "type": "array", - "items": { - "$ref": "#/definitions/PackageDependency" - } - }, - "dependenciesDir": { - "description": "The directory where dependencies are stored.", - "type": "string" - }, - "info": { - "description": "The package metadata.", - "allOf": [ - { - "$ref": "#/definitions/PackageMetadata" - } - ] - }, - "sharedDir": { - "description": "The directory where shared files are stored.", - "type": "string" - }, - "version": { - "description": "The version of the package configuration.", - "default": "0.4.0", - "type": "string", - "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" - }, - "workspace": { - "description": "The workspace configuration.", + "default": { + "description": "Default configuration for all triplets. All triplets will inherit from this.", "default": { + "dependencies": {}, + "devDependencies": {}, + "env": {}, "qmodIncludeDirs": [], - "qmodIncludeFiles": [], - "qmodOutput": null, - "scripts": {} + "qmodIncludeFiles": [] }, "allOf": [ { - "$ref": "#/definitions/WorkspaceConfig" + "$ref": "#/definitions/PackageTriplet" } ] } } }, - "PackageDependency": { - "description": "A dependency of the package.", + "SharedTriplet": { + "description": "Configuration for a shared triplet.", "type": "object", "required": [ - "additionalData", - "id", - "versionRange" + "env", + "restoredDependencies" ], "properties": { - "additionalData": { - "description": "Additional metadata for the dependency", - "allOf": [ - { - "$ref": "#/definitions/PackageDependencyModifier" - } - ] - }, - "id": { - "description": "The unique identifier of the dependency", - "type": "string" + "env": { + "description": "Environment variables for the triplet.", + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "versionRange": { - "description": "The version range of the dependency", - "type": "string", - "properties": { - "format": { - "title": "String", - "type": "string" - } + "restoredDependencies": { + "description": "Triplet map", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/SharedTripletDependencyInfo" } } } }, - "PackageDependencyModifier": { - "description": "Modifies how a dependency should be restored.", + "SharedTripletDependencyInfo": { + "description": "Dependency information for a shared triplet.", "type": "object", + "required": [ + "restoredBinaries", + "restoredEnv", + "restoredTriplet", + "restoredVersion" + ], "properties": { - "extraFiles": { - "description": "Additional files to be downloaded.", - "type": [ - "array", - "null" - ], + "restoredBinaries": { + "description": "Binaries for this triplet.", + "type": "array", "items": { "type": "string" } }, - "includeQmod": { - "description": "If the mod dependency should be included in the generated mod.json. Defaults to true.", - "type": [ - "boolean", - "null" - ] - }, - "libType": { - "description": "Specifies how to restore this dependency.", - "anyOf": [ - { - "$ref": "#/definitions/DependencyLibType" - }, - { - "type": "null" - } - ] - }, - "localPath": { - "description": "Copy a dependency from a location that is local to this root path instead of from a remote URL.", - "type": [ - "string", - "null" - ] - }, - "private": { - "description": "Whether or not the dependency is private and should be used in restore.", - "type": [ - "boolean", - "null" - ] + "restoredEnv": { + "description": "Restored environment variables for the triplet.", + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "required": { - "description": "Whether the mod is optional or required. If omitted, assume true.", - "type": [ - "boolean", - "null" - ] - } - } - }, - "PackageMetadata": { - "description": "Metadata information about the package.", - "type": "object", - "required": [ - "additionalData", - "id", - "name", - "version" - ], - "properties": { - "additionalData": { - "description": "Additional metadata for the package.", + "restoredTriplet": { + "description": "Restored triplet ID of the dependency.", "allOf": [ { - "$ref": "#/definitions/AdditionalPackageMetadata" + "$ref": "#/definitions/TripletId" } ] }, - "id": { - "description": "The unique identifier of the package.", - "type": "string" - }, - "name": { - "description": "The name of the package.", - "type": "string" - }, - "url": { - "description": "The website for the package.", - "type": [ - "string", - "null" - ] - }, - "version": { - "description": "The version of the package.", + "restoredVersion": { + "description": "Version of the dependency.", "type": "string", "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" } } }, - "SharedDependency": { - "description": "A resolved dependency of the package.", - "type": "object", - "required": [ - "dependency", - "version" - ], - "properties": { - "dependency": { - "description": "The resolved dependency", - "allOf": [ - { - "$ref": "#/definitions/Dependency" - } - ] - }, - "version": { - "description": "The resolved version of the dependency", - "type": "string", - "properties": { - "format": { - "title": "String", - "type": "string" - } - } - } - } + "TripletId": { + "type": "string" }, "WorkspaceConfig": { "description": "Configuration for the workspace.", "type": "object", - "required": [ - "ndk" - ], "properties": { - "ndk": { - "description": "The NDK version range.", - "type": "string", - "properties": { - "format": { - "title": "String", - "type": "string" - } - } - }, - "qmodIncludeDirs": { - "description": "List of directories to search during qmod creation.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "qmodIncludeFiles": { - "description": "List of files to include in the resulting qmod.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "qmodOutput": { - "description": "Output path for the qmod.", - "default": null, - "type": [ - "string", - "null" - ] - }, "scripts": { "description": "Scripts associated with the workspace.", "default": {}, From f960f970803b2535180bad1b76620a69a8d131d2 Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:28:23 -0400 Subject: [PATCH 55/62] Rename `default` to `base` --- src/models/triplet.rs | 50 +++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 0003a39..3e25218 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -24,7 +24,7 @@ pub const QPM_ENV_GAME_ID: &str = "QMOD_GAME_ID"; /// Represents the game version for a QMOD package. pub const QPM_ENV_GAME_VERSION: &str = "QMOD_GAME_VERSION"; -pub fn default_triplet_id() -> TripletId { +pub fn base_triplet_id() -> TripletId { TripletId::default() } @@ -34,9 +34,13 @@ pub fn default_triplet_id() -> TripletId { #[serde(rename_all = "camelCase")] #[schemars(description = "Configuration for a package's triplets map")] pub struct PackageTripletsConfig { + /// Default triplet ID for this package. + #[serde(skip_serializing_if = "Option::is_none")] + pub default: Option, + /// Default configuration for all triplets. All triplets will inherit from this. #[serde(default)] - pub default: PackageTriplet, + pub base: PackageTriplet, /// Configuration for specific triplets #[serde(flatten)] pub specific_triplets: HashMap, @@ -60,37 +64,37 @@ impl PackageTripletsConfig { /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration /// * `None` if the triplet is not found in the specific_triplets map pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { - if triplet == &default_triplet_id() { - return Some(self.default.clone()); + if triplet == &base_triplet_id() { + return Some(self.base.clone()); } let found = self.specific_triplets.get(triplet)?.clone(); - let default = self.default.clone(); + let base = self.base.clone(); let mut dependencies = found.dependencies; - dependencies.extend(default.dependencies); + dependencies.extend(base.dependencies); let mut dev_dependencies = found.dev_dependencies; - dev_dependencies.extend(default.dev_dependencies); + dev_dependencies.extend(base.dev_dependencies); let mut env = found.env; - env.extend(default.env); + env.extend(base.env); let compile_options = found .compile_options .clone() - .map(|a| a.merge(default.compile_options.unwrap_or_default())); + .map(|a| a.merge(base.compile_options.unwrap_or_default())); let qmod_include_files = found .qmod_include_files .into_iter() - .chain(default.qmod_include_files) + .chain(base.qmod_include_files) .collect(); let qmod_include_dirs = found .qmod_include_dirs .into_iter() - .chain(default.qmod_include_dirs) + .chain(base.qmod_include_dirs) .collect(); Some(PackageTriplet { @@ -101,27 +105,27 @@ impl PackageTripletsConfig { qmod_include_dirs, qmod_include_files, - out_binaries: found.out_binaries.clone().or(default.out_binaries), - qmod_url: found.qmod_url.clone().or(default.qmod_url), - qmod_id: found.qmod_id.clone().or(default.qmod_id), - qmod_template: found.qmod_template.clone().or(default.qmod_template), - qmod_output: found.qmod_output.clone().or(default.qmod_output), - ndk: found.ndk.clone().or(default.ndk), + out_binaries: found.out_binaries.clone().or(base.out_binaries), + qmod_url: found.qmod_url.clone().or(base.qmod_url), + qmod_id: found.qmod_id.clone().or(base.qmod_id), + qmod_template: found.qmod_template.clone().or(base.qmod_template), + qmod_output: found.qmod_output.clone().or(base.qmod_output), + ndk: found.ndk.clone().or(base.ndk), }) } /// Retrieves the settings for a specific triplet without merging with default settings. pub fn get_triplet_standalone(&self, triplet: &TripletId) -> Option<&PackageTriplet> { - if triplet == &default_triplet_id() { - return Some(&self.default); + if triplet == &base_triplet_id() { + return Some(&self.base); } self.specific_triplets.get(triplet) } /// Retrieves the settings for a specific triplet, allowing mutable access. pub fn get_triplet_standalone_mut(&mut self, triplet: &TripletId) -> Option<&mut PackageTriplet> { - if triplet == &default_triplet_id() { - return Some(&mut self.default); + if triplet == &base_triplet_id() { + return Some(&mut self.base); } self.specific_triplets.get_mut(triplet) @@ -135,12 +139,12 @@ impl PackageTripletsConfig { (k.clone(), Cow::Owned(package_triplet)) }); - let value = (default_triplet_id(), Cow::Borrowed(&self.default)); + let value = (base_triplet_id(), Cow::Borrowed(&self.base)); std::iter::once(value).chain(other) } - pub fn iter_non_default_triplets(&self) -> impl Iterator { + pub fn iter_non_base_triplets(&self) -> impl Iterator { self.specific_triplets.keys().map(|k| { let package_triplet = self.get_triplet_settings(k).unwrap(); (k, package_triplet) From a25999ea9bc084035b5d6081c50043914ae63da7 Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:41:15 -0400 Subject: [PATCH 56/62] Add `get_default_triplet` --- src/models/triplet.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index 3e25218..d8ffbd8 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -47,6 +47,11 @@ pub struct PackageTripletsConfig { } impl PackageTripletsConfig { + pub fn get_default_triplet(&self) -> Option { + let default = self.default.as_ref()?; + self.get_triplet_settings(default) + } + /// Retrieves the settings for a specific triplet, merging with default settings. /// /// This function looks up settings for the specified triplet and combines them with @@ -123,7 +128,10 @@ impl PackageTripletsConfig { self.specific_triplets.get(triplet) } /// Retrieves the settings for a specific triplet, allowing mutable access. - pub fn get_triplet_standalone_mut(&mut self, triplet: &TripletId) -> Option<&mut PackageTriplet> { + pub fn get_triplet_standalone_mut( + &mut self, + triplet: &TripletId, + ) -> Option<&mut PackageTriplet> { if triplet == &base_triplet_id() { return Some(&mut self.base); } From da354a5e13b7208bfff05874f2d72e551d5e5ff7 Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:18:30 -0400 Subject: [PATCH 57/62] Change default triplet id --- src/models/triplet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index d8ffbd8..c61280d 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -272,6 +272,6 @@ impl Display for TripletId { impl Default for TripletId { fn default() -> Self { - TripletId("default".to_owned()) + TripletId("base".to_owned()) } } From 24ce3116b8b7b516f89a1ec9811e92e9f8f3a5f1 Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 23 Aug 2025 10:31:16 -0400 Subject: [PATCH 58/62] Cleaning --- README.md | 5 +++++ src/models/workspace.rs | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 77e36dd..19af220 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # QPM.Package QMOD Package library + +# Generate JSON schemas +``` +cargo run +``` \ No newline at end of file diff --git a/src/models/workspace.rs b/src/models/workspace.rs index c1c6e9d..ac08676 100644 --- a/src/models/workspace.rs +++ b/src/models/workspace.rs @@ -1,10 +1,8 @@ -use std::{collections::BTreeMap, path::PathBuf}; +use std::collections::BTreeMap; use schemars::JsonSchema; -use semver::VersionReq; use serde::{Deserialize, Serialize}; -use crate::models::version_req::make_version_req_schema; pub type WorkspaceScript = Vec; From 746777febea1aa0b2681774f1bcda4a5ada3c31b Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 23 Aug 2025 10:32:12 -0400 Subject: [PATCH 59/62] Make `base` a nullable field for less noise. Improve API names --- src/models/triplet.rs | 56 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index c61280d..c22379d 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -11,6 +11,7 @@ use crate::models::{extra::PackageTripletCompileOptions, package::DependencyId}; #[derive( Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord, )] +#[repr(transparent)] pub struct TripletId(pub String); /// Dependency ID -> Dependency @@ -39,17 +40,17 @@ pub struct PackageTripletsConfig { pub default: Option, /// Default configuration for all triplets. All triplets will inherit from this. - #[serde(default)] - pub base: PackageTriplet, + #[serde(skip_serializing_if = "Option::is_none")] + pub base: Option, /// Configuration for specific triplets #[serde(flatten)] pub specific_triplets: HashMap, } impl PackageTripletsConfig { - pub fn get_default_triplet(&self) -> Option { + pub fn get_default_triplet(&'_ self) -> Option> { let default = self.default.as_ref()?; - self.get_triplet_settings(default) + self.get_merged_triplet(default) } /// Retrieves the settings for a specific triplet, merging with default settings. @@ -68,13 +69,16 @@ impl PackageTripletsConfig { /// # Returns /// * `Some(PackageTripletSettings)` if the triplet exists in the configuration /// * `None` if the triplet is not found in the specific_triplets map - pub fn get_triplet_settings(&self, triplet: &TripletId) -> Option { + pub fn get_merged_triplet(&'_ self, triplet: &TripletId) -> Option> { if triplet == &base_triplet_id() { - return Some(self.base.clone()); + return self.base.as_ref().map(Cow::Borrowed); } + let Some(base) = self.base.clone() else { + return self.specific_triplets.get(triplet).map(Cow::Borrowed); + }; + let found = self.specific_triplets.get(triplet)?.clone(); - let base = self.base.clone(); let mut dependencies = found.dependencies; dependencies.extend(base.dependencies); @@ -102,7 +106,7 @@ impl PackageTripletsConfig { .chain(base.qmod_include_dirs) .collect(); - Some(PackageTriplet { + let package_triplet = PackageTriplet { dependencies, dev_dependencies, env, @@ -116,13 +120,14 @@ impl PackageTripletsConfig { qmod_template: found.qmod_template.clone().or(base.qmod_template), qmod_output: found.qmod_output.clone().or(base.qmod_output), ndk: found.ndk.clone().or(base.ndk), - }) + }; + Some(Cow::Owned(package_triplet)) } /// Retrieves the settings for a specific triplet without merging with default settings. pub fn get_triplet_standalone(&self, triplet: &TripletId) -> Option<&PackageTriplet> { if triplet == &base_triplet_id() { - return Some(&self.base); + return self.base.as_ref(); } self.specific_triplets.get(triplet) @@ -133,28 +138,32 @@ impl PackageTripletsConfig { triplet: &TripletId, ) -> Option<&mut PackageTriplet> { if triplet == &base_triplet_id() { - return Some(&mut self.base); + return self.base.as_mut(); } self.specific_triplets.get_mut(triplet) } /// Iterates over all triplets, including the default one. - pub fn iter_triplets(&self) -> impl Iterator)> { - let other = self.specific_triplets.keys().map(|k| { - let package_triplet = self.get_triplet_settings(k).unwrap(); - - (k.clone(), Cow::Owned(package_triplet)) - }); - - let value = (base_triplet_id(), Cow::Borrowed(&self.base)); - - std::iter::once(value).chain(other) + pub fn iter_merged_triplets( + &'_ self, + ) -> impl Iterator)> { + self.specific_triplets + .keys() + .cloned() + .chain(std::iter::once(base_triplet_id())) + .map(|k| { + let package_triplet = self.get_merged_triplet(&k).unwrap(); + + (k.clone(), package_triplet) + }) } - pub fn iter_non_base_triplets(&self) -> impl Iterator { + pub fn iter_merged_specific_triplets( + &'_ self, + ) -> impl Iterator)> { self.specific_triplets.keys().map(|k| { - let package_triplet = self.get_triplet_settings(k).unwrap(); + let package_triplet = self.get_merged_triplet(k).unwrap(); (k, package_triplet) }) } @@ -174,7 +183,6 @@ pub struct PackageTriplet { #[serde(default)] pub dev_dependencies: TripletDependencyMap, - // TODO: use PackageTripletSettings /// Environment variables for this triplet. #[serde(default)] pub env: TripletEnvironmentMap, From 3414e9434891f6d7196ada43d8bbd597bd8c7b67 Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 23 Aug 2025 11:02:55 -0400 Subject: [PATCH 60/62] Fix unwrap for base triplet if it's empty --- src/models/triplet.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/triplet.rs b/src/models/triplet.rs index c22379d..169b51b 100644 --- a/src/models/triplet.rs +++ b/src/models/triplet.rs @@ -152,10 +152,10 @@ impl PackageTripletsConfig { .keys() .cloned() .chain(std::iter::once(base_triplet_id())) - .map(|k| { - let package_triplet = self.get_merged_triplet(&k).unwrap(); + .filter_map(|k| { + let package_triplet = self.get_merged_triplet(&k)?; - (k.clone(), package_triplet) + Some((k.clone(), package_triplet)) }) } From c1d2a68162ab70547f3ed8c0b0c29f05e86fe91a Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 23 Aug 2025 22:51:40 -0400 Subject: [PATCH 61/62] Update documentation for include paths to specify the extern package's shared directory --- src/models/extra.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/extra.rs b/src/models/extra.rs index c846f05..22fe334 100644 --- a/src/models/extra.rs +++ b/src/models/extra.rs @@ -14,15 +14,15 @@ use serde::{Deserialize, Serialize}; description = "Additional options for compilation and edits to compilation related files." )] pub struct PackageTripletCompileOptions { - /// Additional include paths to add, relative to the extern directory. + /// Additional include paths to add, relative to the extern package's shared directory. #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Additional include paths to add, relative to the extern directory.")] + #[schemars(description = "Additional include paths to add, relative to the extern package's shared directory.")] pub include_paths: Option>, - /// Additional system include paths to add, relative to the extern directory. + /// Additional system include paths to add, relative to the extern package's shared directory. #[serde(skip_serializing_if = "Option::is_none")] #[schemars( - description = "Additional system include paths to add, relative to the extern directory." + description = "Additional system include paths to add, relative to the extern package's shared directory." )] pub system_includes: Option>, From 5f30225fd99d52480fc57db1ce667ff6181b3e2a Mon Sep 17 00:00:00 2001 From: Fernthedev <15272073+Fernthedev@users.noreply.github.com> Date: Sat, 23 Aug 2025 22:53:46 -0400 Subject: [PATCH 62/62] Update schema --- qpm.schema.json | 29 ++++++++++++++++++----------- qpm.shared.schema.json | 29 ++++++++++++++++++----------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/qpm.schema.json b/qpm.schema.json index 8ed7096..0bb0e6c 100644 --- a/qpm.schema.json +++ b/qpm.schema.json @@ -242,7 +242,7 @@ } }, "includePaths": { - "description": "Additional include paths to add, relative to the extern directory.", + "description": "Additional include paths to add, relative to the extern package's shared directory.", "type": [ "array", "null" @@ -252,7 +252,7 @@ } }, "systemIncludes": { - "description": "Additional system include paths to add, relative to the extern directory.", + "description": "Additional system include paths to add, relative to the extern package's shared directory.", "type": [ "array", "null" @@ -309,18 +309,25 @@ "description": "Configuration for a package's triplets map", "type": "object", "properties": { - "default": { + "base": { "description": "Default configuration for all triplets. All triplets will inherit from this.", - "default": { - "dependencies": {}, - "devDependencies": {}, - "env": {}, - "qmodIncludeDirs": [], - "qmodIncludeFiles": [] - }, - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/PackageTriplet" + }, + { + "type": "null" + } + ] + }, + "default": { + "description": "Default triplet ID for this package.", + "anyOf": [ + { + "$ref": "#/definitions/TripletId" + }, + { + "type": "null" } ] } diff --git a/qpm.shared.schema.json b/qpm.shared.schema.json index 23fa9d9..97cde99 100644 --- a/qpm.shared.schema.json +++ b/qpm.shared.schema.json @@ -271,7 +271,7 @@ } }, "includePaths": { - "description": "Additional include paths to add, relative to the extern directory.", + "description": "Additional include paths to add, relative to the extern package's shared directory.", "type": [ "array", "null" @@ -281,7 +281,7 @@ } }, "systemIncludes": { - "description": "Additional system include paths to add, relative to the extern directory.", + "description": "Additional system include paths to add, relative to the extern package's shared directory.", "type": [ "array", "null" @@ -338,18 +338,25 @@ "description": "Configuration for a package's triplets map", "type": "object", "properties": { - "default": { + "base": { "description": "Default configuration for all triplets. All triplets will inherit from this.", - "default": { - "dependencies": {}, - "devDependencies": {}, - "env": {}, - "qmodIncludeDirs": [], - "qmodIncludeFiles": [] - }, - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/PackageTriplet" + }, + { + "type": "null" + } + ] + }, + "default": { + "description": "Default triplet ID for this package.", + "anyOf": [ + { + "$ref": "#/definitions/TripletId" + }, + { + "type": "null" } ] }