]>
git.proxmox.com Git - cargo.git/blob - src/bin/cargo/commands/help.rs
1 use crate::aliased_command
;
2 use cargo
::util
::errors
::CargoResult
;
3 use cargo
::util
::paths
::resolve_executable
;
5 use flate2
::read
::GzDecoder
;
6 use std
::ffi
::OsString
;
11 const COMPRESSED_MAN
: &[u8] = include_bytes
!(concat
!(env
!("OUT_DIR"), "/man.tgz"));
13 /// Checks if the `help` command is being issued.
15 /// This runs before clap processing, because it needs to intercept the `help`
16 /// command if a man page is available.
18 /// Returns `true` if a man page was displayed. In this case, Cargo should
20 pub fn handle_embedded_help(config
: &Config
) -> bool
{
21 match try_help(config
) {
25 log
::warn
!("man failed: {:?}", e
);
31 fn try_help(config
: &Config
) -> CargoResult
<bool
> {
32 let mut args
= std
::env
::args_os()
34 .skip_while(|arg
| arg
.to_str().map_or(false, |s
| s
.starts_with('
-'
)));
37 .map_or(false, |arg
| arg
.to_str() == Some("help"))
41 let subcommand
= match args
.next() {
43 None
=> return Ok(false),
45 let subcommand
= match subcommand
.to_str() {
47 None
=> return Ok(false),
49 // Check if this is a built-in command (or alias);
50 let subcommand
= match check_alias(config
, subcommand
) {
52 None
=> return Ok(false),
54 if resolve_executable(Path
::new("man")).is_ok() {
55 let man
= match extract_man(&subcommand
, "1") {
57 None
=> return Ok(false),
59 write_and_spawn(&man
, "man")?
;
61 let txt
= match extract_man(&subcommand
, "txt") {
63 None
=> return Ok(false),
65 if resolve_executable(Path
::new("less")).is_ok() {
66 write_and_spawn(&txt
, "less")?
;
67 } else if resolve_executable(Path
::new("more")).is_ok() {
68 write_and_spawn(&txt
, "more")?
;
70 drop(std
::io
::stdout().write_all(&txt
));
76 /// Checks if the given subcommand is a built-in command (possibly via an alias).
78 /// Returns None if it is not a built-in command.
79 fn check_alias(config
: &Config
, subcommand
: &str) -> Option
<String
> {
80 if super::builtin_exec(subcommand
).is_some() {
81 return Some(subcommand
.to_string());
83 match aliased_command(config
, subcommand
) {
85 let alias
= alias
.into_iter().next()?
;
86 if super::builtin_exec(&alias
).is_some() {
96 /// Extracts the given man page from the compressed archive.
98 /// Returns None if the command wasn't found.
99 fn extract_man(subcommand
: &str, extension
: &str) -> Option
<Vec
<u8>> {
100 let extract_name
= OsString
::from(format
!("cargo-{}.{}", subcommand
, extension
));
101 let gz
= GzDecoder
::new(COMPRESSED_MAN
);
102 let mut ar
= tar
::Archive
::new(gz
);
103 // Unwraps should be safe here, since this is a static archive generated
104 // by our build script. It should never be an invalid format!
105 for entry
in ar
.entries().unwrap() {
106 let mut entry
= entry
.unwrap();
107 let path
= entry
.path().unwrap();
108 if path
.file_name().unwrap() != extract_name
{
111 let mut result
= Vec
::new();
112 entry
.read_to_end(&mut result
).unwrap();
118 /// Write the contents of a man page to disk and spawn the given command to
120 fn write_and_spawn(contents
: &[u8], command
: &str) -> CargoResult
<()> {
121 let mut tmp
= tempfile
::Builder
::new().prefix("cargo-man").tempfile()?
;
122 let f
= tmp
.as_file_mut();
123 f
.write_all(&contents
)?
;
125 let mut cmd
= std
::process
::Command
::new(command
)