2ステップでファイルを操作するCLIツール『Fuga』

2022-05-09 (Mon)
ファイル操作をシンプルにするCLIツール『Fuga』の開発について

Table of Contents

はじめに

今年のGWは久々に10連休をいただくことができたので、今までやったことがないことをやってみようと思いました。
色々と考えましたが、少し前から勉強し始めたRustを使ってCLIツールを作成してみることにしました。
今回の記事では、今回開発したCLIツール『Fuga』とRustでのCLIツール開発について説明します。

今回開発したCLIツール

まず、今回作成したCLIツールについて紹介いたします。
以下にて公開しています。

まだ実行形式のバイナリファイルを提供できていないので、インストールするにはRustの開発環境を構築する必要がありますが、もし興味のある方は使ってみていただけるととても嬉しいです。
バグや使いにくい点などがあれば、issueに書いていただけると対応を検討します。

開発のモチベーション

今回、CLIツールを開発するにあたり、以前から個人的に不便だと感じていたものを改善できるようなものを作りたいと考えました。
共感してくれる方がどのくらいいるかわかりませんが、私は以前からターミナルにおけるファイル操作に不満を持っていました。
いくつか具体的な例を挙げて説明します。

mvcpコマンドでパスを指定するのが面倒

コマンドでファイルを操作するときには、移動コマンドであるmvとコピーコマンドであるcpを使うのが一般的です。
しかし、これらのコマンドでファイル操作をする際、相対パスで指定しようとするととんでもない長さになることがあります。

例えば、以下のような長々としたコマンドを打った経験はないでしょうか?

$ mv test.txt ../../../path/to/directory/that/you/want/to/move

タブを連打して必死にパスを入力していることが想像できて、見ているだけでも左手の小指が痛くなってきます(笑)

一方、GUIで操作する場合は、対象のファイルを「右クリック→切り取りorコピー」し、対象のディレクトリに移動した後に「右クリック→貼り付け」で操作します。
このように2段階にわけることで操作がシンプルになっていると思いませんか?

cpコマンドでのディレクトリ操作

次の例も私が勝手にハマっていつもイラッとしているのですが、cpコマンドでディレクトリをコピーする場合は-rオプションを使う必要があります。
こちらも先ほどのように長いパスを打っているときに発生するとイライラ度は更に上がります(笑)

$ cp test_dir ../../../path/to/directory/that/you/want/to/copy
cp: -r not specified; omitting directory 'test_dir'

そもそもmvコマンドでは不要なのに、なぜcpコマンドだと-rが必要なんですかね?
理由を知っている人がいれば教えていただきたいです…

lnコマンドの順序問題

lnコマンドを使うことでシンボリックリンクを作成することができます。
そこまで使用頻度が多くないのですが、たまに必要になることがあり、そのときにコマンドに指定するパスの順番がわからなくなることがよくあります。

正しくは、

$ ln -s [対象のファイルorディレクトリ] [作成するシンボリックリンクのパス]

となりますが、たまにしか使わないが故になかなか自信を持って覚えられないという状況です。

『Fuga』の概要

前述の課題を解決するために作成したのが、今回開発したCLIツール『Fuga』です。
読み方は「フーガ」です。
実はちゃんと元ネタはあるのですが、「もしかしてこれでは?」と思うものがある方は、Twitterなどで是非絡んで下さい。

Fugaでできることは、前述の3つのコマンドmvcplnと同様で、「ファイル移動」、「ファイルコピー」、「シンボリックリンクの作成」です。
これらのコマンドと大きく異なる部分は、"マーキング"と"コマンド実行"の2ステップでファイル操作を行うことです。
(もし似たような機能を持ったコマンドが既に存在する場合、教えていただけると大変助かります…)

例えば、ファイルの移動を行う場合は、

  • 対象のファイルをマーキング (fuga mark <target>)
  • 移動先のディレクトリに移動
  • ファイル移動の実行 (fuga move)

のように行うことができます。

// ファイルのマーキング
$ fuga mark test.txt
✅ : 📄 test.txt has marked.

// 移動先のディレクトリへ移動
$ cd ../../..

$ cd path/to/directory/that/you/want/to/move

// ファイル移動の実行
$ fuga move
ℹ️ : Start moving 📄 test.txt from /path/to/source/directory
✅ : 📄 test.txt has moved.

コピーやシンボリックリンクについても基本的には操作は同様です。
マーキング後に以下のコマンドでコピーやシンボリックリンクの作成ができます。

  • fuga copy
  • fuga link

詳細についてはGitHubリポジトリのREADMEをご覧ください。

RustでのCLIツール開発

以前からちまちまとRustは勉強していましたが、実際に何かを作ったのは今回が初めてでした。
そのため、右も左もわからない状況で開発を進めました。
ベストプラクティスにどの程度近づけているのかは不明ですが、今回の開発で用いた主なライブラリをご紹介いたします。

CLIツール開発用ライブラリです。
サブコマンドやコマンドライン引数、フラグなどを簡単に設定できます。
コメントアウトを元にhelpコマンドなども自動で構築してくれるので、大変便利でした。

設定ファイルを簡単に構築し、読み込み・書き込みができるライブラリです。
~/.config以下に指定したディレクトリを自動で作成し、そこで設定ファイルを管理してくれます。
今回はマーキングしたパスをこちらの設定ファイルにて保存しています。

ファイル移動とコピーを実現するライブラリです。
Rustの標準ライブラリにも似たような機能はあるのですが、こちらの方がAPIが整理されており、簡単に使うことができました。
また、後述のindicatifとの相性が良かったのも選択した理由です。

ファイル移動やコピー実行時にプログレスバーを表示するライブラリです。
fs_extraにハンドラーとして渡すことで、ファイル操作の進捗状況を可視化できます。

まとめ

GWを使って、RustでCLIツールを開発してみました。
実は当初もっと多くの機能を考えていたのですが、GW中に完成しなさそうだったので、大幅に路線変更して現在の形になりました。
それらの機能についても今後実装していきたいと思っています。

Author Profile
liebe-magi

りーべ / liebe-magi

ものづくりが大好きな自称フルスタック(?)エンジニア。大学・大学院でコンピュータサイエンスを専攻し、現在は某企業の研究所所属。専門は組み合わせ最適化問題や機械学習など。主に使用している言語はPython、JavaScript (TypeScript)、Rust、Go。最近は競技プログラミングに興味を持ち、AtCoderのコンテスト (ABC) に毎週参加中 (現在緑)。趣味はマジック、漫画・アニメ、ゲーム(電源・電源問わず)。