| @@ -287,7 +287,7 @@ enum DirectoryRoot { · 286 unmodified lines |
| 287 | StandaloneTest, | 287 | StandaloneTest, |
| 288 | } | 288 | } |
| 289 | | 289 | |
| 290 | /// Don't add a suffix to the archive name as `args` are platform dependent, none-deterministic, | 290 | /// Don't add a suffix to the archive name as `args` are platform dependent, non-deterministic, |
| 291 | /// or otherwise don't influence the content of the archive. | 291 | /// or otherwise don't influence the content of the archive. |
| 292 | /// Note that this also means that `args` won't be used to control the hash of the archive itself. | 292 | /// Note that this also means that `args` won't be used to control the hash of the archive itself. |
| 293 | #[derive(Copy, Clone)] | 293 | #[derive(Copy, Clone)] |
| @@ -508,7 +508,7 @@ pub fn copy_recursively_into_existing_dir(src_dir: impl AsRef<Path>, dst_dir: im · 214 unmodified lines |
| 508 | Ok(()) | 508 | Ok(()) |
| 509 | } | 509 | } |
| 510 | | 510 | |
| 511 | /// Like `scripted_fixture_read_only()`], but passes `args` to `script_name`. | 511 | /// Like [`scripted_fixture_read_only()`], but passes `args` to `script_name`. |
| 512 | pub fn scripted_fixture_read_only_with_args( | 512 | pub fn scripted_fixture_read_only_with_args( |
| 513 | script_name: impl AsRef<Path>, | 513 | script_name: impl AsRef<Path>, |
| 514 | args: impl IntoIterator<Item = impl Into<String>>, | 514 | args: impl IntoIterator<Item = impl Into<String>>, |
| @@ -874,7 +874,7 @@ pub fn rust_fixture_read_only<T, F>(name: &str, version: u32, make_fixture: F) - · 359 unmodified lines |
| 874 | where | 874 | where |
| 875 | F: FnOnce(FixtureState<'_>) -> PostResult<T>, | 875 | F: FnOnce(FixtureState<'_>) -> PostResult<T>, |
| 876 | { | 876 | { |
| 877 | rust_fixture_read_only_inner(name, version, make_fixture, None, DirectoryRoot::IntegrationTest) | 877 | rust_fixture_read_only_inner(name, version, None, make_fixture, None, DirectoryRoot::IntegrationTest) |
| 878 | } | 878 | } |
| 879 | | 879 | |
| 880 | /// Like [`rust_fixture_read_only()`], but does not prefix the fixture directory with `tests`. | 880 | /// Like [`rust_fixture_read_only()`], but does not prefix the fixture directory with `tests`. |
| @@ -882,7 +882,7 @@ pub fn rust_fixture_read_only_standalone<T, F>(name: &str, version: u32, make_fi · 1 unmodified line |
| 882 | where | 882 | where |
| 883 | F: FnOnce(FixtureState<'_>) -> PostResult<T>, | 883 | F: FnOnce(FixtureState<'_>) -> PostResult<T>, |
| 884 | { | 884 | { |
| 885 | rust_fixture_read_only_inner(name, version, make_fixture, None, DirectoryRoot::StandaloneTest) | 885 | rust_fixture_read_only_inner(name, version, None, make_fixture, None, DirectoryRoot::StandaloneTest) |
| 886 | } | 886 | } |
| 887 | | 887 | |
| 888 | /// Execute a Rust closure in a directory, returning a writable temporary directory. | 888 | /// Execute a Rust closure in a directory, returning a writable temporary directory. |
| @@ -922,7 +922,7 @@ pub fn rust_fixture_writable<T, F>( · 33 unmodified lines |
| 922 | where | 922 | where |
| 923 | F: FnMut(FixtureState<'_>) -> PostResult<T>, | 923 | F: FnMut(FixtureState<'_>) -> PostResult<T>, |
| 924 | { | 924 | { |
| 925 | rust_fixture_writable_inner(name, version, make_fixture, mode, DirectoryRoot::IntegrationTest) | 925 | rust_fixture_writable_inner(name, version, None, make_fixture, mode, DirectoryRoot::IntegrationTest) |
| 926 | } | 926 | } |
| 927 | | 927 | |
| 928 | /// Like [`rust_fixture_writable()`], but does not prefix the fixture directory with `tests`. | 928 | /// Like [`rust_fixture_writable()`], but does not prefix the fixture directory with `tests`. |
| @@ -935,12 +935,13 @@ pub fn rust_fixture_writable_standalone<T, F>( · 6 unmodified lines |
| 935 | where | 935 | where |
| 936 | F: FnMut(FixtureState<'_>) -> PostResult<T>, | 936 | F: FnMut(FixtureState<'_>) -> PostResult<T>, |
| 937 | { | 937 | { |
| 938 | rust_fixture_writable_inner(name, version, make_fixture, mode, DirectoryRoot::StandaloneTest) | 938 | rust_fixture_writable_inner(name, version, None, make_fixture, mode, DirectoryRoot::StandaloneTest) |
| 939 | } | 939 | } |
| 940 | | 940 | |
| 941 | fn rust_fixture_writable_inner<T, F>( | 941 | fn rust_fixture_writable_inner<T, F>( |
| 942 | name: &str, | 942 | name: &str, |
| 943 | version: u32, | 943 | version: u32, |
| | 944 | object_hash: Option<gix_hash::Kind>, |
| 944 | mut make_fixture: F, | 945 | mut make_fixture: F, |
| 945 | mode: Creation, | 946 | mode: Creation, |
| 946 | root: DirectoryRoot, | 947 | root: DirectoryRoot, |
| @@ -951,13 +952,15 @@ where · 4 unmodified lines |
| 951 | let dst = tempfile::TempDir::new()?; | 952 | let dst = tempfile::TempDir::new()?; |
| 952 | let res = match mode { | 953 | let res = match mode { |
| 953 | Creation::CopyFromReadOnly => { | 954 | Creation::CopyFromReadOnly => { |
| 954 | let (ro_dir, _res_ignored) = rust_fixture_read_only_inner(name, version, &mut make_fixture, None, root)?; | 955 | let (ro_dir, _res_ignored) = |
| | 956 | rust_fixture_read_only_inner(name, version, object_hash, &mut make_fixture, None, root)?; |
| 955 | copy_recursively_into_existing_dir(ro_dir, dst.path())?; | 957 | copy_recursively_into_existing_dir(ro_dir, dst.path())?; |
| 956 | let res = make_fixture(FixtureState::Fresh(dst.path()))?; | 958 | let res = make_fixture(FixtureState::Fresh(dst.path()))?; |
| 957 | res | 959 | res |
| 958 | } | 960 | } |
| 959 | Creation::Execute => { | 961 | Creation::Execute => { |
| 960 | let (_, res) = rust_fixture_read_only_inner(name, version, make_fixture, Some(dst.path()), root)?; | 962 | let (_, res) = |
| | 963 | rust_fixture_read_only_inner(name, version, object_hash, make_fixture, Some(dst.path()), root)?; |
| 961 | res | 964 | res |
| 962 | } | 965 | } |
| 963 | }; | 966 | }; |
| @@ -967,6 +970,7 @@ where · 3 unmodified lines |
| 967 | fn rust_fixture_read_only_inner<T, F>( | 970 | fn rust_fixture_read_only_inner<T, F>( |
| 968 | name: &str, | 971 | name: &str, |
| 969 | version: u32, | 972 | version: u32, |
| | 973 | object_hash: Option<gix_hash::Kind>, |
| 970 | make_fixture: F, | 974 | make_fixture: F, |
| 971 | destination_dir: Option<&Path>, | 975 | destination_dir: Option<&Path>, |
| 972 | root: DirectoryRoot, | 976 | root: DirectoryRoot, |
| @@ -988,7 +992,8 @@ where · 15 unmodified lines |
| 988 | Path::new(ARCHIVE_DIR_NAME).join(format!("{archive_name}.{}", tar_extension())), | 992 | Path::new(ARCHIVE_DIR_NAME).join(format!("{archive_name}.{}", tar_extension())), |
| 989 | root, | 993 | root, |
| 990 | ); | 994 | ); |
| 991 | let (force_run, script_result_directory) = force_and_dir(destination_dir, root, &archive_name, &script_identity); | 995 | let (force_run, script_result_directory) = |
| | 996 | force_and_dir(destination_dir, root, &archive_name, object_hash, &script_identity); |
| 992 | let _marker = marker_if_needed(destination_dir, archive_name)?; | 997 | let _marker = marker_if_needed(destination_dir, archive_name)?; |
| 993 | | 998 | |
| 994 | run_fixture_generator_with_marker_handling( | 999 | run_fixture_generator_with_marker_handling( |
| @@ -1024,16 +1029,16 @@ fn force_and_dir( · 29 unmodified lines |
| 1024 | destination_dir: Option<&Path>, | 1029 | destination_dir: Option<&Path>, |
| 1025 | root: DirectoryRoot, | 1030 | root: DirectoryRoot, |
| 1026 | archive_name: impl AsRef<Path>, | 1031 | archive_name: impl AsRef<Path>, |
| | 1032 | hash_kind: Option<gix_hash::Kind>, |
| 1027 | script_identity: &dyn std::fmt::Display, | 1033 | script_identity: &dyn std::fmt::Display, |
| 1028 | ) -> (bool, PathBuf) { | 1034 | ) -> (bool, PathBuf) { |
| 1029 | destination_dir.map_or_else( | 1035 | destination_dir.map_or_else( |
| 1030 | || { | 1036 | || { |
| 1031 | let dir = fixture_path_inner( | 1037 | let dir = fixture_path_inner( |
| 1032 | Path::new("generated-do-not-edit").join(archive_name).join(format!( | 1038 | Path::new("generated-do-not-edit") |
| 1033 | "{}-{}", | 1039 | .join(archive_name) |
| 1034 | script_identity, | 1040 | .join(hash_kind.unwrap_or_else(hash_kind_from_env).to_string()) |
| 1035 | family_name() | 1041 | .join(format!("{}-{}", script_identity, family_name())), |
| 1036 | )), | | |
| 1037 | root, | 1042 | root, |
| 1038 | ); | 1043 | ); |
| 1039 | (false, dir) | 1044 | (false, dir) |
| @@ -1127,6 +1132,9 @@ where · 87 unmodified lines |
| 1127 | gix_tempfile::signal::handler::Mode::DeleteTempfilesOnTerminationAndRestoreDefaultBehaviour, | 1132 | gix_tempfile::signal::handler::Mode::DeleteTempfilesOnTerminationAndRestoreDefaultBehaviour, |
| 1128 | ); | 1133 | ); |
| 1129 | | 1134 | |
| | 1135 | let hash_kind = hash_kind_from_env(); |
| | 1136 | eprintln!("Using hash '{hash_kind}' when determining which fixture to use or recreate"); |
| | 1137 | |
| 1130 | let script_location = script_name.as_ref(); | 1138 | let script_location = script_name.as_ref(); |
| 1131 | let script_path = fixture_path_inner(script_location, root); | 1139 | let script_path = fixture_path_inner(script_location, root); |
| 1132 | | 1140 | |
| @@ -1135,7 +1143,12 @@ where · 2 unmodified lines |
| 1135 | let post_version = post_process.as_ref().map(|(v, _)| *v); | 1143 | let post_version = post_process.as_ref().map(|(v, _)| *v); |
| 1136 | let script_identity = { | 1144 | let script_identity = { |
| 1137 | let mut map = SCRIPT_IDENTITY.lock(); | 1145 | let mut map = SCRIPT_IDENTITY.lock(); |
| 1138 | let key = args.iter().fold(script_path.clone(), |p, a| p.join(a)); | 1146 | let init = if hash_kind == gix_hash::Kind::Sha1 { |
| | 1147 | script_path.clone() |
| | 1148 | } else { |
| | 1149 | script_path.clone().join(hash_kind.to_string()) |
| | 1150 | }; |
| | 1151 | let key = args.iter().fold(init, |p, a| p.join(a)); |
| 1139 | // Include post_version in the key if present | 1152 | // Include post_version in the key if present |
| 1140 | let key = if let Some(v) = post_version { | 1153 | let key = if let Some(v) = post_version { |
| 1141 | key.join(format!("post-v{v}")) | 1154 | key.join(format!("post-v{v}")) |
| @@ -1178,15 +1191,26 @@ where · 36 unmodified lines |
| 1178 | } | 1191 | } |
| 1179 | ArgsInHash::No => "".into(), | 1192 | ArgsInHash::No => "".into(), |
| 1180 | }; | 1193 | }; |
| | 1194 | let potential_hash_suffix = if hash_kind == gix_hash::Kind::Sha1 { |
| | 1195 | "".into() |
| | 1196 | } else { |
| | 1197 | format!("_{hash_kind}") |
| | 1198 | }; |
| 1181 | Path::new(ARCHIVE_DIR_NAME).join(format!( | 1199 | Path::new(ARCHIVE_DIR_NAME).join(format!( |
| 1182 | "{}{suffix}.{}", | 1200 | "{}{suffix}{potential_hash_suffix}.{}", |
| 1183 | script_basename.to_str().expect("valid UTF-8"), | 1201 | script_basename.to_str().expect("valid UTF-8"), |
| 1184 | tar_extension() | 1202 | tar_extension() |
| 1185 | )) | 1203 | )) |
| 1186 | }, | 1204 | }, |
| 1187 | root, | 1205 | root, |
| 1188 | ); | 1206 | ); |
| 1189 | let (force_run, script_result_directory) = force_and_dir(destination_dir, root, script_basename, &script_identity); | 1207 | let (force_run, script_result_directory) = force_and_dir( |
| | 1208 | destination_dir, |
| | 1209 | root, |
| | 1210 | script_basename, |
| | 1211 | Some(hash_kind), |
| | 1212 | &script_identity, |
| | 1213 | ); |
| 1190 | let _marker = marker_if_needed(destination_dir, script_basename)?; | 1214 | let _marker = marker_if_needed(destination_dir, script_basename)?; |
| 1191 | | 1215 | |
| 1192 | let script_identity_for_archive = match args_in_hash { | 1216 | let script_identity_for_archive = match args_in_hash { |
| @@ -1205,14 +1229,14 @@ where · 12 unmodified lines |
| 1205 | |fixture_state| { | 1229 | |fixture_state| { |
| 1206 | if let FixtureState::Uninitialized(dir) = fixture_state { | 1230 | if let FixtureState::Uninitialized(dir) = fixture_state { |
| 1207 | let mut cmd = std::process::Command::new(&script_absolute_path); | 1231 | let mut cmd = std::process::Command::new(&script_absolute_path); |
| 1208 | let output = match configure_command(&mut cmd, &args, dir).output() { | 1232 | let output = match configure_command(&mut cmd, hash_kind, &args, dir).output() { |
| 1209 | Ok(out) => out, | 1233 | Ok(out) => out, |
| 1210 | Err(err) | 1234 | Err(err) |
| 1211 | if err.kind() == std::io::ErrorKind::PermissionDenied | 1235 | if err.kind() == std::io::ErrorKind::PermissionDenied |
| 1212 | || err.raw_os_error() == Some(193) /* windows */ => | 1236 | || err.raw_os_error() == Some(193) /* windows */ => |
| 1213 | { | 1237 | { |
| 1214 | cmd = std::process::Command::new(bash_program()); | 1238 | cmd = std::process::Command::new(bash_program()); |
| 1215 | configure_command(cmd.arg(&script_absolute_path), &args, dir).output()? | 1239 | configure_command(cmd.arg(&script_absolute_path), hash_kind, &args, dir).output()? |
| 1216 | } | 1240 | } |
| 1217 | Err(err) => return Err(err.into()), | 1241 | Err(err) => return Err(err.into()), |
| 1218 | }; | 1242 | }; |
| @@ -1233,6 +1257,17 @@ where · 14 unmodified lines |
| 1233 | Ok((script_result_directory, res)) | 1257 | Ok((script_result_directory, res)) |
| 1234 | } | 1258 | } |
| 1235 | | 1259 | |
| | 1260 | fn hash_kind_from_env() -> gix_hash::Kind { |
| | 1261 | env::var_os("GIX_TEST_FIXTURE_HASH").and_then(|value| value.into_string().ok()).map(|object_kind| { |
| | 1262 | gix_hash::Kind::from_str(&object_kind).unwrap_or_else(|_| { |
| | 1263 | panic!( |
| | 1264 | "GIX_TEST_FIXTURE_HASH was set to {object_kind} which is an invalid value. Valid values are {}. Exiting.", |
| | 1265 | gix_hash::Kind::all().iter().map(std::string::ToString::to_string).collect::<Vec<_>>().join(", ") |
| | 1266 | ) |
| | 1267 | }) |
| | 1268 | }).unwrap_or_default() |
| | 1269 | } |
| | 1270 | |
| 1236 | #[cfg(windows)] | 1271 | #[cfg(windows)] |
| 1237 | const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used. | 1272 | const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used. |
| 1238 | #[cfg(not(windows))] | 1273 | #[cfg(not(windows))] |
| @@ -1240,6 +1275,7 @@ const NULL_DEVICE: &str = "/dev/null"; · 1 unmodified line |
| 1240 | | 1275 | |
| 1241 | fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>( | 1276 | fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>( |
| 1242 | cmd: &'a mut std::process::Command, | 1277 | cmd: &'a mut std::process::Command, |
| | 1278 | hash_kind: gix_hash::Kind, |
| 1243 | args: I, | 1279 | args: I, |
| 1244 | script_result_directory: &Path, | 1280 | script_result_directory: &Path, |
| 1245 | ) -> &'a mut std::process::Command { | 1281 | ) -> &'a mut std::process::Command { |
| @@ -1279,6 +1315,7 @@ fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>( · 33 unmodified lines |
| 1279 | .env("GIT_CONFIG_VALUE_2", "main") | 1315 | .env("GIT_CONFIG_VALUE_2", "main") |
| 1280 | .env("GIT_CONFIG_KEY_3", "protocol.file.allow") | 1316 | .env("GIT_CONFIG_KEY_3", "protocol.file.allow") |
| 1281 | .env("GIT_CONFIG_VALUE_3", "always") | 1317 | .env("GIT_CONFIG_VALUE_3", "always") |
| | 1318 | .env("GIT_DEFAULT_HASH", hash_kind.to_string()) |
| 1282 | } | 1319 | } |
| 1283 | | 1320 | |
| 1284 | /// Get the path attempted as a `bash` interpreter, for fixture scripts having no `#!` we can use. | 1321 | /// Get the path attempted as a `bash` interpreter, for fixture scripts having no `#!` we can use. |