Skip to content
Merged
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
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/rb-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ path = "src/bin/rb.rs"
[dependencies]
clap = { version = "4.0", features = ["derive", "color", "help", "usage", "env"] }
clap_complete = "4.0"
rb-ruby-installer = { path = "../rb-ruby-installer" }
rb-core = { path = "../rb-core" }
rb-gemfile = { path = "../rb-gemfile" }
rb-progress = { path = "../rb-progress", features = ["rb-task"] }
Expand All @@ -41,3 +42,5 @@ serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
rb-tests = { path = "../rb-tests" }
tempfile = "3.0"
serde_json = "1"
sha2 = "0.10"
6 changes: 6 additions & 0 deletions crates/rb-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,9 @@ setx PATH "%PATH%;C:\bin"
```

Then restart your terminal to use `rb` from anywhere.

## Installing Ruby

On Linux and macOS, `rb install ruby 3.4` installs a prebuilt CRuby into `~/.rubies`, respecting `-R` and `RB_RUBIES_DIR`. Use `rb info runtime --available` to list downloadable versions.

`run`, `exec`, and `sync` automatically install a missing Ruby. Disable this with `--no-auto-install-ruby`, `RB_AUTO_INSTALL_RUBY=false`, or `auto-install-ruby = false` in your Butler config. Use `--auto-install-ruby` to override it for one command.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::config::locator::{EnvReader, StdEnvReader};
use anyhow::{Context, Result};
use std::path::PathBuf;

pub(super) fn directory() -> Result<PathBuf> {
pub(crate) fn directory() -> Result<PathBuf> {
locate(&StdEnvReader, home::home_dir())
}

Expand Down
10 changes: 5 additions & 5 deletions crates/rb-cli/src/commands/exec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::sync_report::Completion;
use crate::packages::PackageRuntime;
use log::{debug, info};
use rb_core::butler::ButlerError;
Expand All @@ -7,6 +6,7 @@ pub(crate) fn exec_command(
butler: PackageRuntime,
program_args: Vec<String>,
backend: &crate::packages::PackageBackend,
report: &mut crate::reporting::PreparationReport,
) -> Result<(), ButlerError> {
if program_args.is_empty() {
return Err(ButlerError::General(
Expand All @@ -32,13 +32,13 @@ pub(crate) fn exec_command(
{
crate::packages::PackageStatus::Ready(runtime) => *runtime,
crate::packages::PackageStatus::NeedsPreparation => {
super::sync_report::report_packages(Completion::Compact, |events| {
backend.prepare(&butler, events)
})?
.runtime
super::sync_report::report_packages(report, |events| backend.prepare(&butler, events))?
.runtime
}
};

report.finish("Your environment is ready");

debug!("Program: {}", program);
debug!("Arguments: {:?}", args);

Expand Down
3 changes: 3 additions & 0 deletions crates/rb-cli/src/commands/info/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ pub fn config_command(config: &TrackedConfig) -> Result<(), ButlerError> {
);
println!();

println!("Auto-install Ruby: {}", config.auto_install_ruby.get());
println!(" Source: {}", config.auto_install_ruby.source);
println!();
println!("Package Backend: {}", config.package_backend.get());
println!(" Source: {}", config.package_backend.source);
println!();
Expand Down
2 changes: 1 addition & 1 deletion crates/rb-cli/src/commands/info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub(crate) fn info_command(
backend: &crate::packages::PackageBackend,
) -> Result<(), ButlerError> {
match command {
InfoCommands::Runtime => runtime::runtime_command(butler_runtime),
InfoCommands::Runtime { .. } => runtime::runtime_command(butler_runtime),
InfoCommands::Env => env::environment_command(butler_runtime, project_file, backend),
InfoCommands::Project => project::project_command(butler_runtime, project_file),
InfoCommands::Config => {
Expand Down
3 changes: 2 additions & 1 deletion crates/rb-cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pub(crate) fn run_command(
args: Vec<String>,
project_file: Option<PathBuf>,
backend: &crate::packages::PackageBackend,
report: &mut crate::reporting::PreparationReport,
) -> Result<(), ButlerError> {
if script_name.is_none() {
return list_available_scripts(butler_runtime, project_file);
Expand Down Expand Up @@ -234,7 +235,7 @@ pub(crate) fn run_command(
info!("Delegating to exec command with args: {:?}", full_args);

// Delegate to exec_command for consistent behavior (auto bundle exec, env composition)
exec_command(butler_runtime, full_args, backend)
exec_command(butler_runtime, full_args, backend, report)
}

/// Parse a command string into program and arguments
Expand Down
6 changes: 2 additions & 4 deletions crates/rb-cli/src/commands/sync.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use super::sync_report::Completion;
use crate::packages::PackageRuntime;
use rb_core::butler::ButlerError;

pub(crate) fn sync_command(
runtime: PackageRuntime,
backend: &crate::packages::PackageBackend,
report: &mut crate::reporting::PreparationReport,
) -> Result<(), ButlerError> {
super::sync_report::report_packages(Completion::Tree, |events| {
backend.prepare(&runtime, events)
})?;
super::sync_report::report_packages(report, |events| backend.prepare(&runtime, events))?;
Ok(())
}
24 changes: 5 additions & 19 deletions crates/rb-cli/src/commands/sync_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,8 @@ use rb_core::bundler::SyncEvent;
use rb_core::bundler::SyncResult;
use rb_core::butler::ButlerError;
use rb_progress::Reporter;
use std::io::IsTerminal;

pub(super) fn sync_reporter() -> Reporter {
if std::io::stderr().is_terminal() && std::io::stdout().is_terminal() {
Reporter::with_writer("Preparing your bundle", std::io::stderr())
} else {
Reporter::with_plain_writer("Preparing your bundle", std::io::stderr())
}
}

pub(super) enum Completion {
Tree,
Compact,
}
use crate::reporting::Completion;

pub(crate) fn report_preparation(
reporter: Reporter,
Expand Down Expand Up @@ -81,10 +69,7 @@ pub(crate) fn report_preparation(
} else {
"Everything is already in order"
};
match completion {
Completion::Tree => reporter.finish_with_summary(summary),
Completion::Compact => reporter.finish_compact(summary),
}
completion.finish(reporter, summary);
Ok(result)
}
Err(error) => {
Expand All @@ -101,12 +86,13 @@ pub(crate) fn report_preparation(
}

pub(crate) fn report_packages(
completion: Completion,
report: &mut crate::reporting::PreparationReport,
run: impl FnOnce(
crate::packages::PackageEvents<'_>,
) -> anyhow::Result<crate::packages::PreparedEnvironment>,
) -> Result<crate::packages::PreparedEnvironment, ButlerError> {
report_preparation(sync_reporter(), completion, run)
let (reporter, completion) = report.take();
report_preparation(reporter, completion, run)
}

#[cfg(test)]
Expand Down
22 changes: 19 additions & 3 deletions crates/rb-cli/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,30 @@ pub(crate) fn generate_completions(
None => print_commands(current_word),
Some(("run", _)) => suggest_script_names(current_word, environment.project_file.as_deref()),
Some(("exec", _)) => suggest_binstubs(current_word, &environment.bin_dirs),
_ => {}
_ => print_nested_commands(&matches, current_word),
}
}

fn print_nested_commands(matches: &clap::ArgMatches, prefix: &str) {
let command = Cli::command();
let mut active = &command;
let mut matches = matches;
while let Some((name, child)) = matches.subcommand() {
let Some(command) = active.find_subcommand(name) else {
return;
};
active = command;
matches = child;
}
print_command_candidates(active, prefix);
}

fn print_commands(prefix: &str) {
let cmd = Cli::command();
print_command_candidates(&Cli::command(), prefix);
}

for subcommand in cmd.get_subcommands() {
fn print_command_candidates(command: &clap::Command, prefix: &str) {
for subcommand in command.get_subcommands() {
if subcommand.is_hide_set() {
continue;
}
Expand Down
14 changes: 14 additions & 0 deletions crates/rb-cli/src/config/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ fn parse_kdl_config(content: &str) -> Result<RbConfig, ConfigError> {
);
}

if let Some(node) = doc.get("auto-install-ruby") {
let value = node
.entries()
.first()
.and_then(|entry| entry.value().as_bool())
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"auto-install-ruby requires a boolean",
)
})?;
config.auto_install_ruby = Some(value);
}

// Parse rubies-dir
if let Some(node) = doc.get("rubies-dir")
&& let Some(entry) = node.entries().first()
Expand Down
Loading
Loading