Skip to content

Commit d389b34

Browse files
committed
Support short channel matching
1 parent 5175056 commit d389b34

File tree

4 files changed

+109
-19
lines changed

4 files changed

+109
-19
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,7 @@ MigrationBackup/
356356
# Ionide (cross platform F# VS Code tools) working folder
357357
.ionide/
358358

359+
# Apple junk
360+
*.DS_Store
361+
359362
!/src/bin

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ To launch a specific Julia version, say in channel `release`, run `julia +releas
150150

151151
The Julia launcher `julia` automatically determines which specific version of Julia to launch. There are several ways to control and override which Juliaup channel should be used:
152152

153-
1. A command line Julia version specifier, such as `julia +release`.
153+
1. A command line Julia version specifier, such as `julia +release`. For non-version channels, any unambiguous installed channel prefix will launch that channel.
154154
2. The `JULIAUP_CHANNEL` environment variable.
155155
3. A directory override, set with the `juliaup override set` command.
156156
3. The default Juliaup channel.

src/bin/julialauncher.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -167,39 +167,70 @@ enum JuliaupChannelSource {
167167
Default,
168168
}
169169

170+
fn only<T, I>(mut iter: I) -> Option<T>
171+
where
172+
I: Iterator<Item = T>,
173+
{
174+
let first = iter.next();
175+
if iter.next().is_some() {
176+
// There are multiple elements
177+
return None;
178+
}
179+
first
180+
}
181+
170182
fn get_julia_path_from_channel(
171183
versions_db: &JuliaupVersionDB,
172184
config_data: &JuliaupConfig,
173-
channel: &str,
185+
requested_channel: &str,
174186
juliaupconfig_path: &Path,
175187
juliaup_channel_source: JuliaupChannelSource,
176188
) -> Result<(PathBuf, Vec<String>)> {
189+
let expanded_channel = if requested_channel
190+
.chars()
191+
.next()
192+
.map(char::is_numeric)
193+
.unwrap_or(false)
194+
{
195+
requested_channel
196+
} else {
197+
match only(
198+
config_data
199+
.installed_channels
200+
.keys()
201+
.filter(|&item| item.starts_with(requested_channel)),
202+
) {
203+
Some(val) => val,
204+
None => requested_channel,
205+
}
206+
};
207+
177208
let channel_info = config_data
178209
.installed_channels
179-
.get(channel)
210+
.get(expanded_channel)
180211
.ok_or_else(|| match juliaup_channel_source {
181212
JuliaupChannelSource::CmdLine => {
182-
if versions_db.available_channels.contains_key(channel) {
183-
UserError { msg: format!("`{}` is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) }
213+
if versions_db.available_channels.contains_key(expanded_channel) {
214+
UserError { msg: format!("`{}` is not installed. Please run `juliaup add {}` to install channel or version.", expanded_channel, expanded_channel) }
184215
} else {
185-
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}`. Please run `juliaup list` to get a list of valid channels and versions.", channel) }
216+
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}`. Please run `juliaup list` to get a list of valid channels and versions.", expanded_channel) }
186217
}
187218
}.into(),
188219
JuliaupChannelSource::EnvVar=> {
189-
if versions_db.available_channels.contains_key(channel) {
190-
UserError { msg: format!("`{}` for environment variable JULIAUP_CHANNEL is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) }
220+
if versions_db.available_channels.contains_key(expanded_channel) {
221+
UserError { msg: format!("`{}` for environment variable JULIAUP_CHANNEL is not installed. Please run `juliaup add {}` to install channel or version.", expanded_channel, expanded_channel) }
191222
} else {
192-
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}` in environment variable JULIAUP_CHANNEL. Please run `juliaup list` to get a list of valid channels and versions.", channel) }
223+
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}` in environment variable JULIAUP_CHANNEL. Please run `juliaup list` to get a list of valid channels and versions.", expanded_channel) }
193224
}
194225
}.into(),
195226
JuliaupChannelSource::Override=> {
196-
if versions_db.available_channels.contains_key(channel) {
197-
UserError { msg: format!("`{}` for directory override is not installed. Please run `juliaup add {}` to install channel or version.", channel, channel) }
227+
if versions_db.available_channels.contains_key(expanded_channel) {
228+
UserError { msg: format!("`{}` for directory override is not installed. Please run `juliaup add {}` to install channel or version.", expanded_channel, expanded_channel) }
198229
} else {
199-
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}` in directory override. Please run `juliaup list` to get a list of valid channels and versions.", channel) }
230+
UserError { msg: format!("ERROR: Invalid Juliaup channel `{}` in directory override. Please run `juliaup list` to get a list of valid channels and versions.", expanded_channel) }
200231
}
201232
}.into(),
202-
JuliaupChannelSource::Default => anyhow!("The Juliaup configuration is in an inconsistent state, the currently configured default channel `{}` is not installed.", channel)
233+
JuliaupChannelSource::Default => anyhow!("The Juliaup configuration is in an inconsistent state, the currently configured default channel `{}` is not installed.", expanded_channel)
203234
})?;
204235

