때로는 재미로, 때로는 특정 문제를 해결하기 위해 제가 만든 간단한 도구와 프로젝트를 선보이는 YOLO 시리즈에 오신 것을 환영합니다. 때로는 순수한 호기심 때문이기도 합니다. 여기서의 목표는 단지 도구를 제시하는 것이 아닙니다. 또한 기술적인 통찰력이든 이 작은 실험을 하면서 얻은 교훈이든 프로세스와 관련된 흥미로운 내용에 대해서도 자세히 알아볼 것입니다.
아무도 요청하지 않았고 원하지도 않았지만 어쨌든 여기 있습니다. 나만 가지고 있는 문제(하지만 레이어 8 문제일 수도 있고 기술 문제일 가능성이 더 높음)를 해결하는 도구인 rrm을 만나보세요.
rrm은 파일을 영구적으로 삭제하는 대신 휴지통으로 이동하여 명령줄 환경에 보안을 강화합니다. 사용자 정의 가능한 유예 기간을 통해 너무 늦기 전에 "아, 사실 그게 필요했어!"라는 사실을 깨달을 수 있는 기회를 얻게 됩니다.
게다가 rrm은 삭제된 파일을 관리하기 위해 외부 구성 파일이나 추적 시스템에 의존하지 않습니다. 대신 파일 시스템의 확장 속성을 활용하여 원본 파일 경로 및 삭제 시간과 같은 필수 메타데이터를 휴지통에 버린 항목 내에 직접 저장합니다.
"비슷하고 더 나은 도구가 있는데 왜 이 도구를 만드는가?"라고 궁금해하실 수도 있습니다. 대답은 간단합니다.
재미있는 참고 사항: std::Path로 작업하는 동안 Rust 표준 라이브러리에서 laputa
라는 폴더를 사용하는 예제를 발견했습니다. 캐슬 인 더 스카이(Castle in the Sky)에 대한 언급인 것은 알지만, 스페인어 사용자들에게는 욕이기도 해서 재미있는 순간이었습니다!<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에서는 이름이 네임스페이스 식별자로 시작됩니다. 이러한 네임스페이스에는 보안, 시스템, 신뢰할 수 있는 및 사용자의 네 가지가 있습니다. 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와 상호 호환됩니다.
확장 속성에 대해 제가 느낀 한 가지 멋진 점은 파일 자체를 수정하지 않는다는 것입니다. 메타데이터는 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를 사용하면서 특정 패턴을 좋아하게 되었습니다. 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에서도 비슷한 일을 해왔습니다. 이번 프로젝트에서는 모콜 크레이트를 사용해보기로 했는데 정말 유용하더군요.
먼저 모의를 이용했어요! 내 구조를 수동으로 조롱하는 매크로입니다. 나는 mockall에 자동 모의 기능이 있다는 것을 알고 있지만, 그것이 사용될 테스트에서 직접 모의 구조체를 정의하는 것을 선호합니다. 이것이 일반적인 경우인지, 커뮤니티에서 이에 대해 다른 기준을 적용하는지 알려주세요.
$ 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
보시다시피 mockall은 모의 메서드를 사용하여 테스트에 대한 특정 동작을 정의하는 기능을 제공합니다.
이게 아주 기본적이거나 별로 흥미롭지 않다고 생각하시는 분들도 계시겠지만, 말씀드렸듯이 이번 YOLO 시리즈에서는 제가 흥미롭거나 그냥 이야기하고 싶은 것들을 공유하고 있습니다. 나는 부분적으로 Go의 제약 때문에 Go에서 이런 종류의 라이브러리를 사용하는 것을 별로 좋아하지 않았지만 Rust에서는 mockall이 정말 유용하다는 것을 알았습니다. Python을 사용하던 시절이 생각나기도 했습니다.
다시 말하지만, 이 섹션은 Rust나 mockall에서의 조롱을 설명하기 위한 것이 아닙니다. 나는 그것을 자세히 다루는 훌륭한 자료가 많이 있다고 확신합니다. 간단하게 언급하고 싶었습니다.
이번 게시물에서는 rrm을 구축하는 이유와 그 과정에서 사용한 도구를 공유했습니다. 확장된 속성을 사용하여 메타데이터 처리를 단순화하는 것부터 Rust에서 테스트하기 위해 모의콜 크레이트를 실험하는 것까지, 이러한 것들이 제 관심을 끌었습니다.
이 YOLO 시리즈의 목표는 간단한 도구를 만드는 데서 오는 재미와 학습을 강조하는 것입니다. 여기에서 유용한 정보를 찾으셨기를 바랍니다. 향후 게시물에서 더 많은 프로젝트와 통찰력을 공유할 수 있기를 기대합니다. 언제나처럼 피드백을 환영합니다!
즐거운 코딩하세요!
위 내용은 Rust와 함께 놀기: 더 안전한 rm을 구축하고 그 과정에서 즐거운 시간을 보내세요의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!