aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/download.rs8
-rw-r--r--src/main.rs35
-rw-r--r--src/minemod.rs36
3 files changed, 62 insertions, 17 deletions
diff --git a/src/download.rs b/src/download.rs
index 8a372ad..75bea57 100644
--- a/src/download.rs
+++ b/src/download.rs
@@ -10,7 +10,7 @@ use zip::ZipArchive;
use super::{
contentdb::{ContentDb, ContentId},
error::{Error, Result},
- minemod::{MineMod, ModId},
+ minemod::{self, ModContainer, ModId},
};
/// A source determines where a mod should be loaded from.
@@ -73,7 +73,7 @@ impl Downloader {
})
}
- pub fn download(&self, source: &Source) -> Result<MineMod> {
+ pub fn download(&self, source: &Source) -> Result<Box<dyn ModContainer>> {
match *source {
Source::Http(ref url) => self.download_http(url),
Source::ContentDb((ref user, ref package)) => {
@@ -96,7 +96,7 @@ impl Downloader {
///
/// The mod is extracted to a temporary directory and has to be copied using
/// [`MineMod::copy_to`].
- pub fn download_http(&self, url: &Url) -> Result<MineMod> {
+ pub fn download_http(&self, url: &Url) -> Result<Box<dyn ModContainer>> {
let mut reader = ureq::request_url("GET", url).call()?.into_reader();
let mut data = Vec::new();
reader.read_to_end(&mut data)?;
@@ -115,6 +115,6 @@ impl Downloader {
archive.extract(self.temp_dir.path())?;
let extracted_path = self.temp_dir.path().join(name);
- MineMod::open(&extracted_path)
+ minemod::open_mod_or_pack(&extracted_path)
}
}
diff --git a/src/main.rs b/src/main.rs
index bff0fe0..da04f9c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,7 +11,9 @@ use itertools::Itertools;
use log::debug;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
-use modderbaas::{Baas, ContentDb, Downloader, MineMod, Snapshot, Source, World};
+use modderbaas::{
+ minemod::ModContainer, Baas, ContentDb, Downloader, MineMod, Snapshot, Source, World,
+};
fn main() -> Result<()> {
stderrlog::new()
@@ -200,7 +202,7 @@ fn install_mods(
.map(|&s| Source::from_str(s))
.collect::<Result<Vec<_>, _>>()?;
- let mut to_install = Vec::<MineMod>::new();
+ let mut to_install = Vec::<Box<dyn ModContainer>>::new();
let mut to_enable = Vec::<MineMod>::new();
let game = snapshot
@@ -213,7 +215,7 @@ fn install_mods(
.map(|m| m.mod_id())
.collect::<Result<Vec<_>, _>>()?;
- while !wanted.is_empty() {
+ 'modloop: while !wanted.is_empty() {
let next_mod = wanted.remove(0);
// Special handling for mods specified by their ID, as those could already exist.
@@ -229,9 +231,11 @@ fn install_mods(
}
// Is this a mod that is already queued for installation?
- for m in &to_install {
- if &m.mod_id()? == id {
- continue;
+ for mod_or_pack in &to_install {
+ for m in mod_or_pack.mods()? {
+ if &m.name()? == id {
+ continue 'modloop;
+ }
}
}
@@ -264,7 +268,9 @@ fn install_mods(
let downloaded = downloader
.download(&next_mod)
.context("Failed to download mod")?;
- wanted.extend(downloaded.dependencies()?.into_iter().map(Source::ModId));
+ for m in downloaded.mods()? {
+ wanted.extend(m.dependencies()?.into_iter().map(Source::ModId));
+ }
to_install.push(downloaded);
}
}
@@ -276,20 +282,25 @@ fn install_mods(
if dry_run {
for m in to_install {
- let mod_id = m.mod_id()?;
+ let mod_id = m.name()?;
let mod_dir = target_dir.join(&mod_id);
- writeln!(output, "Installing {} to {:?}", mod_id, mod_dir)?;
+ writeln!(output, "Installing {} to {:?}", m, mod_dir)?;
+ to_enable.extend(m.mods()?);
+ }
+ for m in to_enable {
+ let mod_id = m.mod_id()?;
+ writeln!(output, "Enabling {}", mod_id)?;
}
return Ok(());
}
for m in to_install {
- let mod_id = m.mod_id()?;
+ let mod_id = m.name()?;
writeln!(output, "Installing {}", mod_id)?;
let installed = m
- .copy_to(target_dir)
+ .install_to(target_dir)
.context(format!("Error installing '{}'", mod_id))?;
- to_enable.push(installed);
+ to_enable.extend(installed.mods()?);
}
for m in to_enable {
diff --git a/src/minemod.rs b/src/minemod.rs
index 6af50e3..d90605c 100644
--- a/src/minemod.rs
+++ b/src/minemod.rs
@@ -126,15 +126,39 @@ impl Modpack {
}
Ok(mods)
}
+
+ /// Copies the modpack to the given path.
+ ///
+ /// Note that the path should not include the modpack directory, that will be appended
+ /// automatically.
+ ///
+ /// Returns a new [`Modpack`] object pointing to the copy.
+ pub fn copy_to<P: AsRef<Path>>(&self, path: P) -> Result<Modpack> {
+ let mut options = CopyOptions::new();
+ options.content_only = true;
+ let path = path.as_ref().join(self.name()?);
+ fs::create_dir_all(&path)?;
+ dir::copy(&self.path, &path, &options)?;
+ Modpack::open(&path)
+ }
+}
+
+impl fmt::Display for Modpack {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{} (pack)", self.name().map_err(|_| fmt::Error)?)
+ }
}
/// A thing that can contain mods.
-pub trait ModContainer: Any {
+pub trait ModContainer: Any + fmt::Display {
/// Returns the name of the mod container.
fn name(&self) -> Result<String>;
/// Return all contained mods.
fn mods(&self) -> Result<Vec<MineMod>>;
+
+ /// Copies the content to the given directory.
+ fn install_to(&self, path: &Path) -> Result<Box<dyn ModContainer>>;
}
impl ModContainer for MineMod {
@@ -145,6 +169,11 @@ impl ModContainer for MineMod {
fn mods(&self) -> Result<Vec<MineMod>> {
Ok(vec![self.clone()])
}
+
+ fn install_to(&self, path: &Path) -> Result<Box<dyn ModContainer>> {
+ self.copy_to(path)
+ .map(|x| Box::new(x) as Box<dyn ModContainer>)
+ }
}
impl ModContainer for Modpack {
@@ -155,6 +184,11 @@ impl ModContainer for Modpack {
fn mods(&self) -> Result<Vec<MineMod>> {
self.mods()
}
+
+ fn install_to(&self, path: &Path) -> Result<Box<dyn ModContainer>> {
+ self.copy_to(path)
+ .map(|x| Box::new(x) as Box<dyn ModContainer>)
+ }
}
/// Attempts to open the given path as either a single mod or a modpack.