@@ -166,7 +166,7 @@ pub fn copy_files_except_ext(
166
166
. expect( "a file should have a file name..." )
167
167
)
168
168
) ;
169
- fs :: copy (
169
+ copy (
170
170
entry. path ( ) ,
171
171
& to. join (
172
172
entry
@@ -180,6 +180,62 @@ pub fn copy_files_except_ext(
180
180
Ok ( ( ) )
181
181
}
182
182
183
+ /// Copies a file.
184
+ fn copy < P : AsRef < Path > , Q : AsRef < Path > > ( from : P , to : Q ) -> Result < ( ) > {
185
+ let from = from. as_ref ( ) ;
186
+ let to = to. as_ref ( ) ;
187
+ return copy_inner ( from, to)
188
+ . with_context ( || format ! ( "failed to copy `{}` to `{}`" , from. display( ) , to. display( ) ) ) ;
189
+
190
+ // This is a workaround for an issue with the macOS file watcher.
191
+ // Rust's `std::fs::copy` function uses `fclonefileat`, which creates
192
+ // clones on APFS. Unfortunately fs events seem to trigger on both
193
+ // sides of the clone, and there doesn't seem to be a way to differentiate
194
+ // which side it is.
195
+ // https://github.com/notify-rs/notify/issues/465#issuecomment-1657261035
196
+ // contains more information.
197
+ //
198
+ // This is essentially a copy of the simple copy code path in Rust's
199
+ // standard library.
200
+ #[ cfg( target_os = "macos" ) ]
201
+ fn copy_inner ( from : & Path , to : & Path ) -> Result < ( ) > {
202
+ use std:: fs:: OpenOptions ;
203
+ use std:: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
204
+
205
+ let mut reader = File :: open ( from) ?;
206
+ let metadata = reader. metadata ( ) ?;
207
+ if !metadata. is_file ( ) {
208
+ anyhow:: bail!(
209
+ "expected a file, `{}` appears to be {:?}" ,
210
+ from. display( ) ,
211
+ metadata. file_type( )
212
+ ) ;
213
+ }
214
+ let perm = metadata. permissions ( ) ;
215
+ let mut writer = OpenOptions :: new ( )
216
+ . mode ( perm. mode ( ) )
217
+ . write ( true )
218
+ . create ( true )
219
+ . truncate ( true )
220
+ . open ( to) ?;
221
+ let writer_metadata = writer. metadata ( ) ?;
222
+ if writer_metadata. is_file ( ) {
223
+ // Set the correct file permissions, in case the file already existed.
224
+ // Don't set the permissions on already existing non-files like
225
+ // pipes/FIFOs or device nodes.
226
+ writer. set_permissions ( perm) ?;
227
+ }
228
+ std:: io:: copy ( & mut reader, & mut writer) ?;
229
+ Ok ( ( ) )
230
+ }
231
+
232
+ #[ cfg( not( target_os = "macos" ) ) ]
233
+ fn copy_inner ( from : & Path , to : & Path ) -> Result < ( ) > {
234
+ fs:: copy ( from, to) ?;
235
+ Ok ( ( ) )
236
+ }
237
+ }
238
+
183
239
pub fn get_404_output_file ( input_404 : & Option < String > ) -> String {
184
240
input_404
185
241
. as_ref ( )
0 commit comments