Compare commits
2 Commits
d806b331db
...
96dda41c46
| Author | SHA1 | Date | |
|---|---|---|---|
|
96dda41c46
|
|||
|
295c9bd8c3
|
14
src/fomod.rs
14
src/fomod.rs
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use std::{fs, io, path::Path};
|
use std::{fs, io, path::Path};
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -55,6 +56,11 @@ pub struct Config {
|
|||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, FOModError> {
|
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 data = fs::read_to_string(path)?;
|
||||||
let config = quick_xml::de::from_str(&data)?;
|
let config = quick_xml::de::from_str(&data)?;
|
||||||
|
|
||||||
@@ -142,7 +148,7 @@ pub struct InstallStep {
|
|||||||
#[serde(rename = "@name")]
|
#[serde(rename = "@name")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
pub visible: Option<CompositeDependency>,
|
pub visible: Option<ModuleDependency>,
|
||||||
|
|
||||||
#[serde(rename = "optionalFileGroups")]
|
#[serde(rename = "optionalFileGroups")]
|
||||||
pub optional_file_groups: GroupList,
|
pub optional_file_groups: GroupList,
|
||||||
@@ -151,6 +157,7 @@ pub struct InstallStep {
|
|||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ModuleDependency {
|
pub struct ModuleDependency {
|
||||||
#[serde(rename = "@operator")]
|
#[serde(rename = "@operator")]
|
||||||
|
#[serde(default)]
|
||||||
pub operator: DependencyOperator,
|
pub operator: DependencyOperator,
|
||||||
#[serde(rename = "$value")]
|
#[serde(rename = "$value")]
|
||||||
pub list: Vec<CompositeDependency>,
|
pub list: Vec<CompositeDependency>,
|
||||||
@@ -207,8 +214,11 @@ pub enum DependencyState {
|
|||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(
|
||||||
|
Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash,
|
||||||
|
)]
|
||||||
pub enum DependencyOperator {
|
pub enum DependencyOperator {
|
||||||
|
#[default]
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||||
use log::warn;
|
use log::{debug, trace, warn};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -114,14 +114,21 @@ fn determain_mod_kind(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn install_fomod(
|
fn install_fomod(
|
||||||
_instance: &ModdedInstance,
|
instance: &ModdedInstance,
|
||||||
module_config_path: impl AsRef<Path>,
|
module_config_path: impl AsRef<Path>,
|
||||||
mod_root: impl AsRef<Path>,
|
mod_root: impl AsRef<Path>,
|
||||||
) -> anyhow::Result<Vec<ModFile>> {
|
) -> anyhow::Result<Vec<ModFile>> {
|
||||||
|
debug!("Running FOmod installer");
|
||||||
let module_config = fomod::Config::load_from_file(module_config_path)?;
|
let module_config = fomod::Config::load_from_file(module_config_path)?;
|
||||||
|
|
||||||
// TODO: add active plugins from instance config
|
let active_plugins: Vec<_> = instance
|
||||||
let files = run_fomod_installer(module_config, &[], install_prompt::prompt)
|
.active_plugins()
|
||||||
|
.map(|e| e.to_string_lossy())
|
||||||
|
.map(|e| e.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
trace!("Current loded plugins: {:?}", active_plugins);
|
||||||
|
let files = run_fomod_installer(module_config, &active_plugins, install_prompt::prompt)
|
||||||
.map_err(|_| InststanceError::FomodRunInstaller)?;
|
.map_err(|_| InststanceError::FomodRunInstaller)?;
|
||||||
|
|
||||||
let mod_files: Vec<_> = files
|
let mod_files: Vec<_> = files
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use std::{
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::types::{self, ModdedInstance, RootConfig};
|
use crate::{types::{self, ModdedInstance, RootConfig}, utils::is_plugin_file};
|
||||||
|
|
||||||
pub fn create_loadorder(
|
pub fn create_loadorder(
|
||||||
root_config: &RootConfig,
|
root_config: &RootConfig,
|
||||||
@@ -76,13 +76,6 @@ pub fn create_loadorder(
|
|||||||
Ok(sorted)
|
Ok(sorted)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_plugin_file(filename: impl AsRef<Path>) -> bool {
|
|
||||||
filename
|
|
||||||
.as_ref()
|
|
||||||
.extension()
|
|
||||||
.is_some_and(|ext| ext == "esp" || ext == "esm" || ext == "esl")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum LoadOrderError {
|
pub enum LoadOrderError {
|
||||||
#[error("Failed to read game directory")]
|
#[error("Failed to read game directory")]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use log::{debug, warn};
|
|||||||
|
|
||||||
use crate::fomod::{
|
use crate::fomod::{
|
||||||
CompositeDependency, Config, DependencyOperator, DependencyState, FileList, FileTypeEnum,
|
CompositeDependency, Config, DependencyOperator, DependencyState, FileList, FileTypeEnum,
|
||||||
Group, GroupType, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum,
|
Group, GroupType, ModuleDependency, Plugin, PluginTypeDescriptorEnum, PluginTypeEnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -101,6 +101,22 @@ fn evaluate_dependency(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn evaluate_module_depbendecy(
|
||||||
|
dep: &ModuleDependency,
|
||||||
|
state: &InstallerState,
|
||||||
|
installed_plugins: &[String],
|
||||||
|
) -> bool {
|
||||||
|
let mut evaluated = dep
|
||||||
|
.list
|
||||||
|
.iter()
|
||||||
|
.map(|e| evaluate_dependency(e, state, installed_plugins));
|
||||||
|
|
||||||
|
match dep.operator {
|
||||||
|
DependencyOperator::And => evaluated.all(|r| r),
|
||||||
|
DependencyOperator::Or => evaluated.any(|r| r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GroupPrompt {
|
pub struct GroupPrompt {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub select_type: GroupType,
|
pub select_type: GroupType,
|
||||||
@@ -191,7 +207,7 @@ pub fn run_fomod_installer(
|
|||||||
if step
|
if step
|
||||||
.visible
|
.visible
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|v| !evaluate_dependency(v, &state, installed_plugins))
|
.is_some_and(|v| !evaluate_module_depbendecy(v, &state, installed_plugins))
|
||||||
{
|
{
|
||||||
// Dependency to show the step not meet. Skipping.
|
// Dependency to show the step not meet. Skipping.
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{link::Link, mod_file::ModFile};
|
use crate::{
|
||||||
|
types::{link::Link, mod_file::ModFile},
|
||||||
|
utils::is_plugin_file,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
pub struct InstalledMod {
|
pub struct InstalledMod {
|
||||||
@@ -36,4 +41,12 @@ impl InstalledMod {
|
|||||||
pub fn files(&self) -> &[Link] {
|
pub fn files(&self) -> &[Link] {
|
||||||
&self.files
|
&self.files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn active_plugins(&self) -> impl Iterator<Item = &OsStr> {
|
||||||
|
self.files
|
||||||
|
.iter()
|
||||||
|
.filter(|e| is_plugin_file(e.dst()))
|
||||||
|
.map(|e| e.dst())
|
||||||
|
.flat_map(|e| e.file_name())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
ffi::OsStr,
|
||||||
fs::{self, read_to_string},
|
fs::{self, read_to_string},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
@@ -88,4 +89,8 @@ impl ModdedInstance {
|
|||||||
pub fn mods(&self) -> &[InstalledMod] {
|
pub fn mods(&self) -> &[InstalledMod] {
|
||||||
&self.mods
|
&self.mods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn active_plugins(&self) -> impl Iterator<Item = &OsStr> {
|
||||||
|
self.mods.iter().flat_map(|e| e.active_plugins())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,3 +56,10 @@ pub fn walk_all_files(
|
|||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_plugin_file(filename: impl AsRef<Path>) -> bool {
|
||||||
|
filename
|
||||||
|
.as_ref()
|
||||||
|
.extension()
|
||||||
|
.is_some_and(|ext| ext == "esp" || ext == "esm" || ext == "esl")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user