Skip to content
This repository was archived by the owner on Sep 13, 2023. It is now read-only.

Commit b3d08d3

Browse files
committed
Add parameters to main!, add logging
1 parent 4f49900 commit b3d08d3

File tree

7 files changed

+239
-11
lines changed

7 files changed

+239
-11
lines changed

Cargo.lock

Lines changed: 142 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ serde = "1.0.27"
1616
serde_derive = "1.0.27"
1717
structopt = "0.1.6"
1818
structopt-derive = "0.1.6"
19+
log = "0.4.1"
20+
env_logger = "0.5.3"
1921

2022
[dev-dependencies]
2123
reqwest = "0.8.3"

Readme.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ Quickly build cool CLI apps in Rust.
2828
serde = "1"
2929
```
3030

31-
3. Now, open up your `src/main.rs`. First, let's import all the good stuff:
31+
3. Now, open up your `src/main.rs`. Let's import all the good stuff:
3232

3333
```rust
3434
#[macro_use] extern crate quicli;
3535
use quicli::prelude::*;
3636
```
37+
38+
That's it. That's all the imports you should need for now.
3739

3840
4. Now, quickly write a cool CLI (it's also okay to type slowly):
3941

@@ -49,11 +51,14 @@ Quickly build cool CLI apps in Rust.
4951
// Add a positional argument that the user has to supply:
5052
/// The file to read
5153
file: String,
54+
/// Pass many times for more log output
55+
#[structopt(long = "verbosity", short = "v")]
56+
verbosity: u64,
5257
}
5358

54-
main!({
55-
let args = Cli::from_args();
56-
let data = read_file(args.file)?;
59+
main!(|args: Cli, log_level: verbosity| {
60+
let data = read_file(&args.file)?;
61+
info!("Reading first {} lines of {:?}", args.count, args.file);
5762
data.lines().take(args.count).for_each(|line| println!("{}", line));
5863
});
5964
```
@@ -65,6 +70,8 @@ Quickly build cool CLI apps in Rust.
6570
3. How about `cargo run -- Cargo.toml --count=4` or `cargo run -- Cargo.toml -n 2`?
6671
4. `cargo run -- --help` -- how cool is that?
6772
5. More fun: Try `--cont 4` (with the missing u).
73+
6. You like log messages? That's what we added the `verbosity` field for!
74+
Give `cargo run -- Cargo.toml -vv` a try!
6875

6976
## Thanks
7077

examples/commit_message.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ struct Cli {
99
/// How many?
1010
#[structopt(long = "amount", default_value = "3")]
1111
amount: i32,
12+
/// Pass many times for more log output
13+
#[structopt(long = "verbosity", short = "v")]
14+
verbosity: u64,
1215
}
1316

1417
#[derive(Debug, Deserialize)]
1518
struct Commit {
1619
commit_message: String,
1720
}
1821

19-
main!({
20-
let args = Cli::from_args();
21-
22+
main!(|args: Cli, log_level: verbosity| {
2223
for i in 0..args.amount {
24+
info!("try {}", i);
2325
let c: Commit = reqwest::get("https://whatthecommit.com/index.json")?.json()?;
2426
println!("{}) {}", i + 1, c.commit_message);
2527
}

examples/readme_example.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ struct Cli {
1414
file: String,
1515
}
1616

17-
main!({
18-
let args = Cli::from_args();
17+
main!(|args: Cli| {
1918
let data = read_file(args.file)?;
2019
data.lines().take(args.count).for_each(|line| println!("{}", line));
2120
});

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ extern crate structopt;
1212
#[macro_use] extern crate failure_derive;
1313
#[macro_use] extern crate failure;
1414

15+
#[macro_use] extern crate log;
16+
extern crate env_logger;
17+
1518
mod fs;
1619
mod main_macro;
1720

@@ -26,6 +29,8 @@ mod reexports {
2629

2730
#[doc(hidden)] pub use failure_derive::*;
2831
#[doc(hidden)] pub use failure::*;
32+
33+
#[doc(hidden)] pub use log::*;
2934
}
3035

3136
/// Prelude – import all of this
@@ -42,4 +47,7 @@ pub mod prelude {
4247
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
4348

4449
pub use fs::{read_file, write_to_file};
50+
51+
#[doc(hidden)] pub use env_logger::Builder as LoggerBuiler;
52+
#[doc(hidden)] pub use log::Level as LogLevel;
4553
}

src/main_macro.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,22 @@
33
/// Inside the block, you can write code using `?`. An `Ok(())` will
44
/// automatically be appended.
55
///
6-
/// _Note:_ This will be deprecated once the `try_main` feature is stabilized in
7-
/// Rust.
6+
/// # Parameters
7+
///
8+
/// You can optionally call this macro with a closure-like syntax to get some
9+
/// default bindings:
10+
///
11+
/// - `main!(|args: Cli| { ... })`: Automatically parses command line flags into
12+
/// a struct `Cli` and binds it to `args`. (Basically, it prepends
13+
/// `let args = Cli::from_args();`).
14+
/// - `main!(|args: Cli, log_level: verbosity| { ... })`: In addition to parsing
15+
/// the command line flags into `args` of type `Cli`, it will also initialize
16+
/// a logger.
17+
///
18+
/// The log level will depend on the integer value of the `verbosity` field of
19+
/// `args` (error = 0, warn = 1, info = 2, debug = 3, trace = ≥4). The field's
20+
/// type should be `u64`, so structopt will automatically give you its
21+
/// number of occurances.
822
///
923
/// # Examples
1024
///
@@ -19,6 +33,60 @@
1933
/// ```
2034
#[macro_export]
2135
macro_rules! main {
36+
(|$args:ident: $cli:ty, log_level: $verbosity:ident| $body:expr) => {
37+
fn main() {
38+
fn run() -> $crate::prelude::Result<()> {
39+
let $args = <$cli>::from_args();
40+
let log_level = match $args.verbosity {
41+
0 => $crate::prelude::LogLevel::Error,
42+
1 => $crate::prelude::LogLevel::Warn,
43+
2 => $crate::prelude::LogLevel::Info,
44+
3 => $crate::prelude::LogLevel::Debug,
45+
_ => $crate::prelude::LogLevel::Trace,
46+
}.to_level_filter();
47+
48+
$crate::prelude::LoggerBuiler::new()
49+
.filter(Some(env!("CARGO_PKG_NAME")), log_level)
50+
.filter(None, $crate::prelude::LogLevel::Info.to_level_filter())
51+
.try_init()?;
52+
53+
$body
54+
55+
Ok(())
56+
}
57+
58+
match run() {
59+
Ok(_) => {}
60+
Err(e) => {
61+
eprintln!("{}", e);
62+
::std::process::exit(1);
63+
}
64+
}
65+
}
66+
};
67+
68+
(|$args:ident: $cli:ty| $body:expr) => {
69+
fn main() {
70+
fn run() -> $crate::prelude::Result<()> {
71+
let $args = <$cli>::from_args();
72+
73+
$body
74+
75+
Ok(())
76+
}
77+
78+
match run() {
79+
Ok(_) => {}
80+
Err(e) => {
81+
eprintln!("{}", e);
82+
::std::process::exit(1);
83+
}
84+
}
85+
}
86+
};
87+
88+
(|| $body:expr) => { main!($body); };
89+
2290
($body:expr) => {
2391
fn main() {
2492
fn run() -> $crate::prelude::Result<()> {

0 commit comments

Comments
 (0)