Skip to content

Commit 429cb86

Browse files
committed
WIP on case-insensitive matching
This ended up being a lot of work and a bit confusing, so I'm not sure it's worth pursuing. But I want to save this work in case I change my mind in the future.
1 parent 8adc59e commit 429cb86

31 files changed

+197
-89
lines changed

Changes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
with a new `UbiBuilder::forge` method.
88
- When looking for macOS assets, `ubi` will now match against `macosx` in asset names, not just
99
`macos` and `osx`. Implemented by @kattouf (Vasiliy Kattouf). GH #80.
10+
- Matching an executable name in the downloaded release is now done case-insensitively. For example,
11+
the project named `bscan/PerlNavigator` releases contain a file named `perlnavigator`. This is now
12+
handled correctly without requiring you to pass `--exe perlnavigator`.
1013

1114
## 0.2.4 - 2024-11-24
1215

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ Options:
8888
--self-upgrade Use ubi to upgrade to the latest version of ubi. The --exe, --in,
8989
--project, --tag, and --url args will be ignored.
9090
-i, --in <in> The directory in which the binary should be placed. Defaults to ./bin.
91-
-e, --exe <exe> The name of this project's executable. By default this is the same as
92-
the project name, so for houseabsolute/precious we look for precious or
93-
precious.exe. When running on Windows the ".exe" suffix will be added
94-
as needed.
91+
-e, --exe <exe> The name of this project's executable. By default, this is the same as
92+
the project name, but case-insensitive. For example, with a project
93+
named `houseabsolute/precious` it looks for `precious`, `precious.exe`,
94+
`Precious`, `PRECIOUS.exe`, etc. When running on Windows the ".exe"
95+
suffix will be added as needed, so you should never include this in the
96+
value passed to `exe`.
9597
-m, --matching <matching> A string that will be matched against the release filename when there
9698
are multiple matching files for your OS/arch. For example, there may be
9799
multiple releases for an OS/arch that differ by compiler (MSVC vs. gcc)
@@ -122,6 +124,25 @@ for anonymous API requests.
122124
However, you can also use the `--url` option to bypass the forge site API by providing the download
123125
link directly.
124126

127+
## Installed Executable Naming
128+
129+
If the release is in the form of a tarball or zip file, `ubi` will look in that archive file for a
130+
file that matches the value given for the `exe` field, if any. Otherwise it looks for a file with
131+
the same name as the project. In either case, does case-insensitive matching/
132+
133+
The file it matches will be installed with whatever casing it has in the archive file. So if a
134+
project is named "SomeProject" and it releases a tarball that contains a "someproject" executable,
135+
`ubi` will find it and install it with that name.
136+
137+
If the release is in the form of a bare executable or a compressed executable, then the installed
138+
executable will use the name of the project instead.
139+
140+
This is a bit inconsistent, but it's how `ubi` has behaved since it was created, and I find this to
141+
be the sanest behavior. Some projects, for example `rust-analyzer`, provide releases as compressed
142+
executables with names like `rust-analyzer-x86_64-apple-darwin.gz` and
143+
`rust-analyzer-x86_64-unknown-linux-musl.gz`, so installing these as `rust-analyzer` seems like
144+
better behavior.
145+
125146
## Upgrading `ubi`
126147

127148
You can run `ubi --self-upgrade` to upgrade `ubi` using `ubi`. Note that you must have write

