Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd "Run piped external commands" example #297
Conversation
ludwigpacifici
referenced this pull request
Sep 26, 2017
Closed
Add "Run piped external commands" example #269
budziq
requested changes
Sep 27, 2017
|
Hi @ludwigpacifici Also, could you rebase the example? It currently is not able to be build due to conflict (the merge commit conflicts with current master) Please ping me If you have any questions or need help! |
| <a name="ex-run-piped-external-commands"></a> | ||
| ## Run piped external commands | ||
|
|
||
| [![clap-badge]][clap] [![cat-os-badge]][cat-os] |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
No need to use clap here.
We would like to make the recipes as short and concise as possible (small snippets that are to the point without additional noise, ready to cut-n-paste into the readers code)
Clap usage makes the example quite noisy. Lets just hardcode the results and directory
| run: `du -ah <directory> | sort -hr | head -n <N>`. | ||
|
|
||
| ```rust,no_run | ||
| # extern crate clap; |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
lets remove the clap dependency.
On the other hand we will use error-chain here to handle all the verbose error boilerplate handling. Please checkout
our note about error handling
| } | ||
| } | ||
| # fn declare_command_line_arguments<'a>() -> ArgMatches<'a> { |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
please remove all the clap related functions. We will not need these
| use std::fs::metadata; | ||
| use std::process::{exit, Command, Stdio}; | ||
| static DU: &'static str = "du"; |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
I'd remove these constants. The example will be shorter and more readable if we write the tool name and argument list directly in the Command::new builder chain
| fn main() { | ||
| let arguments = declare_command_line_arguments(); | ||
| let results = parse_number_of_results(&arguments); |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
i would rename the results variable to more descriptive name such as max_results
| # extern crate clap; | ||
| # use clap::{App, Arg, ArgMatches}; | ||
| use std::error::Error; |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
One we finish, the only use that will be needed here will be use std::process::{Command, Stdio};
| .stdout(Stdio::piped()) | ||
| .spawn() | ||
| { | ||
| Err(why) => { |
This comment has been minimized.
This comment has been minimized.
| Ok(process) => process, | ||
| }; | ||
| let sort_stdout = sort_process.stdout.unwrap_or_else(|| { |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
ditto on error handling and we do not need a separate variable binding. please see my comment on head_output below
| }); | ||
| let head_process = match Command::new(HEAD) | ||
| .arg(HEAD_ARGUMENTS) |
This comment has been minimized.
This comment has been minimized.
| Ok(process) => process, | ||
| }; | ||
| let head_output = head_process.wait_with_output().unwrap_or_else(|err| { |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 27, 2017
Collaborator
No need fo the error boilerplate here and we do not need separate variable binding here. We can use
let head_output = Command::new("head")
.arg("-n")
...
.spawn()?
.wait_with_output()?;
This comment has been minimized.
This comment has been minimized.
|
Thanks for your detailed review! I agree with your comments ; the code is shorter and to the point. Let me know what you think. |
budziq
requested changes
Sep 30, 2017
|
@ludwigpacifici just few final thoughts |
| # } | ||
| # | ||
| fn run() -> Result<()> { | ||
| let directory = "."; |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 30, 2017
Collaborator
we might use https://doc.rust-lang.org/std/env/fn.current_dir.html here instead
| # | ||
| fn run() -> Result<()> { | ||
| let directory = "."; | ||
| let du_process = Command::new("du") |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 30, 2017
Collaborator
We might be tempted to further DRY the code by extracting the builder into a separate fn like
fn spawn_piped<P, I, A, IN>(program: P, args: I, input: IN) -> Result<Child>
where
P: AsRef<OsStr>,
I: IntoIterator<Item = A>,
A: AsRef<OsStr>,
IN: Into<Stdio>,
{
...
}But I'm not sure if this does not make the code harder to read. I'll let you decide here
This comment has been minimized.
This comment has been minimized.
ludwigpacifici
Oct 1, 2017
Author
Contributor
I gave it a try:
I prefer pipe-process.rs:
- The goal is to demonstrate pipe processes, however, the
spawn_pipedfunction tends to bury it. - If the targeted reader is a beginner,
spawn_pipedintroduce concepts of iterators. spawn_pipedwill DRY the code if more processes would be spawn.
If I miss something, let me know, otherwise I will skip spawn_piped.
| .wait_with_output()?; | ||
| println!( | ||
| "Top {} biggest files and directories in '{}':\n{}", |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 30, 2017
Collaborator
I guess that w can hardcode the "10" and lose the variable alltoheter
|
|
||
| Shows up to the 10<sup>th</sup> biggest files and subdirectories in | ||
| the specified the current working directory. It spawns three Unix | ||
| processes as external [`Command`]. It is equivalant to run: `du -ah . | sort -hr | head -n |
This comment has been minimized.
This comment has been minimized.
budziq
Sep 30, 2017
Collaborator
I would mention the Stdio::piped in the description as it's critical here
This comment has been minimized.
This comment has been minimized.
|
Also could you fix the merge conflict and squash the commits into one? |
This comment has been minimized.
This comment has been minimized.
|
Knowing that my commits are already pushed, can I squash and rebase them in this PR or should I create a new PR? |
budziq
requested changes
Oct 1, 2017
|
nice! just some final cleanup and we are ready to merge! @ludwigpacifici |
| .ok_or_else(|| "Could not capture `sort` standard output.")?; | ||
| let head_output = Command::new("head") | ||
| .arg("-n") |
This comment has been minimized.
This comment has been minimized.
| [`seek`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.seek | ||
| [`digest::Context`]: https://docs.rs/ring/*/ring/digest/struct.Context.html | ||
| [`digest::Digest`]: https://docs.rs/ring/*/ring/digest/struct.Digest.html | ||
| [rand-distributions]: https://doc.rust-lang.org/rand/rand/distributions/index.html | ||
| [replacement string syntax]: https://docs.rs/regex/0.2.2/regex/struct.Regex.html#replacement-string-syntax |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
ludwigpacifici
Oct 2, 2017
•
Author
Contributor
I don't understand this one. Are you referring to the below code, as a follow up from your above comment?
.arg("-ah")
.arg(&directory)
This comment has been minimized.
This comment has been minimized.
budziq
Oct 3, 2017
Collaborator
@ludwigpacifici
Well that was not really descriptive on my part
What I mean was:
Please split this commit into one editing the example and second one editing the links
and the "same here" was about making the regex links use wildcard "*" instead of "0.2.2" which happens in two places
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
in regard to the suggested refactoring, I would not be hesitant to introduce iterators as these are already present very early in other examples (please think about cookbook as an appendix to RBE, you know the basics and would like to have an inkling how to solve your problem). I agree that the as for the refactoring proposed by you you do not have to iterate in a for loop, the |
This comment has been minimized.
This comment has been minimized.
Sure you can! You modify the history of your local branch (rebase/squash and whatnot) and just |
This comment has been minimized.
This comment has been minimized.
|
Thank you for the advice |
This comment has been minimized.
This comment has been minimized.
|
Commits splitted. Any other change left to do? |
This comment has been minimized.
This comment has been minimized.
I would prefer for the links to be sorted case insensitively. otherwise we are good to merge once travis finishes :) |
This comment has been minimized.
This comment has been minimized.
|
@budziq I tweaked my editor to change the sort. |
budziq
merged commit 6ffdf8e
into
rust-lang-nursery:master
Oct 4, 2017
This comment has been minimized.
This comment has been minimized.
|
@ludwigpacifici Nicely done! |
This comment has been minimized.
This comment has been minimized.
|
Thanks for your reviews @budziq ! |
This comment has been minimized.
This comment has been minimized.
|
No Problem. Keep them comming |
ludwigpacifici commentedSep 26, 2017
For a given , shows the
<number>biggestfiles/subdirectories and its human readable size.
Equivalant Unix command:
du -ah | sort -hr | head -n