diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a705a..d511387 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## Changes +- When `--export-*` commands are used, result files are created before benchmark execution + to fail early in case of, e.g., wrong permissions. See #306 (@s1ck). - When `--export-*` options are used, result files are written after each individual benchmark command instead of writing after all benchmarks have finished. See #306 (@s1ck). diff --git a/src/hyperfine/export/mod.rs b/src/hyperfine/export/mod.rs index 6e8bdd4..541b1e5 100644 --- a/src/hyperfine/export/mod.rs +++ b/src/hyperfine/export/mod.rs @@ -8,7 +8,7 @@ use self::csv::CsvExporter; use self::json::JsonExporter; use self::markdown::MarkdownExporter; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io::{Result, Write}; use crate::hyperfine::types::BenchmarkResult; @@ -55,7 +55,9 @@ impl ExportManager { } /// Add an additional exporter to the ExportManager - pub fn add_exporter(&mut self, export_type: ExportType, filename: &str) { + pub fn add_exporter(&mut self, export_type: ExportType, filename: &str) -> Result<()> { + let _ = File::create(filename)?; + let exporter: Box = match export_type { ExportType::Asciidoc => Box::new(AsciidocExporter::default()), ExportType::Csv => Box::new(CsvExporter::default()), @@ -66,6 +68,8 @@ impl ExportManager { exporter, filename: filename.to_string(), }); + + Ok(()) } /// Write the given results to all Exporters contained within this manager @@ -80,6 +84,6 @@ impl ExportManager { /// Write the given content to a file with the specified name fn write_to_file(filename: &str, content: &[u8]) -> Result<()> { - let mut file = File::create(filename)?; + let mut file = OpenOptions::new().write(true).open(filename)?; file.write_all(content) } diff --git a/src/main.rs b/src/main.rs index 72d8def..beb3ed6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,8 +71,11 @@ fn run( fn main() { let matches = get_arg_matches(env::args_os()); let options = build_hyperfine_options(&matches); - let export_manager = build_export_manager(&matches); let commands = build_commands(&matches); + let export_manager = match build_export_manager(&matches) { + Ok(export_manager) => export_manager, + Err(ref e) => error(&e.to_string()) + }; let res = match options { Ok(ref opts) => run(&commands, &opts, &export_manager), @@ -202,20 +205,21 @@ fn build_hyperfine_options<'a>( /// Build the ExportManager that will export the results specified /// in the given ArgMatches -fn build_export_manager(matches: &ArgMatches<'_>) -> ExportManager { +fn build_export_manager(matches: &ArgMatches<'_>) -> io::Result { let mut export_manager = ExportManager::new(); { - let mut add_exporter = |flag, exporttype| { + let mut add_exporter = |flag, exporttype| -> io::Result<()> { if let Some(filename) = matches.value_of(flag) { - export_manager.add_exporter(exporttype, filename); + export_manager.add_exporter(exporttype, filename)?; } + Ok(()) }; - add_exporter("export-asciidoc", ExportType::Asciidoc); - add_exporter("export-json", ExportType::Json); - add_exporter("export-csv", ExportType::Csv); - add_exporter("export-markdown", ExportType::Markdown); + add_exporter("export-asciidoc", ExportType::Asciidoc)?; + add_exporter("export-json", ExportType::Json)?; + add_exporter("export-csv", ExportType::Csv)?; + add_exporter("export-markdown", ExportType::Markdown)?; } - export_manager + Ok(export_manager) } /// Build the commands to benchmark