mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
[rdct] launcher: anyhow for error handling
GitOrigin-RevId: b7e0fb01782f332ee7811c5cee1cfe62ffc85d9a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0b6c0bfb90
commit
838765c341
2
native/XPlatLauncher/.idea/XPlatLauncher.iml
generated
2
native/XPlatLauncher/.idea/XPlatLauncher.iml
generated
@@ -4,7 +4,9 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/utils/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/utils/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
||||
58
native/XPlatLauncher/Cargo.lock
generated
58
native/XPlatLauncher/Cargo.lock
generated
@@ -2,6 +2,15 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
@@ -31,6 +40,9 @@ name = "anyhow"
|
||||
version = "1.0.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
@@ -74,6 +86,21 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
@@ -997,6 +1024,12 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.14.4"
|
||||
@@ -1639,6 +1672,15 @@ dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.1"
|
||||
@@ -2121,6 +2163,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -2710,6 +2758,14 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
|
||||
|
||||
[[package]]
|
||||
name = "utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
@@ -2998,7 +3054,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simplelog",
|
||||
"thiserror",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -25,11 +25,12 @@ serde = { version="1.0.136", features = ["derive"] }
|
||||
serde_json = "1.0.79"
|
||||
is_executable = "1.0.1"
|
||||
simplelog = "0.12.0"
|
||||
thiserror = "1.0.30"
|
||||
jni = { version="0.19.0" }
|
||||
libloading = "0.7.3"
|
||||
jni-sys = "0.3.0"
|
||||
path-absolutize = "3.0.13"
|
||||
utils = { path = "utils" }
|
||||
anyhow = { version = "1.0.62", features = ["std", "backtrace"] }
|
||||
|
||||
[dev-dependencies]
|
||||
# external CLI tools, specified here so that they would be added to Cargo.lock organically
|
||||
@@ -41,4 +42,4 @@ fs_extra = "1.2.0"
|
||||
anyhow = "1.0.62"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.9.3"
|
||||
core-foundation = "0.9.3"
|
||||
|
||||
@@ -4,9 +4,9 @@ use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
use log::{debug, warn};
|
||||
use crate::{canonical_non_unc, err_from_string, LaunchConfiguration, LauncherError, ProductInfo};
|
||||
use crate::errors::Result;
|
||||
use crate::utils::{get_path_from_env_var, get_readable_file_from_env_var, is_readable, PathExt, read_file_to_end};
|
||||
use anyhow::{bail, Result};
|
||||
use utils::{canonical_non_unc, get_path_from_env_var, get_readable_file_from_env_var, is_readable, PathExt, read_file_to_end};
|
||||
use crate::{LaunchConfiguration, ProductInfo};
|
||||
|
||||
pub struct DefaultLaunchConfiguration {
|
||||
pub product_info: ProductInfo,
|
||||
@@ -64,15 +64,12 @@ impl LaunchConfiguration for DefaultLaunchConfiguration {
|
||||
let item_canonical_path = match canonical_non_unc(&item_path) {
|
||||
Ok(x) => { x }
|
||||
Err(e) => {
|
||||
match e {
|
||||
LauncherError::IoError(e) => {
|
||||
match e.is::<std::io::Error>() {
|
||||
true => {
|
||||
warn!("{item_path:?}: IoError {e:?} when trying to get canonical path");
|
||||
continue
|
||||
}
|
||||
e => {
|
||||
let message = format!("Failed to get canonical non-UNC path for {item_path:?} {e:?}");
|
||||
return err_from_string(message);
|
||||
}
|
||||
false => bail!("Failed to get canonical non-UNC path for {item_path:?} {e:?}"),
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -214,8 +211,7 @@ impl DefaultLaunchConfiguration {
|
||||
};
|
||||
|
||||
if !default_java_output.status.success() {
|
||||
let message = format!("'command -v java' didn't succeed, exit code: {exit_code}, stdout: {stdout}, stderr: {stderr}");
|
||||
return err_from_string(message)
|
||||
bail!("'command -v java' didn't succeed, exit code: {exit_code}, stdout: {stdout}, stderr: {stderr}");
|
||||
}
|
||||
|
||||
// TODO: check if it's executable? (will be a behaviour change)
|
||||
@@ -252,16 +248,16 @@ impl DefaultLaunchConfiguration {
|
||||
|
||||
let jbr_dir = self.ide_home.join("jbr");
|
||||
if !jbr_dir.is_dir() {
|
||||
return err_from_string(format!("{jbr_dir:?} is not a directory"))
|
||||
bail!("{jbr_dir:?} is not a directory");
|
||||
};
|
||||
|
||||
// TODO: non-mac
|
||||
let java_executable = get_bin_java_path(&jbr_dir);
|
||||
|
||||
match is_executable::is_executable(&java_executable) {
|
||||
true => { Ok(java_executable) }
|
||||
true => Ok(java_executable),
|
||||
// TODO: check if exists, separate method
|
||||
false => { err_from_string(format!("{java_executable:?} is not an executable")) }
|
||||
false => bail!("{java_executable:?} is not an executable")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +285,7 @@ impl DefaultLaunchConfiguration {
|
||||
|
||||
let metadata = jre_path_file.metadata()?;
|
||||
if metadata.len() == 0 {
|
||||
let message = format!("vmoptions file by path {jre_path_file:?} has zero length, will not try to resolve runtime from it");
|
||||
return err_from_string(message);
|
||||
bail!("vmoptions file by path {jre_path_file:?} has zero length, will not try to resolve runtime from it");
|
||||
}
|
||||
|
||||
let content = read_file_to_end(jre_path_file.as_path())?;
|
||||
@@ -303,8 +298,7 @@ impl DefaultLaunchConfiguration {
|
||||
match is_executable::is_executable(&java_executable) {
|
||||
true => { Ok(java_executable) }
|
||||
false => {
|
||||
let message = format!("{java_executable:?} specified in {jre_path_file:?} is not a valid executable");
|
||||
err_from_string(message)
|
||||
bail!("{java_executable:?} specified in {jre_path_file:?} is not a valid executable");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,22 +310,19 @@ impl DefaultLaunchConfiguration {
|
||||
let env_var_value = env::var(env_var_name)?;
|
||||
|
||||
if !env_var_value.is_empty() {
|
||||
let message = format!("Env var {env_var_value} is not set, skipping JDK detection from it");
|
||||
return err_from_string(message);
|
||||
bail!("Env var {env_var_value} is not set, skipping JDK detection from it");
|
||||
}
|
||||
|
||||
let product_jdk_dir = Path::new(env_var_value.as_str());
|
||||
let java_executable = product_jdk_dir.join("bin").join("java");
|
||||
|
||||
if !java_executable.exists() {
|
||||
let message = format!("Java executable from JDK {java_executable:?} does not exist");
|
||||
return err_from_string(message);
|
||||
bail!("Java executable from JDK {java_executable:?} does not exist");
|
||||
}
|
||||
|
||||
// TODO: write the same code ourselves instead of using is_executable crate?
|
||||
if !is_executable::is_executable(&java_executable) {
|
||||
let message = format!("{java_executable:?} is not an executable file");
|
||||
return err_from_string(message);
|
||||
bail!("{java_executable:?} is not an executable file");
|
||||
}
|
||||
|
||||
return Ok(java_executable);
|
||||
@@ -384,9 +375,7 @@ impl DefaultLaunchConfiguration {
|
||||
let user_vm_options_error = &errors[0];
|
||||
let vm_options_error = &errors[1];
|
||||
|
||||
let message = format!(
|
||||
"Failed to resolve any vmoptions files, user_vm_options: {user_vm_options_error:?}, vm_options: {vm_options_error:?}");
|
||||
return err_from_string(message);
|
||||
bail!("Failed to resolve any vmoptions files, user_vm_options: {user_vm_options_error:?}, vm_options: {vm_options_error:?}");
|
||||
}
|
||||
|
||||
return Ok([vm_options, user_vm_options].concat());
|
||||
@@ -397,14 +386,11 @@ impl DefaultLaunchConfiguration {
|
||||
// TODO: there is a relative path in product-info json (launch), maybe use that?
|
||||
let vm_options_file_name = vm_options_base_file_name +
|
||||
match env::consts::OS {
|
||||
"linux" => { "64.vmoptions" }
|
||||
"macos" => { ".vmoptions" }
|
||||
"linux" => "64.vmoptions",
|
||||
"macos" => ".vmoptions",
|
||||
//TODO: check if that's actual for Windows
|
||||
"windows" => { "64.exe.vmoptions" }
|
||||
unsupported_os => {
|
||||
let message = format!("Unsupported OS: {unsupported_os}");
|
||||
return err_from_string(message);
|
||||
}
|
||||
"windows" => "64.exe.vmoptions",
|
||||
unsupported_os => bail!("Unsupported OS: {unsupported_os}"),
|
||||
};
|
||||
|
||||
Ok(vm_options_file_name)
|
||||
@@ -466,14 +452,11 @@ impl DefaultLaunchConfiguration {
|
||||
}
|
||||
|
||||
let os_specific_dir = match env::consts::OS {
|
||||
"linux" => { "linux" }
|
||||
"macos" => { "mac" }
|
||||
"linux" => "linux",
|
||||
"macos" => "mac",
|
||||
//TODO: check if that's actual for Windows
|
||||
"windows" => { "windows" }
|
||||
unsupported_os => {
|
||||
let message = format!("Unsupported OS: {unsupported_os}");
|
||||
return err_from_string(message);
|
||||
}
|
||||
"windows" => "windows",
|
||||
unsupported_os => bail!("Unsupported OS: {unsupported_os}"),
|
||||
};
|
||||
|
||||
let os_specific_vm_options = self.ide_bin.join(os_specific_dir).join(vm_options_file_name);
|
||||
@@ -535,14 +518,11 @@ fn get_lib_path(ide_home: &Path) -> PathBuf {
|
||||
|
||||
fn get_product_info_home(ide_home: &Path) -> Result<PathBuf> {
|
||||
let parent = match env::consts::OS {
|
||||
"linux" => { ide_home.to_path_buf() }
|
||||
"macos" => { ide_home.join("Resources") }
|
||||
"linux" => ide_home.to_path_buf(),
|
||||
"macos" => ide_home.join("Resources"),
|
||||
//TODO: check if that's actual for Windows
|
||||
"windows" => { ide_home.to_path_buf() }
|
||||
unsupported_os => {
|
||||
let message = format!("Unsupported OS: {unsupported_os}");
|
||||
return err_from_string(message);
|
||||
}
|
||||
"windows" => ide_home.to_path_buf(),
|
||||
unsupported_os => bail!("Unsupported OS: {unsupported_os}"),
|
||||
};
|
||||
|
||||
Ok(parent)
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
use std::ffi::NulError;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use log::error;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, LauncherError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum LauncherError {
|
||||
#[error("Error {0}")]
|
||||
HumanReadableError(#[from] HumanReadableError),
|
||||
#[error("I/O error {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("Var error {0}")]
|
||||
VarError(#[from] std::env::VarError),
|
||||
#[error("JSON error {0}")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
#[error("Libloading error {0}")]
|
||||
LibloadingError(#[from] libloading::Error),
|
||||
#[error("JNI error {0}")]
|
||||
JniError(#[from] JniError),
|
||||
#[error("Nul error {0}")]
|
||||
NulError(#[from] NulError),
|
||||
#[error("jni-rs error {0}")]
|
||||
JniRsError(#[from] jni::errors::Error),
|
||||
#[error("SetLoggerError error {0}")]
|
||||
LogSetLoggerError(#[from] log::SetLoggerError),
|
||||
|
||||
}
|
||||
|
||||
pub fn err_from_string<T,S: AsRef<str>>(message: S) -> Result<T> {
|
||||
let error = HumanReadableError { message: message.as_ref().to_string() };
|
||||
return Err(LauncherError::HumanReadableError(error));
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub struct HumanReadableError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub struct JniError {
|
||||
pub message: String
|
||||
}
|
||||
|
||||
impl JniError {
|
||||
fn err_from_string(message: &str) -> Result<()> {
|
||||
let error = JniError { message: message.to_string() };
|
||||
return Err(LauncherError::JniError(error));
|
||||
}
|
||||
|
||||
pub fn check_result(error_code: jni_sys::jint) -> Result<()> {
|
||||
match error_code {
|
||||
jni_sys::JNI_OK => Ok(()),
|
||||
jni_sys::JNI_ERR => JniError::err_from_string("JNI_ERR: unknown error"),
|
||||
jni_sys::JNI_EDETACHED => JniError::err_from_string("JNI_EDETACHED: thread is not attached to JVM"),
|
||||
jni_sys::JNI_EVERSION => JniError::err_from_string("JNI_EVERSION: wrong JNI version"),
|
||||
jni_sys::JNI_ENOMEM => JniError::err_from_string("JNI_ENOMEM: no enought memory"),
|
||||
jni_sys::JNI_EEXIST => JniError::err_from_string("JNI_EEXIST: JVM already exists"),
|
||||
jni_sys::JNI_EINVAL => JniError::err_from_string("JNI_EINVAL? invalid arguments"),
|
||||
i => JniError::err_from_string(format!("Other: {i}").as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for JniError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for HumanReadableError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@ use std::path::{Path, PathBuf};
|
||||
use jni::errors::Error;
|
||||
use jni::objects::{JObject, JValue};
|
||||
use log::{debug, error, info};
|
||||
use crate::{err_from_string, errors};
|
||||
use crate::errors::{LauncherError, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
#[cfg(target_os = "linux")] use {
|
||||
std::thread::sleep,
|
||||
@@ -111,7 +110,16 @@ unsafe fn prepare_jni_env(
|
||||
};
|
||||
debug!("Create VM result={create_jvm_result}");
|
||||
|
||||
errors::JniError::check_result(create_jvm_result)?;
|
||||
match create_jvm_result {
|
||||
jni_sys::JNI_OK => { }
|
||||
jni_sys::JNI_ERR => bail!("JNI_ERR: unknown error"),
|
||||
jni_sys::JNI_EDETACHED => bail!("JNI_EDETACHED: thread is not attached to JVM"),
|
||||
jni_sys::JNI_EVERSION => bail!("JNI_EVERSION: wrong JNI version"),
|
||||
jni_sys::JNI_ENOMEM => bail!("JNI_ENOMEM: no enought memory"),
|
||||
jni_sys::JNI_EEXIST => bail!("JNI_EEXIST: JVM already exists"),
|
||||
jni_sys::JNI_EINVAL => bail!("JNI_EINVAL? invalid arguments"),
|
||||
i => bail!("Other: {i}"),
|
||||
}
|
||||
|
||||
let jni_env = unsafe {
|
||||
jni::JNIEnv::from_raw(jni_env)?
|
||||
@@ -139,13 +147,13 @@ pub fn call_intellij_main(jni_env: jni::JNIEnv<'_>, args: Vec<String>) -> Result
|
||||
match jni_env.call_static_method("com/intellij/idea/Main", "main", "([Ljava/lang/String;)V", &method_call_args) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return match e {
|
||||
match e {
|
||||
Error::JavaException => {
|
||||
jni_env.exception_describe()?;
|
||||
Err(LauncherError::JniRsError(e))
|
||||
Err(e)
|
||||
}
|
||||
_ => Err(LauncherError::JniRsError(e))
|
||||
}
|
||||
_ => Err(e)
|
||||
}?;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,10 +187,7 @@ unsafe fn load_libjvm(libjvm_path: PathBuf) -> Result<libloading::Library> {
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
unsafe fn load_libjvm(libjvm_path: PathBuf) -> Result<libloading::Library> {
|
||||
match unsafe { libloading::Library::new(libjvm_path.as_os_str()) } {
|
||||
Ok(l) => { Ok(l)}
|
||||
Err(e) => { Err(LauncherError::LibloadingError(e))}
|
||||
}
|
||||
unsafe { libloading::Library::new(libjvm_path.as_os_str()) }.context("Failed to load libjvm")
|
||||
}
|
||||
|
||||
fn get_jvm_init_args(vm_options: Vec<String>) -> Result<jni_sys::JavaVMInitArgs> {
|
||||
@@ -209,8 +214,7 @@ fn get_libjvm(java_home: &Path) -> Result<PathBuf> {
|
||||
|
||||
let libjvm = get_libjvm_path(java_home);
|
||||
if !libjvm.exists() {
|
||||
let message = format!("libvjm not found at path {libjvm:?}");
|
||||
return err_from_string(message);
|
||||
bail!("libvjm not found at path {libjvm:?}");
|
||||
}
|
||||
debug!("Found libjvm at {libjvm:?}");
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ unused_results,
|
||||
variant_size_differences
|
||||
)]
|
||||
|
||||
mod errors;
|
||||
mod java;
|
||||
mod utils;
|
||||
mod remote_dev;
|
||||
mod default;
|
||||
|
||||
@@ -44,9 +42,8 @@ use log::{debug, error, LevelFilter};
|
||||
use native_dialog::{MessageDialog, MessageType};
|
||||
use simplelog::{ColorChoice, CombinedLogger, Config, TerminalMode, TermLogger, WriteLogger};
|
||||
use crate::default::DefaultLaunchConfiguration;
|
||||
use crate::errors::{err_from_string, LauncherError, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use crate::remote_dev::RemoteDevLaunchConfiguration;
|
||||
use crate::utils::canonical_non_unc;
|
||||
|
||||
pub fn main_lib() {
|
||||
let main_result = main_impl();
|
||||
@@ -125,10 +122,7 @@ impl ProductInfo {
|
||||
self.launch.iter().find(|&l| l.os.to_lowercase() == current_os);
|
||||
|
||||
match os_specific_launch_field {
|
||||
None => {
|
||||
let message = format!("Could not find current os {current_os} launch element in product-info.json 'launch' field");
|
||||
err_from_string(message)
|
||||
}
|
||||
None => bail!("Could not find current os {current_os} launch element in product-info.json 'launch' field"),
|
||||
Some(x) => Ok(x),
|
||||
}
|
||||
}
|
||||
@@ -181,22 +175,12 @@ fn unwrap_with_human_readable_error<S>(result: Result<S>) -> S {
|
||||
match result {
|
||||
Ok(x) => { x }
|
||||
Err(e) => {
|
||||
let message =
|
||||
match e {
|
||||
LauncherError::HumanReadableError(e) => {
|
||||
e.message
|
||||
}
|
||||
_ => {
|
||||
format!("{e:?}")
|
||||
}
|
||||
};
|
||||
|
||||
eprintln!("{}", message);
|
||||
error!("{}", message);
|
||||
eprintln!("{e:?}");
|
||||
error!("{e:?}");
|
||||
|
||||
match env::var(DO_NOT_SHOW_ERROR_UI_ENV_VAR) {
|
||||
Ok(_) => { }
|
||||
Err(_) => { show_fail_to_start_message("Failed to start", format!("{message:?}").as_str()) }
|
||||
Err(_) => { show_fail_to_start_message("Failed to start", format!("{e:?}").as_str()) }
|
||||
}
|
||||
|
||||
std::process::exit(1);
|
||||
|
||||
@@ -5,10 +5,10 @@ use std::io::{BufWriter, Write};
|
||||
use std::path::PathBuf;
|
||||
use log::{debug, info};
|
||||
use path_absolutize::Absolutize;
|
||||
use crate::errors::Result;
|
||||
use crate::{DefaultLaunchConfiguration, err_from_string, LaunchConfiguration};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use crate::default::get_config_home;
|
||||
use crate::utils::{get_path_from_env_var, PathExt, read_file_to_end};
|
||||
use utils::{get_path_from_env_var, PathExt, read_file_to_end};
|
||||
use crate::{DefaultLaunchConfiguration, LaunchConfiguration};
|
||||
|
||||
pub struct RemoteDevLaunchConfiguration {
|
||||
default: DefaultLaunchConfiguration,
|
||||
@@ -117,7 +117,7 @@ impl DefaultLaunchConfiguration {
|
||||
impl RemoteDevLaunchConfiguration {
|
||||
pub fn parse_remote_dev_args(args: &[String]) -> Result<RemoteDevArgs> {
|
||||
if args.is_empty() {
|
||||
return err_from_string("Starter command is not specified")
|
||||
bail!("Starter command is not specified")
|
||||
}
|
||||
|
||||
let remote_dev_starter_command = args[0].as_str();
|
||||
@@ -130,13 +130,13 @@ impl RemoteDevLaunchConfiguration {
|
||||
"status" => { "cwmHostStatus" }
|
||||
x => {
|
||||
print_help();
|
||||
return err_from_string(format!("Unknown command: {x}"))
|
||||
bail!("Unknown command: {x}")
|
||||
}
|
||||
};
|
||||
|
||||
if args.len() < 1 {
|
||||
print_help();
|
||||
return err_from_string("Project path is not specified");
|
||||
bail!("Project path is not specified");
|
||||
}
|
||||
|
||||
let project_path_string = args[1].as_str();
|
||||
@@ -156,7 +156,7 @@ impl RemoteDevLaunchConfiguration {
|
||||
let project_path = PathBuf::from(project_path_string);
|
||||
if !project_path.exists() {
|
||||
print_help();
|
||||
return err_from_string(format!("Project path does not exist: {project_path_string}"));
|
||||
bail!("Project path does not exist: {project_path_string}");
|
||||
}
|
||||
|
||||
// if [ -d "$PROJECT_PATH" ]; then
|
||||
@@ -196,13 +196,9 @@ impl RemoteDevLaunchConfiguration {
|
||||
}
|
||||
|
||||
pub fn new(project_path: PathBuf, default: DefaultLaunchConfiguration) -> Result<Self> {
|
||||
let per_project_config_dir_name = match project_path.file_name() {
|
||||
None => {
|
||||
let message = format!("Failed to get project dir name, project path: {project_path:?}");
|
||||
err_from_string(message)
|
||||
}
|
||||
Some(x) => Ok(x)
|
||||
}?.to_string_lossy();
|
||||
let per_project_config_dir_name = project_path.file_name()
|
||||
.context("Failed to get project dir name, project path: {project_path:?}")
|
||||
?.to_string_lossy();
|
||||
|
||||
let config_dir = default.prepare_host_config_dir(&per_project_config_dir_name)?;
|
||||
let system_dir = default.prepare_system_config_dir(&per_project_config_dir_name)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{env, fs, io, thread, time};
|
||||
use std::collections::HashMap;
|
||||
@@ -10,6 +10,7 @@ use std::process::{Command, ExitStatus, Output};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Once;
|
||||
use std::time::SystemTime;
|
||||
use utils::get_path_from_env_var;
|
||||
|
||||
static INIT: Once = Once::new();
|
||||
static mut SHARED: Option<TestEnvironmentShared> = None;
|
||||
@@ -196,12 +197,10 @@ pub fn layout_launcher(
|
||||
// ├── jbr/
|
||||
// └── product-info.json
|
||||
|
||||
|
||||
let launcher = project_root
|
||||
.join("target")
|
||||
.join("debug")
|
||||
.join("xplat-launcher");
|
||||
assert!(launcher.exists());
|
||||
let launcher = &get_testing_binary_root(project_root).join("xplat-launcher");
|
||||
if !launcher.exists() {
|
||||
bail!("Didn't find source launcher to layout, expected path: {launcher:?}");
|
||||
}
|
||||
|
||||
layout_launcher_impl(
|
||||
target_dir,
|
||||
@@ -243,11 +242,10 @@ pub fn layout_launcher(
|
||||
// │ └── app.jar
|
||||
// └── jbr/
|
||||
|
||||
let launcher = project_root
|
||||
.join("target")
|
||||
.join("debug")
|
||||
.join("xplat-launcher");
|
||||
assert!(launcher.exists());
|
||||
let launcher = get_testing_binary_root(project_root).join("xplat-launcher");
|
||||
if !launcher.exists() {
|
||||
bail!("Didn't find source launcher to layout, expected path: {launcher:?}");
|
||||
}
|
||||
|
||||
layout_launcher_impl(
|
||||
target_dir,
|
||||
@@ -292,11 +290,10 @@ pub fn layout_launcher(
|
||||
// ├── jbr/
|
||||
// └── product-info.json
|
||||
|
||||
let launcher = project_root
|
||||
.join("target")
|
||||
.join("debug")
|
||||
.join("xplat-launcher.exe");
|
||||
assert!(launcher.exists());
|
||||
let launcher = get_testing_binary_root(project_root).join("xplat-launcher.exe");
|
||||
if !launcher.exists() {
|
||||
bail!("Didn't find source launcher to layout, expected path: {launcher:?}");
|
||||
}
|
||||
|
||||
layout_launcher_impl(
|
||||
target_dir,
|
||||
@@ -318,6 +315,22 @@ pub fn layout_launcher(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_testing_binary_root(project_root: &Path) -> PathBuf {
|
||||
match get_path_from_env_var("XPLAT_LAUNCHER_TESTS_TARGET_BINARY_ROOT") {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
let target = match cfg!(debug_assertions) {
|
||||
true => { "debug".to_string() }
|
||||
false => { "release".to_string() }
|
||||
};
|
||||
|
||||
project_root
|
||||
.join("target")
|
||||
.join(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_launcher_impl(
|
||||
target_dir: &Path,
|
||||
create_dirs: Vec<&str>,
|
||||
|
||||
1
native/XPlatLauncher/utils/.gitignore
vendored
Normal file
1
native/XPlatLauncher/utils/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Cargo.lock
|
||||
10
native/XPlatLauncher/utils/Cargo.toml
Normal file
10
native/XPlatLauncher/utils/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "utils"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.62", features = ["std", "backtrace"] }
|
||||
log = "0.4.14"
|
||||
@@ -1,81 +1,76 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
use std::{env, fs};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use log::debug;
|
||||
use crate::err_from_string;
|
||||
use crate::errors::Result;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn canonical_non_unc(path: &Path) -> Result<String> {
|
||||
let canonical = path.canonicalize()?;
|
||||
let os_str = canonical.as_os_str().to_string_lossy().to_string();
|
||||
let stripped_unc = os_str.strip_prefix("\\\\?\\").unwrap().to_string();
|
||||
Ok(stripped_unc)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
pub fn canonical_non_unc(path: &Path) -> Result<String> {
|
||||
let canonical = path.canonicalize()?;
|
||||
let os_str = canonical.as_os_str().to_string_lossy().to_string();
|
||||
Ok(os_str)
|
||||
}
|
||||
|
||||
pub fn get_readable_file_from_env_var<S:AsRef<OsStr>>(env_var_name: S) -> Result<PathBuf> {
|
||||
let file = get_path_from_env_var(env_var_name)?;
|
||||
let _path_buf = is_readable(&file)?;
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
pub fn get_path_from_env_var<S:AsRef<OsStr>>(env_var_name: S) -> Result<PathBuf> {
|
||||
let env_var_value = env::var(env_var_name)?;
|
||||
|
||||
if env_var_value.is_empty() {
|
||||
let message = format!("Env var {env_var_value} is not set, skipping resolving path from it");
|
||||
return err_from_string(message);
|
||||
}
|
||||
|
||||
let path = PathBuf::from(env_var_value.as_str());
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn is_readable<P: AsRef<Path>>(file: P) -> Result<PathBuf> {
|
||||
// TODO: seems like the best possible x-plat way to verify whether the file is readable
|
||||
// note: file is closed when we exit the scope
|
||||
{
|
||||
let _file = fs::OpenOptions::new().read(true).open(&file)?;
|
||||
}
|
||||
|
||||
Ok(file.as_ref().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn read_file_to_end(path: &Path) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let mut content = String::from("");
|
||||
let bytes_read = reader.read_to_string(&mut content)?;
|
||||
|
||||
debug!("Read {bytes_read} bytes from {path:?}");
|
||||
debug!("Contents of {path:?}: {content}");
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub trait PathExt {
|
||||
fn parent_or_err(&self) -> Result<PathBuf>;
|
||||
}
|
||||
|
||||
impl PathExt for Path {
|
||||
fn parent_or_err(&self) -> Result<PathBuf> {
|
||||
match self.parent() {
|
||||
None => {
|
||||
let message = format!("No parent dir for '{self:?}'");
|
||||
err_from_string(message)
|
||||
}
|
||||
Some(s) => { Ok(s.to_path_buf()) }
|
||||
}
|
||||
}
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
use std::{env, fs};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use anyhow::{bail, Result};
|
||||
use log::debug;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn canonical_non_unc(path: &Path) -> Result<String> {
|
||||
let canonical = path.canonicalize()?;
|
||||
let os_str = canonical.as_os_str().to_string_lossy().to_string();
|
||||
let stripped_unc = os_str.strip_prefix("\\\\?\\").unwrap().to_string();
|
||||
Ok(stripped_unc)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||
pub fn canonical_non_unc(path: &Path) -> Result<String> {
|
||||
let canonical = path.canonicalize()?;
|
||||
let os_str = canonical.as_os_str().to_string_lossy().to_string();
|
||||
Ok(os_str)
|
||||
}
|
||||
|
||||
pub fn get_readable_file_from_env_var<S:AsRef<OsStr>>(env_var_name: S) -> Result<PathBuf> {
|
||||
let file = get_path_from_env_var(env_var_name)?;
|
||||
let _path_buf = is_readable(&file)?;
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
pub fn get_path_from_env_var<S:AsRef<OsStr>>(env_var_name: S) -> Result<PathBuf> {
|
||||
let env_var_value = env::var(env_var_name)?;
|
||||
|
||||
if env_var_value.is_empty() {
|
||||
bail!("Env var {env_var_value} is not set, skipping resolving path from it")
|
||||
}
|
||||
|
||||
let path = PathBuf::from(env_var_value.as_str());
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn is_readable<P: AsRef<Path>>(file: P) -> Result<PathBuf> {
|
||||
// TODO: seems like the best possible x-plat way to verify whether the file is readable
|
||||
// note: file is closed when we exit the scope
|
||||
{
|
||||
let _file = fs::OpenOptions::new().read(true).open(&file)?;
|
||||
}
|
||||
|
||||
Ok(file.as_ref().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn read_file_to_end(path: &Path) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let mut content = String::from("");
|
||||
let bytes_read = reader.read_to_string(&mut content)?;
|
||||
|
||||
debug!("Read {bytes_read} bytes from {path:?}");
|
||||
debug!("Contents of {path:?}: {content}");
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub trait PathExt {
|
||||
fn parent_or_err(&self) -> Result<PathBuf>;
|
||||
}
|
||||
|
||||
impl PathExt for Path {
|
||||
fn parent_or_err(&self) -> Result<PathBuf> {
|
||||
match self.parent() {
|
||||
None => bail!("No parent dir for '{self:?}'"),
|
||||
Some(s) => Ok(s.to_path_buf()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user