From 8e4c2762cdb3e42662773e372dba54bf55bf1be5 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Fri, 15 May 2026 00:42:39 -0500 Subject: [PATCH] reordered close --- src/close_operation.rs | 50 +++++++++++++++++++++--------------------- src/main.rs | 6 ++--- test.sh | 26 +++++++++++++++++----- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/close_operation.rs b/src/close_operation.rs index 5acf4cf..1f9076e 100644 --- a/src/close_operation.rs +++ b/src/close_operation.rs @@ -8,32 +8,32 @@ use crate::utils::*; #[derive(Parser, Debug, PartialEq)] pub struct CloseOperation { - pub drawer_file: PathBuf, - pub target_path: Option, + pub target_path: PathBuf, + pub drawer_file: Option, #[arg(short = 'i')] pub key: Option, } impl Operation for CloseOperation { fn validate(&self) -> Result<(), DrawerError> { - validate_drawer_extension(&self.drawer_file)?; + let drawer_file = self.drawer_file.as_ref().cloned() + .unwrap_or_else(|| self.target_path.with_extension("drawer")); + validate_drawer_extension(&drawer_file)?; validate_ssh_key(&self.key)?; - let target = self.target_path.as_ref().cloned() - .unwrap_or_else(|| default_target(&self.drawer_file, None)); - let meta = std::fs::metadata(&target) - .map_err(|_| DrawerError::TargetInvalid(target.clone()))?; + let meta = std::fs::metadata(&self.target_path) + .map_err(|_| DrawerError::TargetInvalid(self.target_path.clone()))?; if !meta.is_dir() && !meta.is_file() { - return Err(DrawerError::TargetInvalid(target.clone())); + return Err(DrawerError::TargetInvalid(self.target_path.clone())); } - if meta.is_dir() && std::fs::read_dir(&target).is_err() { - return Err(DrawerError::TargetInvalid(target.clone())); + if meta.is_dir() && std::fs::read_dir(&self.target_path).is_err() { + return Err(DrawerError::TargetInvalid(self.target_path.clone())); } - let canon_target = target.canonicalize() - .unwrap_or_else(|_| target.clone()); - let drawer_parent = parent_or_dot(&self.drawer_file); + let canon_target = self.target_path.canonicalize() + .unwrap_or_else(|_| self.target_path.clone()); + let drawer_parent = parent_or_dot(&drawer_file); let canon_drawer = drawer_parent.canonicalize() .unwrap_or_else(|_| drawer_parent.to_path_buf()) - .join(self.drawer_file.file_name().unwrap_or_default()); + .join(drawer_file.file_name().unwrap_or_default()); if canon_drawer.starts_with(&canon_target) { return Err(DrawerError::DrawerInsideTarget); } @@ -41,22 +41,22 @@ impl Operation for CloseOperation { } fn execute(&self) -> Result<(), DrawerError> { - let target = self.target_path.as_ref().cloned() - .unwrap_or_else(|| default_target(&self.drawer_file, None)); - if self.target_path.is_none() { - println!("(assuming from {})", target.display()); + let drawer_file = self.drawer_file.as_ref().cloned() + .unwrap_or_else(|| self.target_path.with_extension("drawer")); + if self.drawer_file.is_none() { + println!("(creating {})", drawer_file.display()); } let mut buf: Vec = Vec::new(); { let gz = GzEncoder::new(&mut buf, Compression::default()); let mut archive = tar::Builder::new(gz); - if target.is_dir() { - archive.append_dir_all(".", &target) + if self.target_path.is_dir() { + archive.append_dir_all(".", &self.target_path) .map_err(|_| DrawerError::TarFailed)?; } else { - let name = target.file_name().unwrap_or_default(); - archive.append_path_with_name(&target, name) + let name = self.target_path.file_name().unwrap_or_default(); + archive.append_path_with_name(&self.target_path, name) .map_err(|_| DrawerError::TarFailed)?; } let gz = archive.into_inner() @@ -65,8 +65,8 @@ impl Operation for CloseOperation { .map_err(|_| DrawerError::TarFailed)?; } - let encrypted = encrypt(&buf, &self.key, &self.drawer_file)?; - std::fs::write(&self.drawer_file, &encrypted) - .map_err(|_| DrawerError::WriteFailed(self.drawer_file.clone())) + let encrypted = encrypt(&buf, &self.key, &drawer_file)?; + std::fs::write(&drawer_file, &encrypted) + .map_err(|_| DrawerError::WriteFailed(drawer_file.clone())) } } diff --git a/src/main.rs b/src/main.rs index 0f6e8c8..f216b25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,12 +32,12 @@ mod tests { #[test] fn test_basic_close() { - let op = parse_args(vec!["drawer", "close", "blah.drawer", "-i", "foo.key", "blah"]); + let op = parse_args(vec!["drawer", "close", "blah", "-i", "foo.key", "blah.drawer"]); assert_eq!(op, Ok( Command::Close(CloseOperation{ - drawer_file: "blah.drawer".into(), + drawer_file: Some("blah.drawer".into()), key: Some(PathBuf::from("foo.key")), - target_path: Some("blah".into()), + target_path: "blah".into(), }) )) } diff --git a/test.sh b/test.sh index 8c7ac80..f079e37 100755 --- a/test.sh +++ b/test.sh @@ -47,10 +47,10 @@ err "key: refuse missing parent" $DRAWER key "$WORK/nosuchdir/test.key" DRAWER_FILE="$WORK/test.drawer" -ok "close: pack test dir" $DRAWER close -i "$KEY" "$DRAWER_FILE" "$TEST_DIR" -err "close: refuse without key" DRAWER_KEY="" $DRAWER close "$DRAWER_FILE" "$TEST_DIR" -err "close: refuse bad key" $DRAWER close -i "$WORK/notakey" "$DRAWER_FILE" "$TEST_DIR" -err "close: refuse bad extension" $DRAWER close -i "$KEY" "$WORK/test.notadrawer" "$TEST_DIR" +ok "close: pack test dir" $DRAWER close -i "$KEY" "$TEST_DIR" "$DRAWER_FILE" +err "close: refuse without key" DRAWER_KEY="" $DRAWER close "$TEST_DIR" "$DRAWER_FILE" +err "close: refuse bad key" $DRAWER close -i "$WORK/notakey" "$TEST_DIR" "$DRAWER_FILE" +err "close: refuse bad extension" $DRAWER close -i "$KEY" "$TEST_DIR" "$WORK/test.notadrawer" # ── open ───────────────────────────────────────────────────────────────────── @@ -76,11 +76,25 @@ err "open: refuse bad key" $DRAWER open -i "$WORK/notakey" "$DRAWER_FI INFER_DRAWER="$WORK/inferred.drawer" INFER_OUT="$WORK/inferred" -ok "close: inferred source" $DRAWER close -i "$KEY" "$INFER_DRAWER" "$TEST_DIR" +ok "close: inferred source" $DRAWER close -i "$KEY" "$TEST_DIR" "$INFER_DRAWER" mkdir -p "$INFER_OUT" ok "open: inferred target" $DRAWER open -i "$KEY" "$INFER_DRAWER" "$INFER_OUT" ok "open: inferred file1.md" test -f "$INFER_OUT/file1.md" +# ── close: inferred drawer file ────────────────────────────────────────────── + +INFER_CLOSE_SRC="$WORK/myproject" +INFER_CLOSE_DRAWER="$WORK/myproject.drawer" +cp -r "$TEST_DIR" "$INFER_CLOSE_SRC" + +ok "close: inferred drawer file" $DRAWER close -i "$KEY" "$INFER_CLOSE_SRC" +ok "close: drawer file created" test -f "$INFER_CLOSE_DRAWER" + +INFER_CLOSE_OUT="$WORK/myproject_out" +mkdir -p "$INFER_CLOSE_OUT" +ok "close: inferred round-trip open" $DRAWER open -i "$KEY" "$INFER_CLOSE_DRAWER" "$INFER_CLOSE_OUT" +ok "close: inferred round-trip file1" test -f "$INFER_CLOSE_OUT/file1.md" + # ── info ───────────────────────────────────────────────────────────────────── $DRAWER info -i "$KEY" "$DRAWER_FILE" 2>/dev/null | grep -q "folder, 2 files" \ @@ -96,7 +110,7 @@ SINGLE_DRAWER="$WORK/file1.drawer" SINGLE_OUT_DIR="$WORK/single_out" mkdir -p "$SINGLE_OUT_DIR" -ok "close: single file" $DRAWER close -i "$KEY" "$SINGLE_DRAWER" "$SINGLE_SRC" +ok "close: single file" $DRAWER close -i "$KEY" "$SINGLE_SRC" "$SINGLE_DRAWER" $DRAWER info -i "$KEY" "$SINGLE_DRAWER" 2>/dev/null | grep -q "file, " \ && pass "info: reports single file" || fail "info: reports single file" ok "open: single file" $DRAWER open -i "$KEY" "$SINGLE_DRAWER" "$SINGLE_OUT_DIR/file1.md"