From a625f30785130586a7d2a59c13a7526eab8b3086 Mon Sep 17 00:00:00 2001 From: Johnny Jazeix Date: Wed, 15 Apr 2020 20:56:56 +0200 Subject: cmake -E: add cat command. Concatenate files and print on the standard output. FIXES: #20557 --- Help/manual/cmake.1.rst | 3 ++ Help/release/dev/command-line-cat.rst | 5 +++ Source/cmcmd.cxx | 35 ++++++++++++++++++++ .../CommandLine/E_cat_directory-result.txt | 1 + .../CommandLine/E_cat_directory-stderr.txt | 1 + .../RunCMake/CommandLine/E_cat_good_cat-stdout.txt | 3 ++ .../CommandLine/E_cat_non_existing_file-result.txt | 1 + .../CommandLine/E_cat_non_existing_file-stderr.txt | 1 + .../CommandLine/E_cat_non_readable_file-result.txt | 1 + .../CommandLine/E_cat_non_readable_file-stderr.txt | 1 + .../E_cat_option_not_handled-result.txt | 1 + .../E_cat_option_not_handled-stderr.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 38 ++++++++++++++++++++++ 13 files changed, 92 insertions(+) create mode 100644 Help/release/dev/command-line-cat.rst create mode 100644 Tests/RunCMake/CommandLine/E_cat_directory-result.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_directory-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_good_cat-stdout.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_non_existing_file-result.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_non_existing_file-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_non_readable_file-result.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_non_readable_file-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_option_not_handled-result.txt create mode 100644 Tests/RunCMake/CommandLine/E_cat_option_not_handled-stderr.txt diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 9a43499..e3e965c 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -554,6 +554,9 @@ Available commands are: ``serverMode`` ``true`` if cmake supports server-mode and ``false`` otherwise. +``cat ...`` + Concatenate files and print on the standard output. + ``chdir [...]`` Change the current working directory and run a command. diff --git a/Help/release/dev/command-line-cat.rst b/Help/release/dev/command-line-cat.rst new file mode 100644 index 0000000..acde835 --- /dev/null +++ b/Help/release/dev/command-line-cat.rst @@ -0,0 +1,5 @@ +Command-Line +------------ +* :manual:`cmake(1)` gained a ``cat`` command line + option that can be used to concatenate files and print them + on standard output. diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index c3bd160..3befb18 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -90,6 +90,7 @@ void CMakeCommandUsage(const char* program) << "Available commands: \n" << " capabilities - Report capabilities built into cmake " "in JSON format\n" + << " cat ... - concat the files and print them to the standard output\n" << " chdir dir cmd [args...] - run command in a given directory\n" << " compare_files [--ignore-eol] file1 file2\n" << " - check if file1 is same as file2\n" @@ -180,6 +181,13 @@ static bool cmTarFilesFrom(std::string const& file, return true; } +static void cmCatFile(const std::string& fileToAppend) +{ + cmsys::ifstream source(fileToAppend.c_str(), + (std::ios::binary | std::ios::in)); + std::cout << source.rdbuf(); +} + static bool cmRemoveDirectory(const std::string& dir, bool recursive = true) { if (cmSystemTools::FileIsSymlink(dir)) { @@ -927,6 +935,33 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) return HashSumFile(args, cmCryptoHash::AlgoSHA512); } + // Command to concat files into one + if (args[1] == "cat" && args.size() >= 3) { + int return_value = 0; + for (auto const& arg : cmMakeRange(args).advance(2)) { + if (cmHasLiteralPrefix(arg, "-")) { + if (arg != "--") { + cmSystemTools::Error(arg + ": option not handled"); + return_value = 1; + } + } else if (!cmSystemTools::TestFileAccess(arg, + cmsys::TEST_FILE_READ) && + cmSystemTools::TestFileAccess(arg, cmsys::TEST_FILE_OK)) { + cmSystemTools::Error(arg + ": permission denied (ignoring)"); + return_value = 1; + } else if (cmSystemTools::FileIsDirectory(arg)) { + cmSystemTools::Error(arg + ": is a directory (ignoring)"); + return_value = 1; + } else if (!cmSystemTools::FileExists(arg)) { + cmSystemTools::Error(arg + ": no such file or directory (ignoring)"); + return_value = 1; + } else { + cmCatFile(arg); + } + } + return return_value; + } + // Command to change directory and run a program. if (args[1] == "chdir" && args.size() >= 4) { std::string const& directory = args[2]; diff --git a/Tests/RunCMake/CommandLine/E_cat_directory-result.txt b/Tests/RunCMake/CommandLine/E_cat_directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_cat_directory-stderr.txt b/Tests/RunCMake/CommandLine/E_cat_directory-stderr.txt new file mode 100644 index 0000000..c4d0d48 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_directory-stderr.txt @@ -0,0 +1 @@ +^CMake Error: .* is a directory diff --git a/Tests/RunCMake/CommandLine/E_cat_good_cat-stdout.txt b/Tests/RunCMake/CommandLine/E_cat_good_cat-stdout.txt new file mode 100644 index 0000000..aae90e6 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_good_cat-stdout.txt @@ -0,0 +1,3 @@ +first file to append +second file to append +àéùç - 한국어 diff --git a/Tests/RunCMake/CommandLine/E_cat_non_existing_file-result.txt b/Tests/RunCMake/CommandLine/E_cat_non_existing_file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_non_existing_file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_cat_non_existing_file-stderr.txt b/Tests/RunCMake/CommandLine/E_cat_non_existing_file-stderr.txt new file mode 100644 index 0000000..0d8fc4b --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_non_existing_file-stderr.txt @@ -0,0 +1 @@ +^CMake Error: .*: no such file or directory \(ignoring\) diff --git a/Tests/RunCMake/CommandLine/E_cat_non_readable_file-result.txt b/Tests/RunCMake/CommandLine/E_cat_non_readable_file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_non_readable_file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_cat_non_readable_file-stderr.txt b/Tests/RunCMake/CommandLine/E_cat_non_readable_file-stderr.txt new file mode 100644 index 0000000..97ec822 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_non_readable_file-stderr.txt @@ -0,0 +1 @@ +^CMake Error: .*: permission denied \(ignoring\) diff --git a/Tests/RunCMake/CommandLine/E_cat_option_not_handled-result.txt b/Tests/RunCMake/CommandLine/E_cat_option_not_handled-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_option_not_handled-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_cat_option_not_handled-stderr.txt b/Tests/RunCMake/CommandLine/E_cat_option_not_handled-stderr.txt new file mode 100644 index 0000000..92f7acf --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat_option_not_handled-stderr.txt @@ -0,0 +1 @@ +^CMake Error: -f: option not handled diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 839aec0..0f806bc 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -459,6 +459,44 @@ if(NOT WIN32 AND NOT CYGWIN) endif() unset(out) +# cat tests +set(out ${RunCMake_BINARY_DIR}/cat_tests) +file(REMOVE_RECURSE "${out}") +file(MAKE_DIRECTORY ${out}) +run_cmake_command(E_cat_non_existing_file + ${CMAKE_COMMAND} -E cat ${out}/non-existing-file.txt) + +if(UNIX) + # test non readable file only if not root + execute_process( + COMMAND id -u $ENV{USER} + OUTPUT_VARIABLE uid + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT "${uid}" STREQUAL "0") + # Create non readable file + set(inside_folder "${out}/in") + file(MAKE_DIRECTORY ${inside_folder}) + file(WRITE "${inside_folder}/non_readable_file.txt" "first file to append\n") + file(COPY "${inside_folder}/non_readable_file.txt" DESTINATION "${out}" FILE_PERMISSIONS OWNER_WRITE) + run_cmake_command(E_cat_non_readable_file + ${CMAKE_COMMAND} -E cat "${out}/non_readable_file.txt") + endif() +endif() + +run_cmake_command(E_cat_option_not_handled + ${CMAKE_COMMAND} -E cat -f) + +run_cmake_command(E_cat_directory + ${CMAKE_COMMAND} -E cat ${out}) + +file(WRITE "${out}/first_file.txt" "first file to append\n") +file(WRITE "${out}/second_file.txt" "second file to append\n") +file(WRITE "${out}/unicode_file.txt" "àéùç - 한국어") # Korean in Korean +run_cmake_command(E_cat_good_cat + ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/unicode_file.txt") +unset(out) + run_cmake_command(E_env-no-command0 ${CMAKE_COMMAND} -E env) run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1) run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1) -- cgit v0.12