mirror of
https://github.com/WarrenHood/MCModpackManager.git
synced 2025-04-29 14:44:59 +01:00
Properly added support for local files in the modpack
This commit is contained in:
parent
d079f448ae
commit
9df380ad18
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -148,6 +148,9 @@ name = "anyhow"
|
|||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
|
|
|
@ -5,7 +5,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
anyhow = { version = "1.0.86", features = ["backtrace"] }
|
||||
clap = { version = "4.5.15", features = ["derive"] }
|
||||
git2 = "0.19.0"
|
||||
home = "0.5.9"
|
||||
|
|
|
@ -1,11 +1,44 @@
|
|||
use crate::providers::DownloadSide;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fmt::Display, path::{Path, PathBuf}, str::FromStr};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
|
||||
pub struct FileMeta {
|
||||
/// Relative path of file in the instance folder
|
||||
pub target_path: String,
|
||||
/// Which side the files should be applied on
|
||||
pub side: DownloadSide,
|
||||
/// When to apply the files to the instance
|
||||
pub apply_policy: FileApplyPolicy
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
|
||||
pub enum FileApplyPolicy {
|
||||
/// Always ensure the file or folder exactly matches that defined in the pack
|
||||
Always,
|
||||
/// Only apply the file or folder if it doesn't already exist in the pack
|
||||
Once
|
||||
}
|
||||
|
||||
impl FromStr for FileApplyPolicy {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"always" => Ok(Self::Always),
|
||||
"once" => Ok(Self::Once),
|
||||
_ => anyhow::bail!("Invalid apply policy {}. Expected one of: always, once", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FileApplyPolicy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Always => write!(f, "Always"),
|
||||
Self::Once => write!(f, "Once"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FileMeta {
|
||||
|
|
|
@ -7,7 +7,7 @@ mod resolver;
|
|||
|
||||
use anyhow::{Error, Result};
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use file_meta::{get_normalized_relative_path, FileMeta};
|
||||
use file_meta::{get_normalized_relative_path, FileApplyPolicy, FileMeta};
|
||||
use mod_meta::{ModMeta, ModProvider};
|
||||
use modpack::ModpackMeta;
|
||||
use profiles::{PackSource, Profile};
|
||||
|
@ -134,10 +134,13 @@ enum FileCommands {
|
|||
local_path: PathBuf,
|
||||
/// Target path to copy the file/folder to relative to the MC instance directory
|
||||
#[arg(short, long)]
|
||||
target_path: Option<PathBuf>,
|
||||
target_path: Option<String>,
|
||||
/// Side to copy the file/folder to
|
||||
#[arg(long, default_value_t = DownloadSide::Server)]
|
||||
side: DownloadSide,
|
||||
/// File apply policy - whether to always apply the file or just apply it once (if the file doesn't exist)
|
||||
#[arg(long, default_value_t = FileApplyPolicy::Always)]
|
||||
apply_policy: FileApplyPolicy,
|
||||
},
|
||||
/// Show metadata about a file in the pack
|
||||
Show {
|
||||
|
@ -437,15 +440,19 @@ async fn main() -> anyhow::Result<()> {
|
|||
local_path,
|
||||
target_path,
|
||||
side,
|
||||
apply_policy,
|
||||
} => {
|
||||
let mut modpack_meta = ModpackMeta::load_from_current_directory()?;
|
||||
let current_dir = &std::env::current_dir()?;
|
||||
let target_path = if let Some(target_path) = target_path {
|
||||
target_path
|
||||
} else {
|
||||
get_normalized_relative_path(&local_path, ¤t_dir)?
|
||||
};
|
||||
let file_meta = FileMeta {
|
||||
target_path: get_normalized_relative_path(
|
||||
&target_path.unwrap_or(local_path.clone()),
|
||||
current_dir,
|
||||
)?,
|
||||
target_path,
|
||||
side,
|
||||
apply_policy,
|
||||
};
|
||||
|
||||
modpack_meta.add_file(&local_path, &file_meta, current_dir)?;
|
||||
|
@ -510,10 +517,10 @@ async fn main() -> anyhow::Result<()> {
|
|||
} else {
|
||||
anyhow::bail!("Profile '{name}' does not exist")
|
||||
};
|
||||
println!("Profile name : {name}");
|
||||
println!("Profile name : {name}");
|
||||
println!("Instance folder : {}", profile.instance_folder.display());
|
||||
println!("Modpack source: {}", profile.pack_source);
|
||||
println!("Side : {}", profile.side);
|
||||
println!("Modpack source : {}", profile.pack_source);
|
||||
println!("Side : {}", profile.side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
file_meta::{get_normalized_relative_path, FileMeta},
|
||||
file_meta::{get_normalized_relative_path, FileApplyPolicy, FileMeta},
|
||||
mod_meta::{ModMeta, ModProvider},
|
||||
providers::DownloadSide,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -130,16 +131,6 @@ impl ModpackMeta {
|
|||
pack_root.display()
|
||||
))?
|
||||
};
|
||||
|
||||
let target_path = PathBuf::from(&file_meta.target_path);
|
||||
if !target_path.is_relative() {
|
||||
anyhow::bail!(
|
||||
"Target path {} for file {} is not relative!",
|
||||
file_meta.target_path,
|
||||
file_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
let full_path = pack_root.join(relative_path);
|
||||
|
||||
// Make sure this path is consistent across platforms
|
||||
|
@ -189,6 +180,86 @@ impl ModpackMeta {
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
/// Installs all the manual files from the pack into the specified directory
|
||||
///
|
||||
/// Files/Folders are added if they don't exist if the policy is set to `FileApplyPolicy::Once`.
|
||||
/// Otherwise, files/folders are always overwritten.
|
||||
///
|
||||
/// Files/Folders, when applied, will ensure that the exact contents of that file or folder match in the instance folder
|
||||
/// Ie. If a folder is being applied, any files in that folder not in the modpack will be removed
|
||||
pub fn install_files(
|
||||
&self,
|
||||
pack_dir: &Path,
|
||||
instance_dir: &Path,
|
||||
side: DownloadSide,
|
||||
) -> Result<()> {
|
||||
println!(
|
||||
"Applying modpack files: {} -> {}...",
|
||||
pack_dir.display(),
|
||||
instance_dir.display()
|
||||
);
|
||||
if let Some(files) = &self.files {
|
||||
for (rel_path, file_meta) in files {
|
||||
let source_path = pack_dir.join(rel_path);
|
||||
let target_path = instance_dir.join(&file_meta.target_path);
|
||||
if !side.contains(file_meta.side) {
|
||||
println!(
|
||||
"Skipping apply of {} -> {}. (Applies for side={}, current side={})",
|
||||
source_path.display(),
|
||||
target_path.display(),
|
||||
file_meta.side.to_string(),
|
||||
side.to_string()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if target_path.exists() && file_meta.apply_policy == FileApplyPolicy::Once {
|
||||
println!(
|
||||
"Skipping apply of {} -> {}. (Already applied once)",
|
||||
source_path.display(),
|
||||
target_path.display(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, this file/folder needs to be applied
|
||||
if source_path.is_dir() {
|
||||
// Sync a folder
|
||||
if target_path.exists() {
|
||||
println!(
|
||||
"Syncing and overwriting existing directory {} -> {}",
|
||||
source_path.display(),
|
||||
target_path.display(),
|
||||
);
|
||||
std::fs::remove_dir_all(&target_path)?;
|
||||
}
|
||||
}
|
||||
self.copy_files(&source_path, &target_path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_files(&self, src: &Path, dst: &Path) -> Result<()> {
|
||||
if src.is_dir() {
|
||||
std::fs::create_dir_all(dst)?;
|
||||
for entry in std::fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let src_path = entry.path();
|
||||
let dst_path = dst.join(entry.file_name());
|
||||
self.copy_files(&src_path, &dst_path)?;
|
||||
}
|
||||
} else {
|
||||
let parent_dir = dst.parent();
|
||||
if let Some(parent_dir) = parent_dir {
|
||||
std::fs::create_dir_all(parent_dir)?;
|
||||
}
|
||||
println!("Syncing file {} -> {}", src.display(), dst.display());
|
||||
std::fs::copy(src, dst)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_project(&self, directory: &Path) -> Result<()> {
|
||||
let modpack_meta_file_path = directory.join(PathBuf::from(MODPACK_FILENAME));
|
||||
if modpack_meta_file_path.exists() {
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::{providers::DownloadSide, resolver::PinnedPackMeta};
|
||||
use crate::{modpack::ModpackMeta, providers::DownloadSide, resolver::PinnedPackMeta};
|
||||
|
||||
const CONFIG_DIR_NAME: &str = "mcmpmgr";
|
||||
const DATA_FILENAME: &str = "data.toml";
|
||||
|
@ -58,16 +58,20 @@ impl Profile {
|
|||
}
|
||||
|
||||
pub async fn install(&self) -> Result<()> {
|
||||
let (pack_lock, temp_dir) = match &self.pack_source {
|
||||
let (pack_lock, pack_directory, _temp_dir) = match &self.pack_source {
|
||||
PackSource::Git { url } => {
|
||||
let (pack_lock, packdir) = PinnedPackMeta::load_from_git_repo(&url, true).await?;
|
||||
(pack_lock, Some(packdir))
|
||||
let pack_path = packdir.path().to_path_buf();
|
||||
(pack_lock, pack_path, Some(packdir))
|
||||
}
|
||||
PackSource::Local { path } => (
|
||||
PinnedPackMeta::load_from_directory(&path, true).await?,
|
||||
path.to_path_buf(),
|
||||
None,
|
||||
),
|
||||
};
|
||||
let modpack_meta = ModpackMeta::load_from_directory(&pack_directory)?;
|
||||
modpack_meta.install_files(&pack_directory, &self.instance_folder, self.side)?;
|
||||
|
||||
pack_lock
|
||||
.download_mods(&self.instance_folder.join("mods"), self.side)
|
||||
|
|
|
@ -28,6 +28,12 @@ pub enum DownloadSide {
|
|||
Client,
|
||||
}
|
||||
|
||||
impl DownloadSide {
|
||||
pub fn contains(self, side: Self) -> bool {
|
||||
self == Self::Both || side == Self::Both || self == side
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for DownloadSide {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
anyhow = { version = "1.0.86", features = ["backtrace"] }
|
||||
iced = { version = "0.12.1", features = ["tokio"] }
|
||||
mcmpmgr = { version = "0.1.0", path = "../mcmpmgr" }
|
||||
rfd = "0.14.1"
|
||||
|
|
Loading…
Reference in a new issue