1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-19 19:43:23 +08:00

Merge branch 'upstream-KWSys' into update-kwsys

# By KWSys Upstream
* upstream-KWSys:
  KWSys 2025-07-24 (bf2d9893)
This commit is contained in:
Brad King
2025-07-24 09:45:32 -04:00
3 changed files with 190 additions and 16 deletions

View File

@@ -2247,6 +2247,48 @@ SystemTools::CopyStatus SystemTools::CopyFileIfDifferent(
return CopyStatus{ Status::Success(), CopyStatus::NoPath }; return CopyStatus{ Status::Success(), CopyStatus::NoPath };
} }
SystemTools::CopyStatus SystemTools::CopyFileIfNewer(
std::string const& source, std::string const& destination)
{
// special check for a destination that is a directory
// FileTimeCompare does not handle file to directory compare
if (SystemTools::FileIsDirectory(destination)) {
std::string const new_destination = FileInDir(source, destination);
if (!SystemTools::ComparePath(new_destination, destination)) {
return SystemTools::CopyFileIfNewer(source, new_destination);
}
// If source and destination are the same path, don't copy
return CopyStatus{ Status::Success(), CopyStatus::NoPath };
}
// source and destination are files so do a copy if source is newer
// Check if source file exists first
if (!SystemTools::FileExists(source)) {
return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath };
}
// If destination doesn't exist, always copy
if (!SystemTools::FileExists(destination)) {
return SystemTools::CopyFileAlways(source, destination);
}
// Check if source is newer than destination
int timeResult;
Status timeStatus =
SystemTools::FileTimeCompare(source, destination, &timeResult);
if (timeStatus.IsSuccess()) {
if (timeResult > 0) {
// Source is newer, copy it
return SystemTools::CopyFileAlways(source, destination);
} else {
// Source is not newer, no need to copy
return CopyStatus{ Status::Success(), CopyStatus::NoPath };
}
} else {
// Time comparison failed, be conservative and copy to ensure updates are
// not missed
return SystemTools::CopyFileAlways(source, destination);
}
}
#define KWSYS_ST_BUFFER 4096 #define KWSYS_ST_BUFFER 4096
bool SystemTools::FilesDiffer(std::string const& source, bool SystemTools::FilesDiffer(std::string const& source,
@@ -2583,15 +2625,31 @@ SystemTools::CopyStatus SystemTools::CopyFileAlways(
return status; return status;
} }
SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
std::string const& destination,
SystemTools::CopyWhen when)
{
switch (when) {
case SystemTools::CopyWhen::Always:
return SystemTools::CopyFileAlways(source, destination);
case SystemTools::CopyWhen::OnlyIfDifferent:
return SystemTools::CopyFileIfDifferent(source, destination);
case SystemTools::CopyWhen::OnlyIfNewer:
return SystemTools::CopyFileIfNewer(source, destination);
default:
break;
}
// Should not reach here
return CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath };
}
SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source, SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
std::string const& destination, std::string const& destination,
bool always) bool always)
{ {
if (always) { return SystemTools::CopyAFile(source, destination,
return SystemTools::CopyFileAlways(source, destination); always ? CopyWhen::Always
} else { : CopyWhen::OnlyIfDifferent);
return SystemTools::CopyFileIfDifferent(source, destination);
}
} }
/** /**
@@ -2599,7 +2657,8 @@ SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
* "destination". * "destination".
*/ */
Status SystemTools::CopyADirectory(std::string const& source, Status SystemTools::CopyADirectory(std::string const& source,
std::string const& destination, bool always) std::string const& destination,
SystemTools::CopyWhen when)
{ {
Status status; Status status;
Directory dir; Directory dir;
@@ -2622,12 +2681,12 @@ Status SystemTools::CopyADirectory(std::string const& source,
std::string fullDestPath = destination; std::string fullDestPath = destination;
fullDestPath += "/"; fullDestPath += "/";
fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum)); fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
status = SystemTools::CopyADirectory(fullPath, fullDestPath, always); status = SystemTools::CopyADirectory(fullPath, fullDestPath, when);
if (!status.IsSuccess()) { if (!status.IsSuccess()) {
return status; return status;
} }
} else { } else {
status = SystemTools::CopyAFile(fullPath, destination, always); status = SystemTools::CopyAFile(fullPath, destination, when);
if (!status.IsSuccess()) { if (!status.IsSuccess()) {
return status; return status;
} }
@@ -2638,6 +2697,14 @@ Status SystemTools::CopyADirectory(std::string const& source,
return status; return status;
} }
Status SystemTools::CopyADirectory(std::string const& source,
std::string const& destination, bool always)
{
return SystemTools::CopyADirectory(source, destination,
always ? CopyWhen::Always
: CopyWhen::OnlyIfDifferent);
}
// return size of file; also returns zero if no file exists // return size of file; also returns zero if no file exists
unsigned long SystemTools::FileLength(std::string const& filename) unsigned long SystemTools::FileLength(std::string const& filename)
{ {

View File

@@ -577,6 +577,13 @@ public:
static CopyStatus CopyFileIfDifferent(std::string const& source, static CopyStatus CopyFileIfDifferent(std::string const& source,
std::string const& destination); std::string const& destination);
/**
* Copy the source file to the destination file only
* if the source file is newer than the destination file.
*/
static CopyStatus CopyFileIfNewer(std::string const& source,
std::string const& destination);
/** /**
* Compare the contents of two files. Return true if different * Compare the contents of two files. Return true if different
*/ */
@@ -658,24 +665,34 @@ public:
static CopyStatus CopyFileAlways(std::string const& source, static CopyStatus CopyFileAlways(std::string const& source,
std::string const& destination); std::string const& destination);
enum class CopyWhen
{
Always,
OnlyIfDifferent,
OnlyIfNewer,
};
/** /**
* Copy a file. If the "always" argument is true the file is always * Copy a file with specified copy behavior.
* copied. If it is false, the file is copied only if it is new or
* has changed.
*/ */
static CopyStatus CopyAFile(std::string const& source, static CopyStatus CopyAFile(std::string const& source,
std::string const& destination, std::string const& destination,
bool always = true); CopyWhen when = CopyWhen::Always);
static CopyStatus CopyAFile(std::string const& source,
std::string const& destination, bool always);
/** /**
* Copy content directory to another directory with all files and * Copy content directory to another directory with all files and
* subdirectories. If the "always" argument is true all files are * subdirectories. The "when" argument controls when files are copied:
* always copied. If it is false, only files that have changed or * Always: all files are always copied.
* are new are copied. * OnlyIfDifferent: only files that have changed are copied.
* OnlyIfNewer: only files that are newer than the destination are copied.
*/ */
static Status CopyADirectory(std::string const& source, static Status CopyADirectory(std::string const& source,
std::string const& destination, std::string const& destination,
bool always = true); CopyWhen when = CopyWhen::Always);
static Status CopyADirectory(std::string const& source,
std::string const& destination, bool always);
/** /**
* Remove a file * Remove a file

View File

@@ -1160,6 +1160,94 @@ static bool CheckCopyFileIfDifferent()
return ret; return ret;
} }
static bool CheckCopyFileIfNewer()
{
bool ret = true;
// Prepare "older" files.
if (!writeFile("older_source.txt", "old content")) {
return false;
}
if (!writeFile("older_dest.txt", "old content")) {
return false;
}
// Small delay to ensure different timestamps
#if defined(_WIN32)
Sleep(1125); // Sleep for 1.125 seconds on Windows
#else
usleep(1125000); // Sleep for 1.125 seconds on Unix
#endif
// Prepare "newer" files.
if (!writeFile("newer_source.txt", "test content")) {
return false;
}
if (!writeFile("newer_source2.txt", "newer content")) {
return false;
}
if (!writeFile("newer_dest2.txt", "new content")) {
return false;
}
if (!kwsys::SystemTools::MakeDirectory("newer_dir_a") ||
!kwsys::SystemTools::MakeDirectory("newer_dir_b")) {
return false;
}
// Test case 1: Copy when destination doesn't exist
if (!kwsys::SystemTools::CopyFileIfNewer("newer_source.txt",
"newer_dest1.txt")) {
std::cerr << "CopyFileIfNewer() failed when destination doesn't exist."
<< std::endl;
ret = false;
} else {
std::string dest_content = readFile("newer_dest1.txt");
if (dest_content != "test content") {
std::cerr << "CopyFileIfNewer() incorrect content when destination "
"doesn't exist."
<< std::endl;
ret = false;
}
}
// Test case 2: Don't copy when source is older
auto copy_result =
kwsys::SystemTools::CopyFileIfNewer("older_source.txt", "newer_dest2.txt");
if (!copy_result) {
std::cerr << "CopyFileIfNewer() failed when source is older." << std::endl;
ret = false;
} else {
std::string dest_content = readFile("newer_dest2.txt");
if (dest_content != "new content") {
std::cerr
<< "CopyFileIfNewer() should not have copied when source is older."
<< std::endl;
ret = false;
}
}
// Test case 3: Copy when source is newer
if (!kwsys::SystemTools::CopyFileIfNewer("newer_source2.txt",
"older_dest.txt")) {
std::cerr << "CopyFileIfNewer() failed when source is newer." << std::endl;
ret = false;
} else {
std::string dest_content = readFile("older_dest.txt");
if (dest_content != "newer content") {
std::cerr << "CopyFileIfNewer() incorrect content when source is newer."
<< std::endl;
ret = false;
}
}
// Test case 4: Directory to directory copy
if (!kwsys::SystemTools::CopyFileIfNewer("newer_dir_a/", "newer_dir_b")) {
ret = false;
}
return ret;
}
static bool CheckURLParsing() static bool CheckURLParsing()
{ {
bool ret = true; bool ret = true;
@@ -1271,6 +1359,8 @@ int testSystemTools(int, char*[])
res &= CheckCopyFileIfDifferent(); res &= CheckCopyFileIfDifferent();
res &= CheckCopyFileIfNewer();
res &= CheckURLParsing(); res &= CheckURLParsing();
res &= CheckSplitString(); res &= CheckSplitString();