pull,context: preserve file mtimes when copying sources
std::fs::copy resets the destination mtime to "now", which breaks timestamp-based build systems (autotools/gnulib). Packages like 'hello' from Debian sid ship pre-generated files alongside their prerequisites; when the copy flattens all mtimes, make considers the generated targets out-of-date and tries to regenerate them with tools (e.g. gperf) that are not declared build-dependencies, failing the build. Restore the source modification and access times after every file copy in pull::copy_dir_all, pull::fetch_archive_sources merge step, and context::unshare copy_dir_recursive/ensure_available.
This commit is contained in:
+34
@@ -113,13 +113,46 @@ fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), Box<dyn Error>> {
|
||||
} else if src_path.is_dir() {
|
||||
copy_dir_all(&src_path, &dst_path)?;
|
||||
} else {
|
||||
// Copy the file, preserving the source modification and access
|
||||
// times. This is important for autotools/gnulib-based packages
|
||||
// (e.g. 'hello' from Debian sid) that ship pre-generated files
|
||||
// alongside their prerequisites: if the copy resets the mtime to
|
||||
// "now", the prerequisites appear as new as the generated targets
|
||||
// and `make` tries to regenerate them using tools (like gperf)
|
||||
// that are not declared build-dependencies.
|
||||
std::fs::copy(&src_path, &dst_path)?;
|
||||
copy_file_times(&src_path, &dst_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Restore the modification and access times of `dest` to match `src`.
|
||||
///
|
||||
/// `std::fs::copy` resets the destination mtime to "now", which breaks
|
||||
/// timestamp-based build systems (autotools/gnulib) that ship pre-generated
|
||||
/// files alongside their prerequisites. Restoring the original timestamps
|
||||
/// prevents `make` from needlessly regenerating those files with tools that
|
||||
/// may not be installed (e.g. `gperf`).
|
||||
fn copy_file_times(src: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
|
||||
let metadata = std::fs::metadata(src)?;
|
||||
let mut times = std::fs::FileTimes::new();
|
||||
let mut have_times = false;
|
||||
if let Ok(mtime) = metadata.modified() {
|
||||
times = times.set_modified(mtime);
|
||||
have_times = true;
|
||||
}
|
||||
if let Ok(atime) = metadata.accessed() {
|
||||
times = times.set_accessed(atime);
|
||||
have_times = true;
|
||||
}
|
||||
if have_times && let Ok(dest_file) = std::fs::File::open(dest) {
|
||||
let _ = dest_file.set_times(times);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to extract tar archive with progress tracking
|
||||
fn extract_tar_archive<D, F>(
|
||||
file_path: &Path,
|
||||
@@ -467,6 +500,7 @@ async fn fetch_archive_sources(
|
||||
copy_dir_all(&sub_path, &target_path)?;
|
||||
} else {
|
||||
std::fs::copy(&sub_path, &target_path)?;
|
||||
copy_file_times(&sub_path, &target_path)?;
|
||||
}
|
||||
}
|
||||
std::fs::remove_dir_all(&src_dir)?;
|
||||
|
||||
Reference in New Issue
Block a user