Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 87 additions & 21 deletions src/bin/julialauncher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ use windows::Win32::System::{
Threading::GetCurrentProcess,
};

/// Check if this binary is being run as 'julia' (the launcher) rather than 'juliaup'
fn is_julia_launcher() -> bool {
std::env::current_exe()
.ok()
.and_then(|path| {
path.file_stem()
.and_then(|stem| stem.to_str())
.map(|name| name == "julia" || name == "julialauncher")
})
.unwrap_or(false)
}

#[derive(thiserror::Error, Debug)]
#[error("{msg}")]
pub struct UserError {
Expand All @@ -49,10 +61,27 @@ fn do_initial_setup(juliaupconfig_path: &Path) -> Result<()> {
if !juliaupconfig_path.exists() {
let juliaup_path = get_juliaup_path().with_context(|| "Failed to obtain juliaup path.")?;

std::process::Command::new(juliaup_path)
// Try to run initial setup, but don't fail Julia startup if it fails
// This ensures Julia can still run even without network connectivity
match std::process::Command::new(juliaup_path)
.arg("46029ef5-0b73-4a71-bff3-d0d05de42aac") // This is our internal command to do the initial setup
.status()
.with_context(|| "Failed to start juliaup for the initial setup.")?;
{
Ok(status) => {
if !status.success() {
// Don't show warnings when running as Julia launcher to avoid confusion
if !is_julia_launcher() {
eprintln!(
"Warning: Initial setup failed, but Julia will still attempt to run."
);
}
}
}
Err(_) => {
// Silently ignore initial setup failures to avoid confusing Julia users
// The initial setup will be retried on next run
}
}
}
Ok(())
}
Expand Down Expand Up @@ -337,20 +366,46 @@ fn run_app() -> Result<i32> {
}
}

let (julia_channel_to_use, juliaup_channel_source) =
if let Some(channel) = channel_from_cmd_line {
(channel, JuliaupChannelSource::CmdLine)
} else if let Ok(channel) = std::env::var("JULIAUP_CHANNEL") {
(channel, JuliaupChannelSource::EnvVar)
} else if let Ok(Some(channel)) = get_override_channel(&config_file) {
(channel, JuliaupChannelSource::Override)
} else if let Some(channel) = config_file.data.default.clone() {
(channel, JuliaupChannelSource::Default)
let (julia_channel_to_use, juliaup_channel_source) = if let Some(channel) =
channel_from_cmd_line
{
(channel, JuliaupChannelSource::CmdLine)
} else if let Ok(channel) = std::env::var("JULIAUP_CHANNEL") {
(channel, JuliaupChannelSource::EnvVar)
} else if let Ok(Some(channel)) = get_override_channel(&config_file) {
(channel, JuliaupChannelSource::Override)
} else if let Some(channel) = config_file.data.default.clone() {
(channel, JuliaupChannelSource::Default)
} else {
// Check if we have any installed channels at all
if config_file.data.installed_channels.is_empty() {
return Err(UserError {
msg: format!(
"No Julia versions are installed. This can happen if Julia installation failed due to network issues.\n\
\n\
To fix this, please run:\n\
\n\
juliaup add release\n\
\n\
when you have network connectivity to install the latest stable Julia version."
)
}.into());
} else {
return Err(anyhow!(
"The Julia launcher failed to figure out which juliaup channel to use."
));
};
return Err(UserError {
msg: format!(
"No default Julia version is set. You have the following versions installed: {}\n\
\n\
To set a default version, please run:\n\
\n\
juliaup default CHANNEL\n\
\n\
where CHANNEL is one of: {}",
config_file.data.installed_channels.keys().map(|s| s.as_str()).collect::<Vec<&str>>().join(", "),
config_file.data.installed_channels.keys().map(|s| s.as_str()).collect::<Vec<&str>>().join(", ")
)
}.into());
}
};

let (julia_path, julia_args) = get_julia_path_from_channel(
&versiondb_data,
Expand Down Expand Up @@ -431,10 +486,11 @@ fn run_app() -> Result<i32> {
ctrlc::set_handler(|| ())
.with_context(|| "Failed to set the Ctrl-C handler.")?;

run_versiondb_update(&config_file)
.with_context(|| "Failed to run version db update")?;
// Silently handle version db update failures to avoid confusing Julia users
let _ = run_versiondb_update(&config_file);

run_selfupdate(&config_file).with_context(|| "Failed to run selfupdate.")?;
// Silently handle selfupdate failures to avoid confusing Julia users
let _ = run_selfupdate(&config_file);
}
Err(_) => panic!("Could not double-fork"),
}
Expand Down Expand Up @@ -495,9 +551,11 @@ fn run_app() -> Result<i32> {
)
};