205236
match channel_info {
@@ -212,12 +243,12 @@ fn get_julia_path_from_channel(
212243
JuliaupConfigChannel::SystemChannel { version } => {
213244
let path = &config_data
214245
.installed_versions.get(version)
215-
.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;
246+
.ok_or_else(|| anyhow!("The juliaup configuration is in an inconsistent state, the channel {} is pointing to Julia version {}, which is not installed.", expanded_channel, version))?.path;
216247

217-
check_channel_uptodate(channel, version, versions_db).with_context(|| {
248+
check_channel_uptodate(expanded_channel, version, versions_db).with_context(|| {
218249
format!(
219250
"The Julia launcher failed while checking whether the channel {} is up-to-date.",
220-
channel
251+
expanded_channel
221252
)
222253
})?;
223254
let absolute_path = juliaupconfig_path
@@ -243,7 +274,7 @@ fn get_julia_path_from_channel(
243274
version: _,
244275
} => {
245276
if local_etag != server_etag {
246-
if channel.starts_with("nightly") {
277+
if expanded_channel.starts_with("nightly") {
247278
// Nightly is updateable several times per day so this message will show
248279
// more often than not unless folks update a couple of times a day.
249280
// Also, folks using nightly are typically more experienced and need
@@ -254,12 +285,15 @@ fn get_julia_path_from_channel(
254285
} else {
255286
eprintln!(
256287
"A new version of Julia for the `{}` channel is available. Run:",
257-
channel
288+
expanded_channel
258289
);
259290
eprintln!();
260291
eprintln!(" juliaup update");
261292
eprintln!();
262-
eprintln!("to install the latest Julia for the `{}` channel.", channel);
293+
eprintln!(
294+
"to install the latest Julia for the `{}` channel.",
295+
expanded_channel
296+
);
263297
}
264298
}
265299

tests/channel_selection.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,57 @@ fn channel_selection() {
125125
.assert()
126126
.failure()
127127
.stderr("ERROR: Invalid Juliaup channel `1.8.6`. Please run `juliaup list` to get a list of valid channels and versions.\n");
128+
129+
// Now testing short channel matching
130+
// At this point, installed channels are: 1.6.7, 1.7.3, 1.8.5
131+
132+
// Test that incomplete number matching does not autocomplete:
133+
// https://github.com/JuliaLang/juliaup/pull/838#issuecomment-2206640506
134+
Command::cargo_bin("julia")
135+
.unwrap()
136+
.arg("+1.8")
137+
.arg("-v")
138+
.env("JULIA_DEPOT_PATH", depot_dir.path())
139+
.env("JULIAUP_DEPOT_PATH", depot_dir.path())
140+
.assert()
141+
.failure();
142+
143+
// Test that completion works only when it should for words
144+
Command::cargo_bin("juliaup")
145+
.unwrap()
146+
.arg("add")
147+
.arg("release")
148+
.env("JULIA_DEPOT_PATH", depot_dir.path())
149+
.env("JULIAUP_DEPOT_PATH", depot_dir.path())
150+
.assert()
151+
.success()
152+
.stdout("");
153+
154+
Command::cargo_bin("julia")
155+
.unwrap()
156+
.arg("+r")
157+
.arg("-v")
158+
.env("JULIA_DEPOT_PATH", depot_dir.path())
159+
.env("JULIAUP_DEPOT_PATH", depot_dir.path())
160+
.assert()
161+
.success();
162+
163+
Command::cargo_bin("juliaup")
164+
.unwrap()
165+
.arg("add")
166+
.arg("rc")
167+
.env("JULIA_DEPOT_PATH", depot_dir.path())
168+
.env("JULIAUP_DEPOT_PATH", depot_dir.path())
169+
.assert()
170+
.success()
171+
.stdout("");
172+
173+
Command::cargo_bin("julia")
174+
.unwrap()
175+
.arg("+r")
176+
.arg("-v")
177+
.env("JULIA_DEPOT_PATH", depot_dir.path())
178+
.env("JULIAUP_DEPOT_PATH", depot_dir.path())
179+
.assert()
180+
.failure();
128181
}

0 commit comments

Comments
 (0)