dirsearch

Usage

bash $ dirsearch --number [num]

Article

こんにちは、@ekusiadadusです。 CLI ツール作っていますか? CLI ツールを Rust で作るときに、毎回環境を整えるのが面倒だったので、テンプレを作りました。 今回はそのテンプレを使って、簡易的な CLI ツールを Rust で爆速で作ってみます。

テンプレートはこちらです。 https://github.com/ekusiadadus/rust-cli-template

今回作るコマンドラインツールはこちらです。 https://github.com/ekusiadadus/dirsearch

テンプレを使って CLI ツールを作る

今回は、よくあるディレクトリ配下に存在するフォルダ、ファイルの数とその大きさを表示する CLI ツールを爆速で作ってみます。

テンプレをクローンする

まずは、テンプレをクローンします。

bash git clone https://github.com/ekusiadadus/rust-cli-template.git

cargo run で実行してみる

テンプレを使うには、テンプレのディレクトリに移動して、cargo runを実行します。

bash cd rust-cli-template cargo run

うまくいけば、こんな感じで、rust-cli-templateという名前の CLI ツールが実行されます。

既にこの段階で、cargo run で CLI ツールが実行できる環境が整っています。

image.png

(余談) mold + cargo watch を使う

mold + cargo watch は使わなくてもいいですが、以下の点で便利です。

ここら辺は、参考記事を貼っておくのでもしよかったら使ってみてください。

https://keens.github.io/blog/2021/12/20/moldwotsukautorustnobirudogahayakunaru/

https://qiita.com/kyamamoto9120/items/2081bc44c6c987b9ec29

今回の場合、cargo watch -s 'mold -run cargo run' でホットリロードできる環境にしています。 Makefile も載せてあるので、make watch で動きます。

保存すると自動的にビルドされて、実行されます。

build-with-mold.gif

ディレクトリ配下のファイル、フォルダの数と大きさを表示する

walkDir を使って、ディレクトリ配下のファイル、フォルダの数と大きさを表示するようにします。

walkDir をインストールする

walkdirをつかいます。

bash cargo add walkdir

walkDir を使うには、use walkdir::WalkDir; を追加します。

ディレクトリ配下のファイル、フォルダを取得する

```rust use walkdir::WalkDir;

fn main() { for entry in WalkDir::new(".") { let entry = entry.unwrap(); println!("{}", entry.path().display()); } } ```

cargo run で実行すると、ディレクトリ配下のファイル、フォルダが表示されます。

image.png

ディレクトリ配下のファイル、フォルダの数と大きさを表示する

ディレクトリ配下のファイルと、フォルダを走査して、ファイルの数と大きさを表示するようにします。 walkdir を使うと非常に簡単にファイルとフォルダを走査できます。

```rust use walkdir::WalkDir; const DIR: &str = "./";

fn main() { let mut size: u64 = 0; let mut count: u64 = 0;

for entry in WalkDir::new(DIR).into_iter().filter_map(|e| e.ok()) {
    let path = entry.path();
    if path.is_file() {
        size += path.metadata().unwrap().len();
        count += 1;
    }
    println!("{}", entry.path().display());
}

println!("{} files, {} bytes", count, size);

} ```

実際にcargo run で走らせてみるとこんな感じ。

image.png

現在のディレクトリ配下には、626 個のファイルが存在して、総合で304742935 bytesの大きさになることがわかります。

(余談 2) ファイルサイズを Rust でいい感じに表示するには...

ファイルサイズを Rust でいい感じに表示するには、file_sizeを使います。

```txt use filesize::fit4;

asserteq!(&fit4(999), "999"); asserteq!(&fit4(12345), "12K"); asserteq!(&fit4(999999), "1.0M"); asserteq!(&fit4(7155456789_012), "7.2T"); ```

こんな感じで、いい感じにファイルサイズを表示してくれるクレートです。

bash println!("{} files, {} bytes", count, fit_4(size));

使ってみるとこんな感じ。

image.png

ええやん。

ディレクトリ配下のファイルで上位 N 件を持ってくる

ディレクトリ配下のファイルで上位 N 件を持ってくるようにします。 あと main が大きくなってきたので、関数に切り出します。

```rust fn getdirsize(dir: &str) -> Result<(), Box> { let mut size: u64 = 0; let mut count: u64 = 0; let mut tops: Vec = Vec::withcapacity(NUM + 1); let mut mintops: u64 = 0;

for entry in WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
    let path = entry.path();
    if path.is_file() {
        let t = path.metadata().unwrap().len();
        if t > min_tops {
            tops.push(Entry {
                path: path.to_str().unwrap().to_string(),
                size: t,
            });
            tops.sort_by(|a, b| b.size.cmp(&a.size));
            tops.truncate(NUM);
            min_tops = tops.last().unwrap().size;
        }
        size += path.metadata().unwrap().len();
        count += 1;
    }
}

println!("{} files, {} bytes", count, fit_4(size));
println!("{} largest files:", NUM);
println!("{} | {}", "Size", "Path");
for t in tops {
    println!("{} | {}", fit_4(t.size), t.path);
}

Ok(())

} ```

実行するとこんな感じ。

image.png

ディレクトリ配下のファイルで上位 N 件を持ってくる (並列処理)

Clap を使って、コマンドラインツールにする

clap v4 を使って、コマンドラインツールにします。 v4 は、v3 とはかなり違うので、clap v4 のドキュメントを見ながら進めましょう。

```rust use clap::Parser;

[derive(Parser)]

[command(author, version, about, long_about = None)] // Read from Cargo.toml

struct Cli { #[arg(long)] number: usize, }

fn main() { let cli = Cli::parse(); let num = cli.number; let dir = DIR;

if num == 0 {
    println!("Number of files to show must be greater than 0");
    return;
}

get_dir_size(dir, num).unwrap();

}

```

実際に実行するとこんな感じになります。

image.png

--number argument を忘れると怒られます。

image.png

例えば、上位 100 件を表示するには、--number 100とします。

image.png

デフォルトで --help が使えるようになっています。

image.png

Cargo.toml に書いた情報が、--help で表示されます。

```toml [package] name = "rust-cli-template" version = "0.1.0" edition = "2021" license = "MIT" description = "🌸 Rust CLI Template using clap v4 🌸" readme = "README.md" homepage = "https://github.com/ekusiadadus/rust-cli-template" repository = "https://github.com/ekusiadadus/rust-cli-template" keywords = ["cli", "Japan", "Rust"] categories = ["command-line-utilities"]

See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies] clap = { version = "4.0.29", features = ["derive"] } file-size = "1.0.3" walkdir = "2.3.2" ```