Skip to content

Commit 5230cf8

Browse files
committed
wip
1 parent 1658da7 commit 5230cf8

File tree

6 files changed

+67
-32
lines changed

6 files changed

+67
-32
lines changed

README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ It mirrors the convenience of `npx` for the Cargo ecosystem while prioritising
88

99
## Features
1010

11-
- Executes `crate[@version]` binaries, installing them on the fly.
12-
- Prefers `cargo-binstall` for fast installs and falls back to `cargo install`.
13-
- Supports `--bin` to pick a specific binary, `--force` to reinstall, and `--quiet`
14-
to reduce installer chatter.
11+
- Executes `crate[@version]` binaries, installing them on demand.
12+
- Prefers `cargo-binstall` for fast installs falling back to `cargo install`.
1513
- Passes through additional arguments to the invoked binary via `--`.
1614

1715
## Usage
@@ -29,23 +27,22 @@ cargox bat ./README.md
2927
# Install and run a pinned version
3028
cargox cargo-deny@0.16.3 check
3129

32-
# Force a reinstall using cargo install instead of cargo-binstall
33-
cargox --force --use-cargo-install cargo-nextest
30+
# Force a reinstall, building from source instead of using cargo-binstall
31+
cargox --force --build-from-source cargo-nextest
3432
```
3533

3634
> [!TIP]
3735
>
3836
> - Arguments before the first positional are passed to `cargox`.
3937
> - Arguments after `--` are passed to the invoked binary.
4038
> - Use `--` if necessary to define the separation point.
41-
> - If the crate exposes multiple binaries, use `--bin <name>` to select one.
4239
4340
### Flags
4441

4542
- `--bin <name>`: choose a specific binary when a crate exposes several.
4643
- `-f`, `--force`: reinstall even if the binary already exists on `PATH`.
4744
- `-q`, `--quiet`: suppress installer output (still prints a short status line).
48-
- `--use-cargo-install`: skip `cargo-binstall` and always use `cargo install`.
45+
- `-s`, `--build-from-source`: build from source using `cargo install` instead of `cargo-binstall`.
4946

5047
### Where binaries are stored
5148

src/cli.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{anyhow, Result};
1+
use anyhow::{Result, anyhow};
22
use clap::Parser;
33
use std::env;
44
use std::ffi::OsString;
@@ -15,17 +15,17 @@ pub struct Cli {
1515
#[arg(long, value_name = "NAME")]
1616
pub bin: Option<String>,
1717

18-
/// Force reinstall even if the binary is already on PATH
18+
/// Force reinstall; ignore any existing binary
1919
#[arg(short, long)]
2020
pub force: bool,
2121

2222
/// Suppress installer output
2323
#[arg(short, long)]
2424
pub quiet: bool,
2525

26-
/// Use `cargo install` instead of `cargo-binstall`
27-
#[arg(long)]
28-
pub use_cargo_install: bool,
26+
/// Build from source using `cargo install` instead of `cargo-binstall`
27+
#[arg(short = 's', long)]
28+
pub build_from_source: bool,
2929

3030
/// Arguments passed to the executed binary (use `--` to delimit)
3131
#[arg(trailing_var_arg = true, value_name = "binary-args")]
@@ -90,15 +90,15 @@ impl Cli {
9090
};
9191

9292
// Parse cargox arguments with clap
93-
let mut cli = match Cli::try_parse_from(
94-
std::iter::once(OsString::from("cargox")).chain(cargox_args),
95-
) {
96-
Ok(cli) => cli,
97-
Err(e) => {
98-
// Let clap print the error/help message and exit
99-
e.exit();
100-
}
101-
};
93+
let mut cli =
94+
match Cli::try_parse_from(std::iter::once(OsString::from("cargox")).chain(cargox_args))
95+
{
96+
Ok(cli) => cli,
97+
Err(e) => {
98+
// Let clap print the error/help message and exit
99+
e.exit();
100+
}
101+
};
102102

103103
// Set the binary arguments
104104
cli.args = binary_args;

src/installer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::paths::get_install_dir;
66
use crate::target::Target;
77

88
pub fn ensure_installed(target: &Target, cli: &Cli) -> Result<()> {
9-
if !cli.use_cargo_install && which::which("cargo-binstall").is_ok() {
9+
if !cli.build_from_source && which::which("cargo-binstall").is_ok() {
1010
install_with_binstall(target, cli)
1111
} else {
1212
log_fallback_reason(cli, target);
@@ -15,9 +15,9 @@ pub fn ensure_installed(target: &Target, cli: &Cli) -> Result<()> {
1515
}
1616

1717
fn log_fallback_reason(cli: &Cli, target: &Target) {
18-
if cli.use_cargo_install {
18+
if cli.build_from_source {
1919
eprintln!(
20-
"cargo-binstall was skipped explicitly; installing {} with cargo install",
20+
"Building {} from source with cargo install",
2121
target.descriptor()
2222
);
2323
} else {

src/main.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use anyhow::{Context, Result};
1212
use cli::Cli;
1313
use executor::execute_binary;
1414
use installer::ensure_installed;
15-
use paths::resolve_binary_path;
15+
use paths::{resolve_binary_path, resolve_cargox_binary_path};
1616
use target::{Target, parse_spec};
1717

1818
fn main() {
@@ -49,7 +49,15 @@ fn parse_target_from_cli(cli: &Cli) -> Result<Target> {
4949
}
5050

5151
fn should_use_existing_binary(cli: &Cli, target: &Target) -> bool {
52-
!cli.force && find_existing_binary(&target.binary).is_some()
52+
if cli.force {
53+
return false;
54+
}
55+
56+
if target.version.is_some() {
57+
return false;
58+
}
59+
60+
find_existing_binary(&target.binary).is_some()
5361
}
5462

5563
fn run_existing_binary(target: &Target, cli: &Cli) -> Result<ExitStatus> {
@@ -60,17 +68,26 @@ fn run_existing_binary(target: &Target, cli: &Cli) -> Result<ExitStatus> {
6068

6169
fn install_and_run_binary(target: &Target, cli: &Cli) -> Result<ExitStatus> {
6270
ensure_installed(target, cli)?;
63-
let binary_path = locate_installed_binary(&target.binary)?;
71+
let binary_path = locate_installed_binary(target)?;
6472
execute_binary(&binary_path, &cli.args)
6573
}
6674

6775
fn find_existing_binary(name: &str) -> Option<PathBuf> {
6876
resolve_binary_path(name).ok()
6977
}
7078

71-
fn locate_installed_binary(binary_name: &str) -> Result<PathBuf> {
72-
resolve_binary_path(binary_name)
73-
.with_context(|| format!("{binary_name} should be on PATH after installation"))
79+
fn locate_installed_binary(target: &Target) -> Result<PathBuf> {
80+
if target.version.is_some() {
81+
return resolve_cargox_binary_path(&target.binary).with_context(|| {
82+
format!(
83+
"{} should be available in cargox's install directory after installation",
84+
target.binary
85+
)
86+
});
87+
}
88+
89+
resolve_binary_path(&target.binary)
90+
.with_context(|| format!("{} should be on PATH after installation", target.binary))
7491
}
7592

7693
fn exit_with_status(status: ExitStatus) -> ! {

src/paths.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,24 @@ pub fn resolve_binary_path(name: &str) -> Result<PathBuf> {
5555
Err(anyhow!("cannot find binary path"))
5656
}
5757

58+
pub fn resolve_cargox_binary_path(name: &str) -> Result<PathBuf> {
59+
for dir in candidate_bin_dirs() {
60+
let candidate = dir.join(name);
61+
if candidate.exists() {
62+
return Ok(candidate);
63+
}
64+
#[cfg(windows)]
65+
{
66+
let exe_candidate = candidate.with_extension("exe");
67+
if exe_candidate.exists() {
68+
return Ok(exe_candidate);
69+
}
70+
}
71+
}
72+
73+
Err(anyhow!("cannot find binary path in cargox install dir"))
74+
}
75+
5876
fn candidate_bin_dirs() -> Vec<PathBuf> {
5977
let mut dirs = Vec::new();
6078

tests/help_flag.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ fn test_cargox_help_still_works() {
6060
"cargox help should appear when --help is used without a crate spec.\nStdout:\n{}",
6161
stdout
6262
);
63-
assert!(output.status.success(), "cargox --help should exit successfully");
63+
assert!(
64+
output.status.success(),
65+
"cargox --help should exit successfully"
66+
);
6467
}
6568

6669
/// Test that flags before the crate spec are still parsed by cargox

0 commit comments

Comments
 (0)