summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-22 15:31:52 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-22 15:31:52 -0600
commit08dba4588e93ce338cf01d740bf0923a4f46ade8 (patch)
treef8888fe3eed524330e247669a516b0b206f375ec
parentwip: jre download stuff (diff)
more jre download stuff
-rw-r--r--Cargo.lock6
-rw-r--r--Cargo.toml1
-rw-r--r--src/launcher/jre.rs109
-rw-r--r--src/launcher/jre/manifest.rs17
-rw-r--r--src/util.rs6
5 files changed, 134 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d31e1be..0600dab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2040,12 +2040,13 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.7.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
+ "serde",
]
[[package]]
@@ -2478,6 +2479,7 @@ dependencies = [
"chrono",
"const_format",
"futures",
+ "indexmap",
"lazy_static",
"log",
"regex",
diff --git a/Cargo.toml b/Cargo.toml
index b5586ae..f3786a3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ cfg-if = "1.0.0"
chrono = { version = "0.4.39", default-features = false, features = ["std", "alloc", "clock", "now", "serde"] }
const_format = "0.2.34"
futures = "0.3.31"
+indexmap = { version = "2.7.1", features = ["serde"] }
lazy_static = "1.5.0"
log = "0.4.22"
regex = "1.11.1"
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>
}
diff --git a/src/util.rs b/src/util.rs
index b7b7c6d..8ad3632 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -68,7 +68,7 @@ pub async fn verify_file(path: impl AsRef<Path>, expect_size: Option<usize>, exp
let path = path.as_ref();
if expect_size.is_none() && expect_sha1.is_none() {
- return match path.metadata() {
+ return match fs::metadata(path).await {
Ok(_) => {
debug!("No size or sha1 for {}, have to assume it's good.", path.display());
Ok(())
@@ -257,6 +257,9 @@ pub fn strip_verbatim(path: &Path) -> &Path {
return path;
};
+ use std::path::Prefix;
+ use std::ffi::OsStr;
+
match p.kind() {
Prefix::VerbatimDisk(_) =>
Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(&path.as_os_str().as_encoded_bytes()[4..]) }),
@@ -283,6 +286,7 @@ impl AsJavaPath for Path {
mod tests {
#[allow(unused_imports)]
use super::*;
+ use std::path::Prefix;
#[test]
#[cfg(windows)]