diff --git a/cli/args/config_file.rs b/cli/args/config_file.rs index 16e11a5a81..904efdff8d 100644 --- a/cli/args/config_file.rs +++ b/cli/args/config_file.rs @@ -429,6 +429,28 @@ pub struct TestConfig { pub files: FilesConfig, } +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(default, deny_unknown_fields)] +struct SerializedBenchConfig { + pub files: SerializedFilesConfig, +} + +impl SerializedBenchConfig { + pub fn into_resolved( + self, + config_file_specifier: &ModuleSpecifier, + ) -> Result { + Ok(BenchConfig { + files: self.files.into_resolved(config_file_specifier)?, + }) + } +} + +#[derive(Clone, Debug, Default)] +pub struct BenchConfig { + pub files: FilesConfig, +} + #[derive(Clone, Debug, Deserialize)] #[serde(untagged)] pub enum LockConfig { @@ -445,6 +467,7 @@ pub struct ConfigFileJson { pub fmt: Option, pub tasks: Option, pub test: Option, + pub bench: Option, pub lock: Option, } @@ -653,9 +676,19 @@ impl ConfigFile { pub fn to_test_config(&self) -> Result, AnyError> { if let Some(config) = self.json.test.clone() { - let lint_config: SerializedTestConfig = serde_json::from_value(config) + let test_config: SerializedTestConfig = serde_json::from_value(config) .context("Failed to parse \"test\" configuration")?; - Ok(Some(lint_config.into_resolved(&self.specifier)?)) + Ok(Some(test_config.into_resolved(&self.specifier)?)) + } else { + Ok(None) + } + } + + pub fn to_bench_config(&self) -> Result, AnyError> { + if let Some(config) = self.json.bench.clone() { + let bench_config: SerializedBenchConfig = serde_json::from_value(config) + .context("Failed to parse \"bench\" configuration")?; + Ok(Some(bench_config.into_resolved(&self.specifier)?)) } else { Ok(None) } diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 3f3f53d183..ebe71c7fab 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -6,6 +6,7 @@ mod lockfile; mod flags_allow_net; +pub use config_file::BenchConfig; pub use config_file::CompilerOptions; pub use config_file::ConfigFile; pub use config_file::EmitConfigOptions; @@ -401,6 +402,14 @@ impl CliOptions { } } + pub fn to_bench_config(&self) -> Result, AnyError> { + if let Some(config_file) = &self.maybe_config_file { + config_file.to_bench_config() + } else { + Ok(None) + } + } + pub fn to_fmt_config(&self) -> Result, AnyError> { if let Some(config) = &self.maybe_config_file { config.to_fmt_config() diff --git a/cli/schemas/config-file.v1.json b/cli/schemas/config-file.v1.json index 7f6dcb4e3c..67650309ea 100644 --- a/cli/schemas/config-file.v1.json +++ b/cli/schemas/config-file.v1.json @@ -356,6 +356,31 @@ } } }, + "bench": { + "description": "Configuration for deno bench", + "type": "object", + "properties": { + "files": { + "type": "object", + "properties": { + "include": { + "type": "array", + "description": "List of files or directories that will be searched for benchmarks.", + "items": { + "type": "string" + } + }, + "exclude": { + "type": "array", + "description": "List of files or directories that will not be searched for benchmarks.", + "items": { + "type": "string" + } + } + } + } + } + }, "lock": { "description": "Whether to use a lock file or the path to use for the lock file. Can be overridden by CLI arguments.", "type": ["string", "boolean"], diff --git a/cli/tests/bench_tests.rs b/cli/tests/bench_tests.rs index 77c1e2a7ef..24d2a4fe92 100644 --- a/cli/tests/bench_tests.rs +++ b/cli/tests/bench_tests.rs @@ -165,6 +165,24 @@ mod bench { exit_code: 1, }); + itest!(bench_with_config { + args: "bench --config bench/collect/deno.jsonc bench/collect", + exit_code: 0, + output: "bench/collect.out", + }); + + itest!(bench_with_config2 { + args: "bench --config bench/collect/deno2.jsonc bench/collect", + exit_code: 0, + output: "bench/collect2.out", + }); + + itest!(bench_with_malformed_config { + args: "bench --config bench/collect/deno.malformed.jsonc", + exit_code: 1, + output: "bench/collect_with_malformed_config.out", + }); + #[test] fn recursive_permissions_pledge() { let output = util::deno_cmd() diff --git a/cli/tests/testdata/bench/collect.out b/cli/tests/testdata/bench/collect.out index 18b27f8b93..a7adc2b588 100644 --- a/cli/tests/testdata/bench/collect.out +++ b/cli/tests/testdata/bench/collect.out @@ -1,7 +1,17 @@ Check [WILDCARD]/bench/collect/bench.ts +Check [WILDCARD]/bench/collect/include/2_bench.ts +Check [WILDCARD]/bench/collect/include/bench.ts cpu: [WILDCARD] runtime: deno [WILDCARD] ([WILDCARD]) [WILDCARD]/bench/collect/bench.ts benchmark time (avg) (min … max) p75 p99 p995 ------------------------------------------------- ----------------------------- + +[WILDCARD]/bench/collect/include/2_bench.ts +benchmark time (avg) (min … max) p75 p99 p995 +------------------------------------------------- ----------------------------- + +[WILDCARD]/bench/collect/include/bench.ts +benchmark time (avg) (min … max) p75 p99 p995 +------------------------------------------------- ----------------------------- diff --git a/cli/tests/testdata/bench/collect/deno.jsonc b/cli/tests/testdata/bench/collect/deno.jsonc new file mode 100644 index 0000000000..f88d137781 --- /dev/null +++ b/cli/tests/testdata/bench/collect/deno.jsonc @@ -0,0 +1,7 @@ +{ + "bench": { + "files": { + "exclude": ["./ignore"] + } + } +} diff --git a/cli/tests/testdata/bench/collect/deno.malformed.jsonc b/cli/tests/testdata/bench/collect/deno.malformed.jsonc new file mode 100644 index 0000000000..02744bc111 --- /dev/null +++ b/cli/tests/testdata/bench/collect/deno.malformed.jsonc @@ -0,0 +1,5 @@ +{ + "bench": { + "dont_know_this_field": {} + } +} diff --git a/cli/tests/testdata/bench/collect/deno2.jsonc b/cli/tests/testdata/bench/collect/deno2.jsonc new file mode 100644 index 0000000000..f24da50491 --- /dev/null +++ b/cli/tests/testdata/bench/collect/deno2.jsonc @@ -0,0 +1,8 @@ +{ + "bench": { + "files": { + "include": ["./include/"], + "exclude": ["./ignore", "./include/2_bench.ts"] + } + } +} diff --git a/cli/tests/testdata/bench/collect/include/2_bench.ts b/cli/tests/testdata/bench/collect/include/2_bench.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/tests/testdata/bench/collect/include/bench.ts b/cli/tests/testdata/bench/collect/include/bench.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/tests/testdata/bench/collect2.out b/cli/tests/testdata/bench/collect2.out new file mode 100644 index 0000000000..e5bb0f1c5d --- /dev/null +++ b/cli/tests/testdata/bench/collect2.out @@ -0,0 +1,12 @@ +Check [WILDCARD]/bench/collect/bench.ts +Check [WILDCARD]/bench/collect/include/bench.ts +cpu: [WILDCARD] +runtime: deno [WILDCARD] ([WILDCARD]) + +[WILDCARD]/bench/collect/bench.ts +benchmark time (avg) (min … max) p75 p99 p995 +------------------------------------------------- ----------------------------- + +[WILDCARD]/bench/collect/include/bench.ts +benchmark time (avg) (min … max) p75 p99 p995 +------------------------------------------------- ----------------------------- diff --git a/cli/tests/testdata/bench/collect_with_malformed_config.out b/cli/tests/testdata/bench/collect_with_malformed_config.out new file mode 100644 index 0000000000..10e64707ca --- /dev/null +++ b/cli/tests/testdata/bench/collect_with_malformed_config.out @@ -0,0 +1,4 @@ +error: Failed to parse "bench" configuration + +Caused by: + unknown field `dont_know_this_field`, expected `files` diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs index eeda3ea1a2..2bebe124b1 100644 --- a/cli/tools/bench.rs +++ b/cli/tools/bench.rs @@ -1,5 +1,6 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use crate::args::BenchConfig; use crate::args::BenchFlags; use crate::args::Flags; use crate::args::TypeCheckMode; @@ -14,6 +15,7 @@ use crate::util::file_watcher; use crate::util::file_watcher::ResolutionResult; use crate::util::fs::collect_specifiers; use crate::util::path::is_supported_ext; +use crate::util::path::specifier_to_file_path; use crate::worker::create_main_worker_for_test_or_bench; use deno_core::error::generic_error; @@ -490,9 +492,13 @@ pub async fn run_benchmarks( let ps = ProcState::build(flags).await?; let permissions = Permissions::from_options(&ps.options.permissions_options())?; + + let selection = + collect_include_ignore(&bench_flags, ps.options.to_bench_config()?); + let specifiers = collect_specifiers( - bench_flags.include.unwrap_or_else(|| vec![".".to_string()]), - &bench_flags.ignore.clone(), + selection.include, + &selection.ignore, is_supported_bench_path, )?; @@ -524,9 +530,11 @@ pub async fn run_benchmarks_with_watch( let permissions = Permissions::from_options(&ps.options.permissions_options())?; - let include = bench_flags.include.unwrap_or_else(|| vec![".".to_string()]); - let ignore = bench_flags.ignore.clone(); - let paths_to_watch: Vec<_> = include.iter().map(PathBuf::from).collect(); + let selection = + collect_include_ignore(&bench_flags, ps.options.to_bench_config()?); + + let paths_to_watch: Vec<_> = + selection.include.iter().map(PathBuf::from).collect(); let no_check = ps.options.type_check_mode() == TypeCheckMode::None; let resolver = |changed: Option>| { @@ -534,8 +542,8 @@ pub async fn run_benchmarks_with_watch( let paths_to_watch_clone = paths_to_watch.clone(); let files_changed = changed.is_some(); - let include = include.clone(); - let ignore = ignore.clone(); + let include = selection.include.clone(); + let ignore = selection.ignore.clone(); let ps = ps.clone(); async move { @@ -650,8 +658,8 @@ pub async fn run_benchmarks_with_watch( let operation = |modules_to_reload: Vec<(ModuleSpecifier, ModuleKind)>| { let filter = bench_flags.filter.clone(); - let include = include.clone(); - let ignore = ignore.clone(); + let include = selection.include.clone(); + let ignore = selection.ignore.clone(); let permissions = permissions.clone(); let ps = ps.clone(); @@ -687,3 +695,42 @@ pub async fn run_benchmarks_with_watch( Ok(()) } + +struct IncludeIgnoreCollection { + include: Vec, + ignore: Vec, +} + +fn collect_include_ignore( + bench_flags: &BenchFlags, + maybe_bench_config: Option, +) -> IncludeIgnoreCollection { + let mut include = bench_flags.include.clone().unwrap_or_default(); + let mut ignore = bench_flags.ignore.clone(); + + if let Some(bench_config) = maybe_bench_config { + if include.is_empty() { + include = bench_config + .files + .include + .iter() + .map(|s| s.to_string()) + .collect::>(); + } + + if ignore.is_empty() { + ignore = bench_config + .files + .exclude + .iter() + .filter_map(|s| specifier_to_file_path(s).ok()) + .collect::>(); + } + } + + if include.is_empty() { + include.push(".".to_string()); + } + + IncludeIgnoreCollection { include, ignore } +}