diff --git a/lib/configuration/command_configuration.ml b/lib/configuration/command_configuration.ml index 163d332d..39e080b8 100644 --- a/lib/configuration/command_configuration.ml +++ b/lib/configuration/command_configuration.ml @@ -54,7 +54,8 @@ let parse_source_directories ?(file_filters = []) exclude_directory_prefix targe Continue acc else begin - if String.is_prefix (Filename.basename absolute_path) ~prefix:exclude_directory_prefix then + if List.exists exclude_directory_prefix + ~f:(fun prefix -> String.is_prefix (Filename.basename absolute_path) ~prefix) then Skip acc else Continue acc @@ -142,7 +143,7 @@ type user_input_options = ; match_only : bool ; target_directory : string ; directory_depth : int option - ; exclude_directory_prefix : string + ; exclude_directory_prefix : string list } type run_options = @@ -337,7 +338,7 @@ type t = { sources : Command_input.t ; specifications : Specification.t list ; file_filters : string list option - ; exclude_directory_prefix : string + ; exclude_directory_prefix : string list ; run_options : run_options ; output_printer : Printer.t ; interactive_review : interactive_review option @@ -526,7 +527,7 @@ let create let sources = match input_source with | Stdin -> `String (In_channel.input_all In_channel.stdin) - (* TODO(RVT): Unify exclude-dir handling. Currently exclude-dir option must be done while processing zip file in main.ml. *) + (* TODO(RVT): Unify exclude-dir handling. Currently the exclude-dir option for zip file is done in pipeline.ml and not here. *) | Zip -> `Zip (Option.value_exn zip_file) | Directory -> let target_directory = diff --git a/lib/configuration/command_configuration.mli b/lib/configuration/command_configuration.mli index 66e80029..df15ea5d 100644 --- a/lib/configuration/command_configuration.mli +++ b/lib/configuration/command_configuration.mli @@ -49,7 +49,7 @@ type user_input_options = ; match_only : bool ; target_directory : string ; directory_depth : int option - ; exclude_directory_prefix : string + ; exclude_directory_prefix : string list } type run_options = @@ -72,7 +72,7 @@ type t = { sources : Command_input.t ; specifications : Specification.t list ; file_filters : string list option - ; exclude_directory_prefix : string + ; exclude_directory_prefix : string list ; run_options : run_options ; output_printer : Printer.t ; interactive_review : interactive_review option diff --git a/lib/pipeline/pipeline.ml b/lib/pipeline/pipeline.ml index c75c03e6..350ee8ed 100644 --- a/lib/pipeline/pipeline.ml +++ b/lib/pipeline/pipeline.ml @@ -299,17 +299,19 @@ let process_paths_for_interactive ~sequential ~f paths scheduler = with_scheduler scheduler ~f:(try_or_skip f ~default:([],0)) let filter_zip_entries file_filters exclude_directory_prefix zip = - let not_in_an_exclude_directory prefix filename = not (String.is_prefix ~prefix filename) in + let exclude_the_directory prefixes filename = + List.exists prefixes ~f:(fun prefix -> String.is_prefix ~prefix filename) + in match file_filters with | Some [] | None -> List.filter (Zip.entries zip) ~f:(fun { is_directory; filename; _ } -> - not is_directory && not_in_an_exclude_directory exclude_directory_prefix filename) + not is_directory && not (exclude_the_directory exclude_directory_prefix filename)) | Some suffixes -> let has_acceptable_suffix filename = List.exists suffixes ~f:(fun suffix -> String.is_suffix ~suffix filename) in List.filter (Zip.entries zip) ~f:(fun { is_directory; filename; _ } -> not is_directory - && not_in_an_exclude_directory exclude_directory_prefix filename + && not (exclude_the_directory exclude_directory_prefix filename) && has_acceptable_suffix filename) let process_zip_file ~sequential ~f scheduler zip_file exclude_directory_prefix file_filters = diff --git a/src/main.ml b/src/main.ml index a570271e..fd2fc902 100644 --- a/src/main.ml +++ b/src/main.ml @@ -128,7 +128,7 @@ let base_command_parameters : (unit -> 'result) Command.Param.t = and newline_separated_rewrites = flag "newline-separated" no_arg ~doc:"Instead of rewriting in place, output rewrites separated by newlines." and count = flag "count" no_arg ~doc:"Display a count of matches in a file." and list = flag "list" no_arg ~doc:"Display supported languages and extensions" - and exclude_directory_prefix = flag "exclude-dir" (optional_with_default "." string) ~doc:"prefix of directories to exclude. Default: '.'" + and exclude_directory_prefix = flag "exclude-dir" (optional_with_default ["."] (Arg_type.comma_separated ~strip_whitespace:true string)) ~doc:"prefixes Comma-separated prefixes of directories to exclude. Do not put whitespace between commas unless the string is quoted. Default: '.' (ignore directories starting with dot)" and interactive_review = flag "review" ~aliases:["r"] no_arg ~doc:"Review each patch and accept, reject, or modify it with your editor of choice. Defaults to $EDITOR. If $EDITOR is unset, defaults to \"vim\". Override $EDITOR with the -editor flag." and editor = flag "editor" (optional string) ~doc:"editor Perform manual review with [editor]. This activates -review mode." and editor_default_is_reject = flag "default-no" no_arg ~doc:"If set, the default action in review (pressing return) will NOT apply the change. Setting this option activates -review mode." diff --git a/test/common/test_cli.ml b/test/common/test_cli.ml index 4081ec61..2384eb91 100644 --- a/test/common/test_cli.ml +++ b/test/common/test_cli.ml @@ -480,7 +480,8 @@ let%expect_test "is_real_directory" = let%expect_test "exclude_dir_option" = let source = "hello world" in let src_dir = "example" ^/ "src" in - let command_args = Format.sprintf "'main' 'pain' -sequential -d %s -exclude-dir 'ignore' -diff" src_dir in + let exclude_dir = "ignore,also-ignore" in + let command_args = Format.sprintf "'main' 'pain' -sequential -d %s -exclude-dir %s -diff" src_dir exclude_dir in let command = Format.sprintf "%s %s" binary_path command_args in let result = read_expect_stdin_and_stdout command source in print_string result; @@ -514,6 +515,11 @@ let%expect_test "exclude_dir_option" = let result = read_expect_stdin_and_stdout command source in print_string result; [%expect{| + --- example/src/also-ignore-me/main.c + +++ example/src/also-ignore-me/main.c + @@ -1,1 +1,1 @@ + -int main() {} + +int pain() {} --- example/src/honor-file-extensions/honor.pb.generic +++ example/src/honor-file-extensions/honor.pb.generic @@ -1,3 +1,3 @@ @@ -644,6 +650,11 @@ let%expect_test "matcher_override" = let result = read_expect_stdin_and_stdout command source in print_string result; [%expect{| + --- example/src/also-ignore-me/main.c + +++ example/src/also-ignore-me/main.c + @@ -1,1 +1,1 @@ + -int main() {} + +int main_unbalanced_match_) {} --- example/src/ignore-me/main.c +++ example/src/ignore-me/main.c @@ -1,1 +1,1 @@ @@ -716,10 +727,10 @@ let%expect_test "diff_only" = [%expect{| -json-only-diff can only be supplied with -json-lines. |}] -let%expect_test "zip_exclude_dir_with_extension" = +let%expect_test "zip_exclude_dir_with_multiple_extension" = let source = "doesn't matter" in let zip = "example" ^/ "zip-test" ^/ "sample-repo.zip" in - let exclude_dir = "sample-repo/vendor" in + let exclude_dir = "sample-repo/vendor,sample-repo/ignore-this" in let command_args = Format.sprintf "'main' 'pain' .go -zip %s -sequential -diff -exclude-dir %s" zip exclude_dir in let command = Format.sprintf "%s %s" binary_path command_args in let result = read_expect_stdin_and_stdout command source in @@ -735,7 +746,7 @@ let%expect_test "zip_exclude_dir_with_extension" = let%expect_test "zip_exclude_dir_no_extension" = let source = "doesn't matter" in let zip = "example" ^/ "zip-test" ^/ "sample-repo.zip" in - let exclude_dir = "sample-repo/vendor" in + let exclude_dir = "sample-repo/vendor,sample-repo/ignore-this" in let command_args = Format.sprintf "'main' 'pain' -zip %s -sequential -diff -exclude-dir %s" zip exclude_dir in let command = Format.sprintf "%s %s" binary_path command_args in let result = read_expect_stdin_and_stdout command source in diff --git a/test/common/test_pipeline.ml b/test/common/test_pipeline.ml index ab909b1b..4058a1f6 100644 --- a/test/common/test_pipeline.ml +++ b/test/common/test_pipeline.ml @@ -10,7 +10,7 @@ let matcher = (module Generic : Matchers.Matcher) let configuration = { sources = `String "source" ; specifications = [] - ; exclude_directory_prefix = "." + ; exclude_directory_prefix = ["."] ; file_filters = None ; run_options = { sequential = true diff --git a/test/example/src/also-ignore-me/main.c b/test/example/src/also-ignore-me/main.c new file mode 100644 index 00000000..237c8ce1 --- /dev/null +++ b/test/example/src/also-ignore-me/main.c @@ -0,0 +1 @@ +int main() {} diff --git a/test/example/zip-test/sample-repo.zip b/test/example/zip-test/sample-repo.zip index 258ab6b0..dd3dd7dd 100644 Binary files a/test/example/zip-test/sample-repo.zip and b/test/example/zip-test/sample-repo.zip differ diff --git a/test/example/zip-test/sample-repo/ignore-this/main.go b/test/example/zip-test/sample-repo/ignore-this/main.go new file mode 100644 index 00000000..4a31737d --- /dev/null +++ b/test/example/zip-test/sample-repo/ignore-this/main.go @@ -0,0 +1,2 @@ +// ignore-this +func main() {}