[[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 ```