Willkommen zu meiner YOLO-Reihe, in der ich einfache Tools und Projekte vorstelle, die ich erstellt habe – manchmal zum Spaß, manchmal zur Lösung spezifischer Probleme. und manchmal auch einfach aus reiner Neugier. Das Ziel besteht hier nicht nur darin, ein Werkzeug vorzustellen; Ich werde auch auf etwas Interessantes im Zusammenhang mit dem Prozess eingehen, sei es ein technischer Einblick oder eine Lektion, die ich bei der Erstellung dieser kleinen Experimente gelernt habe.
Niemand hat danach gefragt und niemand will es – aber hier ist es trotzdem. Lernen Sie rrm kennen, ein Tool, das ein Problem löst, das anscheinend nur ich habe (aber hey, es könnte ein Layer-8-Problem sein – oder, was wahrscheinlicher ist, ein Skill-Problem!).
rrm fügt Ihrer Befehlszeilenerfahrung eine zusätzliche Sicherheitsebene hinzu, indem es Dateien in einen Papierkorb verschiebt, anstatt sie dauerhaft zu löschen. Mit einer anpassbaren Kulanzfrist haben Sie die Möglichkeit zu erkennen: „Ups, das habe ich tatsächlich gebraucht!“ bevor es zu spät ist.
Darüber hinaus ist rrm nicht auf externe Konfigurationsdateien oder Trackingsysteme angewiesen, um gelöschte Dateien zu verwalten. Stattdessen nutzt es die erweiterten Attribute Ihres Dateisystems, um wichtige Metadaten – wie den ursprünglichen Dateipfad und die Löschzeit – direkt im gelöschten Element zu speichern.
Sie fragen sich vielleicht: „Warum baue ich dieses Tool, wenn es ähnliche, möglicherweise bessere Tools gibt?“ Nun, die Antwort ist einfach:
Unterhaltsame Anmerkung: Während der Arbeit mit std::Path habe ich ein Beispiel in der Rust-Standardbibliothek gefunden, das einen Ordner namens laputa
verwendet. Ich weiß, es ist eine Anspielung auf „Castle in the Sky“, aber für Spanischsprachige ist es auch ein Schimpfwort, was es für mich zu einem lustigen Moment machte!<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>Als ich mit der Entwicklung von rrm begann, brauchte ich eine Möglichkeit, den ursprünglichen Pfad gelöschter Dateien und den Zeitpunkt zu verfolgen, zu dem sie dauerhaft entfernt werden sollten. Ich wollte keine JSON-Datei verwenden oder ein seltsames Namensformat implementieren, das diese Informationen enthält – insbesondere, wenn ich später mehr Daten speichern wollte. Eine Datenbank kam mir für eine so kleine Aufgabe wie ein Overkill vor.
Da entdeckte ich erweiterte Attribute.
Nun, ich weiß nicht, wie es Ihnen geht, aber ich wusste nicht, dass es einen integrierten Mechanismus gibt, mit dem Sie benutzerdefinierte Metadaten zu Dateien hinzufügen können, der von den meisten Linux-Dateisystemen und Unix-ähnlichen Systemen wie macOS unterstützt wird . Diese Funktion wird als erweiterte Dateiattribute bezeichnet. Verschiedene Systeme haben ihre eigenen Einschränkungen – z. B. wie viele Daten hinzugefügt werden können oder welche spezifischen Namespaces verwendet werden – aber sie ermöglichen das Speichern benutzerdefinierter Metadaten.
Erweiterte Attribute sind im Wesentlichen Name:Wert-Paare, die dauerhaft mit Dateien und Verzeichnissen verknüpft sind. Wie ich bereits erwähnt habe, unterscheiden sich die Systeme darin, wie sie damit umgehen. Unter Linux beginnt der Name beispielsweise mit einer Namespace-ID. Es gibt vier solcher Namespaces: Sicherheit, System, Vertrauenswürdig und Benutzer. Unter Linux beginnt der Name mit einem dieser Namen, gefolgt von einem Punkt („.“) und einer nullterminierten Zeichenfolge. Unter macOS sind die Dinge etwas anders. macOS benötigt dank seines Unified Metadata Approach überhaupt keine Namespaces, der erweiterte Attribute als zusätzliche Metadaten behandelt, die direkt mit Dateien verknüpft sind, ohne dass sie kategorisiert werden müssen.
In dieser winzigen CLI verwende ich den Crate xattr, der sowohl Linux als auch macOS unterstützt. Was die Namensräume betrifft, die ich zuvor für Linux erwähnt habe, konzentrieren wir uns auf den Benutzernamensraum, da diese Attribute für die Verwendung durch den Benutzer gedacht sind. Im Code sehen Sie also etwa Folgendes:
/// 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); ... }
Das Attribut #[cfg(target_os = "macos")] in Rust wird verwendet, um Code basierend auf dem Zielbetriebssystem bedingt zu kompilieren. In diesem Fall wird sichergestellt, dass der Codeblock nur beim Kompilieren für macOS eingebunden wird. Dies ist relevant, da macOS, wie bereits erwähnt, keinen Namespace für erweiterte Attribute benötigt, sodass XATTR_NAMESPACE auf eine leere Zeichenfolge gesetzt ist. Bei anderen Betriebssystemen ist der Namespace auf „user“ eingestellt. Diese bedingte Kompilierung ermöglicht eine nahtlose Anpassung des Codes an verschiedene Plattformen, wodurch die CLI mit Linux und macOS kreuzkompatibel wird.
Eine Sache, die ich an erweiterten Attributen ziemlich cool fand, ist, dass sie die Datei selbst nicht ändern. Die Metadaten befinden sich in einem separaten Speicherplatz, auf den der Inode verweist. Das bedeutet, dass der eigentliche Inhalt der Datei unverändert bleibt. Wenn wir beispielsweise eine einfache Datei erstellen und Shasum verwenden, um ihre Prüfsumme zu erhalten:
Der Inode (Indexknoten) ist eine Datenstruktur in einem Dateisystem im Unix-Stil, die ein Dateisystemobjekt wie eine Datei oder ein Verzeichnis beschreibt. Link
/// 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); ... }
Nachdem wir die Datei mit rrm gelöscht haben, können wir die gelöschten Dateien auflisten und sehen, dass die Datei mit intakten Metadaten in den Papierkorb verschoben wurde:
$ cat a.txt https://www.kungfudev.com/ $ shasum a.txt e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 a.txt
Wie Sie sehen können, wird der Dateiname in eine UUID geändert. Dies geschieht, um Namenskollisionen beim Löschen von Dateien mit demselben Namen zu vermeiden. Durch die Zuweisung einer eindeutigen Kennung zu jeder Datei stellt rrm sicher, dass jede gelöschte Datei, auch wenn sie identische Namen hat, problemlos nachverfolgt und wiederhergestellt werden kann.
Wir können zum Papierkorbordner navigieren und die Datei überprüfen, um sicherzustellen, dass ihr Inhalt unverändert bleibt:
$ 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 │ ╰──────────────────────────────────────────────────────┴──────────────────────────────────────┴──────┴─────────────────────╯
Darüber hinaus können wir durch die Verwendung von xattr unter macOS überprüfen, ob die Datei über Metadaten wie das Löschdatum und den ursprünglichen Pfad verfügt:
$ shasum 3f566788-75dc-4674-b069-0faeaa86aa55 e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 3f566788-75dc-4674-b069-0faeaa86aa55
Sie können sich die Bandbreite möglicher Anwendungsfälle für einfache Validierungen oder Aktionen mithilfe dieser Metadaten vorstellen. Da erweiterte Attribute funktionieren, ohne die Datei selbst zu ändern, ermöglichen sie Ihnen, die Dateiintegrität zu überprüfen oder andere Vorgänge durchzuführen, ohne den ursprünglichen Inhalt zu beeinträchtigen.
Dies ist nur eine kleine Einführung in erweiterte Attribute und wie sie in diesem Projekt verwendet werden. Es ist nicht als ausführliche Erklärung gedacht, aber wenn Sie mehr erfahren möchten, gibt es zahlreiche detaillierte Ressourcen. Hier sind ein paar Links zu den nützlichsten und am besten beschriebenen Ressourcen zu diesem Thema:
Ich habe ein paar Jahre mit Go gearbeitet und mir sind bestimmte Muster ans Herz gewachsen – ich spötte, weil ich eines davon bin. In Go führe ich die Dinge normalerweise selbst aus, wenn dadurch unnötige Importe vermieden werden oder ich mehr Flexibilität habe. Ich bin an diesen Ansatz so gewöhnt, dass ich, als ich anfing, Tests in Rust zu schreiben, es vorzog, bestimmte Dinge manuell zu verspotten, wie zum Beispiel die Erstellung von Scheinimplementierungen von Merkmalen.
Zum Beispiel habe ich in dieser winzigen CLI eine Eigenschaft erstellt, um den Papierkorb-Manager von der Art und Weise zu entkoppeln, wie er mit den erweiterten Attributen interagiert. Das Trait mit dem Namen ExtendedAttributes war ursprünglich zu Testzwecken gedacht, aber auch, weil ich nicht sicher war, ob ich xattr oder eine andere Implementierung verwenden würde. Also habe ich das folgende Merkmal definiert:
$ 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
In Go würde ich so etwas wie das Folgende erstellen, das eine einfache Implementierung der zuvor erwähnten Schnittstelle bereitstellt. Der folgende Code ist unkompliziert und wird ohne große Überlegung generiert, nur als Beispiel:
/// 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); ... }
Dann würde ich mein Modell verwenden und das spezifische Verhalten einbauen, das für jeden Test erforderlich ist. Auch dies ist ein einfacher Code nur als Beispiel:
$ cat a.txt https://www.kungfudev.com/ $ shasum a.txt e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 a.txt
Ich habe mich in Go an dieses Muster gewöhnt und habe vor, es weiterhin zu verwenden. Aber ich habe auch etwas Ähnliches in Rust gemacht. Für dieses Projekt habe ich beschlossen, die Mockall-Kiste auszuprobieren, und ich fand sie wirklich nützlich.
Zuerst habe ich das Mock verwendet! Makro, um meine Struktur manuell zu verspotten. Ich weiß, dass Mockall über eine Automock-Funktion verfügt, aber ich definiere die Mock-Struktur lieber direkt in meinen Tests, wo sie verwendet wird. Lassen Sie mich wissen, ob dies etwas Gemeinsames ist oder ob die Community dafür einen anderen Standard hat.
$ 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 │ ╰──────────────────────────────────────────────────────┴──────────────────────────────────────┴──────┴─────────────────────╯
Ich fand Mockall wirklich nützlich, da es mir ermöglichte, bestimmte Verhaltensweisen in meine Tests einzubauen, ohne die Ausführlichkeit meines alten Musters.
$ shasum 3f566788-75dc-4674-b069-0faeaa86aa55 e4c51607d5e7494143ffa5a20b73aedd4bc5ceb5 3f566788-75dc-4674-b069-0faeaa86aa55
Wie wir sehen können, gibt uns Mockall die Möglichkeit, mithilfe seiner Mock-Methoden spezifische Verhaltensweisen für unsere Tests zu definieren:
Einige von Ihnen finden das vielleicht sehr einfach oder nicht so interessant, aber wie ich bereits erwähnt habe, teile ich in dieser YOLO-Serie Dinge, die ich interessant finde oder über die ich einfach sprechen möchte. Ich war kein großer Fan der Verwendung dieser Art von Bibliothek in Go, teilweise aufgrund der Einschränkungen von Go, aber in Rust fand ich Mockall wirklich nützlich. Es erinnerte mich sogar an meine alten Tage mit Python.
Auch dieser Abschnitt war nicht dazu gedacht, das Verspotten in Rust oder Mockall zu erklären. Ich bin mir sicher, dass es viele großartige Ressourcen gibt, die das im Detail behandeln. Ich wollte es nur kurz erwähnen.
In diesem Beitrag habe ich einige der Gründe für den Aufbau von rrm und die Tools, die ich dabei verwendet habe, mitgeteilt. Von der Verwendung erweiterter Attribute zur Vereinfachung der Metadatenverarbeitung bis hin zum Experimentieren mit der Mockall-Kiste zum Testen in Rust – das waren nur Dinge, die mein Interesse geweckt haben.
Das Ziel dieser YOLO-Reihe ist es, den Spaß und das Lernen hervorzuheben, die mit dem Bau selbst einfacher Werkzeuge einhergehen. Ich hoffe, Sie haben hier etwas Nützliches gefunden und freue mich darauf, in zukünftigen Beiträgen weitere Projekte und Erkenntnisse zu teilen. Feedback ist wie immer willkommen!
Viel Spaß beim Codieren!
Das obige ist der detaillierte Inhalt vonMit Rost spielen: Ein sichereres Unternehmen aufbauen und dabei Spaß haben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!