@@ -90,73 +90,100 @@ module Exit_status = struct
90
90
[@@ deriving sexp_of ]
91
91
end
92
92
93
+ let null_separator = String. make 1 (Char. of_int_exn 0 )
94
+
93
95
let grep ~vcs ~repo_root ~below =
94
- let files_to_grep = Vcs. ls_files vcs ~repo_root ~below in
95
- let stdin_text =
96
- files_to_grep |> List. map ~f: Vcs.Path_in_repo. to_string |> String. concat ~sep: " \n "
97
- in
98
96
let files_to_grep =
99
- match
100
- let prog =
101
- match Lazy. force find_xargs with
102
- | Some prog -> prog
103
- | None -> failwith " Cannot find xargs in PATH" [@ coverage off]
104
- in
105
- let stdin_reader, stdin_writer = Spawn. safe_pipe () in
106
- let stdout_reader, stdout_writer = Spawn. safe_pipe () in
107
- let stderr_reader, stderr_writer = Spawn. safe_pipe () in
108
- let pid =
109
- Spawn. spawn
110
- ~cwd: (Path (Vcs.Repo_root. to_string repo_root))
111
- ~prog
112
- ~argv:
113
- [ " xargs"
114
- ; " -r"
115
- ; " -d"
116
- ; " \n "
117
- ; " grep"
118
- ; " --no-messages"
119
- ; " -E"
120
- ; " -l"
121
- ; " --binary-files=without-match"
122
- ; cr_pattern_egrep
123
- ]
124
- ~stdin: stdin_reader
125
- ~stdout: stdout_writer
126
- ~stderr: stderr_writer
127
- ()
128
- in
129
- Unix. close stdin_reader;
130
- Unix. close stdout_writer;
131
- Unix. close stderr_writer;
132
- let () =
133
- let stdin_oc = Unix. out_channel_of_descr stdin_writer in
134
- Out_channel. output_string stdin_oc stdin_text;
135
- Out_channel. flush stdin_oc;
136
- Unix. close stdin_writer
97
+ match Vcs. ls_files vcs ~repo_root ~below with
98
+ | [] -> []
99
+ | _ :: _ as files_to_grep ->
100
+ let stdin_text =
101
+ files_to_grep
102
+ |> List. map ~f: Vcs.Path_in_repo. to_string
103
+ |> String. concat ~sep: null_separator
137
104
in
138
- let stdout = read_all_from_fd stdout_reader in
139
- let (_ : string ) = read_all_from_fd stderr_reader in
140
- let pid', process_status = waitpid_non_intr pid in
141
- assert (pid = pid');
142
- match process_status with
143
- | Unix. WEXITED (0 | 123 ) -> `Output stdout
144
- | Unix. WEXITED n -> `Exit_status (`Exited n)
145
- | Unix. WSIGNALED n -> `Exit_status (`Signaled n) [@ coverage off]
146
- | Unix. WSTOPPED n -> `Exit_status (`Stopped n) [@ coverage off]
147
- with
148
- | `Output stdout -> stdout |> String. split_lines |> List. map ~f: Vcs.Path_in_repo. v
149
- | `Exit_status exit_status ->
150
- raise
151
- (Err. E
152
- (Err. create
153
- [ Pp. text " Process xargs exited abnormally."
154
- ; Err. sexp [% sexp { exit_status : Exit_status .t }]
155
- ]))
156
- | exception exn ->
157
- raise
158
- (Err. E (Err. create [ Pp. text " Error while running xargs process." ; Err. exn exn ]))
159
- [@ coverage off]
105
+ let stdout_ref = ref " <Unknown>" in
106
+ let stderr_ref = ref " <Unknown>" in
107
+ (match
108
+ let prog =
109
+ match Lazy. force find_xargs with
110
+ | Some prog -> prog
111
+ | None -> failwith " Cannot find xargs in PATH" [@ coverage off]
112
+ in
113
+ let stdin_reader, stdin_writer = Spawn. safe_pipe () in
114
+ let stdout_reader, stdout_writer = Spawn. safe_pipe () in
115
+ let stderr_reader, stderr_writer = Spawn. safe_pipe () in
116
+ let pid =
117
+ Spawn. spawn
118
+ ~cwd: (Path (Vcs.Repo_root. to_string repo_root))
119
+ ~prog
120
+ ~argv:
121
+ [ " xargs"
122
+ ; " -0"
123
+ ; " grep"
124
+ ; " --no-messages"
125
+ ; " -E"
126
+ ; " -l"
127
+ ; " --binary-files=without-match"
128
+ ; cr_pattern_egrep
129
+ ]
130
+ ~stdin: stdin_reader
131
+ ~stdout: stdout_writer
132
+ ~stderr: stderr_writer
133
+ ()
134
+ in
135
+ Unix. close stdin_reader;
136
+ Unix. close stdout_writer;
137
+ Unix. close stderr_writer;
138
+ let () =
139
+ let stdin_oc = Unix. out_channel_of_descr stdin_writer in
140
+ Out_channel. output_string stdin_oc stdin_text;
141
+ Out_channel. flush stdin_oc;
142
+ Unix. close stdin_writer
143
+ in
144
+ let stdout = read_all_from_fd stdout_reader in
145
+ stdout_ref := stdout;
146
+ let stderr = read_all_from_fd stderr_reader in
147
+ stderr_ref := stderr;
148
+ let pid', process_status = waitpid_non_intr pid in
149
+ assert (pid = pid');
150
+ match process_status with
151
+ | Unix. WEXITED n ->
152
+ (* The exit code of [xargs] is not consistent on all of the platforms
153
+ that we'd like to support. While it always returns [0] in case of
154
+ a match, when the inner [grep] doesn't find a match and returns
155
+ [1], the outer call to [xargs] may return [1] or [123] depending
156
+ on things like the OS. *)
157
+ if Int. equal n 0
158
+ then (
159
+ let files = stdout |> String. split_lines |> List. map ~f: Vcs.Path_in_repo. v in
160
+ `Files files)
161
+ else if
162
+ (Int. equal n 123 || (Int. equal n 1 [@ coverage off] (* On MacOS *) ))
163
+ && String. is_empty stdout
164
+ && String. is_empty stderr
165
+ then `Files []
166
+ else `Error (`Exited n)
167
+ | Unix. WSIGNALED n -> `Error (`Signaled n) [@ coverage off]
168
+ | Unix. WSTOPPED n -> `Error (`Stopped n) [@ coverage off]
169
+ with
170
+ | `Files files -> files
171
+ | `Error exit_status ->
172
+ let stdout = ! stdout_ref in
173
+ let stderr = ! stderr_ref in
174
+ raise
175
+ (Err. E
176
+ (Err. create
177
+ [ Pp. text " Process xargs exited abnormally."
178
+ ; Err. sexp
179
+ [% sexp
180
+ { exit_status : Exit_status .t ; stdout : string ; stderr : string }]
181
+ ]))
182
+ | exception exn ->
183
+ raise
184
+ (Err. E
185
+ (Err. create [ Pp. text " Error while running xargs process." ; Err. exn exn ]))
186
+ [@ coverage off])
160
187
in
161
188
List. concat_map files_to_grep ~f: (fun path_in_repo ->
162
189
let file_contents =
0 commit comments