diff --git a/Cargo.lock b/Cargo.lock index bad8777d5..8cb3cc0d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -809,7 +809,6 @@ dependencies = [ "hemtt-config", "hemtt-pbo", "hemtt-preprocessor", - "hemtt-project", "hemtt-signing", "num_cpus", "peekmore", @@ -835,8 +834,11 @@ dependencies = [ name = "hemtt-common" version = "1.0.0" dependencies = [ + "ariadne", + "git2", "serde", "thiserror", + "toml", "tracing", "vfs", ] @@ -850,7 +852,6 @@ dependencies = [ "chumsky", "hemtt-common", "hemtt-preprocessor", - "hemtt-project", "lsp-types", "paste", "serde", @@ -887,19 +888,6 @@ dependencies = [ "vfs", ] -[[package]] -name = "hemtt-project" -version = "1.0.0" -dependencies = [ - "git2", - "hemtt-common", - "hemtt-pbo", - "serde", - "toml", - "tracing", - "vfs", -] - [[package]] name = "hemtt-signing" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 0c9f21f46..280f034be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ members = [ "libs/config", "libs/pbo", "libs/preprocessor", - "libs/project", "libs/signing", ] resolver = "2" diff --git a/bin/Cargo.toml b/bin/Cargo.toml index fd7a6f5a4..9e1b1080b 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -20,7 +20,6 @@ hemtt-common = { path = "../libs/common", version = "1.0.0" } hemtt-config = { path = "../libs/config", version = "1.0.0" } hemtt-pbo = { path = "../libs/pbo", version = "1.0.1" } hemtt-preprocessor = { path = "../libs/preprocessor", version = "1.0.0" } -hemtt-project = { path = "../libs/project", version = "1.0.0" } hemtt-signing = { path = "../libs/signing", version = "1.0.0" } ariadne = { workspace = true } diff --git a/bin/src/addons.rs b/bin/src/addons.rs index 98b0f6fda..d8962bf64 100644 --- a/bin/src/addons.rs +++ b/bin/src/addons.rs @@ -1,7 +1,7 @@ use std::{fs::DirEntry, path::PathBuf, str::FromStr}; use hemtt_common::prefix::{self, Prefix}; -use hemtt_project::AddonConfig; +use hemtt_common::project::AddonConfig; use crate::error::Error; diff --git a/bin/src/commands/launch.rs b/bin/src/commands/launch.rs index 34a758518..9b4f78926 100644 --- a/bin/src/commands/launch.rs +++ b/bin/src/commands/launch.rs @@ -4,7 +4,7 @@ use std::{ }; use clap::{ArgMatches, Command}; -use hemtt_project::{hemtt::LaunchOptions, ProjectConfig}; +use hemtt_common::project::{hemtt::LaunchOptions, ProjectConfig}; use steamlocate::SteamDir; use crate::{error::Error, utils::create_link}; diff --git a/bin/src/context.rs b/bin/src/context.rs index a91ebf952..9f8aa46b7 100644 --- a/bin/src/context.rs +++ b/bin/src/context.rs @@ -4,8 +4,8 @@ use std::{ path::PathBuf, }; +use hemtt_common::project::ProjectConfig; use hemtt_common::workspace::{Workspace, WorkspacePath}; -use hemtt_project::ProjectConfig; use crate::{addons::Addon, error::Error}; @@ -77,11 +77,11 @@ impl Context { if include.is_dir() { builder = builder.physical(&include); } - builder.memory().finish()? + builder.memory().finish(Some(config.clone()))? }; { let version = config.version().get(workspace.vfs()); - if let Err(hemtt_project::Error::Git(_)) = version { + if let Err(hemtt_common::project::Error::Git(_)) = version { error!("Failed to find a git repository with at least one commit, if you are not using git add the following to your project.toml"); println!("\n[version]\ngit_hash = 0\n"); std::process::exit(1); diff --git a/bin/src/error.rs b/bin/src/error.rs index 035ba8940..9eea90970 100644 --- a/bin/src/error.rs +++ b/bin/src/error.rs @@ -52,7 +52,7 @@ pub enum Error { #[error("Prefix error: {0}")] Prefix(#[from] hemtt_common::prefix::Error), #[error("`a hemtt project file is invalid: {0}")] - Project(#[from] hemtt_project::Error), + Project(#[from] hemtt_common::project::Error), #[error("Signing error: {0}")] Signing(#[from] hemtt_signing::Error), #[error("Version Error: {0}")] diff --git a/libs/common/Cargo.toml b/libs/common/Cargo.toml index 61faa3f9b..28bdcd24d 100644 --- a/libs/common/Cargo.toml +++ b/libs/common/Cargo.toml @@ -6,7 +6,10 @@ description = "A library for common Hemtt functionality" license = "GPL-2.0" [dependencies] +ariadne = { workspace = true } +git2 = { workspace = true } serde = { workspace = true } thiserror = "1.0.49" +toml = { workspace = true } tracing = { workspace = true } vfs = { workspace = true } diff --git a/libs/common/src/arma/dlc.rs b/libs/common/src/arma/dlc.rs index 776692842..a1bf927d5 100644 --- a/libs/common/src/arma/dlc.rs +++ b/libs/common/src/arma/dlc.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Serialize)] +#[derive(PartialEq, Eq, Clone, Debug, Serialize)] /// DLCs that require opt-in. pub enum DLC { #[serde(rename = "contact")] diff --git a/libs/common/src/error.rs b/libs/common/src/error.rs index 0f1014e43..32e550df7 100644 --- a/libs/common/src/error.rs +++ b/libs/common/src/error.rs @@ -1,3 +1,30 @@ //! HEMTT - Error Types +#![allow(missing_docs)] + pub use thiserror; + +#[derive(thiserror::Error, Debug)] +/// HEMTT Error +pub enum Error { + #[error("Invalid config: {0}")] + /// Invalid config + ConfigInvalid(String), + + #[error("Git Error: {0}")] + Git(#[from] git2::Error), + #[error("IO Error: {0}")] + Io(#[from] std::io::Error), + #[error("Toml Error: {0}")] + Toml(#[from] toml::de::Error), + #[error("Version Error: {0}")] + Version(#[from] crate::version::Error), + #[error("Vfs Error {0}")] + Vfs(Box), +} + +impl From for Error { + fn from(e: vfs::VfsError) -> Self { + Self::Vfs(Box::new(e)) + } +} diff --git a/libs/common/src/lib.rs b/libs/common/src/lib.rs index a07676306..76fa8f725 100644 --- a/libs/common/src/lib.rs +++ b/libs/common/src/lib.rs @@ -9,6 +9,10 @@ pub mod io; pub mod math; pub mod position; pub mod prefix; +pub mod project; pub mod reporting; pub mod version; pub mod workspace; + +mod sign_version; +pub use sign_version::BISignVersion; diff --git a/libs/common/src/workspace/mod.rs b/libs/common/src/workspace/mod.rs index e08a9aad6..620149105 100644 --- a/libs/common/src/workspace/mod.rs +++ b/libs/common/src/workspace/mod.rs @@ -12,12 +12,16 @@ pub use error::Error; #[allow(clippy::module_name_repetitions)] pub use path::WorkspacePath; -use crate::prefix::{Prefix, FILES}; +use crate::{ + prefix::{Prefix, FILES}, + project::ProjectConfig, +}; #[derive(Debug, PartialEq, Eq)] /// A workspace (directory) containing addons and / or missions pub struct Workspace { pub(crate) vfs: VfsPath, + pub(crate) project: Option, pub(crate) pointers: HashMap, pub(crate) addons: Vec, pub(crate) missions: Vec, @@ -30,13 +34,20 @@ impl Workspace { WorkspaceBuilder::default() } + #[must_use] + /// Returns the project config + pub const fn project(&self) -> Option<&ProjectConfig> { + self.project.as_ref() + } + /// Create a new workspace from a vfs path /// /// # Errors /// [`Error::Vfs`] if the workspace could not be created - pub fn create(vfs: VfsPath) -> Result { + pub fn create(vfs: VfsPath, project: Option) -> Result { let mut workspace = Self { vfs, + project, pointers: HashMap::new(), addons: Vec::new(), missions: Vec::new(), @@ -104,9 +115,9 @@ impl WorkspaceBuilder { /// /// # Errors /// [`Error::Vfs`] if the workspace could not be built - pub fn finish(self) -> Result { + pub fn finish(self, project: Option) -> Result { let mut layers = self.layers; layers.reverse(); - Workspace::create(OverlayFS::new(&layers).into()) + Workspace::create(OverlayFS::new(&layers).into(), project) } } diff --git a/libs/common/src/workspace/path.rs b/libs/common/src/workspace/path.rs index 01ddeb3a4..710608209 100644 --- a/libs/common/src/workspace/path.rs +++ b/libs/common/src/workspace/path.rs @@ -20,6 +20,12 @@ impl WorkspacePath { &self.path } + #[must_use] + /// Returns the workspace + pub fn workspace(&self) -> &Workspace { + &self.workspace + } + /// join a path to the workspace path /// /// # Errors diff --git a/libs/config/Cargo.toml b/libs/config/Cargo.toml index 08d9fb068..a2c9c7e3c 100644 --- a/libs/config/Cargo.toml +++ b/libs/config/Cargo.toml @@ -12,7 +12,6 @@ bench = false hemtt-common = { path = "../common", version = "1.0.0" } hemtt-preprocessor = { path = "../preprocessor", version = "1.0.0" } -hemtt-project = { path = "../project", version = "1.0.0" } ariadne = { workspace = true } byteorder = { workspace = true } diff --git a/libs/config/src/analyze/array.rs b/libs/config/src/analyze/array.rs index 71ccd394d..0e1737aca 100644 --- a/libs/config/src/analyze/array.rs +++ b/libs/config/src/analyze/array.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::{ analyze::codes::{ce1_invalid_value::InvalidValue, ce2_invalid_value_macro::InvalidValueMacro}, diff --git a/libs/config/src/analyze/class.rs b/libs/config/src/analyze/class.rs index bb53836f6..7e1312197 100644 --- a/libs/config/src/analyze/class.rs +++ b/libs/config/src/analyze/class.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::Class; diff --git a/libs/config/src/analyze/config.rs b/libs/config/src/analyze/config.rs index d22f4b9b8..3720784e3 100644 --- a/libs/config/src/analyze/config.rs +++ b/libs/config/src/analyze/config.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, HashSet}; +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::{Class, Config, Ident, Item, Property, Str, Value}; diff --git a/libs/config/src/analyze/mod.rs b/libs/config/src/analyze/mod.rs index af0950282..c63d885a3 100644 --- a/libs/config/src/analyze/mod.rs +++ b/libs/config/src/analyze/mod.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; mod array; mod class; diff --git a/libs/config/src/analyze/number.rs b/libs/config/src/analyze/number.rs index cbc1c4662..4ad27c887 100644 --- a/libs/config/src/analyze/number.rs +++ b/libs/config/src/analyze/number.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::Number; diff --git a/libs/config/src/analyze/property.rs b/libs/config/src/analyze/property.rs index 1265cb09c..6fffda787 100644 --- a/libs/config/src/analyze/property.rs +++ b/libs/config/src/analyze/property.rs @@ -1,7 +1,7 @@ use std::ops::Range; +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use super::{ codes::{ diff --git a/libs/config/src/analyze/str.rs b/libs/config/src/analyze/str.rs index 85d8f278d..e2eb80368 100644 --- a/libs/config/src/analyze/str.rs +++ b/libs/config/src/analyze/str.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::Str; diff --git a/libs/config/src/analyze/value.rs b/libs/config/src/analyze/value.rs index d9b1531a5..69b42747b 100644 --- a/libs/config/src/analyze/value.rs +++ b/libs/config/src/analyze/value.rs @@ -1,5 +1,5 @@ +use hemtt_common::project::ProjectConfig; use hemtt_common::reporting::{Code, Processed}; -use hemtt_project::ProjectConfig; use crate::{ analyze::codes::{ce1_invalid_value::InvalidValue, ce2_invalid_value_macro::InvalidValueMacro}, diff --git a/libs/config/src/lib.rs b/libs/config/src/lib.rs index 790cb934d..7601cffa1 100644 --- a/libs/config/src/lib.rs +++ b/libs/config/src/lib.rs @@ -16,7 +16,7 @@ use chumsky::{prelude::Simple, Parser}; use hemtt_common::reporting::{Code, Processed}; pub use error::Error; -use hemtt_project::ProjectConfig; +use hemtt_common::project::ProjectConfig; pub use model::*; pub mod parse; pub mod rapify; diff --git a/libs/config/tests/errors.rs b/libs/config/tests/errors.rs index dd4d08e13..9e0836fda 100644 --- a/libs/config/tests/errors.rs +++ b/libs/config/tests/errors.rs @@ -19,7 +19,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source).unwrap(); diff --git a/libs/config/tests/rapify.rs b/libs/config/tests/rapify.rs index a29264123..3a6a07251 100644 --- a/libs/config/tests/rapify.rs +++ b/libs/config/tests/rapify.rs @@ -20,7 +20,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source).unwrap(); diff --git a/libs/config/tests/warnings.rs b/libs/config/tests/warnings.rs index 8535b47c6..e84bf3a5c 100644 --- a/libs/config/tests/warnings.rs +++ b/libs/config/tests/warnings.rs @@ -19,7 +19,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source).unwrap(); diff --git a/libs/pbo/src/lib.rs b/libs/pbo/src/lib.rs index b089e2191..19a4305d1 100644 --- a/libs/pbo/src/lib.rs +++ b/libs/pbo/src/lib.rs @@ -17,15 +17,16 @@ mod error; mod file; mod model; mod read; -mod sign_version; mod write; pub use error::Error; pub use model::{Checksum, Header, Mime}; pub use read::ReadablePbo; -pub use sign_version::BISignVersion; pub use write::WritablePbo; +// Re-exported from common +pub use hemtt_common::BISignVersion; + trait WritePbo { fn write_pbo(&self, output: &mut O) -> Result<(), Error>; } diff --git a/libs/pbo/src/sign_version.rs b/libs/pbo/src/sign_version.rs deleted file mode 100644 index b44f78c19..000000000 --- a/libs/pbo/src/sign_version.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::{ffi::OsStr, path::PathBuf}; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Copy, Clone, Debug, Default)] -#[allow(clippy::module_name_repetitions)] -/// Version of BI's signature -pub enum BISignVersion { - /// Version 2 - /// - /// Hashes the following file extensions: - /// - fxy - /// - jpg - /// - lip - /// - ogg - /// - p3d - /// - paa - /// - pac - /// - png - /// - rtm - /// - rvmat - /// - tga - /// - wrp - /// - wss - V2, - #[default] - /// Version 3 - /// - /// Hashes the following file extensions: - /// - bikb - /// - cfg - /// - ext - /// - fsm - /// - h - /// - hpp - /// - inc - /// - sqf - /// - sqfc - /// - sqm - /// - sqs - V3, -} - -impl BISignVersion { - #[must_use] - /// Should a file be hashed? - pub fn should_hash_file(&self, name: &str) -> bool { - let path = PathBuf::from(name); - let ext = path.extension().unwrap_or_else(|| OsStr::new("")); - match self { - Self::V2 => [ - OsStr::new("fxy"), - OsStr::new("jpg"), - OsStr::new("lip"), - OsStr::new("ogg"), - OsStr::new("p3d"), - OsStr::new("paa"), - OsStr::new("pac"), - OsStr::new("png"), - OsStr::new("rtm"), - OsStr::new("rvmat"), - OsStr::new("tga"), - OsStr::new("wrp"), - OsStr::new("wss"), - ] - .contains(&ext), - Self::V3 => [ - OsStr::new("bikb"), - OsStr::new("cfg"), - OsStr::new("ext"), - OsStr::new("fsm"), - OsStr::new("h"), - OsStr::new("hpp"), - OsStr::new("inc"), - OsStr::new("sqf"), - OsStr::new("sqfc"), - OsStr::new("sqm"), - OsStr::new("sqs"), - ] - .contains(&ext), - } - } - - #[must_use] - pub(crate) const fn nothing(&self) -> &str { - match self { - Self::V2 => "nothing", - Self::V3 => "gnihton", - } - } -} - -impl From for u32 { - fn from(v: BISignVersion) -> Self { - match v { - BISignVersion::V2 => 0x02, - BISignVersion::V3 => 0x03, - } - } -} - -impl Serialize for BISignVersion { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u32(u32::from(*self)) - } -} - -impl<'de> Deserialize<'de> for BISignVersion { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let v = u32::deserialize(deserializer)?; - match v { - 0x02 => Ok(Self::V2), - 0x03 => Ok(Self::V3), - _ => Err(serde::de::Error::custom(format!( - "Invalid BISignVersion: {v}" - ))), - } - } -} diff --git a/libs/preprocessor/benches/ace_dogtags.rs b/libs/preprocessor/benches/ace_dogtags.rs index e7583b223..334bf62d6 100644 --- a/libs/preprocessor/benches/ace_dogtags.rs +++ b/libs/preprocessor/benches/ace_dogtags.rs @@ -8,7 +8,7 @@ fn criterion_benchmark(c: &mut Criterion) { let workspace = hemtt_common::workspace::Workspace::builder() .physical(&PathBuf::from("benches")) .memory() - .finish() + .finish(None) .unwrap(); let source = workspace.join("ace_dogtags.hpp").unwrap(); hemtt_preprocessor::Processor::run(&source).unwrap(); diff --git a/libs/preprocessor/src/defines.rs b/libs/preprocessor/src/defines.rs index 4ac1ccd90..6dd973ee8 100644 --- a/libs/preprocessor/src/defines.rs +++ b/libs/preprocessor/src/defines.rs @@ -96,9 +96,23 @@ impl Defines { key.clone(), Definition::Value(vec![ Token::new(Symbol::DoubleQuote, key.position().clone()), - Token::new( - Symbol::Word(site.path().as_str().to_string()), - key.position().clone(), + site.path().workspace().project().map_or_else( + || { + Token::new( + Symbol::Word(site.path().as_str().to_string()), + key.position().clone(), + ) + }, + |project| { + Token::new( + Symbol::Word(format!( + "{}\\{}", + project.prefix(), + site.path().as_str() + )), + key.position().clone(), + ) + }, ), Token::new(Symbol::DoubleQuote, key.position().clone()), ]), diff --git a/libs/preprocessor/src/parse/mod.rs b/libs/preprocessor/src/parse/mod.rs index 87624aa08..b6a927e0e 100644 --- a/libs/preprocessor/src/parse/mod.rs +++ b/libs/preprocessor/src/parse/mod.rs @@ -131,7 +131,7 @@ mod tests { fn simple() { let workspace = hemtt_common::workspace::Workspace::builder() .memory() - .finish() + .finish(None) .unwrap(); let test = workspace.join("test.hpp").unwrap(); test.create_file() @@ -146,7 +146,7 @@ mod tests { fn unicode() { let workspace = hemtt_common::workspace::Workspace::builder() .memory() - .finish() + .finish(None) .unwrap(); let test = workspace.join("test.hpp").unwrap(); let content = "² ƒ ‡ Œ Š – µ œ š ˆ ˜ € º ¨ ¬ 🤔"; diff --git a/libs/preprocessor/src/processor/mod.rs b/libs/preprocessor/src/processor/mod.rs index 92c506545..afb8e4ec9 100644 --- a/libs/preprocessor/src/processor/mod.rs +++ b/libs/preprocessor/src/processor/mod.rs @@ -259,7 +259,7 @@ pub mod tests { pub fn setup(content: &str) -> PeekMoreIterator> { let workspace = hemtt_common::workspace::Workspace::builder() .memory() - .finish() + .finish(None) .unwrap(); let test = workspace.join("test.hpp").unwrap(); test.create_file() diff --git a/libs/preprocessor/tests/bootstrap.rs b/libs/preprocessor/tests/bootstrap.rs index fde903977..4ee7385c2 100644 --- a/libs/preprocessor/tests/bootstrap.rs +++ b/libs/preprocessor/tests/bootstrap.rs @@ -17,7 +17,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source); diff --git a/libs/preprocessor/tests/errors.rs b/libs/preprocessor/tests/errors.rs index d76db5d43..9e9a5a3ec 100644 --- a/libs/preprocessor/tests/errors.rs +++ b/libs/preprocessor/tests/errors.rs @@ -19,7 +19,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source); diff --git a/libs/preprocessor/tests/warnings.rs b/libs/preprocessor/tests/warnings.rs index c97afd4b5..f4a237843 100644 --- a/libs/preprocessor/tests/warnings.rs +++ b/libs/preprocessor/tests/warnings.rs @@ -19,7 +19,7 @@ fn check(dir: &str) { let folder = std::path::PathBuf::from(ROOT).join(dir); let workspace = hemtt_common::workspace::Workspace::builder() .physical(&folder) - .finish() + .finish(None) .unwrap(); let source = workspace.join("source.hpp").unwrap(); let processed = Processor::run(&source); diff --git a/libs/project/Cargo.toml b/libs/project/Cargo.toml deleted file mode 100644 index e7b79a992..000000000 --- a/libs/project/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "hemtt-project" -version = "1.0.0" -edition = "2021" -description = "Project configuration for HEMTT" -license = "GPL-2.0" - -[lib] -bench = false - -[dependencies] -hemtt-common = { path = "../common", version = "1.0.0" } -hemtt-pbo = { path = "../pbo", version = "1.0.0" } - -git2 = { workspace = true } -serde = { workspace = true } -toml = { workspace = true } -tracing = { workspace = true } -vfs = { workspace = true } diff --git a/libs/project/src/addon/mod.rs b/libs/project/src/addon/mod.rs deleted file mode 100644 index 67cad58d2..000000000 --- a/libs/project/src/addon/mod.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::{collections::HashMap, path::Path, str::FromStr}; - -use serde::{Deserialize, Serialize}; -use tracing::warn; - -use crate::error::Error; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AddonConfig { - #[serde(default)] - /// Preprocess config - preprocess: Option, - - #[serde(default)] - /// A list of files to skip binarizing - no_bin: Vec, - #[serde(default)] - /// Binarze config - binarize: BinarizeConfig, - - #[serde(default)] - /// Properties to add to the pbo - properties: HashMap, - - #[serde(default)] - /// Files to exclude from the pbo - /// Supports glob patterns - exclude: Vec, - #[serde(default)] - /// Files to exclude from the pbo - files: FilesConfig, -} - -impl AddonConfig { - #[must_use] - pub fn preprocess(&self) -> PreprocessConfig { - match &self.preprocess { - Some(PreprocessCompatibility::Deprecated(enabled)) => PreprocessConfig { - enabled: *enabled, - exclude: Vec::new(), - }, - Some(PreprocessCompatibility::New(config)) => config.clone(), - None => PreprocessConfig { - enabled: false, - exclude: Vec::new(), - }, - } - } - - #[must_use] - pub fn binarize(&self) -> BinarizeConfig { - let mut config = self.binarize.clone(); - config.exclude.append(&mut self.no_bin.clone()); - config - } - - /// Load a configuration from a file. - /// - /// # Errors - /// - /// If the file cannot be read, or if the file is not valid TOML, or if the - /// file does not contain a valid configuration, an error is returned. - pub fn from_file(path: &Path) -> Result { - let file = std::fs::read_to_string(path)?; - let config = Self::from_str(&file); - if let Ok(inner) = config.as_ref() { - if !inner.exclude.is_empty() { - warn!("`exclude` is deprecated, use `files.exclude` instead. See for more information."); - } - if !inner.no_bin.is_empty() { - warn!("`no_bin` is deprecated, use `binarize.exclude` instead. See for more information."); - } - if let Some(PreprocessCompatibility::Deprecated(_)) = inner.preprocess { - warn!("`preprocess` as a field is deprecated, use a `preprocess` object instead. See for more information."); - } - } - config - } - - #[must_use] - /// Properties to be added to the built PBO - pub const fn properties(&self) -> &HashMap { - &self.properties - } - - #[must_use] - /// Files to exclude from the PBO - pub fn files(&self) -> FilesConfig { - let mut config = self.files.clone(); - config.exclude.append(&mut self.exclude.clone()); - config - } -} - -impl FromStr for AddonConfig { - type Err = Error; - - fn from_str(s: &str) -> Result { - toml::from_str(s).map_err(Error::from) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum PreprocessCompatibility { - Deprecated(bool), - New(PreprocessConfig), -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct PreprocessConfig { - #[serde(default)] - enabled: bool, - #[serde(default)] - exclude: Vec, -} - -impl PreprocessConfig { - #[must_use] - pub const fn enabled(&self) -> bool { - self.enabled - } - - #[must_use] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct BinarizeConfig { - #[serde(default)] - pub enabled: Option, - #[serde(default)] - pub exclude: Vec, -} - -impl BinarizeConfig { - #[must_use] - pub fn enabled(&self) -> bool { - self.enabled.unwrap_or(true) - } - - #[must_use] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct FilesConfig { - #[serde(default)] - pub exclude: Vec, -} - -impl FilesConfig { - #[must_use] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} diff --git a/libs/project/src/asc.rs b/libs/project/src/asc.rs deleted file mode 100644 index 105e63f0d..000000000 --- a/libs/project/src/asc.rs +++ /dev/null @@ -1,22 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - #[serde(default)] - enabled: Option, - #[serde(default)] - exclude: Vec, -} - -impl Options { - #[must_use] - pub fn enabled(&self) -> bool { - self.enabled.unwrap_or(true) - } - - #[must_use] - #[cfg(not(target_os = "macos"))] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} diff --git a/libs/project/src/error.rs b/libs/project/src/error.rs deleted file mode 100644 index 3f56bfad8..000000000 --- a/libs/project/src/error.rs +++ /dev/null @@ -1,24 +0,0 @@ -use hemtt_common::error::thiserror; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Invalid config: {0}")] - ConfigInvalid(String), - - #[error("Git Error: {0}")] - Git(#[from] git2::Error), - #[error("IO Error: {0}")] - Io(#[from] std::io::Error), - #[error("Toml Error: {0}")] - Toml(#[from] toml::de::Error), - #[error("Version Error: {0}")] - Version(#[from] hemtt_common::version::Error), - #[error("Vfs Error {0}")] - Vfs(Box), -} - -impl From for Error { - fn from(e: vfs::VfsError) -> Self { - Self::Vfs(Box::new(e)) - } -} diff --git a/libs/project/src/files.rs b/libs/project/src/files.rs deleted file mode 100644 index 3df850c55..000000000 --- a/libs/project/src/files.rs +++ /dev/null @@ -1,50 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - #[serde(default)] - /// Files to be included in the output folder, supports glob patterns - include: Vec, - #[serde(default)] - /// Files to be excluded from being included in PBO files, supports glob patterns - exclude: Vec, -} - -impl Options { - #[must_use] - pub fn include(&self) -> Vec { - let mut files = self - .include - .iter() - .map(|i| { - if i.starts_with('/') { - i.to_string() - } else { - format!("/{i}") - } - }) - .collect::>(); - for default in [ - "/mod.cpp", - "/meta.cpp", - "/LICENSE", - "/logo_ca.paa", - "/logo_co.paa", - ] - .iter() - .map(std::string::ToString::to_string) - { - if !files.contains(&default) { - files.push(default.clone()); - } - } - files.sort(); - files.dedup(); - files - } - - #[must_use] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} diff --git a/libs/project/src/hemtt.rs b/libs/project/src/hemtt.rs deleted file mode 100644 index 5ffa3a232..000000000 --- a/libs/project/src/hemtt.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::{borrow::Cow, collections::HashMap}; - -use hemtt_common::arma::dlc::DLC; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Features { - #[serde(default)] - dev: DevOptions, - - #[serde(default)] - launch: HashMap, - - #[serde(default)] - build: BuildOptions, - - #[serde(default)] - release: ReleaseOptions, -} - -impl Features { - #[must_use] - pub const fn dev(&self) -> &DevOptions { - &self.dev - } - - #[must_use] - pub fn launch(&self, key: &str) -> Option> { - self.launch.get(key).map(Cow::Borrowed) - } - - #[must_use] - pub const fn build(&self) -> &BuildOptions { - &self.build - } - - #[must_use] - pub const fn release(&self) -> &ReleaseOptions { - &self.release - } -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct DevOptions { - #[serde(default)] - exclude: Vec, -} - -impl DevOptions { - #[must_use] - pub fn exclude(&self) -> &[String] { - &self.exclude - } -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct LaunchOptions { - #[serde(default)] - /// Workshop mods that should be launched with the mod - workshop: Vec, - - #[serde(default)] - /// DLCs that should be launched with the mod - dlc: Vec, - - #[serde(default)] - /// Optional addons that should be built into the mod - optionals: Vec, - - #[serde(default)] - /// Extra launch parameters - parameters: Vec, - - #[serde(default)] - /// Binary to launch, defaults to `arma3_x64.exe` - executable: Option, -} - -impl LaunchOptions { - #[must_use] - pub fn workshop(&self) -> &[String] { - &self.workshop - } - - #[must_use] - pub fn dlc(&self) -> &[DLC] { - &self.dlc - } - - #[must_use] - pub fn optionals(&self) -> &[String] { - &self.optionals - } - - #[must_use] - pub fn parameters(&self) -> &[String] { - &self.parameters - } - - #[must_use] - pub fn executable(&self) -> String { - let executable = self - .executable - .clone() - .unwrap_or_else(|| "arma3_x64".to_owned()); - if cfg!(target_os = "windows") { - format!("{executable}.exe") - } else { - executable - } - } -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct BuildOptions { - #[serde(default)] - /// Should optionals be built into their own mod? - /// Default: true - optional_mod_folders: Option, -} - -impl BuildOptions { - #[must_use] - pub const fn optional_mod_folders(&self) -> bool { - if let Some(optional) = self.optional_mod_folders { - optional - } else { - true - } - } -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct ReleaseOptions { - #[serde(default)] - /// The folder name of the project - /// Default: `prefix` - folder: Option, - #[serde(default)] - /// Should the PBOs be signed? - /// Default: true - sign: Option, - #[serde(default)] - /// Create an archive of the release - /// Default: true - archive: Option, -} - -impl ReleaseOptions { - #[must_use] - pub fn folder(&self) -> Option { - self.folder.clone() - } - - #[must_use] - pub const fn sign(&self) -> bool { - if let Some(sign) = self.sign { - sign - } else { - true - } - } - - #[must_use] - pub const fn archive(&self) -> bool { - if let Some(archive) = self.archive { - archive - } else { - true - } - } -} diff --git a/libs/project/src/lib.rs b/libs/project/src/lib.rs deleted file mode 100644 index 5f132b65b..000000000 --- a/libs/project/src/lib.rs +++ /dev/null @@ -1,138 +0,0 @@ -use std::{collections::HashMap, path::Path, str::FromStr}; - -use serde::{Deserialize, Serialize}; - -mod addon; -mod asc; -mod error; -mod files; -pub mod hemtt; -mod lint; -mod signing; -mod version; - -pub use {addon::*, error::Error}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProjectConfig { - /// The name of the project - name: String, - /// Prefix for the project - prefix: String, - /// Main prefix for the project - mainprefix: Option, - - #[serde(default)] - /// version of the project - version: version::Options, - - #[serde(default)] - /// Properties to be added to built PBOs - properties: HashMap, - - #[serde(default)] - /// Files to be included in the root of the project, supports glob patterns - files: files::Options, - - #[serde(default)] - hemtt: hemtt::Features, - - #[serde(default)] - signing: signing::Options, - - #[serde(default)] - asc: asc::Options, - - #[serde(default)] - lint: lint::Options, -} - -impl ProjectConfig { - #[must_use] - pub fn name(&self) -> &str { - &self.name - } - - #[must_use] - pub const fn version(&self) -> &version::Options { - &self.version - } - - #[must_use] - pub fn prefix(&self) -> &str { - &self.prefix - } - - #[must_use] - pub const fn mainprefix(&self) -> Option<&String> { - self.mainprefix.as_ref() - } - - #[must_use] - /// Properties to be added to built PBOs - pub const fn properties(&self) -> &HashMap { - &self.properties - } - - #[must_use] - /// Files to be included / excluded in the root of the project, supports glob patterns - pub const fn files(&self) -> &files::Options { - &self.files - } - - #[must_use] - pub const fn hemtt(&self) -> &hemtt::Features { - &self.hemtt - } - - #[must_use] - pub const fn signing(&self) -> &signing::Options { - &self.signing - } - - #[must_use] - pub const fn asc(&self) -> &asc::Options { - &self.asc - } - - #[must_use] - pub const fn lint(&self) -> &lint::Options { - &self.lint - } - - #[must_use] - /// The folder name to use for the release - /// Default: `@{prefix}` - pub fn folder_name(&self) -> String { - self.hemtt() - .release() - .folder() - .map_or_else(|| self.prefix().to_string(), |folder| folder) - } - - /// Load a configuration from a file. - /// - /// # Errors - /// - /// If the file cannot be read, or if the file is not valid TOML, or if the - /// file does not contain a valid configuration, an error is returned. - pub fn from_file(path: &Path) -> Result { - let file = std::fs::read_to_string(path)?; - let config = Self::from_str(&file.replace("[hemtt.launch]", "[hemtt.launch.default]"))?; - - // Validate - if config.prefix.is_empty() { - return Err(Error::ConfigInvalid("prefix cannot be empty".to_string())); - } - - Ok(config) - } -} - -impl FromStr for ProjectConfig { - type Err = Error; - - fn from_str(s: &str) -> Result { - toml::from_str(s).map_err(Error::from) - } -} diff --git a/libs/project/src/lint/mod.rs b/libs/project/src/lint/mod.rs deleted file mode 100644 index a4eb4cd58..000000000 --- a/libs/project/src/lint/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -use serde::{Deserialize, Serialize}; - -mod sqf; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - #[serde(default)] - sqf: sqf::Options, -} - -impl Options { - #[must_use] - pub const fn sqf(&self) -> &sqf::Options { - &self.sqf - } -} diff --git a/libs/project/src/lint/sqf.rs b/libs/project/src/lint/sqf.rs deleted file mode 100644 index c3cc1ef47..000000000 --- a/libs/project/src/lint/sqf.rs +++ /dev/null @@ -1,21 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - #[serde(default)] - enabled: Option, - #[serde(default)] - exclude: Vec, -} - -impl Options { - #[must_use] - pub fn enabled(&self) -> bool { - self.enabled.unwrap_or(true) - } - - #[must_use] - pub const fn exclude(&self) -> &Vec { - &self.exclude - } -} diff --git a/libs/project/src/signing.rs b/libs/project/src/signing.rs deleted file mode 100644 index 0a19b73d9..000000000 --- a/libs/project/src/signing.rs +++ /dev/null @@ -1,29 +0,0 @@ -use hemtt_pbo::BISignVersion; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - version: Option, - - #[serde(default)] - authority: Option, -} - -impl Options { - #[must_use] - pub const fn version(&self) -> BISignVersion { - if let Some(version) = self.version { - version - } else { - BISignVersion::V3 - } - } - - /// Get the authority for signing - /// - /// # Errors - /// Returns an error if the authority is not set - pub const fn authority(&self) -> Option<&String> { - self.authority.as_ref() - } -} diff --git a/libs/project/src/version.rs b/libs/project/src/version.rs deleted file mode 100644 index 3ab063485..000000000 --- a/libs/project/src/version.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::mem::MaybeUninit; - -use git2::Repository; -use hemtt_common::version::Version; -use serde::{Deserialize, Serialize}; -use tracing::{error, trace}; -use vfs::VfsPath; - -use crate::error::Error; - -#[allow(clippy::unsafe_derive_deserialize)] -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct Options { - #[serde(default)] - path: Option, - - #[serde(default)] - major: Option, - #[serde(default)] - minor: Option, - #[serde(default)] - patch: Option, - #[serde(default)] - build: Option, - - #[serde(default)] - git_hash: Option, -} - -static mut VERSION: MaybeUninit = MaybeUninit::uninit(); -static mut INIT: bool = false; - -impl Options { - /// Get the version of the project - /// - /// # Errors - /// - /// Returns an error if the version is not a valid semver version - /// or a points to a file that does not contain a valid version macro - pub fn get(&self, vfs: &VfsPath) -> Result { - // Check for a cached version - unsafe { - if INIT { - return Ok(VERSION.assume_init_ref().clone()); - } - } - - let mut version = self._get(vfs)?; - - if let Some(length) = self.git_hash() { - let repo = Repository::discover(".")?; - let rev = repo.revparse_single("HEAD")?; - let id = rev.id().to_string(); - version.set_build(&id[0..length as usize]); - }; - - unsafe { - VERSION = MaybeUninit::new(version); - INIT = true; - return Ok(VERSION.assume_init_ref().clone()); - } - } - - /// Invalidate the cached version - #[allow(clippy::unused_self)] - pub fn invalidate(&self) { - unsafe { - INIT = false; - } - } - - fn _get(&self, vfs: &VfsPath) -> Result { - // Check for a defined major version - if let Some(major) = self.major { - trace!("reading version from project.toml"); - let Some(minor) = self.minor else { - return Err(hemtt_common::version::Error::ExpectedMinor.into()); - }; - let Some(patch) = self.patch else { - return Err(hemtt_common::version::Error::ExpectedPatch.into()); - }; - return Ok(Version::new(major, minor, patch, self.build)); - } - - let version = self.path.as_ref().map_or("script_version", |v| v.as_str()); - - // Check for script_version.hpp in the main addon - let binding = if version == "script_version" { - String::from("addons/main/script_version.hpp") - } else { - version.replace('\\', "/") - }; - let path = vfs.join(binding)?; - - // Check for a path to a version macro file - if path.exists()? { - trace!("checking for version macro in {:?}", path); - let content = path.read_to_string()?; - return Version::try_from_script_version(&content).map_err(Into::into); - } - error!("could not find version macro file: {:?}", path); - - Err(hemtt_common::version::Error::UnknownVersion.into()) - } - - #[must_use] - pub const fn git_hash(&self) -> Option { - if let Some(include) = self.git_hash { - if include == 0 { - return None; - } - Some(include) - } else { - Some(8) - } - } -}