From 01bb417c5d880f645f54a83849876bac3518daf4 Mon Sep 17 00:00:00 2001
From: Nils Gladitz <nilsgladitz@gmail.com>
Date: Fri, 14 Jun 2013 22:55:31 +0200
Subject: [PATCH] implemented cmake_host_system_information with extensible
 interface

---
 Source/cmCMakeHostSystemInformationCommand.cxx     | 126 +++++++++++++++++++++
 Source/cmCMakeHostSystemInformationCommand.h       | 101 +++++++++++++++++
 Source/cmCommands.cxx                              |   2 +
 .../CMakeHostSystemInformation-BadArg1.cmake       |   1 +
 .../CMakeHostSystemInformation-BadArg2.cmake       |   1 +
 .../CMakeHostSystemInformation-BadArg3.cmake       |   1 +
 .../CMakeHostSystemInformation-QueryList.cmake     |   5 +
 .../CMakeHostSystemInformationTest.cmake.in        |  33 ++++++
 Tests/CMakeTests/CMakeLists.txt                    |   1 +
 9 files changed, 271 insertions(+)
 create mode 100644 Source/cmCMakeHostSystemInformationCommand.cxx
 create mode 100644 Source/cmCMakeHostSystemInformationCommand.h
 create mode 100644 Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake
 create mode 100644 Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake
 create mode 100644 Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake
 create mode 100644 Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake
 create mode 100644 Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in

diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
new file mode 100644
index 0000000..10e5c23
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -0,0 +1,126 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmCMakeHostSystemInformationCommand.h"
+
+#include <cmsys/ios/sstream>
+
+// cmCMakeHostSystemInformation
+bool cmCMakeHostSystemInformationCommand
+::InitialPass(std::vector<std::string> const &args, cmExecutionStatus &)
+{
+  size_t current_index = 0;
+
+  if(args.size() < (current_index + 2) || args[current_index] != "RESULT")
+  {
+  this->SetError("missing RESULT specification.");
+  return false;
+  }
+
+  std::string variable = args[current_index + 1];
+  current_index += 2;
+
+  if(args.size() < (current_index + 2) || args[current_index] != "QUERY")
+  {
+  this->SetError("missing QUERY specification");
+  return false;
+  }
+
+  cmsys::SystemInformation info;
+  info.RunCPUCheck();
+  info.RunOSCheck();
+  info.RunMemoryCheck();
+
+  std::string result_list;
+  for(std::size_t i = current_index + 1; i < args.size(); ++i)
+  {
+    std::string key = args[i];
+    if(i != current_index + 1)
+    {
+      result_list += ";";
+    }
+    std::string value;
+    if(!this->GetValue(info, key, value)) return false;
+
+    result_list += value;
+  }
+
+  this->Makefile->AddDefinition(variable.c_str(), result_list.c_str());
+
+  return true;
+}
+
+bool cmCMakeHostSystemInformationCommand
+::GetValue(cmsys::SystemInformation &info,
+  std::string const& key, std::string &value)
+{
+  if(key == "NUMBER_OF_LOGICAL_CORES")
+    {
+  value = this->ValueToString(info.GetNumberOfLogicalCPU());
+    }
+  else if(key == "NUMBER_OF_PHYSICAL_CORES")
+    {
+  value = this->ValueToString(info.GetNumberOfPhysicalCPU());
+    }
+  else if(key == "HOSTNAME")
+    {
+  value = this->ValueToString(info.GetHostname());
+    }
+  else if(key == "FQDN")
+    {
+  value = this->ValueToString(info.GetFullyQualifiedDomainName());
+    }
+  else if(key == "TOTAL_VIRTUAL_MEMORY")
+    {
+  value = this->ValueToString(info.GetTotalVirtualMemory());
+    }
+  else if(key == "AVAILABLE_VIRTUAL_MEMORY")
+    {
+  value = this->ValueToString(info.GetAvailableVirtualMemory());
+    }
+  else if(key == "TOTAL_PHYSICAL_MEMORY")
+    {
+  value = this->ValueToString(info.GetTotalPhysicalMemory());
+    }
+  else if(key == "AVAILABLE_PHYSICAL_MEMORY")
+    {
+  value = this->ValueToString(info.GetAvailablePhysicalMemory());
+    }
+  else
+    {
+    std::string e = "does not recognize <key> " + key;
+    this->SetError(e.c_str());
+    return false;
+    }
+
+  return true;
+}
+
+std::string cmCMakeHostSystemInformationCommand
+::ValueToString(std::size_t value) const
+{
+  cmsys_ios::stringstream tmp;
+  tmp << value;
+  return tmp.str();
+}
+
+std::string cmCMakeHostSystemInformationCommand
+::ValueToString(const char *value) const
+{
+  std::string safe_string = value ? value : "";
+  return safe_string;
+}
+
+std::string cmCMakeHostSystemInformationCommand
+::ValueToString(std::string const& value) const
+{
+  return value;
+}
diff --git a/Source/cmCMakeHostSystemInformationCommand.h b/Source/cmCMakeHostSystemInformationCommand.h
new file mode 100644
index 0000000..60ac625
--- /dev/null
+++ b/Source/cmCMakeHostSystemInformationCommand.h
@@ -0,0 +1,101 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmCMakeHostSystemInformationCommand_h
+#define cmCMakeHostSystemInformationCommand_h
+
+#include "cmCommand.h"
+
+#include <cmsys/SystemInformation.hxx>
+
+/** \class cmCMakeHostSystemInformationCommand
+ * \brief Query host system specific information
+ *
+ * cmCMakeHostSystemInformationCommand queries system information of
+ * the sytem on which CMake runs.
+ */
+class cmCMakeHostSystemInformationCommand : public cmCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  virtual cmCommand* Clone()
+    {
+    return new cmCMakeHostSystemInformationCommand;
+    }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  virtual bool InitialPass(std::vector<std::string> const& args,
+               cmExecutionStatus &status);
+
+   /**
+   * This determines if the command is invoked when in script mode.
+   */
+  virtual bool IsScriptable() const { return true; }
+
+   /**
+   * The name of the command as specified in CMakeList.txt.
+   */
+  virtual const char* GetName() const
+    {
+    return "cmake_host_system_information";
+    }
+
+   /**
+   * Succinct documentation.
+   */
+  virtual const char* GetTerseDocumentation() const
+    {
+    return "Query host system specific information.";
+    }
+
+  /**
+   * More documentation.
+   */
+  virtual const char* GetFullDocumentation() const
+    {
+    return
+    "  cmake_host_system_information(<key> <variable>)\n"
+    "Queries system information of the host system on which cmake runs. "
+    "The queried value is stored in <variable>. "
+    "<key> selects the information to be queried and can be one of the "
+    "following values:\n"
+    "  NUMBER_OF_LOGICAL_CORES   = Number of logical cores.\n"
+    "  NUMBER_OF_PHYSICAL_CORES  = Number of physical cores.\n"
+    "  HOSTNAME                  = Hostname.\n"
+    "  FQDN                      = Fully qualified domain name.\n"
+    "  TOTAL_VIRTUAL_MEMORY      = "
+      "Total virtual memory in megabytes.\n"
+    "  AVAILABLE_VIRTUAL_MEMORY  = "
+      "Available virtual memory in megabytes.\n"
+    "  TOTAL_PHYSICAL_MEMORY     = "
+      "Total physical memory in megabytes.\n"
+    "  AVAILABLE_PHYSICAL_MEMORY = "
+      "Available physical memory in megabytes.\n"
+    ;
+    }
+
+  cmTypeMacro(cmCMakeHostSystemInformationCommand, cmCommand);
+
+private:
+  bool GetValue(cmsys::SystemInformation &info,
+    std::string const& key, std::string &value);
+
+  std::string ValueToString(std::size_t value) const;
+  std::string ValueToString(const char *value) const;
+  std::string ValueToString(std::string const& value) const;
+};
+
+#endif
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 3cfbf43..1e2a85c 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -14,6 +14,7 @@
 #include "cmAddCompileOptionsCommand.cxx"
 #include "cmAuxSourceDirectoryCommand.cxx"
 #include "cmBuildNameCommand.cxx"
