From 394ab1fcfbeeb67eeae8f730c5aae0039a01e374 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Mon, 12 Jan 2026 13:56:39 -0500 Subject: [PATCH] cmake -E *sum: Add ability to read from stdin --- Help/manual/cmake.1.rst | 18 ++++++++++++++ Help/release/dev/E_sum-stdin.rst | 6 +++++ Source/cmCryptoHash.cxx | 24 +++++++++++++------ Source/cmCryptoHash.h | 13 ++++++++++ Source/cmcmd.cxx | 17 +++++++++++-- .../CommandLine/E_md5sum-stdin-stdout.txt | 1 + .../CommandLine/E_sha1sum-stdin-stdout.txt | 1 + .../CommandLine/E_sha224sum-stdin-stdout.txt | 1 + .../CommandLine/E_sha256sum-stdin-stdout.txt | 1 + .../CommandLine/E_sha384sum-stdin-stdout.txt | 1 + .../CommandLine/E_sha512sum-stdin-stdout.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 9 +++++++ Tests/RunCMake/RunCMake.cmake | 4 +++- 13 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 Help/release/dev/E_sum-stdin.rst create mode 100644 Tests/RunCMake/CommandLine/E_md5sum-stdin-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_sha1sum-stdin-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_sha224sum-stdin-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_sha256sum-stdin-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_sha384sum-stdin-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_sha512sum-stdin-stdout.txt diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 0c73bdd9c6..0276abd351 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -1312,6 +1312,9 @@ Available commands are: 351abe79cd3800b38cdfb25d45015a15 file1.txt 052f86c15bbde68af55c7f7b340ab639 file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: sha1sum ... .. versionadded:: 3.10 @@ -1321,6 +1324,9 @@ Available commands are: 4bb7932a29e6f73c97bb9272f2bdc393122f86e0 file1.txt 1df4c8f318665f9a5f2ed38f55adadb7ef9f559c file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: sha224sum ... .. versionadded:: 3.10 @@ -1330,6 +1336,9 @@ Available commands are: b9b9346bc8437bbda630b0b7ddfc5ea9ca157546dbbf4c613192f930 file1.txt 6dfbe55f4d2edc5fe5c9197bca51ceaaf824e48eba0cc453088aee24 file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: sha256sum ... .. versionadded:: 3.10 @@ -1339,6 +1348,9 @@ Available commands are: 76713b23615d31680afeb0e9efe94d47d3d4229191198bb46d7485f9cb191acc file1.txt 15b682ead6c12dedb1baf91231e1e89cfc7974b3787c1e2e01b986bffadae0ea file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: sha384sum ... .. versionadded:: 3.10 @@ -1348,6 +1360,9 @@ Available commands are: acc049fedc091a22f5f2ce39a43b9057fd93c910e9afd76a6411a28a8f2b8a12c73d7129e292f94fc0329c309df49434 file1.txt 668ddeb108710d271ee21c0f3acbd6a7517e2b78f9181c6a2ff3b8943af92b0195dcb7cce48aa3e17893173c0a39e23d file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: sha512sum ... .. versionadded:: 3.10 @@ -1357,6 +1372,9 @@ Available commands are: 2a78d7a6c5328cfb1467c63beac8ff21794213901eaadafd48e7800289afbc08e5fb3e86aa31116c945ee3d7bf2a6194489ec6101051083d1108defc8e1dba89 file1.txt 7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d file2.txt + .. versionchanged:: 4.3 + Passing ``-`` reads from standard input. + .. option:: remove [-f] ... .. deprecated:: 3.17 diff --git a/Help/release/dev/E_sum-stdin.rst b/Help/release/dev/E_sum-stdin.rst new file mode 100644 index 0000000000..6780bcee94 --- /dev/null +++ b/Help/release/dev/E_sum-stdin.rst @@ -0,0 +1,6 @@ +E_sum-stdin +----------- + +* The :manual:`cmake(1)` ``-E`` commands ``md5sum``, ``sha1sum``, + ``sha224sum``, ``sha256sum``, ``sha384sum``, and ``sha512sum`` now have the + ability to read from standard input by passing ``-``. diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 5d1936fd6e..e01f2d685e 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -153,10 +153,9 @@ std::vector cmCryptoHash::ByteHashString(cm::string_view input) return this->Finalize(); } -std::vector cmCryptoHash::ByteHashFile(std::string const& file) +std::vector cmCryptoHash::ByteHashStream(std::istream& sin) { - cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary); - if (fin) { + if (sin) { this->Initialize(); { // Should be efficient enough on most system: @@ -169,14 +168,14 @@ std::vector cmCryptoHash::ByteHashFile(std::string const& file) // incorrect to not check the error condition on the fin.read() // before using the data, but the fin.gcount() will be zero if an // error occurred. Therefore, the loop should be safe everywhere. - while (fin) { - fin.read(buffer_c, sizeof(buffer)); - if (int gcount = static_cast(fin.gcount())) { + while (sin) { + sin.read(buffer_c, sizeof(buffer)); + if (int gcount = static_cast(sin.gcount())) { this->Append(buffer_uc, gcount); } } } - if (fin.eof()) { + if (sin.eof()) { // Success return this->Finalize(); } @@ -187,11 +186,22 @@ std::vector cmCryptoHash::ByteHashFile(std::string const& file) return std::vector(); } +std::vector cmCryptoHash::ByteHashFile(std::string const& file) +{ + cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary); + return this->ByteHashStream(fin); +} + std::string cmCryptoHash::HashString(cm::string_view input) { return ByteHashToString(this->ByteHashString(input)); } +std::string cmCryptoHash::HashStream(std::istream& sin) +{ + return ByteHashToString(this->ByteHashStream(sin)); +} + std::string cmCryptoHash::HashFile(std::string const& file) { return ByteHashToString(this->ByteHashFile(file)); diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 600a50c31e..80ffa49e3d 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include +#include #include #include #include @@ -58,6 +59,12 @@ public: /// @return Binary hash vector std::vector ByteHashString(cm::string_view input); + /// @brief Calculates a binary hash from stream content + /// @see ByteHashString() + /// @return Non empty binary hash vector if the stream was read successfully. + /// An empty vector otherwise. + std::vector ByteHashStream(std::istream& sin); + /// @brief Calculates a binary hash from file content /// @see ByteHashString() /// @return Non empty binary hash vector if the file was read successfully. @@ -68,6 +75,12 @@ public: /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(cm::string_view input); + /// @brief Calculates a hash string from stream content + /// @see HashString() + /// @return Non empty hash string if the stream was read successfully. + /// An empty string otherwise. + std::string HashStream(std::istream& sin); + /// @brief Calculates a hash string from file content /// @see HashString() /// @return Non empty hash string if the file was read successfully. diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 702c0d91be..58e0998af5 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -1920,8 +1920,21 @@ int cmcmd::HashSumFile(std::vector const& args, int retval = 0; for (auto const& filename : cmMakeRange(args).advance(2)) { - // Cannot compute sum of a directory - if (cmSystemTools::FileIsDirectory(filename)) { + if (filename == "-") { +#ifdef _WIN32 + _setmode(fileno(stdin), _O_BINARY); +#endif + cmCryptoHash hasher(algo); + std::string value = hasher.HashStream(std::cin); + if (value.empty()) { + // To mimic "md5sum/shasum" behavior in a shell: + std::cerr << filename << ": No such file or directory\n"; + retval++; + } else { + std::cout << value << " " << filename << '\n'; + } + } else if (cmSystemTools::FileIsDirectory(filename)) { + // Cannot compute sum of a directory std::cerr << "Error: " << filename << " is a directory\n"; retval++; } else { diff --git a/Tests/RunCMake/CommandLine/E_md5sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_md5sum-stdin-stdout.txt new file mode 100644 index 0000000000..1441a1d455 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-stdin-stdout.txt @@ -0,0 +1 @@ +275876e34cf609db118f3d84b799a790 - diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_sha1sum-stdin-stdout.txt new file mode 100644 index 0000000000..cc27e2baf7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-stdin-stdout.txt @@ -0,0 +1 @@ +829c3804401b0727f70f73d4415e162400cbe57b - diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_sha224sum-stdin-stdout.txt new file mode 100644 index 0000000000..5bda4bf633 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-stdin-stdout.txt @@ -0,0 +1 @@ +37d32c6dbabed711cb1d4620b64090fef0ef63ab16a4a51d668259e6 - diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_sha256sum-stdin-stdout.txt new file mode 100644 index 0000000000..684b5a4eae --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-stdin-stdout.txt @@ -0,0 +1 @@ +b5a2c96250612366ea272ffac6d9744aaf4b45aacd96aa7cfcb931ee3b558259 - diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_sha384sum-stdin-stdout.txt new file mode 100644 index 0000000000..cd5f3cf5b7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-stdin-stdout.txt @@ -0,0 +1 @@ +43c1835ceba2e29596f05e3859d4fe2b6d124a181ed670f68e914bd3ed251b02b4be609608a13f23ec3d98da6c4eb8cd - diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-stdin-stdout.txt b/Tests/RunCMake/CommandLine/E_sha512sum-stdin-stdout.txt new file mode 100644 index 0000000000..c1f94f7adf --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-stdin-stdout.txt @@ -0,0 +1 @@ +1692526aab84461a8aebcefddcba2b33fb5897ab180c53e8b345ae125484d0aaa35baf60487050be21ed8909a48eace93851bf139087ce1f7a87d97b6120a651 - diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index c198881693..95bd3e49d4 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -904,6 +904,15 @@ run_cmake_command(E_sha224sum ${CMAKE_COMMAND} -E sha224sum ../dummy) run_cmake_command(E_sha256sum ${CMAKE_COMMAND} -E sha256sum ../dummy) run_cmake_command(E_sha384sum ${CMAKE_COMMAND} -E sha384sum ../dummy) run_cmake_command(E_sha512sum ${CMAKE_COMMAND} -E sha512sum ../dummy) +block() + set(RunCMake-stdin-file ${RunCMake_BINARY_DIR}/dummy) + run_cmake_command(E_md5sum-stdin ${CMAKE_COMMAND} -E md5sum -) + run_cmake_command(E_sha1sum-stdin ${CMAKE_COMMAND} -E sha1sum -) + run_cmake_command(E_sha224sum-stdin ${CMAKE_COMMAND} -E sha224sum -) + run_cmake_command(E_sha256sum-stdin ${CMAKE_COMMAND} -E sha256sum -) + run_cmake_command(E_sha384sum-stdin ${CMAKE_COMMAND} -E sha384sum -) + run_cmake_command(E_sha512sum-stdin ${CMAKE_COMMAND} -E sha512sum -) +endblock() file(REMOVE "${RunCMake_BINARY_DIR}/dummy") set(RunCMake_DEFAULT_stderr ".") diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index a53b41eb07..293cfa238f 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -96,8 +96,10 @@ function(run_cmake test) else() set(maybe_timeout "") endif() - if(RunCMake-stdin-file AND EXISTS ${top_src}/${RunCMake-stdin-file}) + if(RunCMake-stdin-file AND NOT IS_ABSOLUTE "${RunCMake-stdin-file}" AND EXISTS ${top_src}/${RunCMake-stdin-file}) set(maybe_input_file INPUT_FILE ${top_src}/${RunCMake-stdin-file}) + elseif(RunCMake-stdin-file AND IS_ABSOLUTE "${RunCMake-stdin-file}" AND EXISTS "${RunCMake-stdin-file}") + set(maybe_input_file INPUT_FILE ${RunCMake-stdin-file}) elseif(EXISTS ${top_src}/${test}-stdin.txt) set(maybe_input_file INPUT_FILE ${top_src}/${test}-stdin.txt) else()