@@ -224,6 +224,15 @@ enum DirectoryRoot {
224224 StandaloneTest ,
225225}
226226
227+ /// Don't add a suffix to the archive name as `args` are platform dependent, none-deterministic,
228+ /// or otherwise don't influence the content of the archive.
229+ /// Note that this also means that `args` won't be used to control the hash of the archive itself.
230+ #[ derive( Copy , Clone ) ]
231+ enum ArgsInHash {
232+ Yes ,
233+ No ,
234+ }
235+
227236/// Return the path to the `<crate-root>/tests/fixtures/<path>` directory.
228237pub fn fixture_path ( path : impl AsRef < Path > ) -> PathBuf {
229238 fixture_path_inner ( path, DirectoryRoot :: IntegrationTest )
@@ -309,7 +318,19 @@ pub fn scripted_fixture_writable_with_args(
309318 args : impl IntoIterator < Item = impl Into < String > > ,
310319 mode : Creation ,
311320) -> Result < tempfile:: TempDir > {
312- scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: IntegrationTest )
321+ scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: IntegrationTest , ArgsInHash :: Yes )
322+ }
323+
324+ /// Like [`scripted_fixture_writable()`], but passes `args` to `script_name` while providing control over
325+ /// the way files are created with `mode`.
326+ ///
327+ /// See [`scripted_fixture_read_only_with_args_single_archive()`] for important details on what `single_archive` means.
328+ pub fn scripted_fixture_writable_with_args_single_archive (
329+ script_name : impl AsRef < Path > ,
330+ args : impl IntoIterator < Item = impl Into < String > > ,
331+ mode : Creation ,
332+ ) -> Result < tempfile:: TempDir > {
333+ scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: IntegrationTest , ArgsInHash :: No )
313334}
314335
315336/// Like [`scripted_fixture_writable_with_args`], but does not prefix the fixture directory with `tests`
@@ -318,24 +339,36 @@ pub fn scripted_fixture_writable_with_args_standalone(
318339 args : impl IntoIterator < Item = impl Into < String > > ,
319340 mode : Creation ,
320341) -> Result < tempfile:: TempDir > {
321- scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: StandaloneTest )
342+ scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: StandaloneTest , ArgsInHash :: Yes )
343+ }
344+
345+ /// Like [`scripted_fixture_writable_with_args`], but does not prefix the fixture directory with `tests`
346+ ///
347+ /// See [`scripted_fixture_read_only_with_args_single_archive()`] for important details on what `single_archive` means.
348+ pub fn scripted_fixture_writable_with_args_standalone_single_archive (
349+ script_name : & str ,
350+ args : impl IntoIterator < Item = impl Into < String > > ,
351+ mode : Creation ,
352+ ) -> Result < tempfile:: TempDir > {
353+ scripted_fixture_writable_with_args_inner ( script_name, args, mode, DirectoryRoot :: StandaloneTest , ArgsInHash :: No )
322354}
323355
324356fn scripted_fixture_writable_with_args_inner (
325357 script_name : impl AsRef < Path > ,
326358 args : impl IntoIterator < Item = impl Into < String > > ,
327359 mode : Creation ,
328360 root : DirectoryRoot ,
361+ args_in_hash : ArgsInHash ,
329362) -> Result < tempfile:: TempDir > {
330363 let dst = tempfile:: TempDir :: new ( ) ?;
331364 Ok ( match mode {
332365 Creation :: CopyFromReadOnly => {
333- let ro_dir = scripted_fixture_read_only_with_args_inner ( script_name, args, None , root) ?;
366+ let ro_dir = scripted_fixture_read_only_with_args_inner ( script_name, args, None , root, args_in_hash ) ?;
334367 copy_recursively_into_existing_dir ( ro_dir, dst. path ( ) ) ?;
335368 dst
336369 }
337370 Creation :: ExecuteScript => {
338- scripted_fixture_read_only_with_args_inner ( script_name, args, dst. path ( ) . into ( ) , root) ?;
371+ scripted_fixture_read_only_with_args_inner ( script_name, args, dst. path ( ) . into ( ) , root, args_in_hash ) ?;
339372 dst
340373 }
341374 } )
@@ -365,22 +398,49 @@ pub fn scripted_fixture_read_only_with_args(
365398 script_name : impl AsRef < Path > ,
366399 args : impl IntoIterator < Item = impl Into < String > > ,
367400) -> Result < PathBuf > {
368- scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: IntegrationTest )
401+ scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: IntegrationTest , ArgsInHash :: Yes )
402+ }
403+
404+ /// Like `scripted_fixture_read_only()`], but passes `args` to `script_name`.
405+ ///
406+ /// Also, don't add a suffix to the archive name as `args` are platform dependent, none-deterministic,
407+ /// or otherwise don't influence the content of the archive.
408+ /// Note that this also means that `args` won't be used to control the hash of the archive itself.
409+ ///
410+ /// Sometimes, this should be combined with adding the archive name to `.gitignore` to prevent its creation
411+ /// in the first place.
412+ ///
413+ /// Note that suffixing archives by default helps to learn what calls are made, and forces the author to
414+ /// think about what should be done to get it right.
415+ pub fn scripted_fixture_read_only_with_args_single_archive (
416+ script_name : impl AsRef < Path > ,
417+ args : impl IntoIterator < Item = impl Into < String > > ,
418+ ) -> Result < PathBuf > {
419+ scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: IntegrationTest , ArgsInHash :: No )
369420}
370421
371422/// Like [`scripted_fixture_read_only_with_args()`], but does not prefix the fixture directory with `tests`
372423pub fn scripted_fixture_read_only_with_args_standalone (
373424 script_name : impl AsRef < Path > ,
374425 args : impl IntoIterator < Item = impl Into < String > > ,
375426) -> Result < PathBuf > {
376- scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: StandaloneTest )
427+ scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: StandaloneTest , ArgsInHash :: Yes )
428+ }
429+
430+ /// Like [`scripted_fixture_read_only_with_args_standalone()`], only has a single archive.
431+ pub fn scripted_fixture_read_only_with_args_standalone_single_archive (
432+ script_name : impl AsRef < Path > ,
433+ args : impl IntoIterator < Item = impl Into < String > > ,
434+ ) -> Result < PathBuf > {
435+ scripted_fixture_read_only_with_args_inner ( script_name, args, None , DirectoryRoot :: StandaloneTest , ArgsInHash :: No )
377436}
378437
379438fn scripted_fixture_read_only_with_args_inner (
380439 script_name : impl AsRef < Path > ,
381440 args : impl IntoIterator < Item = impl Into < String > > ,
382441 destination_dir : Option < & Path > ,
383442 root : DirectoryRoot ,
443+ args_in_hash : ArgsInHash ,
384444) -> Result < PathBuf > {
385445 // Assure tempfiles get removed when aborting the test.
386446 gix_tempfile:: signal:: setup (
@@ -414,11 +474,23 @@ fn scripted_fixture_read_only_with_args_inner(
414474
415475 let script_basename = script_location. file_stem ( ) . unwrap_or ( script_location. as_os_str ( ) ) ;
416476 let archive_file_path = fixture_path_inner (
417- Path :: new ( "generated-archives" ) . join ( format ! (
418- "{}.tar{}" ,
419- script_basename. to_str( ) . expect( "valid UTF-8" ) ,
420- if cfg!( feature = "xz" ) { ".xz" } else { "" }
421- ) ) ,
477+ {
478+ let suffix = match args_in_hash {
479+ ArgsInHash :: Yes => {
480+ let mut suffix = args. join ( "_" ) ;
481+ if !suffix. is_empty ( ) {
482+ suffix. insert ( 0 , '_' ) ;
483+ }
484+ suffix. replace ( [ '\\' , '/' , ' ' , '.' ] , "_" )
485+ }
486+ ArgsInHash :: No => "" . into ( ) ,
487+ } ;
488+ Path :: new ( "generated-archives" ) . join ( format ! (
489+ "{}{suffix}.tar{}" ,
490+ script_basename. to_str( ) . expect( "valid UTF-8" ) ,
491+ if cfg!( feature = "xz" ) { ".xz" } else { "" }
492+ ) )
493+ } ,
422494 root,
423495 ) ;
424496 let ( force_run, script_result_directory) = destination_dir. map_or_else (
@@ -447,7 +519,15 @@ fn scripted_fixture_read_only_with_args_inner(
447519 std:: fs:: remove_dir_all ( & script_result_directory) . map_err ( |err| format ! ( "Failed to remove '{script_result_directory:?}', please try to do that by hand. Original error: {err}" ) ) ?
448520 }
449521 std:: fs:: create_dir_all ( & script_result_directory) ?;
450- match extract_archive ( & archive_file_path, & script_result_directory, script_identity) {
522+ let script_identity_for_archive = match args_in_hash {
523+ ArgsInHash :: Yes => script_identity,
524+ ArgsInHash :: No => 0 ,
525+ } ;
526+ match extract_archive (
527+ & archive_file_path,
528+ & script_result_directory,
529+ script_identity_for_archive,
530+ ) {
451531 Ok ( ( archive_id, platform) ) => {
452532 eprintln ! (
453533 "Extracted fixture from archive '{}' ({}, {:?})" ,
@@ -489,12 +569,15 @@ fn scripted_fixture_read_only_with_args_inner(
489569 output. stdout. as_bstr( ) ,
490570 output. stderr. as_bstr( )
491571 ) ;
492- create_archive_if_not_on_ci ( & script_result_directory, & archive_file_path, script_identity) . map_err (
493- |err| {
494- write_failure_marker ( & failure_marker) ;
495- err
496- } ,
497- ) ?;
572+ create_archive_if_not_on_ci (
573+ & script_result_directory,
574+ & archive_file_path,
575+ script_identity_for_archive,
576+ )
577+ . map_err ( |err| {
578+ write_failure_marker ( & failure_marker) ;
579+ err
580+ } ) ?;
498581 }
499582 }
500583 }
0 commit comments