From 947cc519281f6ae1762b4641bbf80207372d3646 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Sun, 30 Jul 2023 09:42:42 +0100 Subject: [PATCH] feat: changed files --- Cargo.lock | 7 ++ crates/rome_cli/src/cli_options.rs | 35 ++++++++++ crates/rome_cli/src/commands/check.rs | 3 + crates/rome_cli/src/commands/ci.rs | 2 + crates/rome_cli/src/commands/format.rs | 4 +- crates/rome_cli/src/commands/lint.rs | 3 + crates/rome_cli/src/commands/migrate.rs | 1 + crates/rome_cli/src/diagnostics.rs | 8 +-- crates/rome_cli/src/execute/mod.rs | 14 +++- crates/rome_cli/src/execute/traverse.rs | 13 +++- crates/rome_cli/src/vcs.rs | 12 ++++ crates/rome_cli/src/vcs/git.rs | 28 ++++++++ crates/rome_cli/tests/cases/changed_files.rs | 28 ++++++++ crates/rome_cli/tests/cases/mod.rs | 1 + .../emits_an_error_if_vcs_is_not_enabled.snap | 17 +++++ .../main_commands_check/check_help.snap | 2 + .../snapshots/main_commands_ci/ci_help.snap | 2 + .../main_commands_format/format_help.snap | 2 + .../main_commands_lint/check_help.snap | 2 + .../lsp_proxy_help.snap | 4 +- .../main_commands_migrate/migrate_help.snap | 2 + crates/rome_fs/Cargo.toml | 1 + crates/rome_fs/src/fs.rs | 10 ++- crates/rome_fs/src/fs/memory.rs | 13 +++- crates/rome_fs/src/fs/os.rs | 69 ++++++++++++++++--- website/package.json | 2 +- 26 files changed, 260 insertions(+), 25 deletions(-) create mode 100644 crates/rome_cli/src/vcs/git.rs create mode 100644 crates/rome_cli/tests/cases/changed_files.rs create mode 100644 crates/rome_cli/tests/snapshots/main_cases_changed_files/emits_an_error_if_vcs_is_not_enabled.snap diff --git a/Cargo.lock b/Cargo.lock index 1e910542dc3..8d7386ce0cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1260,6 +1260,12 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1877,6 +1883,7 @@ dependencies = [ "crossbeam", "indexmap", "parking_lot", + "path-slash", "rayon", "rome_console", "rome_diagnostics", diff --git a/crates/rome_cli/src/cli_options.rs b/crates/rome_cli/src/cli_options.rs index f4a5a10f753..145a7ff7634 100644 --- a/crates/rome_cli/src/cli_options.rs +++ b/crates/rome_cli/src/cli_options.rs @@ -1,4 +1,8 @@ +use crate::vcs::create_vcs_client; +use crate::CliDiagnostic; use bpaf::Bpaf; +use rome_console::markup; +use rome_service::Configuration; use std::str::FromStr; /// Global options applied to all commands @@ -44,6 +48,37 @@ pub struct CliOptions { /// Reports information using the JSON format #[bpaf(long("json"), switch, hide_usage)] pub json: bool, + + /// Only runs the operation on files that have changed. VCS support needs to be enabled. Doesn't work when running `rome ci`. + #[bpaf(long("changed"), switch)] + pub changed: bool, +} + +impl CliOptions { + /// It validates the current CLI options against. If not errors are found, it calls the VCS client + /// via [std::process::Command] and returns a list of changed files + /// + /// ## Errors + /// - `--changed` is passed and the VCS support is disabled + /// - errors are raised when calling the VCS client via [std::process::Command] + pub(crate) fn compute_changed_files( + &self, + configuration: &Configuration, + ) -> Result, CliDiagnostic> { + if let Some(vcs) = configuration.vcs.as_ref() { + if vcs.is_disabled() && self.changed { + return Err(CliDiagnostic::incompatible_end_configuration(markup! { + "You provided the ""--changed"" argument, but you haven't enabled VCS support. This is an error." + })); + } + if let Some(client_kind) = vcs.client_kind.as_ref() { + let vcs_client = create_vcs_client(client_kind); + return vcs_client.changed_files(); + } + } + + Ok(vec![]) + } } #[derive(Debug, Clone)] diff --git a/crates/rome_cli/src/commands/check.rs b/crates/rome_cli/src/commands/check.rs index 65a3394ad7b..36998d13e91 100644 --- a/crates/rome_cli/src/commands/check.rs +++ b/crates/rome_cli/src/commands/check.rs @@ -84,6 +84,8 @@ pub(crate) fn check( fs_configuration.merge_with(configuration); + let changed_files = cli_options.compute_changed_files(&fs_configuration)?; + // check if support of git ignore files is enabled let vcs_base_path = configuration_path.or(session.app.fs.working_directory()); store_path_to_ignore_from_vcs( @@ -122,5 +124,6 @@ pub(crate) fn check( session, &cli_options, paths, + changed_files, ) } diff --git a/crates/rome_cli/src/commands/ci.rs b/crates/rome_cli/src/commands/ci.rs index 114e80d4420..ae9cb2e186a 100644 --- a/crates/rome_cli/src/commands/ci.rs +++ b/crates/rome_cli/src/commands/ci.rs @@ -91,5 +91,7 @@ pub(crate) fn ci(mut session: CliSession, payload: CiCommandPayload) -> Result<( session, &payload.cli_options, payload.paths, + // we never process changed files in CI + vec![], ) } diff --git a/crates/rome_cli/src/commands/format.rs b/crates/rome_cli/src/commands/format.rs index 7765a180f9e..2ef345017e7 100644 --- a/crates/rome_cli/src/commands/format.rs +++ b/crates/rome_cli/src/commands/format.rs @@ -48,6 +48,8 @@ pub(crate) fn format( configuration.merge_with(vcs_configuration); configuration.merge_with(files_configuration); + let changed_files = cli_options.compute_changed_files(&configuration)?; + // check if support of git ignore files is enabled let vcs_base_path = configuration_path.or(session.app.fs.working_directory()); store_path_to_ignore_from_vcs( @@ -92,5 +94,5 @@ pub(crate) fn format( }) }; - execute_mode(execution, session, &cli_options, paths) + execute_mode(execution, session, &cli_options, paths, changed_files) } diff --git a/crates/rome_cli/src/commands/lint.rs b/crates/rome_cli/src/commands/lint.rs index cc690606ad8..3311ddb498d 100644 --- a/crates/rome_cli/src/commands/lint.rs +++ b/crates/rome_cli/src/commands/lint.rs @@ -52,6 +52,8 @@ pub(crate) fn lint( fs_configuration.merge_with(configuration); + let changed_files = cli_options.compute_changed_files(&fs_configuration)?; + // check if support of git ignore files is enabled let vcs_base_path = configuration_path.or(session.app.fs.working_directory()); store_path_to_ignore_from_vcs( @@ -90,5 +92,6 @@ pub(crate) fn lint( session, &cli_options, paths, + changed_files, ) } diff --git a/crates/rome_cli/src/commands/migrate.rs b/crates/rome_cli/src/commands/migrate.rs index c3bc61d6a68..27128483a8a 100644 --- a/crates/rome_cli/src/commands/migrate.rs +++ b/crates/rome_cli/src/commands/migrate.rs @@ -26,6 +26,7 @@ pub(crate) fn migrate( session, &cli_options, vec![], + vec![], ) } else { Err(CliDiagnostic::MigrateError(MigrationDiagnostic { diff --git a/crates/rome_cli/src/diagnostics.rs b/crates/rome_cli/src/diagnostics.rs index 77e535f6015..321eec6bfcb 100644 --- a/crates/rome_cli/src/diagnostics.rs +++ b/crates/rome_cli/src/diagnostics.rs @@ -1,4 +1,4 @@ -use rome_console::fmt::Formatter; +use rome_console::fmt::{Display, Formatter}; use rome_console::markup; use rome_diagnostics::adapters::{BpafError, IoError}; use rome_diagnostics::{ @@ -219,7 +219,7 @@ pub struct ServerNotRunning; ) )] pub struct IncompatibleEndConfiguration { - reason: String, + reason: MessageAndDescription, } #[derive(Debug, Diagnostic)] @@ -430,9 +430,9 @@ impl CliDiagnostic { /// results in a combination of options that doesn't allow to run the command correctly. /// /// A reason needs to be provided - pub fn incompatible_end_configuration(reason: impl Into) -> Self { + pub fn incompatible_end_configuration(reason: impl Display) -> Self { Self::IncompatibleEndConfiguration(IncompatibleEndConfiguration { - reason: reason.into(), + reason: MessageAndDescription::from(markup! {{reason}}.to_owned()), }) } diff --git a/crates/rome_cli/src/execute/mod.rs b/crates/rome_cli/src/execute/mod.rs index 8a5554ab166..b2936ba7b85 100644 --- a/crates/rome_cli/src/execute/mod.rs +++ b/crates/rome_cli/src/execute/mod.rs @@ -219,6 +219,7 @@ pub(crate) fn execute_mode( session: CliSession, cli_options: &CliOptions, paths: Vec, + changed_files: Vec, ) -> Result<(), CliDiagnostic> { if cli_options.max_diagnostics > MAXIMUM_DISPLAYABLE_DIAGNOSTICS { return Err(CliDiagnostic::overflown_argument( @@ -229,6 +230,17 @@ pub(crate) fn execute_mode( mode.max_diagnostics = cli_options.max_diagnostics; + // At this point, we should already have checked if the configuration has already enabled the VCS support + // let changed_files = if cli_options.changed && !mode.is_ci() { + // if let Some(vcs) = vcs { + // vcs.changed_files()? + // } else { + // vec![] + // } + // } else { + // vec![] + // }; + // don't do any traversal if there's some content coming from stdin if let Some((path, content)) = mode.as_stdin_file() { let rome_path = RomePath::new(path); @@ -240,6 +252,6 @@ pub(crate) fn execute_mode( { migrate::run(session, write, configuration_path, cli_options.verbose) } else { - traverse(mode, session, cli_options, paths) + traverse(mode, session, cli_options, paths, changed_files) } } diff --git a/crates/rome_cli/src/execute/traverse.rs b/crates/rome_cli/src/execute/traverse.rs index 3a9570ad439..2a22087701f 100644 --- a/crates/rome_cli/src/execute/traverse.rs +++ b/crates/rome_cli/src/execute/traverse.rs @@ -60,6 +60,7 @@ pub(crate) fn traverse( session: CliSession, cli_options: &CliOptions, inputs: Vec, + changed_files: Vec, ) -> Result<(), CliDiagnostic> { init_thread_pool(); if inputs.is_empty() && execution.as_stdin_file().is_none() { @@ -112,6 +113,7 @@ pub(crate) fn traverse( traverse_inputs( fs, inputs, + changed_files, &TraversalOptions { fs, workspace, @@ -239,12 +241,17 @@ fn init_thread_pool() { /// Initiate the filesystem traversal tasks with the provided input paths and /// run it to completion, returning the duration of the process -fn traverse_inputs(fs: &dyn FileSystem, inputs: Vec, ctx: &TraversalOptions) -> Duration { +fn traverse_inputs( + fs: &dyn FileSystem, + inputs: Vec, + changed_files: Vec, + ctx: &TraversalOptions, +) -> Duration { let start = Instant::now(); - + let changed_files = changed_files.as_slice(); fs.traversal(Box::new(move |scope: &dyn TraversalScope| { for input in inputs { - scope.spawn(ctx, PathBuf::from(input)); + scope.spawn(ctx, PathBuf::from(input), changed_files); } })); diff --git a/crates/rome_cli/src/vcs.rs b/crates/rome_cli/src/vcs.rs index a04a0b61c8e..b8a6c23681f 100644 --- a/crates/rome_cli/src/vcs.rs +++ b/crates/rome_cli/src/vcs.rs @@ -9,6 +9,8 @@ use rome_service::configuration::FilesConfiguration; use rome_service::{Configuration, WorkspaceError}; use std::path::PathBuf; +mod git; + /// This function will check if the configuration is set to use the VCS integration and try to /// read the ignored files. pub(crate) fn store_path_to_ignore_from_vcs( @@ -98,3 +100,13 @@ pub(crate) fn read_vcs_ignore_file( Ok(vec![]) } + +pub(crate) trait VcsClient { + fn changed_files(&self) -> Result, CliDiagnostic>; +} + +pub(crate) fn create_vcs_client(client_kind: &VcsClientKind) -> Box { + Box::new(match client_kind { + VcsClientKind::Git => git::Git, + }) +} diff --git a/crates/rome_cli/src/vcs/git.rs b/crates/rome_cli/src/vcs/git.rs new file mode 100644 index 00000000000..8a6a3231c93 --- /dev/null +++ b/crates/rome_cli/src/vcs/git.rs @@ -0,0 +1,28 @@ +use crate::vcs::VcsClient; +use crate::CliDiagnostic; +use std::io::Read; +use std::process::{Command, Stdio}; + +pub(crate) struct Git; + +impl Git { + const COMMAND: &'static str = "git"; +} + +impl VcsClient for Git { + fn changed_files(&self) -> Result, CliDiagnostic> { + let process = Command::new(Git::COMMAND) + .arg("diff") + .arg("--name-only") + .stdout(Stdio::piped()) + .spawn()?; + + if let Some(mut output) = process.stdout { + let mut buffer = String::new(); + output.read_to_string(&mut buffer)?; + Ok(buffer.lines().map(String::from).collect::>()) + } else { + Ok(Vec::new()) + } + } +} diff --git a/crates/rome_cli/tests/cases/changed_files.rs b/crates/rome_cli/tests/cases/changed_files.rs new file mode 100644 index 00000000000..c41668d3b52 --- /dev/null +++ b/crates/rome_cli/tests/cases/changed_files.rs @@ -0,0 +1,28 @@ +use crate::run_cli; +use crate::snap_test::{assert_cli_snapshot, SnapshotPayload}; +use bpaf::Args; +use rome_console::BufferConsole; +use rome_fs::MemoryFileSystem; +use rome_service::DynRef; + +#[test] +fn emits_an_error_if_vcs_is_not_enabled() { + let mut fs = MemoryFileSystem::default(); + let mut console = BufferConsole::default(); + + let result = run_cli( + DynRef::Borrowed(&mut fs), + &mut console, + Args::from([("check"), "--changed", "./file.js"].as_slice()), + ); + + assert!(result.is_err(), "run_cli returned {result:?}"); + + assert_cli_snapshot(SnapshotPayload::new( + module_path!(), + "emits_an_error_if_vcs_is_not_enabled", + fs, + console, + result, + )); +} diff --git a/crates/rome_cli/tests/cases/mod.rs b/crates/rome_cli/tests/cases/mod.rs index 176f3d8eb39..f3c36e5d05e 100644 --- a/crates/rome_cli/tests/cases/mod.rs +++ b/crates/rome_cli/tests/cases/mod.rs @@ -1,4 +1,5 @@ //! Add here test cases that are not related directly to a command, but to specific //! case that affects many commands +mod changed_files; mod config_extends; diff --git a/crates/rome_cli/tests/snapshots/main_cases_changed_files/emits_an_error_if_vcs_is_not_enabled.snap b/crates/rome_cli/tests/snapshots/main_cases_changed_files/emits_an_error_if_vcs_is_not_enabled.snap new file mode 100644 index 00000000000..c78fb06635a --- /dev/null +++ b/crates/rome_cli/tests/snapshots/main_cases_changed_files/emits_an_error_if_vcs_is_not_enabled.snap @@ -0,0 +1,17 @@ +--- +source: crates/rome_cli/tests/snap_test.rs +expression: content +--- +# Termination Message + +```block +internalError/io ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × The combination of configuration and arguments is invalid: + You provided the --changed argument, but you haven't enabled VCS support. This is an error. + + + +``` + + diff --git a/crates/rome_cli/tests/snapshots/main_commands_check/check_help.snap b/crates/rome_cli/tests/snapshots/main_commands_check/check_help.snap index d940f2f87a4..f058c98f2df 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_check/check_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_check/check_help.snap @@ -51,6 +51,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available positional items: PATH Single file, single path or list of paths diff --git a/crates/rome_cli/tests/snapshots/main_commands_ci/ci_help.snap b/crates/rome_cli/tests/snapshots/main_commands_ci/ci_help.snap index 1059bc2f7d6..e2b62c15128 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_ci/ci_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_ci/ci_help.snap @@ -52,6 +52,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available positional items: PATH Single file, single path or list of paths diff --git a/crates/rome_cli/tests/snapshots/main_commands_format/format_help.snap b/crates/rome_cli/tests/snapshots/main_commands_format/format_help.snap index c3596856de3..bc47c5c8422 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_format/format_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_format/format_help.snap @@ -46,6 +46,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available positional items: PATH Single file, single path or list of paths. diff --git a/crates/rome_cli/tests/snapshots/main_commands_lint/check_help.snap b/crates/rome_cli/tests/snapshots/main_commands_lint/check_help.snap index 131a7a4bd93..e19f22577b8 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_lint/check_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_lint/check_help.snap @@ -51,6 +51,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available positional items: PATH Single file, single path or list of paths diff --git a/crates/rome_cli/tests/snapshots/main_commands_lsp_proxy/lsp_proxy_help.snap b/crates/rome_cli/tests/snapshots/main_commands_lsp_proxy/lsp_proxy_help.snap index 77bd08ebb9b..5b7e325f818 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_lsp_proxy/lsp_proxy_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_lsp_proxy/lsp_proxy_help.snap @@ -8,7 +8,7 @@ expression: content Acts as a server for the Language Server Protocol over stdin/stdout Usage: lsp-proxy [--colors=] [--use-server] [--verbose] [--config-path=PATH] [--max-diagnostics -=NUMBER] [--skip-errors] [--no-errors-on-unmatched] [--error-on-warnings] +=NUMBER] [--skip-errors] [--no-errors-on-unmatched] [--error-on-warnings] [--changed] Global options applied to all commands --colors= Set the formatting mode for markup: "off" prints everything as plain text, @@ -25,6 +25,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available options: -h, --help Prints help information diff --git a/crates/rome_cli/tests/snapshots/main_commands_migrate/migrate_help.snap b/crates/rome_cli/tests/snapshots/main_commands_migrate/migrate_help.snap index edfc6ea8445..cbe0db0fcdf 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_migrate/migrate_help.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_migrate/migrate_help.snap @@ -24,6 +24,8 @@ Global options applied to all commands during the execution of the command. --error-on-warnings Tell Rome to exit with an error code if some diagnostics emit warnings. --json Reports information using the JSON format + --changed Only runs the operation on files that have changed. VCS support needs to + be enabled. Doesn't work when running `rome ci`. Available options: --write Writes the new configuration file to disk diff --git a/crates/rome_fs/Cargo.toml b/crates/rome_fs/Cargo.toml index 0b65ad08a6b..35ab537dd13 100644 --- a/crates/rome_fs/Cargo.toml +++ b/crates/rome_fs/Cargo.toml @@ -18,6 +18,7 @@ rome_diagnostics = { workspace = true } schemars = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"], optional = true } tracing = { workspace = true } +path-slash = "0.2.1" [features] serde = ["dep:serde", "schemars", "rome_diagnostics/schema"] diff --git a/crates/rome_fs/src/fs.rs b/crates/rome_fs/src/fs.rs index b0d53993408..78b6aa3f01b 100644 --- a/crates/rome_fs/src/fs.rs +++ b/crates/rome_fs/src/fs.rs @@ -4,6 +4,7 @@ pub use os::OsFileSystem; use rome_diagnostics::{console, Advices, Diagnostic, LogCategory, Visit}; use rome_diagnostics::{Error, Severity}; use serde::{Deserialize, Serialize}; +use std::ffi::OsString; use std::io; use std::panic::RefUnwindSafe; use std::path::{Path, PathBuf}; @@ -16,6 +17,8 @@ mod os; pub const CONFIG_NAME: &str = "rome.json"; pub trait FileSystem: Send + Sync + RefUnwindSafe { + fn set_changed_files(&mut self) -> Result<(), FileSystemDiagnostic>; + /// It opens a file with the given set of options fn open_with_options(&self, path: &Path, options: OpenOptions) -> io::Result>; @@ -242,7 +245,12 @@ pub trait TraversalScope<'scope> { /// directory, it will be recursively traversed and all the files the /// [`can_handle`](TraversalContext::can_handle) method of the context /// returns true for will be handled as well - fn spawn(&self, context: &'scope dyn TraversalContext, path: PathBuf); + fn spawn( + &self, + context: &'scope dyn TraversalContext, + path: PathBuf, + changed_files: &'scope [String], + ); } pub trait TraversalContext: Sync { diff --git a/crates/rome_fs/src/fs/memory.rs b/crates/rome_fs/src/fs/memory.rs index 039594e30e1..fdb7502bdd5 100644 --- a/crates/rome_fs/src/fs/memory.rs +++ b/crates/rome_fs/src/fs/memory.rs @@ -1,5 +1,6 @@ use std::collections::hash_map::Entry; use std::collections::{hash_map::IntoIter, HashMap}; +use std::ffi::OsString; use std::io; use std::panic::AssertUnwindSafe; use std::path::{Path, PathBuf}; @@ -219,7 +220,12 @@ pub struct MemoryTraversalScope<'scope> { } impl<'scope> TraversalScope<'scope> for MemoryTraversalScope<'scope> { - fn spawn(&self, ctx: &'scope dyn TraversalContext, base: PathBuf) { + fn spawn( + &self, + ctx: &'scope dyn TraversalContext, + base: PathBuf, + _changed_files: &'scope [String], + ) { // Traversal is implemented by iterating on all keys, and matching on // those that are prefixed with the provided `base` path { @@ -470,9 +476,10 @@ mod tests { visited: Mutex::default(), }; + let changed_files = vec![]; // Traverse a directory fs.traversal(Box::new(|scope| { - scope.spawn(&ctx, PathBuf::from("dir1")); + scope.spawn(&ctx, PathBuf::from("dir1"), changed_files.as_slice()); })); let mut visited = Vec::new(); @@ -484,7 +491,7 @@ mod tests { // Traverse a single file fs.traversal(Box::new(|scope| { - scope.spawn(&ctx, PathBuf::from("dir2/file2")); + scope.spawn(&ctx, PathBuf::from("dir2/file2"), changed_files.as_slice()); })); let mut visited = Vec::new(); diff --git a/crates/rome_fs/src/fs/os.rs b/crates/rome_fs/src/fs/os.rs index a5946614be7..031ae60c335 100644 --- a/crates/rome_fs/src/fs/os.rs +++ b/crates/rome_fs/src/fs/os.rs @@ -8,6 +8,7 @@ use crate::{ use rayon::{scope, Scope}; use rome_diagnostics::{adapters::IoError, DiagnosticExt, Error, Severity}; use std::fs::{DirEntry, FileType}; +use std::path::Component; use std::{ env, ffi::OsStr, @@ -106,7 +107,12 @@ impl<'scope> OsTraversalScope<'scope> { } impl<'scope> TraversalScope<'scope> for OsTraversalScope<'scope> { - fn spawn(&self, ctx: &'scope dyn TraversalContext, mut path: PathBuf) { + fn spawn( + &self, + ctx: &'scope dyn TraversalContext, + mut path: PathBuf, + changed_files: &'scope [String], + ) { let mut file_type = match path.metadata() { Ok(meta) => meta.file_type(), Err(err) => { @@ -129,15 +135,23 @@ impl<'scope> TraversalScope<'scope> for OsTraversalScope<'scope> { let _ = ctx.interner().intern_path(path.clone()); if file_type.is_file() { - self.scope.spawn(move |_| { - ctx.handle_file(&path); - }); + if !changed_files.is_empty() { + if path_is_in_changed_flles(&path, changed_files) { + self.scope.spawn(move |_| { + ctx.handle_file(&path); + }); + } + } else { + self.scope.spawn(move |_| { + ctx.handle_file(&path); + }); + } return; } if file_type.is_dir() { self.scope.spawn(move |scope| { - handle_dir(scope, ctx, &path, None); + handle_dir(scope, ctx, &path, None, changed_files); }); return; } @@ -161,6 +175,7 @@ fn handle_dir<'scope>( path: &Path, // The unresolved origin path in case the directory is behind a symbolic link origin_path: Option, + changed_files: &'scope [String], ) { if let Some(file_name) = path.file_name().and_then(OsStr::to_str) { if DEFAULT_IGNORE.contains(&file_name) { @@ -178,7 +193,7 @@ fn handle_dir<'scope>( for entry in iter { match entry { - Ok(entry) => handle_dir_entry(scope, ctx, entry, origin_path.clone()), + Ok(entry) => handle_dir_entry(scope, ctx, entry, origin_path.clone(), changed_files), Err(err) => { ctx.push_diagnostic(IoError::from(err).with_file_path(path.display().to_string())); } @@ -194,6 +209,7 @@ fn handle_dir_entry<'scope>( entry: DirEntry, // The unresolved origin path in case the directory is behind a symbolic link mut origin_path: Option, + changed_files: &'scope [String], ) { let mut path = entry.path(); @@ -232,7 +248,7 @@ fn handle_dir_entry<'scope>( if file_type.is_dir() { if ctx.can_handle(&RomePath::new(path.clone())) { scope.spawn(move |scope| { - handle_dir(scope, ctx, &path, origin_path); + handle_dir(scope, ctx, &path, origin_path, changed_files); }); } return; @@ -273,9 +289,17 @@ fn handle_dir_entry<'scope>( return; } - scope.spawn(move |_| { - ctx.handle_file(&path); - }); + if !changed_files.is_empty() { + if path_is_in_changed_flles(&path, changed_files) { + scope.spawn(move |_| { + ctx.handle_file(&path); + }); + } + } else { + scope.spawn(move |_| { + ctx.handle_file(&path); + }); + } return; } @@ -371,3 +395,28 @@ impl From for ErrorKind { Self::UnknownFileType } } + +fn path_is_in_changed_flles(current_path: &Path, changed_files: &[String]) -> bool { + 'changed_files: for changed_file in changed_files { + let mut matches = false; + let mut components = current_path.components().rev(); + while let Some(component) = components.next() { + match component { + Component::Normal(name) => { + if changed_file.contains(name.to_str().unwrap()) { + matches = true; + } else { + continue 'changed_files; + } + } + _ => {} + } + } + if matches { + return true; + } else { + continue 'changed_files; + } + } + false +} diff --git a/website/package.json b/website/package.json index c8547312941..79d156b5d6a 100644 --- a/website/package.json +++ b/website/package.json @@ -5,7 +5,7 @@ "start": "astro dev", "format": "cargo rome-cli-dev format --write .", "tsc": "tsc --skipLibCheck", - "check": "cargo rome-cli-dev check ./", + "check": "cargo rome-cli-dev check --changed ./", "check:apply": "cargo rome-cli-dev check ./ --apply-unsafe", "start:playground": "pnpm build:wasm-dev && pnpm start", "build": "pnpm build:wasm && pnpm build:js",