gsr in Rust
以前の 投稿 で、git status を再帰的に全Gitディレクトリで実行して、変更のあるリポジトリを簡単に見つける
というのを golang
で書いていたのだが、それを rust
で書き直してみた。
インストールは、 cargo
で実施。
$ cargo install --git https://github.com/yukimemi/gsr-rs $ gsr -h gsr 0.2.2 USAGE: gsr [FLAGS] [input] FLAGS: --ahead Print ahead repo -a, --all Print all git directory --behind Print behind repo -f, --fetch Execute git fetch before check -h, --help Prints help information -V, --version Prints version information ARGS: <input> Input directory. default is $(ghq root) or '.'
使い方は、だいたい 以前の投稿 で書いた golang
版と同じ。
いくつかライブラリを使っていて、便利だったものを紹介。
structopt
使い方は、 github 上の README を読めばすぐわかると思う。
yukimemi/gsr-rs では、以下のようにしてオプションの定義を実施。
#![feature(attr_literals)] extern crate structopt; #[macro_use] extern crate structopt_derive; use structopt::StructOpt; #[derive(StructOpt, Debug)] struct Opt { #[structopt(short = "a", long = "all", help = "Print all git directory")] all: bool, #[structopt(short = "f", long = "fetch", help = "Execute git fetch before check")] fetch: bool, #[structopt(long = "behind", help = "Print behind repo")] behind: bool, #[structopt(long = "ahead", help = "Print ahead repo")] ahead: bool, #[structopt(required = false, help = "Input directory. default is $(ghq root) or '.'")] input: Option<String>, }
これで、上記で書いたようないい感じの help が表示される。 内部的に clap を使ってるみたい。
walkdir, rust-threadpool
ディレクトリやファイルを再帰的に取得するやつ。 だいたい cli でなんかするときには必要な気がする。 yukimemi/gsr-rs では、以下のようにして、 git のディレクトリをリスティングしている。
fn get_rootdir(input: &Option<String>) -> WalkDir { match *input { Some(ref inp) => WalkDir::new(inp), None => { if let Ok(out) = Command::new("ghq").arg("root").output() { return WalkDir::new(String::from_utf8_lossy(&out.stdout).trim_right()); } WalkDir::new(".") } } } fn get_gsrs(walk_dir: WalkDir, fetch: bool) -> mpsc::Receiver<Gsr> { let (tx, rx) = mpsc::channel::<Gsr>(); let pool = ThreadPool::new(WORKERS); thread::spawn(move || { walk_dir .into_iter() .map(|e| match e { Ok(e) => { if e.file_name().to_str().unwrap_or("").eq(".git") { let tx = tx.clone(); pool.execute(move || { let parent = e.path().parent().unwrap(); let gsr = Gsr::new(parent); if fetch { gsr.fetch(); } let gsr = gsr.status().diff().is_ahead().is_behind(); tx.send(gsr).unwrap(); }); } } Err(e) => eprintln!("{}", e), }) .collect::<Vec<_>>(); pool.join(); drop(tx); }); rx }
ここでは、ディレクトリリスティングと、 git status などの取得をパラレルで行うために、 rust-threadpool も使用している。
この crate
も非常に便利だった。
参考
Thanks for reading! Read other posts?