@@ -12,6 +12,8 @@ pub mod rustc;
1212pub mod rustdoc;
1313
1414use std:: env;
15+ use std:: fs;
16+ use std:: io;
1517use std:: path:: { Path , PathBuf } ;
1618use std:: process:: { Command , Output } ;
1719
@@ -201,6 +203,71 @@ pub fn set_host_rpath(cmd: &mut Command) {
201203 } ) ;
202204}
203205
206+ /// Copy a directory into another.
207+ pub fn copy_dir_all ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) {
208+ fn copy_dir_all_inner ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) -> io:: Result < ( ) > {
209+ let dst = dst. as_ref ( ) ;
210+ if !dst. is_dir ( ) {
211+ fs:: create_dir_all ( & dst) ?;
212+ }
213+ for entry in fs:: read_dir ( src) ? {
214+ let entry = entry?;
215+ let ty = entry. file_type ( ) ?;
216+ if ty. is_dir ( ) {
217+ copy_dir_all_inner ( entry. path ( ) , dst. join ( entry. file_name ( ) ) ) ?;
218+ } else {
219+ fs:: copy ( entry. path ( ) , dst. join ( entry. file_name ( ) ) ) ?;
220+ }
221+ }
222+ Ok ( ( ) )
223+ }
224+
225+ if let Err ( e) = copy_dir_all_inner ( & src, & dst) {
226+ // Trying to give more context about what exactly caused the failure
227+ panic ! (
228+ "failed to copy `{}` to `{}`: {:?}" ,
229+ src. as_ref( ) . display( ) ,
230+ dst. as_ref( ) . display( ) ,
231+ e
232+ ) ;
233+ }
234+ }
235+
236+ /// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise.
237+ pub fn recursive_diff ( dir1 : impl AsRef < Path > , dir2 : impl AsRef < Path > ) {
238+ fn read_file ( path : & Path ) -> Vec < u8 > {
239+ match fs:: read ( path) {
240+ Ok ( c) => c,
241+ Err ( e) => panic ! ( "Failed to read `{}`: {:?}" , path. display( ) , e) ,
242+ }
243+ }
244+
245+ let dir2 = dir2. as_ref ( ) ;
246+ for entry in fs:: read_dir ( dir1) . unwrap ( ) {
247+ let entry = entry. unwrap ( ) ;
248+ let entry_name = entry. file_name ( ) ;
249+ let path = entry. path ( ) ;
250+
251+ if path. is_dir ( ) {
252+ recursive_diff ( & path, & dir2. join ( entry_name) ) ;
253+ } else {
254+ let path2 = dir2. join ( entry_name) ;
255+ let file1 = read_file ( & path) ;
256+ let file2 = read_file ( & path2) ;
257+
258+ // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
259+ // Why not using String? Because there might be minified files or even potentially
260+ // binary ones, so that would display useless output.
261+ assert ! (
262+ file1 == file2,
263+ "`{}` and `{}` have different content" ,
264+ path. display( ) ,
265+ path2. display( ) ,
266+ ) ;
267+ }
268+ }
269+ }
270+
204271/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
205272/// containing a `cmd: Command` field and a `output` function. The provided helpers are:
206273///
0 commit comments