run_versiondb_update(&config_file).with_context(|| "Failed to run version db update")?;
// Silently handle version db update failures to avoid confusing Julia users
let _ = run_versiondb_update(&config_file);

run_selfupdate(&config_file).with_context(|| "Failed to run selfupdate.")?;
// Silently handle selfupdate failures to avoid confusing Julia users
let _ = run_selfupdate(&config_file);

let status = child_process
.wait()
Expand Down Expand Up @@ -537,7 +595,15 @@ fn main() -> Result<std::process::ExitCode> {

return Ok(std::process::ExitCode::FAILURE);
} else {
return Err(client_status.unwrap_err());
// If we're running as the Julia launcher, don't fail on juliaup errors
// This ensures 'julia' command never fails due to juliaup issues
if is_julia_launcher() {
eprintln!("Julia startup encountered an issue: {}", err);
eprintln!("Julia installation may be incomplete. Please run 'juliaup add release' to fix this.");
return Ok(std::process::ExitCode::FAILURE);
} else {
return Err(client_status.unwrap_err());
}
}
}
}
Expand Down
30 changes: 26 additions & 4 deletions src/command_initial_setup_from_launcher.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
use crate::{command_add::run_command_add, global_paths::GlobalPaths};
use crate::{
command_add::run_command_add,
config_file::{load_mut_config_db, save_config_db},
global_paths::GlobalPaths,
};
use anyhow::{Context, Result};

pub fn run_command_initial_setup_from_launcher(paths: &GlobalPaths) -> Result<()> {
run_command_add("release", paths)
.with_context(|| "Failed to run `run_command_add` from the `run_command_initial_setup_from_launcher` command.")?;
// Try to add the release channel normally
match run_command_add("release", paths) {
Ok(()) => {
// Success - everything is set up properly
Ok(())
}
Err(_) => {
// Silently create a minimal config file so we don't keep trying to do initial setup
// This ensures Julia can start even if the initial installation fails
let mut config_file = load_mut_config_db(paths)
.with_context(|| "Failed to create minimal configuration file.")?;

Ok(())
// Just save the config file - this creates the basic structure
save_config_db(&mut config_file)
.with_context(|| "Failed to save minimal configuration file.")?;

// Note: We don't print warnings here as this is called from the Julia launcher
// and users expect Julia to "just work" without juliaup messages

Ok(())
}
}
}
2 changes: 1 addition & 1 deletion src/command_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use cli_table::{
format::{Border, HorizontalLine, Separator},
print_stdout, ColorChoice, Table, WithTitle,
};
use numeric_sort::cmp;
use itertools::Itertools;
use numeric_sort::cmp;

#[derive(Table)]
struct ChannelRow {
Expand Down
2 changes: 1 addition & 1 deletion src/command_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use cli_table::{
format::{Border, Justify},
print_stdout, Table, WithTitle,
};
use numeric_sort::cmp;
use itertools::Itertools;
use numeric_sort::cmp;

#[derive(Table)]
struct ChannelRow {
Expand Down
4 changes: 2 additions & 2 deletions src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1649,7 +1649,7 @@ fn download_direct_download_etags(
let mut requests = Vec::new();

for (channel_name, installed_channel) in &config_data.installed_channels {
if let Some(chan) = channel{
if let Some(chan) = channel {
// TODO: convert to an if-let chain once stabilized https://github.com/rust-lang/rust/pull/132833
if chan != channel_name {
continue;
Expand Down Expand Up @@ -1720,7 +1720,7 @@ fn download_direct_download_etags(
let mut requests = Vec::new();

for (channel_name, installed_channel) in &config_data.installed_channels {
if let Some(chan) = channel{
if let Some(chan) = channel {
// TODO: convert to an if-let chain once stabilized https://github.com/rust-lang/rust/pull/132833
if chan != channel_name {
continue;
Expand Down
Loading
Loading