Files
fomod-manager/src/fomod.rs

358 lines
9.7 KiB
Rust

// This file incorporates code from luctius/fomod:
// https://github.com/luctius/fomod/
// Original license: MIT / Apache-2.0
use std::{fs, io, path::Path};
use log::debug;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Deserialize, PartialEq)]
pub struct Info {
#[serde(rename = "Name")]
pub name: Option<String>,
#[serde(rename = "Description")]
pub description: Option<String>,
#[serde(rename = "Version")]
pub version: Option<String>,
#[serde(rename = "Author")]
pub author: Option<String>,
#[serde(rename = "Website")]
pub website: Option<String>,
#[serde(rename = "CategoryId")]
pub category_id: Option<usize>,
}
impl Info {
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, FOModError> {
let data = fs::read_to_string(path)?;
let config = quick_xml::de::from_str(&data)?;
Ok(config)
}
}
#[derive(Debug, Deserialize, PartialEq)]
pub struct Config {
#[serde(rename = "moduleName")]
pub module_name: String,
#[serde(rename = "moduleImage")]
pub module_image: Option<HeaderImage>,
#[serde(rename = "moduleDependencies")]
pub module_dependencies: Option<ModuleDependency>,
#[serde(rename = "requiredInstallFiles")]
pub required_install_files: Option<FileList>,
#[serde(rename = "installSteps")]
pub install_steps: Option<StepList>,
#[serde(rename = "conditionalFileInstalls")]
pub conditional_file_installs: Option<ConditionalFileInstallList>,
}
impl Config {
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, FOModError> {
debug!(
"Loading FOmod config from {}",
path.as_ref().to_string_lossy()
);
let data = fs::read_to_string(path)?;
let config = quick_xml::de::from_str(&data)?;
Ok(config)
}
}
#[derive(Error, Debug)]
pub enum FOModError {
#[error("Failed to read file")]
Io(#[from] io::Error),
#[error("Failed to parse config")]
Parse(#[from] quick_xml::de::DeError),
}
#[derive(
Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash, Default,
)]
pub enum OrderEnum {
#[default]
Ascending,
Explicit,
Descending,
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PluginTypeEnum {
Required,
Optional,
Recommended,
NotUsable,
CouldBeUsable,
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PluginType {
#[serde(rename = "@name")]
pub name: PluginTypeEnum,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PluginTypeDescriptor {
#[serde(rename = "$value")]
pub value: PluginTypeDescriptorEnum,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PluginTypeDescriptorEnum {
#[serde(rename = "dependencyType")]
DependencyType(DependencyPluginType),
#[serde(rename = "type")]
PluginType(PluginType),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DependencyPluginType {
#[serde(rename = "defaultType")]
pub default_type: PluginType,
pub patterns: DependencyPatternList,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DependencyPatternList {
pub pattern: Vec<DependencyPattern>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DependencyPattern {
pub dependencies: Vec<CompositeDependency>,
#[serde(rename = "type")]
pub typ: PluginType,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct StepList {
#[serde(rename = "@order", default)]
pub order: OrderEnum,
#[serde(rename = "installStep")]
pub install_step: Vec<InstallStep>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InstallStep {
#[serde(rename = "@name")]
pub name: String,
pub visible: Option<ModuleDependency>,
#[serde(rename = "optionalFileGroups")]
pub optional_file_groups: GroupList,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleDependency {
#[serde(rename = "@operator")]
#[serde(default)]
pub operator: DependencyOperator,
#[serde(rename = "$value")]
pub list: Vec<CompositeDependency>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CompositeDependency {
#[serde(rename = "fileDependency")]
File(FileDependency),
#[serde(rename = "flagDependency")]
Flag(FlagDependency),
#[serde(rename = "gameDependency")]
Game(VersionDependency),
#[serde(rename = "fommDependency")]
Fomm(VersionDependency),
#[serde(rename = "dependencies")]
Dependency(ModuleDependency),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FlagDependency {
#[serde(rename = "@flag")]
pub flag: String,
#[serde(rename = "@value")]
pub value: String,
}
impl From<SetConditionFlag> for FlagDependency {
fn from(scf: SetConditionFlag) -> Self {
Self {
flag: scf.name,
value: scf.flag_value,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VersionDependency {
#[serde(rename = "@version")]
pub version: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileDependency {
#[serde(rename = "@file")]
pub file_name: String,
#[serde(rename = "@state")]
pub state: DependencyState,
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DependencyState {
Active,
Inactive,
Missing,
}
#[derive(
Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
pub enum DependencyOperator {
#[default]
And,
Or,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileList {
#[serde(rename = "$value")]
pub list: Option<Vec<FileTypeEnum>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum FileTypeEnum {
#[serde(rename = "file")]
File(FileType),
#[serde(rename = "folder")]
Folder(FileType),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileType {
#[serde(rename = "@source")]
pub source: String,
#[serde(rename = "@destination")]
pub destination: Option<String>,
#[serde(rename = "@alwaysInstall")]
pub always_install: Option<String>,
#[serde(rename = "@installIfUsable", default = "false_bool")]
pub install_if_usable: bool,
#[serde(rename = "@priority")]
pub priority: Option<isize>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupList {
#[serde(rename = "@order", default)]
pub order: OrderEnum,
pub group: Vec<Group>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Group {
#[serde(rename = "@name")]
pub name: String,
#[serde(rename = "@type")]
pub typ: GroupType,
pub plugins: PluginList,
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GroupType {
SelectAtLeastOne,
SelectAtMostOne,
SelectExactlyOne,
SelectAll,
SelectAny,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PluginList {
#[serde(rename = "@order", default)]
pub order: OrderEnum,
pub plugin: Vec<Plugin>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Plugin {
#[serde(rename = "@name")]
pub name: String,
pub description: String,
pub image: Option<Image>,
pub files: Option<FileList>,
#[serde(rename = "conditionFlags")]
pub condition_flags: Option<ConditionFlagList>,
#[serde(rename = "typeDescriptor")]
pub type_descriptor: Option<PluginTypeDescriptor>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Image {
#[serde(rename = "@path")]
pub path: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct HeaderImage {
#[serde(rename = "@path")]
pub path: Option<String>,
#[serde(rename = "@showImage", default = "false_bool")]
pub show_image: bool,
#[serde(rename = "@showFade", default = "false_bool")]
pub show_fade: bool,
pub height: Option<isize>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConditionFlagList {
pub flag: Vec<SetConditionFlag>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SetConditionFlag {
#[serde(rename = "@name")]
pub name: String,
#[serde(rename = "$value")]
pub flag_value: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConditionalFileInstallList {
pub patterns: ConditionalInstallPatternList,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConditionalInstallPatternList {
pub pattern: Vec<ConditionalInstallPattern>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConditionalInstallPattern {
pub dependencies: ModuleDependency,
pub files: FileList,
}
fn false_bool() -> bool {
false
}