From 96651dbf60a4e4639ac087e3ea624986281875aa Mon Sep 17 00:00:00 2001 From: David Anthoff Date: Tue, 29 Oct 2024 16:30:32 -0700 Subject: [PATCH 1/2] Reapply "Launch the manifest-specified Julia version v2" This reverts commit 64579cc41f2fd2ef1b08c98d08851ae64f5f3491. --- Cargo.lock | 11 + Cargo.toml | 1 + src/bin/julialauncher.rs | 381 ++++++++++++++----- src/bin/juliaup.rs | 4 + src/cli.rs | 6 + src/command_config_featuremanifestsupport.rs | 50 +++ src/config_file.rs | 9 + src/lib.rs | 1 + tests/channel_selection.rs | 201 ++++++++++ 9 files changed, 564 insertions(+), 100 deletions(-) create mode 100644 src/command_config_featuremanifestsupport.rs diff --git a/Cargo.lock b/Cargo.lock index e7297bde..a37f9e18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1031,6 +1031,7 @@ dependencies = [ "tar", "tempfile", "thiserror", + "toml 0.8.19", "url", "windows", "winres", @@ -1974,6 +1975,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", + "winnow", ] [[package]] @@ -2446,6 +2448,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "winres" version = "0.1.12" diff --git a/Cargo.toml b/Cargo.toml index 65c0a9a5..e72f5373 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ is-terminal = "0.4" path-absolutize = "3.1.0" human-sort = "0.2.2" regex = "1.10" +toml = "0.8.19" [target.'cfg(windows)'.dependencies] windows = { version = "0.58.0", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_Security", "Win32_System_JobObjects", "Win32_System_Console", "Win32_System_Threading", "Services_Store", "Foundation", "Foundation_Collections", "Web_Http", "Web_Http_Headers", "Storage_Streams", "Management_Deployment"] } diff --git a/src/bin/julialauncher.rs b/src/bin/julialauncher.rs index 1c40c0f0..4a41767d 100644 --- a/src/bin/julialauncher.rs +++ b/src/bin/julialauncher.rs @@ -13,12 +13,14 @@ use nix::{ unistd::{fork, ForkResult}, }; use normpath::PathExt; +use semver::Version; #[cfg(not(windows))] use std::os::unix::process::CommandExt; #[cfg(windows)] use std::os::windows::io::{AsRawHandle, RawHandle}; use std::path::Path; use std::path::PathBuf; +use toml::Value; #[cfg(windows)] use windows::Win32::System::{ JobObjects::{AssignProcessToJobObject, SetInformationJobObject}, @@ -161,26 +163,59 @@ fn check_channel_uptodate( Ok(()) } +#[derive(PartialEq, Eq)] enum JuliaupChannelSource { - CmdLine, - EnvVar, - Override, - Default, + CmdLine { channel: String }, + EnvVar { channel: String }, + Override { channel: String }, + Manifest { version: String }, + Default { channel: String }, } fn get_julia_path_from_channel( versions_db: &JuliaupVersionDB, config_data: &JuliaupConfig, - channel: &str, + launch_parameters: &JuliaupChannelSource, juliaupconfig_path: &Path, - juliaup_channel_source: JuliaupChannelSource, ) -> Result<(PathBuf, Vec)> { - let channel_valid = is_valid_channel(versions_db, &channel.to_string())?; - let channel_info = config_data + if let JuliaupChannelSource::Manifest { version } = launch_parameters { + let version_string = versions_db.available_channels.get(version) + .ok_or_else(|| UserError {msg: format!("The project you are trying to launch uses Julia {}, but no such Julia version exists. Please make sure you are using a valid Julia manifest file.", version) } )?; + + let version_config = config_data.installed_versions.get(&version_string.version) + .ok_or_else(|| UserError {msg: format!("The project you are trying to launch uses Julia {}, but you do not have that version installed. You can install it by running `juliaup add {}`.", version, version) } )?; + + let absolute_path = juliaupconfig_path + .parent() + .unwrap() // unwrap OK because there should always be a parent + .join(&version_config.path) + .join("bin") + .join(format!("julia{}", std::env::consts::EXE_SUFFIX)) + .normalize() + .with_context(|| { + format!( + "Failed to normalize path for Julia binary, starting from `{}`.", + juliaupconfig_path.display() + ) + })?; + + return Ok((absolute_path.into_path_buf(), Vec::new())); + } else { + let channel = match launch_parameters { + JuliaupChannelSource::CmdLine { channel } => channel, + JuliaupChannelSource::Default { channel } => channel, + JuliaupChannelSource::EnvVar { channel } => channel, + JuliaupChannelSource::Override { channel } => channel, + _ => unreachable!(), + }; + + let channel_valid = is_valid_channel(versions_db, &channel.to_string())?; + + let channel_info = config_data .installed_channels .get(channel) - .ok_or_else(|| match juliaup_channel_source { - JuliaupChannelSource::CmdLine => { + .ok_or_else(|| match launch_parameters { + JuliaupChannelSource::CmdLine {..} => { if channel_valid { UserError { msg: format!("`{}` is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) } } else if is_pr_channel(&channel.to_string()) { @@ -189,7 +224,7 @@ fn get_julia_path_from_channel( UserError { msg: format!("Invalid Juliaup channel `{}`. Please run `juliaup list` to get a list of valid channels and versions.", channel) } } }.into(), - JuliaupChannelSource::EnvVar=> { + JuliaupChannelSource::EnvVar {..} => { if channel_valid { UserError { msg: format!("`{}` from environment variable JULIAUP_CHANNEL is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) } } else if is_pr_channel(&channel.to_string()) { @@ -198,7 +233,7 @@ fn get_julia_path_from_channel( UserError { msg: format!("Invalid Juliaup channel `{}` from environment variable JULIAUP_CHANNEL. Please run `juliaup list` to get a list of valid channels and versions.", channel) } } }.into(), - JuliaupChannelSource::Override=> { + JuliaupChannelSource::Override {..} => { if channel_valid { UserError { msg: format!("`{}` from directory override is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) } } else if is_pr_channel(&channel.to_string()){ @@ -207,84 +242,86 @@ fn get_julia_path_from_channel( UserError { msg: format!("Invalid Juliaup channel `{}` from directory override. Please run `juliaup list` to get a list of valid channels and versions.", channel) } } }.into(), - JuliaupChannelSource::Default => UserError {msg: format!("The Juliaup configuration is in an inconsistent state, the currently configured default channel `{}` is not installed.", channel) } + JuliaupChannelSource::Manifest {..} => unreachable!(), + JuliaupChannelSource::Default {..} => UserError {msg: format!("The Juliaup configuration is in an inconsistent state, the currently configured default channel `{}` is not installed.", channel) } })?; - match channel_info { - JuliaupConfigChannel::LinkedChannel { command, args } => { - return Ok(( - PathBuf::from(command), - args.as_ref().map_or_else(Vec::new, |v| v.clone()), - )) - } - JuliaupConfigChannel::SystemChannel { version } => { - let path = &config_data + match channel_info { + JuliaupConfigChannel::LinkedChannel { command, args } => { + return Ok(( + PathBuf::from(command), + args.as_ref().map_or_else(Vec::new, |v| v.clone()), + )) + } + JuliaupConfigChannel::SystemChannel { version } => { + let path = &config_data .installed_versions.get(version) .ok_or_else(|| anyhow!("The juliaup configuration is in an inconsistent state, the channel {} is pointing to Julia version {}, which is not installed.", channel, version))?.path; - check_channel_uptodate(channel, version, versions_db).with_context(|| { + check_channel_uptodate(channel, version, versions_db).with_context(|| { format!( "The Julia launcher failed while checking whether the channel {} is up-to-date.", channel ) })?; - let absolute_path = juliaupconfig_path - .parent() - .unwrap() // unwrap OK because there should always be a parent - .join(path) - .join("bin") - .join(format!("julia{}", std::env::consts::EXE_SUFFIX)) - .normalize() - .with_context(|| { - format!( - "Failed to normalize path for Julia binary, starting from `{}`.", - juliaupconfig_path.display() - ) - })?; - return Ok((absolute_path.into_path_buf(), Vec::new())); - } - JuliaupConfigChannel::DirectDownloadChannel { - path, - url: _, - local_etag, - server_etag, - version: _, - } => { - if local_etag != server_etag { - if channel.starts_with("nightly") { - // Nightly is updateable several times per day so this message will show - // more often than not unless folks update a couple of times a day. - // Also, folks using nightly are typically more experienced and need - // less detailed prompting - eprintln!( - "A new `nightly` version is available. Install with `juliaup update`." - ); - } else { - eprintln!( - "A new version of Julia for the `{}` channel is available. Run:", - channel - ); - eprintln!(); - eprintln!(" juliaup update"); - eprintln!(); - eprintln!("to install the latest Julia for the `{}` channel.", channel); - } + let absolute_path = juliaupconfig_path + .parent() + .unwrap() // unwrap OK because there should always be a parent + .join(path) + .join("bin") + .join(format!("julia{}", std::env::consts::EXE_SUFFIX)) + .normalize() + .with_context(|| { + format!( + "Failed to normalize path for Julia binary, starting from `{}`.", + juliaupconfig_path.display() + ) + })?; + return Ok((absolute_path.into_path_buf(), Vec::new())); } + JuliaupConfigChannel::DirectDownloadChannel { + path, + url: _, + local_etag, + server_etag, + version: _, + } => { + if local_etag != server_etag { + if channel.starts_with("nightly") { + // Nightly is updateable several times per day so this message will show + // more often than not unless folks update a couple of times a day. + // Also, folks using nightly are typically more experienced and need + // less detailed prompting + eprintln!( + "A new `nightly` version is available. Install with `juliaup update`." + ); + } else { + eprintln!( + "A new version of Julia for the `{}` channel is available. Run:", + channel + ); + eprintln!(); + eprintln!(" juliaup update"); + eprintln!(); + eprintln!("to install the latest Julia for the `{}` channel.", channel); + } + } - let absolute_path = juliaupconfig_path - .parent() - .unwrap() - .join(path) - .join("bin") - .join(format!("julia{}", std::env::consts::EXE_SUFFIX)) - .normalize() - .with_context(|| { - format!( - "Failed to normalize path for Julia binary, starting from `{}`.", - juliaupconfig_path.display() - ) - })?; - return Ok((absolute_path.into_path_buf(), Vec::new())); + let absolute_path = juliaupconfig_path + .parent() + .unwrap() + .join(path) + .join("bin") + .join(format!("julia{}", std::env::consts::EXE_SUFFIX)) + .normalize() + .with_context(|| { + format!( + "Failed to normalize path for Julia binary, starting from `{}`.", + juliaupconfig_path.display() + ) + })?; + return Ok((absolute_path.into_path_buf(), Vec::new())); + } } } } @@ -308,6 +345,151 @@ fn get_override_channel( } } +fn get_program_file(args: &Vec) -> Option<(usize, &String)> { + let mut program_file: Option<(usize, &String)> = None; + let no_arg_short_switches = ['v', 'h', 'i', 'q']; + let no_arg_long_switches = [ + "--version", + "--help", + "--help-hidden", + "--interactive", + "--quiet", + // Hidden options + "--lisp", + "--image-codegen", + "--rr-detach", + "--strip-metadata", + "--strip-ir", + "--permalloc-pkgimg", + "--heap-size-hint", + "--trim", + ]; + let mut skip_next = false; + for (i, arg) in args.iter().skip(1).enumerate() { + if skip_next { + skip_next = false; + } else if arg == "--" { + if i + 1 < args.len() { + program_file = Some((i + 1, args.get(i + 1).unwrap())); + } + break; + } else if arg.starts_with("--") { + if !no_arg_long_switches.contains(&arg.as_str()) && !arg.contains('=') { + skip_next = true; + } + } else if arg.starts_with("-") { + let arg: Vec = arg.chars().skip(1).collect(); + if arg.iter().all(|&c| no_arg_short_switches.contains(&c)) { + continue; + } + for (j, &c) in arg.iter().enumerate() { + if no_arg_short_switches.contains(&c) { + continue; + } else if j < arg.len() - 1 { + break; + } else { + // `j == arg.len() - 1` + skip_next = true; + } + } + } else { + program_file = Some((i, arg)); + break; + } + } + return program_file; +} + +fn get_project(args: &Vec, config: &JuliaupConfig) -> Option { + if !config.settings.feature_manifest_support { + return None; + } + + let program_file = get_program_file(args); + let recognised_proj_flags: [&str; 4] = ["--project", "--projec", "--proje", "--proj"]; + let mut project_arg: Option = None; + for arg in args + .iter() + .take(program_file.map_or(args.len(), |(i, _)| i)) + { + if arg.starts_with("--proj") { + let mut parts = arg.splitn(2, '='); + if recognised_proj_flags.contains(&parts.next().unwrap_or("")) { + project_arg = Some(parts.next().unwrap_or("@.").to_string()); + } + } + } + let project = if project_arg.is_some() { + project_arg.unwrap() + } else if let Ok(val) = std::env::var("JULIA_PROJECT") { + val + } else { + return None; + }; + if project == "@" { + return None; + } else if project == "@." || project == "" { + let mut path = PathBuf::from(std::env::current_dir().unwrap()); + while !path.join("Project.toml").exists() && !path.join("JuliaProject.toml").exists() { + if !path.pop() { + return None; + } + } + return Some(path); + } else if project == "@script" { + if let Some((_, file)) = program_file { + let mut path = PathBuf::from(file); + path.pop(); + while !path.join("Project.toml").exists() && !path.join("JuliaProject.toml").exists() { + if !path.pop() { + return None; + } + } + return Some(path); + } else { + return None; + } + } else if project.starts_with('@') { + let depot = match std::env::var("JULIA_DEPOT_PATH") { + Ok(val) => match val.split(':').next() { + Some(p) => PathBuf::from(p), + None => dirs::home_dir().unwrap().join(".julia"), + }, + _ => dirs::home_dir().unwrap().join(".julia"), + }; + let path = depot.join("environments").join(&project[1..]); + if path.exists() { + return Some(path); + } else { + return None; + } + } else { + return Some(PathBuf::from(project)); + } +} + +fn julia_version_from_manifest(path: PathBuf) -> Option { + let manifest = if path.join("JuliaManifest.toml").exists() { + path.join("JuliaManifest.toml") + } else if path.join("Manifest.toml").exists() { + path.join("Manifest.toml") + } else { + return None; + }; + let content = std::fs::read_to_string(manifest) + .ok()? + .parse::() + .ok()?; + if let Some(manifest_format) = content.get("manifest_format") { + if manifest_format.as_str()?.starts_with("2.") { + if let Some(julia_version) = content.get("julia_version") { + return julia_version.as_str().and_then(|v| Version::parse(v).ok()); + } + } + } + return None; +} + fn run_app() -> Result { if std::io::stdout().is_terminal() { // Set console title @@ -337,34 +519,33 @@ fn run_app() -> Result { } } - 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 { - return Err(anyhow!( - "The Julia launcher failed to figure out which juliaup channel to use." - )); - }; + let julia_launch_config = if let Some(channel) = channel_from_cmd_line { + JuliaupChannelSource::CmdLine { channel: channel } + } else if let Ok(channel) = std::env::var("JULIAUP_CHANNEL") { + JuliaupChannelSource::EnvVar { channel: channel } + } else if let Ok(Some(channel)) = get_override_channel(&config_file) { + JuliaupChannelSource::Override { channel: channel } + } else if let Some(version) = + get_project(&args, &config_file.data).and_then(julia_version_from_manifest) + { + JuliaupChannelSource::Manifest { + version: version.to_string(), + } + } else if let Some(channel) = config_file.data.default.clone() { + JuliaupChannelSource::Default { channel: channel } + } else { + return Err(anyhow!( + "The Julia launcher failed to figure out which juliaup channel to use." + )); + }; let (julia_path, julia_args) = get_julia_path_from_channel( &versiondb_data, &config_file.data, - &julia_channel_to_use, + &julia_launch_config, &paths.juliaupconfig, - juliaup_channel_source, ) - .with_context(|| { - format!( - "The Julia launcher failed to determine the command for the `{}` channel.", - julia_channel_to_use - ) - })?; + .with_context(|| "The Julia launcher failed to determine the Julia version to launch.")?; let mut new_args: Vec = Vec::new(); diff --git a/src/bin/juliaup.rs b/src/bin/juliaup.rs index 33835acf..7439e136 100644 --- a/src/bin/juliaup.rs +++ b/src/bin/juliaup.rs @@ -3,6 +3,7 @@ use clap::Parser; use juliaup::cli::{ConfigSubCmd, Juliaup, OverrideSubCmd, SelfSubCmd}; use juliaup::command_api::run_command_api; use juliaup::command_completions::run_command_completions; +use juliaup::command_config_featuremanifestsupport::run_command_config_featuremanifestsupport; #[cfg(not(windows))] use juliaup::command_config_symlinks::run_command_config_symlinks; use juliaup::command_config_versionsdbupdate::run_command_config_versionsdbupdate; @@ -123,6 +124,9 @@ fn main() -> Result<()> { ConfigSubCmd::VersionsDbUpdateInterval { value } => { run_command_config_versionsdbupdate(value, false, &paths) } + ConfigSubCmd::FeatureManifestSupport { value } => { + run_command_config_featuremanifestsupport(value, false, &paths) + } }, Juliaup::Api { command } => run_command_api(&command, &paths), Juliaup::InitialSetupFromLauncher {} => run_command_initial_setup_from_launcher(&paths), diff --git a/src/cli.rs b/src/cli.rs index 5d7bc76a..69af596f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -157,4 +157,10 @@ pub enum ConfigSubCmd { /// New value value: Option, }, + /// Enable Julia version selection from manifests + #[clap(name = "featuremanifestsupport")] + FeatureManifestSupport { + /// New value + value: Option, + }, } diff --git a/src/command_config_featuremanifestsupport.rs b/src/command_config_featuremanifestsupport.rs new file mode 100644 index 00000000..02f76112 --- /dev/null +++ b/src/command_config_featuremanifestsupport.rs @@ -0,0 +1,50 @@ +use crate::config_file::{load_config_db, load_mut_config_db, save_config_db}; +use anyhow::{Context, Result}; + +pub fn run_command_config_featuremanifestsupport( + value: Option, + quiet: bool, + paths: &crate::global_paths::GlobalPaths, +) -> Result<()> { + match value { + Some(value) => { + let mut config_file = load_mut_config_db(paths) + .with_context(|| "`config` command failed to load configuration data.")?; + + let mut value_changed = false; + + if value != config_file.data.settings.feature_manifest_support { + config_file.data.settings.feature_manifest_support = value; + + value_changed = true; + } + + save_config_db(&mut config_file) + .with_context(|| "Failed to save configuration file from `config` command.")?; + + if !quiet { + if value_changed { + eprintln!("Property 'featuremanifestsupport' set to '{}'", value); + } else { + eprintln!( + "Property 'featuremanifestsupport' is already set to '{}'", + value + ); + } + } + } + None => { + let config_file = load_config_db(paths, None) + .with_context(|| "`config` command failed to load configuration data.")?; + + if !quiet { + eprintln!( + "Property 'featuremanifestsupport' set to '{}'", + config_file.data.settings.feature_manifest_support + ); + } + } + }; + + Ok(()) +} diff --git a/src/config_file.rs b/src/config_file.rs index 07f11d7b..c907e230 100644 --- a/src/config_file.rs +++ b/src/config_file.rs @@ -67,6 +67,12 @@ pub struct JuliaupConfigSettings { skip_serializing_if = "is_default_versionsdb_update_interval" )] pub versionsdb_update_interval: i64, + #[serde( + rename = "FeatureManifestSupport", + default, + skip_serializing_if = "is_default" + )] + pub feature_manifest_support: bool, } impl Default for JuliaupConfigSettings { @@ -74,6 +80,7 @@ impl Default for JuliaupConfigSettings { JuliaupConfigSettings { create_channel_symlinks: false, versionsdb_update_interval: default_versionsdb_update_interval(), + feature_manifest_support: false, } } } @@ -203,6 +210,7 @@ pub fn load_config_db( settings: JuliaupConfigSettings { create_channel_symlinks: false, versionsdb_update_interval: default_versionsdb_update_interval(), + feature_manifest_support: false, }, last_version_db_update: None, }, @@ -301,6 +309,7 @@ pub fn load_mut_config_db(paths: &GlobalPaths) -> Result { settings: JuliaupConfigSettings { create_channel_symlinks: false, versionsdb_update_interval: default_versionsdb_update_interval(), + feature_manifest_support: false, }, last_version_db_update: None, }; diff --git a/src/lib.rs b/src/lib.rs index 92675479..f8ea1caf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod command_add; pub mod command_api; pub mod command_completions; pub mod command_config_backgroundselfupdate; +pub mod command_config_featuremanifestsupport; pub mod command_config_modifypath; pub mod command_config_startupselfupdate; pub mod command_config_symlinks; diff --git a/tests/channel_selection.rs b/tests/channel_selection.rs index ed375c9f..8485f0af 100644 --- a/tests/channel_selection.rs +++ b/tests/channel_selection.rs @@ -165,3 +165,204 @@ fn channel_selection() { .failure() .stderr("ERROR: `pr1` is not installed. Please run `juliaup add pr1` to install pull request channel if available.\n"); } + +#[test] +fn manifest_version_selection() { + let depot_dir = assert_fs::TempDir::new().unwrap(); + + Command::cargo_bin("juliaup") + .unwrap() + .arg("add") + .arg("1.6.2") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout(""); + + Command::cargo_bin("juliaup") + .unwrap() + .arg("add") + .arg("1.10.1") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout(""); + + Command::cargo_bin("juliaup") + .unwrap() + .arg("add") + .arg("1.11.1") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout(""); + + Command::cargo_bin("juliaup") + .unwrap() + .arg("default") + .arg("1.11.1") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout(""); + + Command::cargo_bin("julia") + .unwrap() + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout("1.11.1"); + + let proj1_dir = assert_fs::TempDir::new().unwrap(); + + // We are adding and then removing a package here to force generation of an actual Project.toml + Command::cargo_bin("julia") + .unwrap() + .arg("+1.10.1") + .arg("-e") + .arg("using Pkg; Pkg.activate(\".\"); Pkg.add(\"StringBuilders\"); Pkg.rm(\"StringBuilders\"); print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj1_dir) + .assert() + .success() + .stdout("1.10.1"); + + // First we try this with the feature disabled + Command::cargo_bin("julia") + .unwrap() + .arg("--project=.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj1_dir) + .assert() + .success() + .stdout("1.11.1"); + + // Now we enable the feature + Command::cargo_bin("juliaup") + .unwrap() + .arg("config") + .arg("featuremanifestsupport") + .arg("true") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .assert() + .success() + .stdout(""); + + Command::cargo_bin("julia") + .unwrap() + .arg("--project=.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj1_dir) + .assert() + .success() + .stdout("1.10.1"); + + // TODO This currently fails, but it shouldn't + Command::cargo_bin("julia") + .unwrap() + .arg("--project") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj1_dir) + .assert() + .success() + .stdout("1.10.1"); + + Command::cargo_bin("julia") + .unwrap() + .arg("--project=@.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj1_dir) + .assert() + .success() + .stdout("1.10.1"); + + let sub_dir1 = &proj1_dir.path().join("subdir1"); + std::fs::create_dir(&sub_dir1).unwrap(); + + Command::cargo_bin("julia") + .unwrap() + .arg("--project=.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&sub_dir1) + .assert() + .success() + .stdout("1.11.1"); + + // TODO This currently fails, but it shouldn't + Command::cargo_bin("julia") + .unwrap() + .arg("--project") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&sub_dir1) + .assert() + .success() + .stdout("1.10.1"); + + Command::cargo_bin("julia") + .unwrap() + .arg("--project=@.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&sub_dir1) + .assert() + .success() + .stdout("1.10.1"); + + // Now we try with a Julia version that generates schema v1 manifests + let proj2_dir = assert_fs::TempDir::new().unwrap(); + + // We are adding and then removing a package here to force generation of an actual Project.toml + Command::cargo_bin("julia") + .unwrap() + .arg("+1.6.2") + .arg("-e") + .arg("using Pkg; Pkg.activate(\".\"); Pkg.add(\"StringBuilders\"); Pkg.rm(\"StringBuilders\"); print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj2_dir) + .assert() + .success() + .stdout("1.6.2"); + + // It shouldn't pick up the version from the manifest, as it isn't stored in the manifest + Command::cargo_bin("julia") + .unwrap() + .arg("--project=.") + .arg("-e") + .arg("print(VERSION)") + .env("JULIA_DEPOT_PATH", depot_dir.path()) + .env("JULIAUP_DEPOT_PATH", depot_dir.path()) + .current_dir(&proj2_dir) + .assert() + .success() + .stdout("1.11.1"); +} From cb788321172e6d8f19168140a15deb8a6dcffa4e Mon Sep 17 00:00:00 2001 From: TEC Date: Thu, 31 Oct 2024 01:51:35 +0800 Subject: [PATCH 2/2] Remove comment about failing test that now passes --- tests/channel_selection.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/channel_selection.rs b/tests/channel_selection.rs index 8485f0af..7ce415f7 100644 --- a/tests/channel_selection.rs +++ b/tests/channel_selection.rs @@ -312,7 +312,6 @@ fn manifest_version_selection() { .success() .stdout("1.11.1"); - // TODO This currently fails, but it shouldn't Command::cargo_bin("julia") .unwrap() .arg("--project")