Skip to content

Commit

Permalink
feat(rust): paginate help texts
Browse files Browse the repository at this point in the history
using $PAGER if set, defaulting to `less` and falling back to `more`
or no pagination if no pager is available.

Addresses build-trust#3434
  • Loading branch information
i-b-o-t committed Jun 6, 2023
1 parent a9ee38f commit e85fda7
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions implementations/rust/ockam/ockam_command/Cargo.toml
Expand Up @@ -55,6 +55,7 @@ path = "src/bin/ockam.rs"
anyhow = "1"
async-recursion = { version = "1.0.0" }
async-trait = "0.1"
atty = "0.2.14"
clap = { version = "4.3.2", features = ["derive", "cargo", "wrap_help"] }
clap_complete = "4.3.1"
clap_mangen = "0.2.12"
Expand Down
95 changes: 86 additions & 9 deletions implementations/rust/ockam/ockam_command/src/lib.rs
Expand Up @@ -80,8 +80,7 @@ use secure_channel::{listener::SecureChannelListenerCommand, SecureChannelComman
use service::ServiceCommand;
use space::SpaceCommand;
use status::StatusCommand;
use std::path::PathBuf;
use std::sync::Mutex;
use std::{ffi::OsString, path::Path, path::PathBuf, process, process::Stdio, sync::Mutex};
use tcp::{
connection::TcpConnectionCommand, inlet::TcpInletCommand, listener::TcpListenerCommand,
outlet::TcpOutletCommand,
Expand Down Expand Up @@ -112,7 +111,7 @@ after_long_help = docs::after_help(AFTER_LONG_HELP),
version,
long_version = Version::long(),
next_help_heading = "Global Options",
disable_help_flag = true
disable_help_flag = true,
)]
pub struct OckamCommand {
#[command(subcommand)]
Expand Down Expand Up @@ -315,13 +314,16 @@ pub fn run() {
.map(replace_hyphen_with_stdin)
.collect::<Vec<_>>();

let command = OckamCommand::parse_from(input);

if !command.global_args.test_argument_parser {
check_if_an_upgrade_is_available();
}
match OckamCommand::try_parse_from(input) {
Ok(command) => {
if !command.global_args.test_argument_parser {
check_if_an_upgrade_is_available();
}

command.run();
command.run();
}
Err(help) => show_help(help),
};
}

impl OckamCommand {
Expand Down Expand Up @@ -469,3 +471,78 @@ pub(crate) fn replace_hyphen_with_stdin(s: String) -> String {
s
}
}

const ENV_FORCE_COLOR: &str = "ockam_force_color";

fn show_help(help: clap::Error) {
use std::env;
let mut try_fallback = false;
let preferred_pager = env::var_os("PAGER").unwrap_or_else(|| {
try_fallback = true;
OsString::from("less")
});

if preferred_pager == "false" {
use clap::{ColorChoice::*, CommandFactory};
let possibly_forced = if env::var_os(ENV_FORCE_COLOR).is_some() {
Always
} else {
Auto
};

help.with_cmd(&OckamCommand::command().color(possibly_forced))
.exit();
}

if let Ok(()) = paginate_with(preferred_pager, &help) {
return;
}
if try_fallback {
if let Ok(()) = paginate_with(OsString::from("more"), &help) {
return;
}
}
paginate_with(OsString::from("false"), &help)
.expect("displaying help without pagination should always work");
}

fn paginate_with(pager: OsString, help: &clap::Error) -> Result<()> {
let mut pager_invocation = process::Command::new(&pager);
if Path::new(&pager)
.file_name()
.map_or("", |s| s.to_str().unwrap_or(""))
== "less"
{
pager_invocation.env("LESS", "FRX");
// - F: no pagination if the text fits entirely into the window
// - R: allow ANSI escapes output formatting
// - X: prevents clearing the screen on exit
// - using env var in case a lesser `less` poses as `less`
}
let mut pager_process = pager_invocation.stdin(Stdio::piped()).spawn()?;
let pipe = Stdio::from(pager_process.stdin.take().expect("stdin open?"));

let exit_status = {
let mut my_args = std::env::args_os();
let my_exe_name = my_args.next().unwrap_or("ockam".into());

let mut rerun = process::Command::new(my_exe_name);
rerun.args(my_args).env("PAGER", "false");
use atty::Stream::*;
let output_stream = if help.use_stderr() {
rerun.stderr(pipe);
Stderr
} else {
rerun.stdout(pipe);
Stdout
};
if atty::is(output_stream) {
rerun.env(ENV_FORCE_COLOR, "_");
}
rerun.status()?.code().unwrap_or(exitcode::SOFTWARE)
// dropping owned pipe hands over pager control to the user
};

pager_process.wait()?;
process::exit(exit_status);
}

0 comments on commit e85fda7

Please sign in to comment.