diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/file_system/TARGETS | 2 | ||||
-rw-r--r-- | src/buildtool/file_system/file_system_manager.hpp | 49 | ||||
-rw-r--r-- | src/buildtool/system/TARGETS | 1 | ||||
-rw-r--r-- | src/buildtool/system/system.hpp | 36 | ||||
-rw-r--r-- | src/utils/cpp/concepts.hpp | 14 |
5 files changed, 88 insertions, 14 deletions
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 <chrono> #include <cstdio> // for std::fopen #include <exception> #include <filesystem> @@ -118,7 +119,7 @@ class FileSystemManager { } } - template <ObjectType kType> + template <ObjectType kType, bool kSetEpochTime = false> 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 <bool kSetEpochTime = false> [[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<ObjectType::File>(file_path, - link_path); + return CreateFileHardlinkAs<ObjectType::File, kSetEpochTime>( + file_path, link_path); case ObjectType::Executable: - return CreateFileHardlinkAs<ObjectType::Executable>(file_path, - link_path); + return CreateFileHardlinkAs<ObjectType::Executable, + kSetEpochTime>(file_path, + link_path); case ObjectType::Tree: return false; } @@ -206,7 +210,7 @@ class FileSystemManager { return CopyFileImpl(src, dst, opt); } - template <ObjectType kType> + template <ObjectType kType, bool kSetEpochTime = false> 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 <bool kSetEpochTime = false> [[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<ObjectType::File>(src, dst, fd_less, opt); + return CopyFileAs<ObjectType::File, kSetEpochTime>( + src, dst, fd_less, opt); case ObjectType::Executable: - return CopyFileAs<ObjectType::Executable>( + return CopyFileAs<ObjectType::Executable, kSetEpochTime>( src, dst, fd_less, opt); case ObjectType::Tree: break; @@ -513,16 +520,18 @@ class FileSystemManager { return WriteFileImpl(content, file); } - template <ObjectType kType> + template <ObjectType kType, bool kSetEpochTime = false> 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 <bool kSetEpochTime = false> [[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<ObjectType::File>(content, file, fd_less); + return WriteFileAs<ObjectType::File, kSetEpochTime>( + content, file, fd_less); case ObjectType::Executable: - return WriteFileAs<ObjectType::Executable>( + return WriteFileAs<ObjectType::Executable, kSetEpochTime>( 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<std::chrono::file_clock>(); + 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 <chrono> + +#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 <class T_Clock> +static auto GetPosixEpoch() -> std::chrono::time_point<T_Clock> { + // Since C++20, the system clock's default value is the POSIX epoch time. + std::chrono::time_point<std::chrono::system_clock> sys_epoch{}; + if constexpr (std::is_same_v<T_Clock, std::chrono::system_clock>) { + // No conversion necessary for the system clock. + return sys_epoch; + } + else if constexpr (ClockHasFromSys<T_Clock>) { + // The correct C++20 way to perform the time point conversion. + return T_Clock::from_sys(sys_epoch); + } + else if constexpr (ClockHasFromTime<T_Clock>) { + // 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<T_Clock, std::chrono::system_clock> or + ClockHasFromSys<T_Clock> or ClockHasFromTime<T_Clock>, + "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 <chrono> #include <string> #include <type_traits> @@ -52,4 +53,17 @@ template <class T> concept InputIterableStringContainer = InputIterableContainer<T>and ContainsString<T>; +// TODO(modernize): remove this once we require clang version >= 14.0.0 +template <typename T> +concept ClockHasFromSys = + requires(std::chrono::time_point<std::chrono::system_clock> const tp) { + T::from_sys(tp); +}; + +// TODO(modernize): remove this once we require clang version >= 14.0.0 +template <typename T> +concept ClockHasFromTime = requires(std::time_t const t) { + T::from_time_t(t); +}; + #endif // INCLUDED_SRC_UTILS_CPP_CONCEPTS_HPP |