私の YOLO シリーズへようこそ。ここでは私が構築した単純なツールとプロジェクトを紹介します。時には楽しみのために、時には特定の問題を解決するために、あるいは単に純粋な好奇心からの場合もあります。ここでの目標は、ツールを提供することだけではありません。また、技術的な洞察や、これらの小さな実験を作成する際に学んだ教訓など、プロセスに関連した興味深い内容についても詳しく説明します。
誰もそれを求めていませんし、誰もそれを望んでいません—しかし、とにかくそれはここにあります。 rrm をご紹介します。これは、私だけが抱えていると思われる問題を解決するツールです (ただし、これはレイヤー 8 の問題である可能性があります。あるいは、スキルの問題である可能性が高いです!)。
rrm は、ファイルを完全に削除するのではなく、ゴミ箱に移動することにより、コマンドライン エクスペリエンスに安全層を追加します。カスタマイズ可能な猶予期間を使用すると、手遅れになる前に 「ああ、これが本当に必要だったんだ!」 と気づく機会が得られます。
さらに、rrm は削除されたファイルを管理するために外部設定ファイルや追跡システムに依存しません。代わりに、ファイルシステムの拡張属性を利用して、元のファイルのパスや削除時刻などの重要なメタデータをゴミ箱に入れられたアイテム内に直接保存します。
あなたは疑問に思っているかもしれません。「類似した、おそらくより優れたツールが存在するのに、なぜこのツールを作成するのでしょうか?」 答えは簡単です:
面白いメモ: std::Path を使って作業しているときに、Rust 標準ライブラリで laputa
という名前のフォルダーを使用する例を見つけました。これが天空の城ラピュタを引用していることはわかっていますが、スペイン語話者にとっては呪いの言葉でもあり、私にとっては面白い瞬間でした!<script> // Detect dark theme var iframe = document.getElementById('tweet-1844834987184410735-190'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1844834987184410735&theme=dark" } </script>私が rrm の構築を開始したとき、削除されたファイルの元のパスとそれらが永久に削除されるべき時間を追跡する方法が必要でした。特に後でさらに多くのデータを保存したい場合には、JSON ファイルを使用したり、この情報を含む奇妙な命名形式を実装したくありませんでした。このような小さなタスクに対してデータベースは過剰に感じられました。
そのとき、拡張属性を発見しました。
皆さんはどうか知りませんが、ファイルにカスタム メタデータを追加できる組み込みメカニズムがあるとは知りませんでした。これは、ほとんどの Linux ファイルシステムと macOS などの Unix 系システムでサポートされています。 。この機能は拡張ファイル属性と呼ばれます。システムごとに、追加できるデータの量や使用される特定の名前空間など、独自の制限がありますが、ユーザー定義のメタデータを保存できます。
拡張属性は本質的に、ファイルとディレクトリに永続的に関連付けられる名前:値のペアです。前に述べたように、これを処理する方法はシステムによって異なります。たとえば、Linux では、名前は名前空間識別子で始まります。このような名前空間には、セキュリティ、システム、信頼済み、ユーザーの 4 つがあります。 Linux では、名前はこれらのいずれかで始まり、その後にドット (「.」)、そして NULL で終わる文字列が続きます。 macOS では、状況が少し異なります。 macOS は、統合メタデータ アプローチ のおかげで、名前空間をまったく必要としません。これは、拡張属性を、分類することなくファイルに直接関連付けられた追加のメタデータとして扱います。
この小さな CLI では、Linux と macOS の両方をサポートするクレート xattr を使用しています。 Linux について前述した名前空間については、ユーザー名前空間に焦点を当てます。これらの属性はユーザーが使用することを目的としているためです。したがって、コードには次のような内容が表示されます:
/// Namespace for extended attributes (xattrs) on macOS and other operating systems. /// On macOS, this is an empty string, while on other operating systems, it is "user.". #[cfg(target_os = "macos")] const XATTR_NAMESPACE: &str = ""; #[cfg(not(target_os = "macos"))] const XATTR_NAMESPACE: &str = "user."; ... fn set_attr(&self, path: &Path, attr: &str, value: &str) -> Result<()> { let attr_name = format!("{}{}", XATTR_NAMESPACE, attr); ... }
Rust の #[cfg(target_os = "macos")] 属性は、ターゲット オペレーティング システムに基づいてコードを条件付きでコンパイルするために使用されます。この場合、macOS 用にコンパイルする場合にのみコード ブロックが含まれることが保証されます。これが関係するのは、前述したように、macOS では拡張属性に名前空間が必要ないため、XATTR_NAMESPACE は空の文字列に設定されるからです。他のオペレーティング システムの場合、名前空間は「user.」に設定されます。この条件付きコンパイルにより、コードがさまざまなプラットフォーム間でシームレスに適応できるようになり、CLI が Linux と macOS の両方と相互互換性を持つようになります。
拡張属性について非常に優れていると感じた点の 1 つは、拡張属性がファイル自体を変更しないことです。メタデータは、inode によって参照される別のディスク領域に存在します。これは、ファイルの実際の内容が変更されないことを意味します。たとえば、単純なファイルを作成し、shasum を使用してそのチェックサムを取得するとします。
inode (インデックス ノード) は、ファイルやディレクトリなどのファイル システム オブジェクトを記述する Unix スタイルのファイル システムのデータ構造です。リンク
/// Namespace for extended attributes (xattrs) on macOS and other operating systems. /// On macOS, this is an empty string, while on other operating systems, it is "user.". #[cfg(target_os = "macos")] const XATTR_NAMESPACE: &str = ""; #[cfg(not(target_os = "macos"))] const XATTR_NAMESPACE: &str = "user."; ... fn set_attr(&self, path: &Path, attr: &str, value: &str) -> Result<()> { let attr_name = format!("{}{}", XATTR_NAMESPACE, attr); ... }
rrm を使用してファイルを削除した後、削除されたファイルを一覧表示すると、ファイルがメタデータをそのままにしてゴミ箱に移動されたことが確認できます。
$ cat a.txt https://www.kungfudev.com/ $ shasum a.txt e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 a.txt
ご覧のとおり、ファイル名が UUID に変更されます。これは、同じ名前のファイルを削除するときに名前の衝突を避けるために行われます。 rrm は、各ファイルに一意の識別子を割り当てることにより、削除されたすべてのファイル(名前が同じであっても)を問題なく追跡および復元できるようにします。
ゴミ箱フォルダーに移動し、ファイルを検査して、その内容が変更されていないことを確認できます。
$ rrm rm a.txt $ rrm list ╭──────────────────────────────────────────────────────┬──────────────────────────────────────┬──────┬─────────────────────╮ │ Original Path ┆ ID ┆ Kind ┆ Deletion Date │ ╞══════════════════════════════════════════════════════╪══════════════════════════════════════╪══════╪═════════════════════╡ │ /Users/douglasmakey/workdir/personal/kungfudev/a.txt ┆ 3f566788-75dc-4674-b069-0faeaa86aa55 ┆ File ┆ 2024-10-27 04:10:19 │ ╰──────────────────────────────────────────────────────┴──────────────────────────────────────┴──────┴─────────────────────╯
さらに、macOS で xattr を使用すると、ファイルに削除日や元のパスなどのメタデータがあることを確認できます。
$ shasum 3f566788-75dc-4674-b069-0faeaa86aa55 e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 3f566788-75dc-4674-b069-0faeaa86aa55
このメタデータを使用した単純な検証やアクションの潜在的なユースケースの範囲を想像できます。拡張属性はファイル自体を変更せずに機能するため、元のコンテンツに影響を与えることなく、ファイルの整合性をチェックしたり、その他の操作を実行したりできます。
これは、拡張属性とそれがこのプロジェクトでどのように使用されるかを簡単に紹介したものです。詳細な説明を目的としたものではありませんが、さらに詳しく知りたい場合は、詳細なリソースがたくさんあります。このトピックに関する最も有用でよく説明されたリソースへのリンクをいくつか示します:
私は Go を使って数年間仕事をしてきましたが、特定のパターンが好きになり、そのパターンの 1 つであることを嘲笑しています。 Go では、不必要なインポートを回避したり、柔軟性を高めたりする場合は、通常、自分で実装します。私はこのアプローチに慣れているため、Rust でテストを書き始めたとき、特性のモック実装の作成など、特定のものを手動でモックすることを好む自分に気づきました。
たとえば、この小さな CLI では、ゴミ箱マネージャーを拡張属性と対話する方法から切り離す特性を作成しました。 ExtendedAttributes という名前のこのトレイトは、当初はテスト目的でしたが、xattr を使用するか別の実装を使用するか確信がなかったためでもありました。そこで、次の特性を定義しました:
$ xattr -l 3f566788-75dc-4674-b069-0faeaa86aa55 deletion_date: 2024-10-27T04:10:19.875614+00:00 original_path: /Users/douglasmakey/workdir/personal/kungfudev/a.txt
Go では、前述のインターフェイスの簡単な実装を提供する次のようなものを作成します。以下のコードは単純であり、単なる例として、あまり考慮せずに生成されています。
/// Namespace for extended attributes (xattrs) on macOS and other operating systems. /// On macOS, this is an empty string, while on other operating systems, it is "user.". #[cfg(target_os = "macos")] const XATTR_NAMESPACE: &str = ""; #[cfg(not(target_os = "macos"))] const XATTR_NAMESPACE: &str = "user."; ... fn set_attr(&self, path: &Path, attr: &str, value: &str) -> Result<()> { let attr_name = format!("{}{}", XATTR_NAMESPACE, attr); ... }
次に、モックを使用して、各テストに必要な特定の動作を挿入します。繰り返しますが、これは例を目的とした単純なコードです:
$ cat a.txt https://www.kungfudev.com/ $ shasum a.txt e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 a.txt
Go のこのパターンには慣れてきたので、今後も使用していくつもりです。しかし、私はRustでも同様のことを行ってきました。このプロジェクトでは、モコール クレートを試してみることにしました。これが非常に便利であることがわかりました。
まずはモックを使ってみました!私の構造を手動でモックするマクロ。モックコールにオートモック機能があることは知っていますが、使用されるテストでモック構造体を直接定義することを好みます。 これが一般的なことなのか、それともコミュニティでこれとは異なる基準があるのかを教えてください。
$ rrm rm a.txt $ rrm list ╭──────────────────────────────────────────────────────┬──────────────────────────────────────┬──────┬─────────────────────╮ │ Original Path ┆ ID ┆ Kind ┆ Deletion Date │ ╞══════════════════════════════════════════════════════╪══════════════════════════════════════╪══════╪═════════════════════╡ │ /Users/douglasmakey/workdir/personal/kungfudev/a.txt ┆ 3f566788-75dc-4674-b069-0faeaa86aa55 ┆ File ┆ 2024-10-27 04:10:19 │ ╰──────────────────────────────────────────────────────┴──────────────────────────────────────┴──────┴─────────────────────╯
モックコールは非常に便利で、古いパターンの冗長さを省いて特定の動作をテストに挿入できることがわかりました。
$ shasum 3f566788-75dc-4674-b069-0faeaa86aa55 e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 3f566788-75dc-4674-b069-0faeaa86aa55
ご覧のとおり、モックコールでは、モック メソッドを使用してテストの特定の動作を定義する機能が提供されます。
これは超基本的な内容だったり、それほど面白くないと思う人もいるかもしれませんが、前述したように、この YOLO シリーズでは、私が面白いと思うものや話したいことを共有しています。私は Go の制約もあって、この種のライブラリを Go で使用することはあまり好きではありませんでしたが、Rust ではモコールが非常に便利であることがわかりました。 Python を使っていた昔のことさえ思い出しました。
繰り返しになりますが、このセクションは Rust またはモコールでのモックを説明することを目的としたものではありません。詳細をカバーする素晴らしいリソースがたくさんあると思います。簡単に触れておきたかっただけです。
この投稿では、rrm の構築の背後にある理由の一部と、その過程で使用したツールを共有しました。メタデータの処理を簡素化するための拡張属性の使用から、Rust でのテスト用のモックオール クレートの実験まで、これらは私の興味をそそるものでした。
この YOLO シリーズの目標は、たとえ単純なツールでも構築することに伴う楽しさと学習を強調することです。ここで何か役に立つことがあれば幸いです。今後の投稿でさらに多くのプロジェクトや洞察を共有できることを楽しみにしています。いつものように、フィードバックは大歓迎です!
コーディングを楽しんでください!
以上がRust で遊ぶ: より安全な rm を構築し、途中で楽しむの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。