0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-07 23:06:50 -05:00

use WorkspaceFileContainer for bench --watch

This commit is contained in:
Nayeem Rahman 2024-12-10 09:51:25 +00:00
parent b8b9eea548
commit 37d45d0e84
2 changed files with 60 additions and 230 deletions

View file

@ -21,7 +21,6 @@ use crate::resolver::SloppyImportsCachedFs;
use crate::tools::check; use crate::tools::check;
use crate::tools::check::TypeChecker; use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path;
use deno_config::deno_json::JsxImportSourceConfig; use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig; use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
@ -44,7 +43,6 @@ use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError; use deno_graph::ModuleGraphError;
use deno_graph::ResolutionError; use deno_graph::ResolutionError;
use deno_graph::SpecifierError; use deno_graph::SpecifierError;
use deno_path_util::url_to_file_path;
use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind;
use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FileSystem;
use deno_runtime::deno_node; use deno_runtime::deno_node;
@ -53,7 +51,6 @@ use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv; use deno_semver::package::PackageNv;
use import_map::ImportMapError; use import_map::ImportMapError;
use node_resolver::InNpmPackageChecker; use node_resolver::InNpmPackageChecker;
use std::collections::HashSet;
use std::error::Error; use std::error::Error;
use std::ops::Deref; use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
@ -989,37 +986,6 @@ fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> {
maybe_specifier.map(|s| s.as_str()) maybe_specifier.map(|s| s.as_str())
} }
/// Gets if any of the specified root's "file:" dependents are in the
/// provided changed set.
pub fn has_graph_root_local_dependent_changed(
graph: &ModuleGraph,
root: &ModuleSpecifier,
canonicalized_changed_paths: &HashSet<PathBuf>,
) -> bool {
let mut dependent_specifiers = graph.walk(
std::iter::once(root),
deno_graph::WalkOptions {
follow_dynamic: true,
kind: GraphKind::All,
prefer_fast_check_graph: true,
check_js: true,
},
);
while let Some((s, _)) = dependent_specifiers.next() {
if let Ok(path) = url_to_file_path(s) {
if let Ok(path) = canonicalize_path(&path) {
if canonicalized_changed_paths.contains(&path) {
return true;
}
}
} else {
// skip walking this remote module's dependencies
dependent_specifiers.skip_previous_dependencies();
}
}
false
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FileWatcherReporter { pub struct FileWatcherReporter {
watcher_communicator: Arc<WatcherCommunicator>, watcher_communicator: Arc<WatcherCommunicator>,

View file

@ -8,7 +8,6 @@ use crate::display::write_json_to_stdout;
use crate::factory::CliFactory; use crate::factory::CliFactory;
use crate::factory::SpecifierInfo; use crate::factory::SpecifierInfo;
use crate::factory::WorkspaceFileContainer; use crate::factory::WorkspaceFileContainer;
use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::ops; use crate::ops;
use crate::tools::test::format_test_error; use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter; use crate::tools::test::TestFilter;
@ -42,7 +41,6 @@ use indexmap::IndexSet;
use log::Level; use log::Level;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@ -267,124 +265,6 @@ async fn bench_specifier_inner(
/// Test a collection of specifiers with test modes concurrently. /// Test a collection of specifiers with test modes concurrently.
async fn bench_specifiers( async fn bench_specifiers(
worker_factory: Arc<CliMainWorkerFactory>,
permissions: &Permissions,
permissions_desc_parser: &Arc<RuntimePermissionDescriptorParser>,
specifiers: Vec<ModuleSpecifier>,
options: BenchSpecifierOptions,
) -> Result<(), AnyError> {
let (sender, mut receiver) = unbounded_channel::<BenchEvent>();
let log_level = options.log_level;
let option_for_handles = options.clone();
let join_handles = specifiers.into_iter().map(move |specifier| {
let worker_factory = worker_factory.clone();
let permissions_container = PermissionsContainer::new(
permissions_desc_parser.clone(),
permissions.clone(),
);
let sender = sender.clone();
let options = option_for_handles.clone();
spawn_blocking(move || {
let future = bench_specifier(
worker_factory,
permissions_container,
specifier,
sender,
options.filter,
);
create_and_run_current_thread(future)
})
});
let join_stream = stream::iter(join_handles)
.buffer_unordered(1)
.collect::<Vec<Result<Result<(), AnyError>, tokio::task::JoinError>>>();
let handler = {
spawn(async move {
let mut used_only = false;
let mut report = BenchReport::new();
let mut reporter =
create_reporter(log_level != Some(Level::Error), options.json);
let mut benches = IndexMap::new();
while let Some(event) = receiver.recv().await {
match event {
BenchEvent::Plan(plan) => {
report.total += plan.total;
if plan.used_only {
used_only = true;
}
reporter.report_plan(&plan);
}
BenchEvent::Register(desc) => {
reporter.report_register(&desc);
benches.insert(desc.id, desc);
}
BenchEvent::Wait(id) => {
reporter.report_wait(benches.get(&id).unwrap());
}
BenchEvent::Output(output) => {
reporter.report_output(&output);
}
BenchEvent::Result(id, result) => {
let desc = benches.get(&id).unwrap();
reporter.report_result(desc, &result);
match result {
BenchResult::Ok(stats) => {
report.measurements.push((desc.clone(), stats));
}
BenchResult::Failed(failure) => {
report.failed += 1;
report.failures.push((desc.clone(), failure));
}
};
}
BenchEvent::UncaughtError(origin, error) => {
report.failed += 1;
reporter.report_uncaught_error(&origin, error);
}
}
}
reporter.report_end(&report);
if used_only {
return Err(generic_error(
"Bench failed because the \"only\" option was used",
));
}
if report.failed > 0 {
return Err(generic_error("Bench failed"));
}
Ok(())
})
};
let (join_results, result) = future::join(join_stream, handler).await;
// propagate any errors
for join_result in join_results {
join_result??;
}
result??;
Ok(())
}
/// Test a collection of specifiers with test modes concurrently.
async fn bench_specifiers2(
factories_with_specifiers: Vec<( factories_with_specifiers: Vec<(
Arc<CliMainWorkerFactory>, Arc<CliMainWorkerFactory>,
Vec<ModuleSpecifier>, Vec<ModuleSpecifier>,
@ -599,7 +479,7 @@ pub async fn run_benchmarks(
return Ok(()); return Ok(());
} }
bench_specifiers2( bench_specifiers(
file_container.worker_factories_with_checked_specifiers(), file_container.worker_factories_with_checked_specifiers(),
&permissions, &permissions,
&permission_desc_parser, &permission_desc_parser,
@ -614,7 +494,6 @@ pub async fn run_benchmarks(
Ok(()) Ok(())
} }
// TODO(bartlomieju): heavy duplication of code with `cli/tools/test.rs`
pub async fn run_benchmarks_with_watch( pub async fn run_benchmarks_with_watch(
flags: Arc<Flags>, flags: Arc<Flags>,
bench_flags: BenchFlags, bench_flags: BenchFlags,
@ -640,96 +519,81 @@ pub async fn run_benchmarks_with_watch(
let cli_options = factory.cli_options()?; let cli_options = factory.cli_options()?;
let workspace_bench_options = let workspace_bench_options =
cli_options.resolve_workspace_bench_options(&bench_flags); cli_options.resolve_workspace_bench_options(&bench_flags);
let permission_desc_parser = factory.permission_desc_parser()?;
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
let graph_kind = cli_options.type_check_mode().as_graph_kind();
let module_graph_creator = factory.module_graph_creator().await?;
let members_with_bench_options =
cli_options.resolve_bench_options_for_members(&bench_flags)?;
let watch_paths = members_with_bench_options
.iter()
.filter_map(|(_, bench_options)| {
bench_options
.files
.include
.as_ref()
.map(|set| set.base_paths())
})
.flatten()
.collect::<Vec<_>>();
let _ = watcher_communicator.watch_paths(watch_paths);
let collected_bench_modules = members_with_bench_options
.iter()
.map(|(_, bench_options)| {
collect_specifiers(
bench_options.files.clone(),
cli_options.vendor_dir_path().map(ToOwned::to_owned),
is_supported_bench_path,
)
})
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>();
// Various bench files should not share the same permissions in terms of
// `PermissionsContainer` - otherwise granting/revoking permissions in one
// file would have impact on other files, which is undesirable.
let permission_desc_parser = factory.permission_desc_parser()?.clone();
let permissions = Permissions::from_options( let permissions = Permissions::from_options(
permission_desc_parser.as_ref(), permission_desc_parser.as_ref(),
&cli_options.permissions_options(), &cli_options.permissions_options(),
)?; )?;
let log_level = cli_options.log_level();
let graph = module_graph_creator let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
.create_graph(graph_kind, collected_bench_modules.clone()) let workspace_dirs_with_files = if cli_options.is_discovered_config() {
.await?; cli_options
module_graph_creator.graph_valid(&graph)?; .resolve_bench_options_for_members(&bench_flags)?
let bench_modules = &graph.roots; .into_iter()
.map(|(d, o)| (Arc::new(d), o.files))
let bench_modules_to_reload = if let Some(changed_paths) = changed_paths .collect()
{
let changed_paths = changed_paths.into_iter().collect::<HashSet<_>>();
let mut result = IndexSet::with_capacity(bench_modules.len());
for bench_module_specifier in bench_modules {
if has_graph_root_local_dependent_changed(
&graph,
bench_module_specifier,
&changed_paths,
) {
result.insert(bench_module_specifier.clone());
}
}
result
} else { } else {
bench_modules.clone() let patterns = bench_flags
.files
.as_file_patterns(cli_options.initial_cwd())?;
let config = cli_options.start_dir.to_bench_config(patterns)?;
let options = BenchOptions::resolve(config, &bench_flags);
vec![(cli_options.start_dir.clone(), options.files)]
}; };
let watch_paths = workspace_dirs_with_files
let worker_factory = .iter()
Arc::new(factory.create_cli_main_worker_factory().await?); .filter_map(|(_, files)| {
files.include.as_ref().map(|set| set.base_paths())
let specifiers = collected_bench_modules })
.into_iter() .flatten()
.filter(|specifier| bench_modules_to_reload.contains(specifier)) .collect::<Vec<_>>();
.collect::<Vec<ModuleSpecifier>>(); let _ = watcher_communicator.watch_paths(watch_paths);
let file_container =
factory WorkspaceFileContainer::from_workspace_dirs_with_files(
.main_module_graph_container() workspace_dirs_with_files,
.await? &factory,
.check_specifiers(&specifiers, cli_options.ext_flag().as_ref()) None,
|patterns, cli_options, _, _| {
async move {
let info = SpecifierInfo {
check: true,
check_doc: false,
};
collect_specifiers(
patterns,
cli_options.vendor_dir_path().map(ToOwned::to_owned),
is_supported_bench_path,
)
.map(|s| s.into_iter().map(|s| (s, info)).collect())
}
.boxed_local()
},
(),
)
.await?; .await?;
file_container.check().await?;
if workspace_bench_options.no_run { if workspace_bench_options.no_run {
return Ok(()); return Ok(());
} }
let log_level = cli_options.log_level(); let factories_with_specifiers =
if let Some(changed_paths) = changed_paths {
file_container
.worker_factories_with_dependent_checked_specifiers(
&changed_paths.into_iter().collect(),
)
.await?
} else {
file_container.worker_factories_with_checked_specifiers()
};
bench_specifiers( bench_specifiers(
worker_factory, factories_with_specifiers,
&permissions, &permissions,
&permission_desc_parser, &permission_desc_parser,
specifiers,
BenchSpecifierOptions { BenchSpecifierOptions {
filter: TestFilter::from_flag(&workspace_bench_options.filter), filter: TestFilter::from_flag(&workspace_bench_options.filter),
json: workspace_bench_options.json, json: workspace_bench_options.json,