From 44fd71decbca329d9cdfc196a073a62668af53f2 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 26 Jan 2015 13:28:31 -0500
Subject: cmake: Teach "-E tar" command a "--files-from=" option

Read file names from the lines of a specified file.  Reject input lines
starting in '-' to leave room for option parsing to be added later.  Add
just '--add-file=' now to allow files starting in '-' to be specified.
---
 Help/release/dev/cmake-E-tar-files-from.rst        |  6 +++
 Source/cmcmd.cxx                                   | 53 ++++++++++++++++++++++
 .../CommandLine/E_tar-bad-from1-result.txt         |  1 +
 .../CommandLine/E_tar-bad-from1-stderr.txt         |  1 +
 .../CommandLine/E_tar-bad-from2-result.txt         |  1 +
 .../CommandLine/E_tar-bad-from2-stderr.txt         |  1 +
 .../CommandLine/E_tar-bad-from3-result.txt         |  1 +
 .../CommandLine/E_tar-bad-from3-stderr.txt         |  2 +
 Tests/RunCMake/CommandLine/E_tar-bad-from3.txt     |  1 +
 .../CommandLine/E_tar-bad-from4-result.txt         |  1 +
 .../CommandLine/E_tar-bad-from4-stderr.txt         |  2 +
 Tests/RunCMake/CommandLine/E_tar-bad-from4.txt     |  2 +
 .../CommandLine/E_tar-bad-from5-result.txt         |  1 +
 .../CommandLine/E_tar-bad-from5-stderr.txt         |  2 +
 Tests/RunCMake/CommandLine/E_tar-bad-from5.txt     |  2 +
 Tests/RunCMake/CommandLine/RunCMakeTest.cmake      |  5 ++
 16 files changed, 82 insertions(+)
 create mode 100644 Help/release/dev/cmake-E-tar-files-from.rst
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from1-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from1-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from2-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from2-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from3-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from3-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from3.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from4-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from4-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from4.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from5-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from5-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_tar-bad-from5.txt

diff --git a/Help/release/dev/cmake-E-tar-files-from.rst b/Help/release/dev/cmake-E-tar-files-from.rst
new file mode 100644
index 0000000..f6087ff
--- /dev/null
+++ b/Help/release/dev/cmake-E-tar-files-from.rst
@@ -0,0 +1,6 @@
+cmake-E-tar-files-from
+----------------------
+
+* The :manual:`cmake(1)` ``-E tar`` command learned a new
+  ``--files-from=<file>`` option to specify file names using
+  lines in a file to overcome command-line length limits.
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 7ca3eb3..28fcd27 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -94,6 +94,51 @@ void CMakeCommandUsage(const char* program)
   cmSystemTools::Error(errorStream.str().c_str());
 }
 
+static bool cmTarFilesFrom(std::string const& file,
+                           std::vector<std::string>& files)
+{
+  if (cmSystemTools::FileIsDirectory(file))
+    {
+    std::ostringstream e;
+    e << "-E tar --files-from= file '" << file << "' is a directory";
+    cmSystemTools::Error(e.str().c_str());
+    return false;
+    }
+  cmsys::ifstream fin(file.c_str());
+  if (!fin)
+    {
+    std::ostringstream e;
+    e << "-E tar --files-from= file '" << file << "' not found";
+    cmSystemTools::Error(e.str().c_str());
+    return false;
+    }
+  std::string line;
+  while (cmSystemTools::GetLineFromStream(fin, line))
+    {
+    if (line.empty())
+      {
+      continue;
+      }
+    if (cmHasLiteralPrefix(line, "--add-file="))
+      {
+      files.push_back(line.substr(11));
+      }
+    else if (cmHasLiteralPrefix(line, "-"))
+      {
+      std::ostringstream e;
+      e << "-E tar --files-from='" << file << "' file invalid line:\n"
+        << line << "\n";
+      cmSystemTools::Error(e.str().c_str());
+      return false;
+      }
+    else
+      {
+      files.push_back(line);
+      }
+    }
+  return true;
+}
+
 int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
 {
   // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
@@ -744,6 +789,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
             {
             mtime = arg.substr(8);
             }
+          else if (cmHasLiteralPrefix(arg, "--files-from="))
+            {
+            std::string const& files_from = arg.substr(13);
+            if (!cmTarFilesFrom(files_from, files))
+              {
+              return 1;
+              }
+            }
           else
             {
             cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str());
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from1-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from1-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from1-stderr.txt
new file mode 100644
index 0000000..d67431d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from1-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: -E tar --files-from= file 'bad' not found$
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from2-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from2-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from2-stderr.txt
new file mode 100644
index 0000000..d1d278c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from2-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: -E tar --files-from= file '\.' is a directory$
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from3-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from3-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from3-stderr.txt
new file mode 100644
index 0000000..147bd80
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from3-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: -E tar --files-from='.*/Tests/RunCMake/CommandLine/E_tar-bad-from3.txt' file invalid line:
+-add-file=option-typo$
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from3.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from3.txt
new file mode 100644
index 0000000..5bad1c3
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from3.txt
@@ -0,0 +1 @@
+-add-file=option-typo
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from4-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from4-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from4-stderr.txt
new file mode 100644
index 0000000..1417d4d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from4-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from4.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from4.txt
new file mode 100644
index 0000000..4b97f79
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from4.txt
@@ -0,0 +1,2 @@
+
+does-not-exist
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from5-result.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from5-stderr.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from5-stderr.txt
new file mode 100644
index 0000000..1417d4d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from5-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: archive_read_disk_entry_from_file 'does-not-exist':.*
+CMake Error: Problem creating tar: bad.tar$
diff --git a/Tests/RunCMake/CommandLine/E_tar-bad-from5.txt b/Tests/RunCMake/CommandLine/E_tar-bad-from5.txt
new file mode 100644
index 0000000..9ea755b
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_tar-bad-from5.txt
@@ -0,0 +1,2 @@
+
+--add-file=does-not-exist
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 2994f16..2be6651 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -2,6 +2,11 @@ include(RunCMake)
 
 run_cmake_command(E_tar-bad-opt1   ${CMAKE_COMMAND} -E tar cvf bad.tar --bad)
 run_cmake_command(E_tar-bad-mtime1 ${CMAKE_COMMAND} -E tar cvf bad.tar --mtime=bad .)
+run_cmake_command(E_tar-bad-from1  ${CMAKE_COMMAND} -E tar cvf bad.tar --files-from=bad)
+run_cmake_command(E_tar-bad-from2  ${CMAKE_COMMAND} -E tar cvf bad.tar --files-from=.)
+run_cmake_command(E_tar-bad-from3  ${CMAKE_COMMAND} -E tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/E_tar-bad-from3.txt)
+run_cmake_command(E_tar-bad-from4  ${CMAKE_COMMAND} -E tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/E_tar-bad-from4.txt)
+run_cmake_command(E_tar-bad-from5  ${CMAKE_COMMAND} -E tar cvf bad.tar --files-from=${CMAKE_CURRENT_LIST_DIR}/E_tar-bad-from5.txt)
 run_cmake_command(E_tar-end-opt1   ${CMAKE_COMMAND} -E tar cvf bad.tar -- --bad)
 run_cmake_command(E_tar-end-opt2   ${CMAKE_COMMAND} -E tar cvf bad.tar --)
 run_cmake_command(E_tar-mtime      ${CMAKE_COMMAND} -E tar cvf bad.tar "--mtime=1970-01-01 00:00:00 UTC")
-- 
cgit v0.12