From f08ea2051eeff565d7d63d721371206133c48b63 Mon Sep 17 00:00:00 2001 From: Oliver Reiche Date: Wed, 9 Mar 2022 18:11:20 +0100 Subject: FileSystemManager: Support set epoch time on file creation --- src/buildtool/file_system/TARGETS | 2 +- src/buildtool/file_system/file_system_manager.hpp | 49 +++++++++++++++++------ src/buildtool/system/TARGETS | 1 + src/buildtool/system/system.hpp | 36 +++++++++++++++++ src/utils/cpp/concepts.hpp | 14 +++++++ 5 files changed, 88 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/buildtool/file_system/TARGETS b/src/buildtool/file_system/TARGETS index d780c47a..929c372f 100644 --- a/src/buildtool/file_system/TARGETS +++ b/src/buildtool/file_system/TARGETS @@ -66,4 +66,4 @@ ] , "stage": ["src", "buildtool", "file_system"] } -} \ No newline at end of file +} diff --git a/src/buildtool/file_system/file_system_manager.hpp b/src/buildtool/file_system/file_system_manager.hpp index 0bdfb8a6..c5618e8b 100644 --- a/src/buildtool/file_system/file_system_manager.hpp +++ b/src/buildtool/file_system/file_system_manager.hpp @@ -1,6 +1,7 @@ #ifndef INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_FILE_SYSTEM_MANAGER_HPP #define INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_FILE_SYSTEM_MANAGER_HPP +#include #include // for std::fopen #include #include @@ -118,7 +119,7 @@ class FileSystemManager { } } - template + template requires(IsFileObject(kType)) [[nodiscard]] static auto CreateFileHardlinkAs( std::filesystem::path const& file_path, @@ -127,20 +128,23 @@ class FileSystemManager { // that the created link has the correct permissions as soon as the link // creation is finished. return SetFilePermissions(file_path, IsExecutableObject(kType)) and + (not kSetEpochTime or SetEpochTime(file_path)) and CreateFileHardlink(file_path, link_path); } + template [[nodiscard]] static auto CreateFileHardlinkAs( std::filesystem::path const& file_path, std::filesystem::path const& link_path, ObjectType output_type) noexcept -> bool { switch (output_type) { case ObjectType::File: - return CreateFileHardlinkAs(file_path, - link_path); + return CreateFileHardlinkAs( + file_path, link_path); case ObjectType::Executable: - return CreateFileHardlinkAs(file_path, - link_path); + return CreateFileHardlinkAs(file_path, + link_path); case ObjectType::Tree: return false; } @@ -206,7 +210,7 @@ class FileSystemManager { return CopyFileImpl(src, dst, opt); } - template + template requires(IsFileObject(kType)) [[nodiscard]] static auto CopyFileAs( std::filesystem::path const& src, std::filesystem::path const& dst, @@ -215,9 +219,11 @@ class FileSystemManager { std::filesystem::copy_options::overwrite_existing) noexcept -> bool { return CopyFile(src, dst, fd_less, opt) and - SetFilePermissions(dst, IsExecutableObject(kType)); + SetFilePermissions(dst, IsExecutableObject(kType)) and + (not kSetEpochTime or SetEpochTime(dst)); } + template [[nodiscard]] static auto CopyFileAs( std::filesystem::path const& src, std::filesystem::path const& dst, @@ -228,9 +234,10 @@ class FileSystemManager { -> bool { switch (type) { case ObjectType::File: - return CopyFileAs(src, dst, fd_less, opt); + return CopyFileAs( + src, dst, fd_less, opt); case ObjectType::Executable: - return CopyFileAs( + return CopyFileAs( src, dst, fd_less, opt); case ObjectType::Tree: break; @@ -513,16 +520,18 @@ class FileSystemManager { return WriteFileImpl(content, file); } - template + template requires(IsFileObject(kType)) [[nodiscard]] static auto WriteFileAs(std::string const& content, std::filesystem::path const& file, bool fd_less = false) noexcept -> bool { return WriteFile(content, file, fd_less) and - SetFilePermissions(file, IsExecutableObject(kType)); + SetFilePermissions(file, IsExecutableObject(kType)) and + (not kSetEpochTime or SetEpochTime(file)); } + template [[nodiscard]] static auto WriteFileAs(std::string const& content, std::filesystem::path const& file, ObjectType output_type, @@ -530,9 +539,10 @@ class FileSystemManager { -> bool { switch (output_type) { case ObjectType::File: - return WriteFileAs(content, file, fd_less); + return WriteFileAs( + content, file, fd_less); case ObjectType::Executable: - return WriteFileAs( + return WriteFileAs( content, file, fd_less); case ObjectType::Tree: return false; @@ -681,6 +691,19 @@ class FileSystemManager { return false; } } + + static auto SetEpochTime(std::filesystem::path const& file_path) noexcept + -> bool { + static auto const kPosixEpochTime = + System::GetPosixEpoch(); + try { + std::filesystem::last_write_time(file_path, kPosixEpochTime); + return true; + } catch (std::exception const& e) { + Logger::Log(LogLevel::Error, e.what()); + return false; + } + } }; // class FileSystemManager #endif // INCLUDED_SRC_BUILDTOOL_FILE_SYSTEM_FILE_SYSTEM_MANAGER_HPP diff --git a/src/buildtool/system/TARGETS b/src/buildtool/system/TARGETS index d71245b1..ddc7ae4d 100644 --- a/src/buildtool/system/TARGETS +++ b/src/buildtool/system/TARGETS @@ -9,6 +9,7 @@ , "cond": {"type": "var", "name": "VALGRIND_BUILD"} , "then": ["VALGRIND_BUILD"] } + , "deps": [["src/utils/cpp", "concepts"]] , "stage": ["src", "buildtool", "system"] } , "system_command": diff --git a/src/buildtool/system/system.hpp b/src/buildtool/system/system.hpp index 2038d5c7..fc67471b 100644 --- a/src/buildtool/system/system.hpp +++ b/src/buildtool/system/system.hpp @@ -1,10 +1,46 @@ #ifndef INCLUDED_SRC_BUILDTOOL_SYSTEM_SYSTEM_HPP #define INCLUDED_SRC_BUILDTOOL_SYSTEM_SYSTEM_HPP +#include + +#include "src/utils/cpp/concepts.hpp" + namespace System { void ExitWithoutCleanup(int exit_code); +/// \brief Obtain POSIX epoch time for a given clock. +/// Clocks may have different epoch times. To obtain the POSIX epoch time +/// (1970-01-01 00:00:00 UTC) for a given clock, it must be converted. +template +static auto GetPosixEpoch() -> std::chrono::time_point { + // Since C++20, the system clock's default value is the POSIX epoch time. + std::chrono::time_point sys_epoch{}; + if constexpr (std::is_same_v) { + // No conversion necessary for the system clock. + return sys_epoch; + } + else if constexpr (ClockHasFromSys) { + // The correct C++20 way to perform the time point conversion. + return T_Clock::from_sys(sys_epoch); + } + else if constexpr (ClockHasFromTime) { + // Older releases of libcxx did not implement the standard conversion + // function from_sys() for std::chrono::file_clock. Instead the + // non-standard function file_clock::from_time_t() must be used. Since + // libcxx 14.0.0, this has been fixed by: + // - https://reviews.llvm.org/D113027 + // - https://reviews.llvm.org/D113430 + // TODO(modernize): remove this once we require clang version >= 14.0.0 + return T_Clock::from_time_t( + std::chrono::system_clock::to_time_t(sys_epoch)); + } + static_assert(std::is_same_v or + ClockHasFromSys or ClockHasFromTime, + "Time point conversion function unavailable."); + return {}; } +} // namespace System + #endif // INCLUDED_SRC_BUILDTOOL_SYSTEM_SYSTEM_HPP diff --git a/src/utils/cpp/concepts.hpp b/src/utils/cpp/concepts.hpp index 92718b43..597179e1 100644 --- a/src/utils/cpp/concepts.hpp +++ b/src/utils/cpp/concepts.hpp @@ -1,6 +1,7 @@ #ifndef INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP #define INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP +#include #include #include @@ -52,4 +53,17 @@ template concept InputIterableStringContainer = InputIterableContainerand ContainsString; +// TODO(modernize): remove this once we require clang version >= 14.0.0 +template +concept ClockHasFromSys = + requires(std::chrono::time_point const tp) { + T::from_sys(tp); +}; + +// TODO(modernize): remove this once we require clang version >= 14.0.0 +template +concept ClockHasFromTime = requires(std::time_t const t) { + T::from_time_t(t); +}; + #endif // INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP -- cgit v1.2.3