Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub fn check_file_signature(
path: &Path,
extensions: &[Extension],
question_policy: QuestionPolicy,
question_action: QuestionAction,
) -> Result<CheckFileSignatureControlFlow> {
debug_assert!(path.file_name().is_some());

Expand Down Expand Up @@ -71,7 +72,7 @@ pub fn check_file_signature(
);

// TODO: change question to: "do you want to proceed regardless of that"?
if !user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
if !user_wants_to_continue(path, question_policy, question_action)? {
return Ok(CheckFileSignatureControlFlow::HaltProgram);
}

Expand Down
4 changes: 2 additions & 2 deletions src/commands/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub fn list_archive_contents(
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Listing)? {
return Ok(());
}
}
Expand Down Expand Up @@ -138,7 +138,7 @@ pub fn list_archive_contents(
// Make thread own locks to keep output messages adjacent
let locks = lock_and_flush_output_stdio();
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Listing)? {
return Ok(());
}
drop(locks);
Expand Down
9 changes: 7 additions & 2 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,12 @@ pub fn run(args: CliArgs, question_policy: QuestionPolicy, file_visibility_polic
let (output_path, mut extensions) = extension::separate_known_extensions_from_name(path)?;
let mut output_path = output_path.to_owned();

match check::check_file_signature(path, &extensions, question_policy)? {
match check::check_file_signature(
path,
&extensions,
question_policy,
QuestionAction::Decompression,
)? {
CheckFileSignatureControlFlow::HaltProgram => return Ok(()),
CheckFileSignatureControlFlow::Continue => {}
CheckFileSignatureControlFlow::ChangeToDetectedExtension {
Expand Down Expand Up @@ -375,7 +380,7 @@ pub fn run(args: CliArgs, question_policy: QuestionPolicy, file_visibility_polic
for path in files.iter() {
let mut extensions = extension::extensions_from_path(path)?;

match check::check_file_signature(path, &extensions, question_policy)? {
match check::check_file_signature(path, &extensions, question_policy, QuestionAction::Listing)? {
CheckFileSignatureControlFlow::HaltProgram => return Ok(()),
CheckFileSignatureControlFlow::Continue => {}
CheckFileSignatureControlFlow::ChangeToDetectedExtension { new_extension, .. } => {
Expand Down
5 changes: 5 additions & 0 deletions src/utils/question.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub enum QuestionAction {
Compression,
/// question called from a decompression function
Decompression,
/// question called from a listing function
Listing,
}

#[derive(Default)]
Expand Down Expand Up @@ -68,6 +70,7 @@ pub fn user_wants_to_overwrite(
QuestionPolicy::AlwaysYes => match question_action {
QuestionAction::Decompression => Ok(Op::Merge),
QuestionAction::Compression => Ok(Op::Overwrite),
QuestionAction::Listing => unreachable!("Listing cannot create file conflicts"),
},
QuestionPolicy::AlwaysNo => Ok(Op::Cancel),
QuestionPolicy::Ask => prompt_user_for_file_conflict_resolution(path, question_action),
Expand Down Expand Up @@ -110,6 +113,7 @@ pub fn prompt_user_for_file_conflict_resolution(
],
)
.ask(),
QuestionAction::Listing => unreachable!("Listing cannot create file conflicts"),
}
}

Expand Down Expand Up @@ -176,6 +180,7 @@ pub fn user_wants_to_continue(
let action = match question_action {
QuestionAction::Compression => "compress",
QuestionAction::Decompression => "decompress",
QuestionAction::Listing => "list",
};
let path = format!("{}", PathFmt(path));
let path = Some(&*path);
Expand Down
140 changes: 140 additions & 0 deletions tests/list_prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
mod utils;

use std::io::Write;

use fs_err as fs;
use zip::{CompressionMethod, ZipWriter, write::SimpleFileOptions};

fn custom_extension_zip(dir: &std::path::Path) -> Vec<u8> {
let file = fs::File::create(dir.join("package.sublime-package")).unwrap();
let mut writer = ZipWriter::new(file);
writer
.start_file(
"note.txt",
SimpleFileOptions::default().compression_method(CompressionMethod::Stored),
)
.unwrap();
writer.write_all(b"synthetic archive contents").unwrap();
writer.finish().unwrap();
fs::read(dir.join("package.sublime-package")).unwrap()
}

#[test]
fn list_custom_extension_asks_to_list_and_does_not_extract() {
let (_tempdir, dir) = utils::testdir().unwrap();
let archive = custom_extension_zip(dir);
let output = utils::cargo_bin()
.current_dir(dir)
.args(["list", "package.sublime-package", "--tree"])
.write_stdin("y\n")
.assert()
.success()
.get_output()
.clone();
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("Do you want to list '"), "{stderr}");
assert!(!stderr.contains("Do you want to decompress '"), "{stderr}");
assert!(String::from_utf8(output.stdout).unwrap().contains("note.txt"));
assert_eq!(fs::read(dir.join("package.sublime-package")).unwrap(), archive);
assert_eq!(fs::read_dir(dir).unwrap().count(), 1);
}

#[test]
fn custom_extension_confirmation_policies_preserve_listing_and_extraction() {
for operation in ["list", "decompress"] {
for (flags, answer, proceed, prompt, format_warning) in [
(vec![], "y\n", true, true, true),
(vec![], "n\n", false, true, true),
(vec!["--yes"], "", true, false, true),
(vec!["--no"], "", false, false, true),
(vec!["--format", "zip"], "", true, false, false),
(vec!["--quiet"], "y\n", true, true, false),
] {
let (_tempdir, dir) = utils::testdir().unwrap();
let archive = custom_extension_zip(dir);
let mut command = utils::cargo_bin();
command
.current_dir(dir)
.args([operation, "package.sublime-package"])
.args(&flags);
if operation == "list" {
command.arg("--tree");
} else {
command.args(["--dir", "output"]);
}
let output = command.write_stdin(answer).assert().success().get_output().clone();
let stderr = String::from_utf8(output.stderr).unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
let expected = format!("Do you want to {operation} '");
assert_eq!(stderr.contains(&expected), prompt, "{operation} {flags:?}: {stderr}");
assert_eq!(
stderr.contains("[WARNING] No recognized extensions in "),
format_warning,
"{operation} {flags:?}: {stderr}"
);
if operation == "list" {
assert!(!stderr.contains("Do you want to decompress '"), "{stderr}");
assert_eq!(stdout.contains("note.txt"), proceed, "{stdout}");
assert_eq!(fs::read_dir(dir).unwrap().count(), 1);
} else if proceed {
assert_eq!(
fs::read(dir.join("output/note.txt")).unwrap(),
b"synthetic archive contents"
);
assert_eq!(fs::read_dir(dir).unwrap().count(), 2);
} else {
assert_eq!(fs::read_dir(dir).unwrap().count(), 1);
}
assert_eq!(fs::read(dir.join("package.sublime-package")).unwrap(), archive);
}
}
}

#[test]
fn layered_archive_listing_confirmation_uses_list() {
for format in ["zip", "7z"] {
for answer in ["y\n", "n\n"] {
let (_tempdir, dir) = utils::testdir().unwrap();
let zip = custom_extension_zip(dir);
let archive = if format == "zip" {
zip
} else {
fs::write(dir.join("note.txt"), b"synthetic archive contents").unwrap();
utils::cargo_bin()
.current_dir(dir)
.args(["compress", "note.txt", "archive.7z", "--yes"])
.assert()
.success();
let bytes = fs::read(dir.join("archive.7z")).unwrap();
fs::remove_file(dir.join("archive.7z")).unwrap();
fs::remove_file(dir.join("note.txt")).unwrap();
bytes
};
fs::remove_file(dir.join("package.sublime-package")).unwrap();
let name = format!("archive.{format}.gz");
let file = fs::File::create(dir.join(&name)).unwrap();
let mut encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
encoder.write_all(&archive).unwrap();
encoder.finish().unwrap();
let original = fs::read(dir.join(&name)).unwrap();
let output = utils::cargo_bin()
.current_dir(dir)
.args(["list", &name, "--tree"])
.write_stdin(answer)
.assert()
.success()
.get_output()
.clone();
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("[WARNING]"), "{stderr}");
assert!(stderr.contains("Do you want to list '"), "{stderr}");
assert!(!stderr.contains("Do you want to decompress '"), "{stderr}");
assert_eq!(
String::from_utf8(output.stdout).unwrap().contains("note.txt"),
answer == "y\n"
);
assert_eq!(fs::read(dir.join(&name)).unwrap(), original);
assert_eq!(fs::read_dir(dir).unwrap().count(), 1);
}
}
}
Loading