| @@ -287,7 +287,7 @@ enum DirectoryRoot { · 286 unmodified lines |
| 287 | 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 | 291 | /// or otherwise don't influence the content of the archive. |
| 292 | 292 | /// Note that this also means that `args` won't be used to control the hash of the archive itself. |
| 293 | 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 | 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 | 512 | pub fn scripted_fixture_read_only_with_args( |
| 513 | 513 | script_name: impl AsRef<Path>, |
| 514 | 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 | 874 | where |
| 875 | 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 | 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 | 882 | where |
| 883 | 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 | 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 | 922 | where |
| 923 | 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 | 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 | 935 | where |
| 936 | 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 | 941 | fn rust_fixture_writable_inner<T, F>( |
| 942 | 942 | name: &str, |
| 943 | 943 | version: u32, |
| 944 | + object_hash: Option<gix_hash::Kind>, |
| 944 | 945 | mut make_fixture: F, |
| 945 | 946 | mode: Creation, |
| 946 | 947 | root: DirectoryRoot, |
| @@ -951,13 +952,15 @@ where · 4 unmodified lines |
| 951 | 952 | let dst = tempfile::TempDir::new()?; |
| 952 | 953 | let res = match mode { |
| 953 | 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 | 957 | copy_recursively_into_existing_dir(ro_dir, dst.path())?; |
| 956 | 958 | let res = make_fixture(FixtureState::Fresh(dst.path()))?; |
| 957 | 959 | res |
| 958 | 960 | } |
| 959 | 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 | 964 | res |
| 962 | 965 | } |
| 963 | 966 | }; |
| @@ -967,6 +970,7 @@ where · 3 unmodified lines |
| 967 | 970 | fn rust_fixture_read_only_inner<T, F>( |
| 968 | 971 | name: &str, |
| 969 | 972 | version: u32, |
| 973 | + object_hash: Option<gix_hash::Kind>, |
| 970 | 974 | make_fixture: F, |
| 971 | 975 | destination_dir: Option<&Path>, |
| 972 | 976 | root: DirectoryRoot, |
| @@ -988,7 +992,8 @@ where · 15 unmodified lines |
| 988 | 992 | Path::new(ARCHIVE_DIR_NAME).join(format!("{archive_name}.{}", tar_extension())), |
| 989 | 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 | 997 | let _marker = marker_if_needed(destination_dir, archive_name)?; |
| 993 | 998 | |
| 994 | 999 | run_fixture_generator_with_marker_handling( |
| @@ -1024,16 +1029,16 @@ fn force_and_dir( · 29 unmodified lines |
| 1024 | 1029 | destination_dir: Option<&Path>, |
| 1025 | 1030 | root: DirectoryRoot, |
| 1026 | 1031 | archive_name: impl AsRef<Path>, |
| 1032 | + hash_kind: Option<gix_hash::Kind>, |
| 1027 | 1033 | script_identity: &dyn std::fmt::Display, |
| 1028 | 1034 | ) -> (bool, PathBuf) { |
| 1029 | 1035 | destination_dir.map_or_else( |
| 1030 | 1036 | || { |
| 1031 | 1037 | let dir = fixture_path_inner( |
| 1032 | | − Path::new("generated-do-not-edit").join(archive_name).join(format!( |
| 1033 | | − "{}-{}", |
| 1034 | | − script_identity, |
| 1035 | | − family_name() |
| 1036 | | − )), |
| 1038 | + Path::new("generated-do-not-edit") |
| 1039 | + .join(archive_name) |
| 1040 | + .join(hash_kind.unwrap_or_else(hash_kind_from_env).to_string()) |
| 1041 | + .join(format!("{}-{}", script_identity, family_name())), |
| 1037 | 1042 | root, |
| 1038 | 1043 | ); |
| 1039 | 1044 | (false, dir) |
| @@ -1127,6 +1132,9 @@ where · 87 unmodified lines |
| 1127 | 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 | 1138 | let script_location = script_name.as_ref(); |
| 1131 | 1139 | let script_path = fixture_path_inner(script_location, root); |
| 1132 | 1140 | |
| @@ -1135,7 +1143,12 @@ where · 2 unmodified lines |
| 1135 | 1143 | let post_version = post_process.as_ref().map(|(v, _)| *v); |
| 1136 | 1144 | let script_identity = { |
| 1137 | 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 | 1152 | // Include post_version in the key if present |
| 1140 | 1153 | let key = if let Some(v) = post_version { |
| 1141 | 1154 | key.join(format!("post-v{v}")) |
| @@ -1178,15 +1191,26 @@ where · 36 unmodified lines |
| 1178 | 1191 | } |
| 1179 | 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 | 1199 | Path::new(ARCHIVE_DIR_NAME).join(format!( |
| 1182 | | − "{}{suffix}.{}", |
| 1200 | + "{}{suffix}{potential_hash_suffix}.{}", |
| 1183 | 1201 | script_basename.to_str().expect("valid UTF-8"), |
| 1184 | 1202 | tar_extension() |
| 1185 | 1203 | )) |
| 1186 | 1204 | }, |
| 1187 | 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 | 1214 | let _marker = marker_if_needed(destination_dir, script_basename)?; |
| 1191 | 1215 | |
| 1192 | 1216 | let script_identity_for_archive = match args_in_hash { |
| @@ -1205,14 +1229,14 @@ where · 12 unmodified lines |
| 1205 | 1229 | |fixture_state| { |
| 1206 | 1230 | if let FixtureState::Uninitialized(dir) = fixture_state { |
| 1207 | 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 | 1233 | Ok(out) => out, |
| 1210 | 1234 | Err(err) |
| 1211 | 1235 | if err.kind() == std::io::ErrorKind::PermissionDenied |
| 1212 | 1236 | || err.raw_os_error() == Some(193) /* windows */ => |
| 1213 | 1237 | { |
| 1214 | 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 | 1241 | Err(err) => return Err(err.into()), |
| 1218 | 1242 | }; |
| @@ -1233,6 +1257,17 @@ where · 14 unmodified lines |
| 1233 | 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 | 1271 | #[cfg(windows)] |
| 1237 | 1272 | const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used. |
| 1238 | 1273 | #[cfg(not(windows))] |
| @@ -1240,6 +1275,7 @@ const NULL_DEVICE: &str = "/dev/null"; · 1 unmodified line |
| 1240 | 1275 | |
| 1241 | 1276 | fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>( |
| 1242 | 1277 | cmd: &'a mut std::process::Command, |
| 1278 | + hash_kind: gix_hash::Kind, |
| 1243 | 1279 | args: I, |
| 1244 | 1280 | script_result_directory: &Path, |
| 1245 | 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 | 1315 | .env("GIT_CONFIG_VALUE_2", "main") |
| 1280 | 1316 | .env("GIT_CONFIG_KEY_3", "protocol.file.allow") |
| 1281 | 1317 | .env("GIT_CONFIG_VALUE_3", "always") |
| 1318 | + .env("GIT_DEFAULT_HASH", hash_kind.to_string()) |
| 1282 | 1319 | } |
| 1283 | 1320 | |
| 1284 | 1321 | /// Get the path attempted as a `bash` interpreter, for fixture scripts having no `#!` we can use. |