Various final backend fixes (#117)

* Various final backend fixes

* Add FS watching

* run lint

* Autodetect installed jars
This commit is contained in:
Geometrically
2023-05-16 15:30:04 -07:00
committed by GitHub
parent 5cb54b44be
commit 3fa0e99de2
26 changed files with 941 additions and 529 deletions

View File

@@ -1,14 +1,15 @@
use dunce::canonicalize;
use futures::prelude::*;
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::{collections::HashSet, path::Path};
use tempfile::NamedTempFile;
use tokio::task::JoinError;
use crate::State;
#[cfg(target_os = "windows")]
use winreg::{
enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY, KEY_WOW64_64KEY},
@@ -19,6 +20,7 @@ use winreg::{
pub struct JavaVersion {
pub path: String,
pub version: String,
pub architecture: String,
}
// Entrypoint function (Windows)
@@ -30,6 +32,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
// Add JRES directly on PATH
jre_paths.extend(get_all_jre_path().await?);
jre_paths.extend(get_all_autoinstalled_jre_path().await?);
// Hard paths for locations for commonly installed .exes
let java_paths = [r"C:/Program Files/Java", r"C:/Program Files (x86)/Java"];
@@ -110,6 +113,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
// Add JREs directly on PATH
jre_paths.extend(get_all_jre_path().await?);
jre_paths.extend(get_all_autoinstalled_jre_path().await?);
// Hard paths for locations for commonly installed .exes
let java_paths = [
@@ -128,6 +132,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
jre_paths.insert(entry);
}
}
// Get JRE versions from potential paths concurrently
let j = check_java_at_filepaths(jre_paths)
.await?
@@ -146,6 +151,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
// Add JREs directly on PATH
jre_paths.extend(get_all_jre_path().await?);
jre_paths.extend(get_all_autoinstalled_jre_path().await?);
// Hard paths for locations for commonly installed locations
let java_paths = [
@@ -177,6 +183,30 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
Ok(j)
}
// Gets all JREs from the PATH env variable
#[tracing::instrument]
async fn get_all_autoinstalled_jre_path() -> Result<HashSet<PathBuf>, JREError>
{
let state = State::get().await.map_err(|_| JREError::StateError)?;
let mut jre_paths = HashSet::new();
let base_path = state.directories.java_versions_dir();
if base_path.is_dir() {
for entry in std::fs::read_dir(base_path)? {
let entry = entry?;
let file_path = entry.path().join("bin");
let contents = std::fs::read_to_string(file_path)?;
let entry = entry.path().join(contents);
println!("{:?}", entry);
jre_paths.insert(entry);
}
}
Ok(jre_paths)
}
// Gets all JREs from the PATH env variable
#[tracing::instrument]
async fn get_all_jre_path() -> Result<HashSet<PathBuf>, JREError> {
@@ -231,26 +261,49 @@ pub async fn check_java_at_filepath(path: &Path) -> Option<JavaVersion> {
return None;
};
// Run 'java -version' using found java binary
let output = Command::new(&java).arg("-version").output().ok()?;
let stderr = String::from_utf8_lossy(&output.stderr);
let mut file = NamedTempFile::new().ok()?;
file.write_all(include_bytes!("../../library/JavaInfo.class"))
.ok()?;
// Match: version "1.8.0_361"
// Extracting version numbers
lazy_static! {
static ref JAVA_VERSION_CAPTURE: Regex =
Regex::new(r#"version "([\d\._]+)""#)
.expect("Error creating java version capture regex");
let original_path = file.path().to_path_buf();
let mut new_path = original_path.clone();
new_path.set_file_name("JavaInfo");
new_path.set_extension("class");
tokio::fs::rename(&original_path, &new_path).await.ok()?;
// Run java checker on java binary
let output = Command::new(&java)
.arg("-cp")
.arg(file.path().parent().unwrap())
.arg("JavaInfo")
.output()
.ok()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let mut java_version = None;
let mut java_arch = None;
for line in stdout.lines() {
let mut parts = line.split('=');
let key = parts.next().unwrap_or_default();
let value = parts.next().unwrap_or_default();
if key == "os.arch" {
java_arch = Some(value);
} else if key == "java.version" {
java_version = Some(value);
}
}
// Extract version info from it
if let Some(captures) = JAVA_VERSION_CAPTURE.captures(&stderr) {
if let Some(version) = captures.get(1) {
let Some(path) = java.to_str() else { return None };
let path = path.to_string();
if let Some(arch) = java_arch {
if let Some(version) = java_version {
let path = java.to_string_lossy().to_string();
return Some(JavaVersion {
path,
version: version.as_str().to_string(),
version: version.to_string(),
architecture: arch.to_string(),
});
}
}
@@ -311,6 +364,9 @@ pub enum JREError {
#[error("No stored tag for Minecraft Version {0}")]
NoMinecraftVersionFound(String),
#[error("Error getting launcher sttae")]
StateError,
}
#[cfg(test)]

View File

@@ -8,27 +8,27 @@ pub trait OsExt {
fn native() -> Self;
/// Gets the OS + Arch of the current system
fn native_arch() -> Self;
fn native_arch(java_arch: &str) -> Self;
}
impl OsExt for Os {
fn native_arch() -> Self {
fn native_arch(java_arch: &str) -> Self {
if std::env::consts::OS == "windows" {
if std::env::consts::ARCH == "aarch64" {
if java_arch == "aarch64" {
Os::WindowsArm64
} else {
Os::Windows
}
} else if std::env::consts::OS == "linux" {
if std::env::consts::ARCH == "aarch64" {
if java_arch == "aarch64" {
Os::LinuxArm64
} else if std::env::consts::ARCH == "arm" {
} else if java_arch == "arm" {
Os::LinuxArm32
} else {
Os::Linux
}
} else if std::env::consts::OS == "macos" {
if std::env::consts::ARCH == "aarch64" {
if java_arch == "aarch64" {
Os::OsxArm64
} else {
Os::Osx
@@ -39,30 +39,6 @@ impl OsExt for Os {
}
fn native() -> Self {
if std::env::consts::OS == "windows" {
if std::env::consts::ARCH == "aarch64" {
Os::WindowsArm64
} else {
Os::Windows
}
} else if std::env::consts::OS == "linux" {
if std::env::consts::ARCH == "aarch64" {
Os::LinuxArm64
} else if std::env::consts::ARCH == "arm" {
Os::LinuxArm32
} else {
Os::Linux
}
} else if std::env::consts::OS == "macos" {
if std::env::consts::ARCH == "aarch64" {
Os::OsxArm64
} else {
Os::Osx
}
} else {
Os::Unknown
};
match std::env::consts::OS {
"windows" => Self::Windows,
"macos" => Self::Osx,
@@ -80,7 +56,7 @@ pub const ARCH_WIDTH: &str = "64";
pub const ARCH_WIDTH: &str = "32";
// Platform rule handling
pub fn os_rule(rule: &OsRule) -> bool {
pub fn os_rule(rule: &OsRule, java_arch: &str) -> bool {
let mut rule_match = true;
if let Some(ref arch) = rule.arch {
@@ -88,7 +64,8 @@ pub fn os_rule(rule: &OsRule) -> bool {
}
if let Some(name) = &rule.name {
rule_match &= &Os::native() == name || &Os::native_arch() == name;
rule_match &=
&Os::native() == name || &Os::native_arch(java_arch) == name;
}
if let Some(version) = &rule.version {
@@ -101,8 +78,8 @@ pub fn os_rule(rule: &OsRule) -> bool {
rule_match
}
pub fn classpath_separator() -> &'static str {
match Os::native_arch() {
pub fn classpath_separator(java_arch: &str) -> &'static str {
match Os::native_arch(java_arch) {
Os::Osx
| Os::OsxArm64
| Os::Linux