[[Command Line Applications in Rust]]を参考に構築する。
## Project setup
```bash
cargo new <project>
```
## CLIフレームワークのインストール
[[clap]]のv3-betaを使ってみる。
```toml
[dependencies]
clap = "3.0.0-beta.2"
```
ファイル名を指定して中身を表示するところまで実装。詳細は[[clap#MOC]]などを参考に。
```rust
use clap::Clap;
use std::fs::read_to_string;
use std::path::PathBuf;
#[derive(Clap, Debug)]
#[clap(version = "0.1", author = "tadashi-aikawa")]
struct Opts {
/// The path of the config file to load
#[clap(short, long, default_value = ".tatsuwo.yaml")]
config: String,
#[clap(subcommand)]
subcmd: SubCommand,
#[clap(short, long, parse(from_occurrences), global = true)]
verbose: i32,
}
#[derive(Clap, Debug)]
enum SubCommand {
/// Show file contents
Show(ShowOpts),
}
#[derive(Clap, Debug)]
struct ShowOpts {
#[clap(parse(from_os_str))]
input: PathBuf,
}
fn main() {
let opts: Opts = Opts::parse();
match opts.subcmd {
SubCommand::Show(op) => cmd_show(&op),
}
}
fn cmd_show(op: &ShowOpts) {
let content = read_to_string(&op.input).expect("Could not read file.");
println!("{}", content)
}
```
実行コマンド。
```shell
$ cargo run -- show .\Cargo.toml
```
## Loggerのインストール
[[log]]と[[env_logger]]を使う。
```toml
[dependencies]
log = "0.4.14"
env_logger = "0.8.3"
```
```rust
use log::{debug, info};
// 中略...
fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let opts: Opts = Opts::parse();
debug!("Options: {:?}", opts);
match opts.subcmd {
SubCommand::Show(op) => {
info!("Execute command show");
cmd_show(&op)
}
}
}
fn cmd_show(op: &ShowOpts) {
let content = read_to_string(&op.input).expect("Could not read file.");
println!("{}", content)
}
```
## Error Handlingの効率化
[[anyhow]]を使う。`Result<()>`でお手軽なエラーハンドリングが可能に。[[Question mark operator]]も頼もしい。
```toml
[dependencies]
anyhow = "1.0.38"
```
```rust
use anyhow::{Context, Result};
// 中略。。
fn main() -> Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let opts: Opts = Opts::parse();
debug!("Options: {:?}", opts);
match opts.subcmd {
SubCommand::Show(op) => {
info!("Execute command show");
cmd_show(&op)?
}
}
Ok(())
}
fn cmd_show(op: &ShowOpts) -> Result<()> {
let content = read_to_string(&op.input).with_context(|| "Could not read file.")?;
println!("{}", content);
Ok(())
}
```
## 進捗状況の可視化
[[®indicatif]]を使う。
```rust
```