+#include "cmCMakeHostSystemInformationCommand.cxx"
 #include "cmElseIfCommand.cxx"
 #include "cmExportCommand.cxx"
 #include "cmExportLibraryDependencies.cxx"
@@ -56,6 +57,7 @@ void GetPredefinedCommands(std::list<cmCommand*>&
   commands.push_back(new cmAddCompileOptionsCommand);
   commands.push_back(new cmAuxSourceDirectoryCommand);
   commands.push_back(new cmBuildNameCommand);
+  commands.push_back(new cmCMakeHostSystemInformationCommand);
   commands.push_back(new cmElseIfCommand);
   commands.push_back(new cmExportCommand);
   commands.push_back(new cmExportLibraryDependenciesCommand);
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake
new file mode 100644
index 0000000..1655eb4
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg1.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(HOSTNAME)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake
new file mode 100644
index 0000000..1f056d5
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg2.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT FQDN HOSTNAME)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake
new file mode 100644
index 0000000..9c5a558
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-BadArg3.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT RESULT QUERY FOOBAR)
diff --git a/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake b/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake
new file mode 100644
index 0000000..1c3156d
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformation-QueryList.cmake
@@ -0,0 +1,5 @@
+cmake_host_system_information(RESULT RESULT
+  QUERY NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES
+)
+
+message("[${RESULT}]")
diff --git a/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in b/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in
new file mode 100644
index 0000000..3294a2f
--- /dev/null
+++ b/Tests/CMakeTests/CMakeHostSystemInformationTest.cmake.in
@@ -0,0 +1,33 @@
+set(BadArg1-RESULT 1)
+set(BadArg1-STDERR "missing RESULT specification")
+set(BadArg2-RESULT 1)
+set(BadArg2-STDERR "missing QUERY specification")
+set(BadArg3-RESULT 1)
+set(BadArg3-STDERR "does not recognize <key> FOOBAR")
+set(QueryList-RESULT 0)
+set(QueryList-STDERR "\\[[0-9]+;[0-9]+\\]")
+
+function(try_and_print key)
+	cmake_host_system_information(RESULT RESULT QUERY ${key})
+	message(STATUS "[${key}] [${RESULT}]")
+endfunction()
+
+message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+
+try_and_print(NUMBER_OF_LOGICAL_CORES)
+try_and_print(NUMBER_OF_PHYSICAL_CORES)
+try_and_print(HOSTNAME)
+try_and_print(FQDN)
+try_and_print(TOTAL_VIRTUAL_MEMORY)
+try_and_print(AVAILABLE_VIRTUAL_MEMORY)
+try_and_print(TOTAL_PHYSICAL_MEMORY)
+try_and_print(AVAILABLE_PHYSICAL_MEMORY)
+
+include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake")
+
+check_cmake_test(CMakeHostSystemInformation
+	BadArg1
+	BadArg2
+	BadArg3
+	QueryList
+)
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index b049995..344b772 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -32,6 +32,7 @@ AddCMakeTest(CompilerIdVendor "")
 AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>")
 AddCMakeTest(PushCheckState "")
 AddCMakeTest(While "")
+AddCMakeTest(CMakeHostSystemInformation "")
 
 AddCMakeTest(FileDownload "")
 set_property(TEST CMake.FileDownload PROPERTY
-- 
1.8.1.2