ubi-cli/src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ fn cmd() -> Command {
9999
.help("The directory in which the binary should be placed. Defaults to ./bin."),
100100
)
101101
.arg(Arg::new("exe").long("exe").short('e').help(concat!(
102-
"The name of this project's executable. By default this is the same as the",
103-
" project name, so for houseabsolute/precious we look for precious or",
104-
r#" precious.exe. When running on Windows the ".exe" suffix will be added"#,
105-
" as needed.",
102+
"The name of this project's executable. By default, this is the same as the project",
103+
" name, but matched case-insensitively. For example, with a project named",
104+
" `houseabsolute/precious` it looks for `precious`, `precious.exe`, `Precious`,",
105+
r#" `PRECIOUS.exe`, etc. When running on Windows the ".exe" suffix will be added as"#,
106+
" needed, so you should never include this in the value passed to `exe`.",
106107
)))
107108
.arg(
108109
Arg::new("matching")

ubi-cli/tests/ubi.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,15 @@ fn integration_tests() -> Result<()> {
436436
make_exe_pathbuf(&["bin", "wren_cli"]),
437437
)?;
438438

439+
// The executable in the release files is named "perlnavigator", but the project is
440+
// "PerlNavigator". This tests that exe extraction is case-insensitive.
441+
run_test(
442+
td.path(),
443+
ubi.as_ref(),
444+
&["--project", "bscan/PerlNavigator", "--tag", "v0.8.15"],
445+
make_exe_pathbuf(&["bin", "perlnavigator"]),
446+
)?;
447+
439448
run_test(
440449
td.path(),
441450
ubi.as_ref(),

ubi/src/builder.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use reqwest::{
1414
header::{HeaderMap, HeaderValue, USER_AGENT},
1515
Client,
1616
};
17-
use std::{env, fs::create_dir_all, path::PathBuf, str::FromStr};
17+
use std::{env, path::PathBuf, str::FromStr};
1818
use url::Url;
1919
use which::which;
2020

@@ -93,9 +93,11 @@ impl<'a> UbiBuilder<'a> {
9393
self
9494
}
9595

96-
/// Set the name of the executable to look for in archive files. By default this is the same as
97-
/// the project name, so for `houseabsolute/precious` we look for `precious` or
98-
/// `precious.exe`. When running on Windows the ".exe" suffix will be added as needed.
96+
/// Set the name of the executable to look for in archive files. By default, this is the same as
97+
/// the project name, but matched case-insensitively. For example, with a project named
98+
/// `houseabsolute/precious` it looks for `precious`, `precious.exe`, `Precious`, `PRECIOUS.exe`,
99+
/// etc. When running on Windows the ".exe" suffix will be added as needed, so you should never
100+
/// include this in the value passed to `exe`.
99101
#[must_use]
100102
pub fn exe(mut self, exe: &'a str) -> Self {
101103
self.exe = Some(exe);
@@ -180,14 +182,14 @@ impl<'a> UbiBuilder<'a> {
180182
parse_project_name(self.project, asset_url.as_ref(), self.forge.clone())?;
181183
let exe = exe_name(self.exe, &project_name, &platform);
182184
let forge = self.new_forge(project_name, &forge_type)?;
183-
let install_path = install_path(self.install_dir, &exe)?;
185+
let install_dir = install_dir(self.install_dir)?;
184186
let is_musl = self.is_musl.unwrap_or_else(|| platform_is_musl(&platform));
185187

186188
Ok(Ubi::new(
187189
forge,
188190
asset_url,
189191
AssetPicker::new(self.matching, platform, is_musl),
190-
Installer::new(install_path, exe),
192+
Installer::new(install_dir, exe),
191193
reqwest_client()?,
192194
))
193195
}
@@ -274,17 +276,15 @@ fn parse_project_name(
274276
))
275277
}
276278

277-
fn install_path(install_dir: Option<PathBuf>, exe: &str) -> Result<PathBuf> {
278-
let mut path = if let Some(i) = install_dir {
279+
fn install_dir(install_dir: Option<PathBuf>) -> Result<PathBuf> {
280+
let path = if let Some(i) = install_dir {
279281
i
280282
} else {
281283
let mut i = env::current_dir()?;
282284
i.push("bin");
283285
i
284286
};
285-
create_dir_all(&path)?;
286-
path.push(exe);
287-
debug!("install path = {}", path.to_string_lossy());
287+
debug!("install dir = {}", path.to_string_lossy());
288288
Ok(path)
289289
}
290290

0 commit comments

Comments
 (0)