summaryrefslogtreecommitdiffstats
path: root/src/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'src/launcher')
-rw-r--r--src/launcher/jre.rs109
-rw-r--r--src/launcher/jre/manifest.rs17
2 files changed, 124 insertions, 2 deletions
diff --git a/src/launcher/jre.rs b/src/launcher/jre.rs
index 40fd8c1..4be4c7b 100644
--- a/src/launcher/jre.rs
+++ b/src/launcher/jre.rs
@@ -1,6 +1,9 @@
+use std::collections::HashSet;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::path::{Path, PathBuf};
+use std::sync::Arc;
+use futures::{stream, StreamExt, TryStreamExt};
use log::{debug, info, warn};
use tokio::{fs, io, io::ErrorKind};
use tokio::fs::File;
@@ -11,7 +14,8 @@ mod manifest;
use arch::JRE_ARCH;
use manifest::JavaRuntimesManifest;
-use crate::launcher::jre::manifest::JavaRuntimeManifest;
+use manifest::JavaRuntimeManifest;
+use crate::launcher::jre::manifest::JavaRuntimeFile;
use crate::util;
use crate::util::{EnsureFileError, FileVerifyError, IntegrityError};
use crate::version::DownloadInfo;
@@ -91,6 +95,109 @@ impl JavaRuntimeRepository {
self.load_runtime_manifest(component, &runtime.manifest).await
}
+
+ fn clean_up_runtime_sync(path: &Path, manifest: Arc<JavaRuntimeManifest>) -> Result<(), io::Error> {
+ for entry in walkdir::WalkDir::new(path).contents_first(true) {
+ let entry = entry?;
+
+ if !entry.path().strip_prefix(path)
+ .expect("walkdir escaped root (???)")
+ .to_str().map_or(None, |s| manifest.files.get(s))
+ .is_none_or(|f| (f.is_file() != entry.file_type().is_file())
+ || (f.is_directory() != entry.file_type().is_dir())
+ || (f.is_link() != entry.file_type().is_symlink())) {
+ // path is invalid utf-8, extraneous, or of the wrong type
+ debug!("File {} is extraneous or of wrong type ({:?}). Deleting it.", entry.path().display(), entry.file_type());
+
+ if entry.file_type().is_dir() {
+ std::fs::remove_dir(entry.path())?;
+ } else {
+ std::fs::remove_file(entry.path())?;
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ async fn clean_up_runtime(path: &Path, manifest: Arc<JavaRuntimeManifest>) -> Result<(), io::Error> {
+ let (tx, rx) = tokio::sync::oneshot::channel();
+
+ let path = path.to_owned();
+ let manifest = manifest.clone();
+
+ tokio::task::spawn_blocking(move || {
+ let res = Self::clean_up_runtime_sync(&path, manifest);
+ let _ = tx.send(res);
+ }).await.expect("clean_up_runtime_sync panicked");
+
+ rx.await.expect("clean_up_runtime_sync hung up")
+ }
+
+ async fn ensure_jre_dirs(&self, path: &Path, manifest: &JavaRuntimeManifest) -> Result<(), JavaRuntimeError> {
+ stream::iter(manifest.files.iter().filter(|(_, f)| f.is_directory()))
+ .map::<Result<_, JavaRuntimeError>, _>(|(name, _)| Ok(async move {
+ let ent_path = util::check_path(name).map_err(JavaRuntimeError::MalformedManifest)?;
+ let ent_path = [path, ent_path].into_iter().collect::<PathBuf>();
+
+ match fs::metadata(&ent_path).await {
+ Ok(meta) => {
+ if !meta.is_dir() {
+ debug!("Deleting misplaced file at {}", ent_path.display());
+ fs::remove_file(&ent_path).await.map_err(|e| JavaRuntimeError::IO {
+ what: "deleting misplaced file",
+ error: e
+ })?;
+ }
+ },
+ Err(e) if e.kind() == ErrorKind::NotFound => (),
+ Err(e) => return Err(JavaRuntimeError::IO { what: "'stat'ing directory", error: e })
+ }
+
+ match fs::create_dir(&ent_path).await {
+ Ok(_) => {
+ debug!("Created directory at {}", ent_path.display());
+ Ok(())
+ },
+ Err(e) if e.kind() == ErrorKind::AlreadyExists => Ok(()),
+ Err(e) => {
+ warn!("Could not create directory {} for JRE!", ent_path.display());
+ return Err(JavaRuntimeError::IO { what: "creating directory", error: e });
+ }
+ }
+ }))
+ .try_buffer_unordered(32)
+ .try_fold((), |_, _| async { Ok(()) }).await
+ }
+
+ async fn ensure_jre_files(path: &Path, manifest: &JavaRuntimeManifest) -> Result<(), JavaRuntimeError> {
+ stream::iter(manifest.files.iter().filter(|(_, f)| f.is_file()))
+ .map(|(name, file)| Ok(async move {
+
+ }));
+
+ todo!()
+ }
+
+ async fn ensure_jre(&self, component: &str, manifest: JavaRuntimeManifest) -> Result<(), JavaRuntimeError> {
+ let runtime_path = self.get_component_dir(component);
+ let runtime_path = runtime_path.join("runtime");
+ let manifest = Arc::new(manifest);
+
+ fs::create_dir_all(&runtime_path).await
+ .map_err(|e| JavaRuntimeError::IO { what: "creating runtime directory", error: e })?;
+
+ debug!("Cleaning up JRE directory for {component}");
+ Self::clean_up_runtime(runtime_path.as_path(), manifest).await
+ .map_err(|e| JavaRuntimeError::IO { what: "cleaning up runtime directory", error: e })?;
+
+ debug!("Building directory structure for {component}");
+ self.ensure_jre_dirs(&runtime_path, manifest.as_ref()).await?;
+
+
+
+ todo!()
+ }
}
#[derive(Debug)]
diff --git a/src/launcher/jre/manifest.rs b/src/launcher/jre/manifest.rs
index ca21a2b..41780d0 100644
--- a/src/launcher/jre/manifest.rs
+++ b/src/launcher/jre/manifest.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use indexmap::IndexMap;
use serde::Deserialize;
use crate::version::DownloadInfo;
@@ -44,7 +45,21 @@ pub enum JavaRuntimeFile {
}
}
+impl JavaRuntimeFile {
+ pub fn is_file(&self) -> bool {
+ matches!(*self, JavaRuntimeFile::File { .. })
+ }
+
+ pub fn is_directory(&self) -> bool {
+ matches!(*self, JavaRuntimeFile::Directory)
+ }
+
+ pub fn is_link(&self) -> bool {
+ matches!(*self, JavaRuntimeFile::Link { .. })
+ }
+}
+
#[derive(Debug, Deserialize)]
pub struct JavaRuntimeManifest {
- pub files: HashMap<String, JavaRuntimeFile>
+ pub files: IndexMap<String, JavaRuntimeFile>
}