Improve program name reporting.
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 30 Jun 2013 09:52:48 +0000 (12:52 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Mon, 22 Jul 2013 09:28:49 +0000 (11:28 +0200)
Now, the wrapper binary reports the name of the program as
'gmx-<module>' as soon as a module has been selected.  Error and help
messages are clearer, as well as the header printed during program
start-up.

Change-Id: I2754539ae6815405aeb22e42ad8b5452e525dbb3

src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlinemodulemanager.h
src/gromacs/commandline/tests/cmdlinemodulemanager.cpp
src/gromacs/gmxlib/copyrite.cpp
src/gromacs/gmxlib/oenv.cpp
src/gromacs/gmxlib/statutil.cpp
src/gromacs/utility/errorformat.cpp
src/gromacs/utility/programinfo.cpp
src/gromacs/utility/programinfo.h
src/programs/gmx/gmx.cpp

index c9dd7aa773ec32b7b89a37f47be4c02fa835cf8e..2f5969e312150f981866f877c40a0839ddfb56c8 100644 (file)
@@ -323,13 +323,12 @@ void CommandLineHelpModule::writeHelp(const HelpWriterContext &context) const
 class CommandLineModuleManager::Impl
 {
     public:
-
         /*! \brief
          * Initializes the implementation class.
          *
-         * \param[in] programInfo  Program information for the running binary.
+         * \param     programInfo  Program information for the running binary.
          */
-        explicit Impl(const ProgramInfo &programInfo);
+        explicit Impl(ProgramInfo *programInfo);
 
         /*! \brief
          * Finds a module that matches a name.
@@ -386,7 +385,7 @@ class CommandLineModuleManager::Impl
          */
         CommandLineModuleMap    modules_;
         //! Information about the currently running program.
-        const ProgramInfo      &programInfo_;
+        ProgramInfo            &programInfo_;
         /*! \brief
          * Module that implements help for the binary.
          *
@@ -399,10 +398,13 @@ class CommandLineModuleManager::Impl
         bool                    bQuiet_;
         //! Whether to write the startup information to stdout iso stderr.
         bool                    bStdOutInfo_;
+
+    private:
+        GMX_DISALLOW_COPY_AND_ASSIGN(Impl);
 };
 
-CommandLineModuleManager::Impl::Impl(const ProgramInfo &programInfo)
-    : programInfo_(programInfo), helpModule_(NULL), bQuiet_(false),
+CommandLineModuleManager::Impl::Impl(ProgramInfo *programInfo)
+    : programInfo_(*programInfo), helpModule_(NULL), bQuiet_(false),
       bStdOutInfo_(false)
 {
 }
@@ -487,6 +489,8 @@ CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
         std::string message = formatString("'%s' is not a GROMACS command.", moduleName);
         GMX_THROW(InvalidInputError(message));
     }
+    programInfo_.setDisplayName(
+            programInfo_.realBinaryName() + "-" + module->first);
     *argc -= moduleArgOffset;
     *argv += moduleArgOffset;
     return module->second.get();
@@ -496,7 +500,7 @@ CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
  * CommandLineModuleManager
  */
 
-CommandLineModuleManager::CommandLineModuleManager(const ProgramInfo &programInfo)
+CommandLineModuleManager::CommandLineModuleManager(ProgramInfo *programInfo)
     : impl_(new Impl(programInfo))
 {
     impl_->helpModule_ = new CommandLineHelpModule(impl_->modules_);
index 11198b8dd416bac8cdec3e5683d8ce7fc80bdb4b..7230d878eb5c609346af5b46c608803e165df87a 100644 (file)
@@ -90,13 +90,16 @@ class CommandLineModuleManager
         /*! \brief
          * Initializes a command-line module manager.
          *
-         * \param[in] programInfo  Program information for the running binary.
+         * \param     programInfo  Program information for the running binary.
          * \throws    std::bad_alloc if out of memory.
          *
          * The binary name is used to detect when the binary is run through a
          * symlink, and automatically invoke a matching module in such a case.
+         *
+         * \p programInfo is non-const to allow the manager to amend it based
+         * on the actual module that is getting executed.
          */
-        explicit CommandLineModuleManager(const ProgramInfo &programInfo);
+        explicit CommandLineModuleManager(ProgramInfo *programInfo);
         ~CommandLineModuleManager();
 
         /*! \brief
index a32e1cdb02ad74267c3d47f51d41ad5b2637350b..6c8c2e774eb24f43598780ad23a3bb13763fba0e 100644 (file)
@@ -115,7 +115,7 @@ void CommandLineModuleManagerTest::initManager(const CommandLine &args)
 {
     manager_.reset();
     programInfo_.reset(new gmx::ProgramInfo("g_test", args.argc(), args.argv()));
-    manager_.reset(new gmx::CommandLineModuleManager(*programInfo_));
+    manager_.reset(new gmx::CommandLineModuleManager(programInfo_.get()));
     manager_->setQuiet(true);
 }
 
index f91355b2215f369de06aef51c2a1b3da2b6dd20a..6e0794a8f3d8731a5f31f2c78bea4e7aa294fa6f 100644 (file)
@@ -706,7 +706,7 @@ void printBinaryInformation(FILE *fp, const ProgramInfo &programInfo,
 #ifdef GMX_DOUBLE
     precisionString = " (double precision)";
 #endif
-    const std::string &name = programInfo.programName();
+    const std::string &name = programInfo.displayName();
     if (settings.bGeneratedByHeader_)
     {
         fprintf(fp, "%sCreated by:%s\n", prefix, suffix);
index 11c2d5c525ea9de22dba18adf6db7c4115ab0c75..95281af76257364fd605344ac79cd57c761b2320 100644 (file)
@@ -217,6 +217,7 @@ const char *output_env_get_short_program_name(const output_env_t oenv)
 {
     try
     {
+        // TODO: Use the display name once it doesn't break anything.
         return oenv->programInfo.programName().c_str();
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
index 5e554d1885f82bd39f736c7519f51363c634a38d..ac75c8ec19bb0895e56984442e3ca5e2a4684f38 100644 (file)
@@ -91,6 +91,7 @@ const char *ShortProgram(void)
 {
     try
     {
+        // TODO: Use the display name once it doesn't break anything.
         return gmx::ProgramInfo::getInstance().programName().c_str();
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
index f13df46188dc26dc9aa21f8d635049931c987b72..a63112a0fdcc84aed3bd587ac966d7f54fb1f828 100644 (file)
@@ -69,7 +69,7 @@ void printFatalErrorHeader(FILE *fp, const char *title,
     const char *programName = "GROMACS";
     try
     {
-        programName = ProgramInfo::getInstance().programName().c_str();
+        programName = ProgramInfo::getInstance().displayName().c_str();
     }
     catch (const std::exception &)
     {
index 0e42df125091d03ba0abd47cd4c0794ec4e198b3..afa5089e0becf05480601739a84cde0a26931bd7 100644 (file)
@@ -58,6 +58,7 @@
 #include "gromacs/legacyheaders/thread_mpi/mutex.h"
 
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -66,10 +67,25 @@ namespace gmx
 
 namespace
 {
+
 //! Mutex for updates to the global program info objects.
 tMPI::mutex                    g_programInfoMutex;
 //! Global program info; stores the object initialized with ProgramInfo::init().
 boost::scoped_ptr<ProgramInfo> g_programInfo;
+
+/*! \brief
+ * Quotes a string if it contains spaces.
+ */
+std::string quoteIfNecessary(const char *str)
+{
+    const bool bSpaces = (std::strchr(str, ' ') != NULL);
+    if (bSpaces)
+    {
+        return formatString("'%s'", str);
+    }
+    return str;
+}
+
 }   // namespace
 
 /********************************************************************
@@ -82,11 +98,13 @@ class ProgramInfo::Impl
         Impl();
         Impl(const char *realBinaryName, int argc, const char *const argv[]);
 
-        std::string realBinaryName_;
-        std::string fullInvokedProgram_;
-        std::string programName_;
-        std::string invariantProgramName_;
-        std::string commandLine_;
+        std::string             realBinaryName_;
+        std::string             fullInvokedProgram_;
+        std::string             programName_;
+        std::string             invariantProgramName_;
+        std::string             commandLine_;
+        std::string             displayName_;
+        mutable tMPI::mutex     displayNameMutex_;
 };
 
 ProgramInfo::Impl::Impl()
@@ -122,23 +140,11 @@ ProgramInfo::Impl::Impl(const char *realBinaryName,
         realBinaryName_ = invariantProgramName_;
     }
 
-    for (int i = 0; i < argc; ++i)
+    commandLine_ = quoteIfNecessary(programName_.c_str());
+    for (int i = 1; i < argc; ++i)
     {
-        if (i > 0)
-        {
-            commandLine_.append(" ");
-        }
-        const char *arg     = argv[i];
-        bool        bSpaces = (std::strchr(arg, ' ') != NULL);
-        if (bSpaces)
-        {
-            commandLine_.append("'");
-        }
-        commandLine_.append(arg);
-        if (bSpaces)
-        {
-            commandLine_.append("'");
-        }
+        commandLine_.append(" ");
+        commandLine_.append(quoteIfNecessary(argv[i]));
     }
 }
 
@@ -165,8 +171,8 @@ const ProgramInfo &ProgramInfo::init(int argc, const char *const argv[])
 }
 
 // static
-const ProgramInfo &ProgramInfo::init(const char *realBinaryName,
-                                     int argc, const char *const argv[])
+ProgramInfo &ProgramInfo::init(const char *realBinaryName,
+                               int argc, const char *const argv[])
 {
     try
     {
@@ -209,6 +215,14 @@ ProgramInfo::~ProgramInfo()
 {
 }
 
+void ProgramInfo::setDisplayName(const std::string &name)
+{
+    tMPI::lock_guard<tMPI::mutex> lock(impl_->displayNameMutex_);
+    GMX_RELEASE_ASSERT(impl_->displayName_.empty(),
+                       "Can only set display name once");
+    impl_->displayName_ = name;
+}
+
 const std::string &ProgramInfo::realBinaryName() const
 {
     return impl_->realBinaryName_;
@@ -229,6 +243,14 @@ const std::string &ProgramInfo::invariantProgramName() const
     return impl_->invariantProgramName_;
 }
 
+const std::string &ProgramInfo::displayName() const
+{
+    tMPI::lock_guard<tMPI::mutex> lock(impl_->displayNameMutex_);
+    return impl_->displayName_.empty()
+        ? impl_->programName_
+        : impl_->displayName_;
+}
+
 const std::string &ProgramInfo::commandLine() const
 {
     return impl_->commandLine_;
index dcfef24f318a3f4cbd839c1b97bd6f4536bf042f..101cd2c26cf8747a59b45684878f28afd886e9f7 100644 (file)
@@ -112,8 +112,8 @@ class ProgramInfo
          *
          * Does not throw. Terminates the program on out-of-memory error.
          */
-        static const ProgramInfo &init(const char *realBinaryName,
-                                       int argc, const char *const argv[]);
+        static ProgramInfo &init(const char *realBinaryName,
+                                 int argc, const char *const argv[]);
 
         /*! \brief
          * Constructs an empty program info objects.
@@ -152,6 +152,17 @@ class ProgramInfo
                     int argc, const char *const argv[]);
         ~ProgramInfo();
 
+        /*! \brief
+         * Sets a display name for the binary.
+         *
+         * \throws std::bad_alloc if out of memory.
+         * \throws tMPI::system_error on thread synchronization errors.
+         *
+         * This is used with the wrapper binary to add the name of the invoked
+         * module to the name of the binary shown.
+         */
+        void setDisplayName(const std::string &name);
+
         /*! \brief
          * Returns the real name of the binary.
          *
@@ -182,6 +193,15 @@ class ProgramInfo
          * Does not throw.
          */
         const std::string &invariantProgramName() const;
+        /*! \brief
+         * Returns a display name of the current module.
+         *
+         * \throws  tMPI::system_error on thread synchronization errors.
+         *
+         * The returned value equals programName(), unless a separate display
+         * name has been set with setDisplayName().
+         */
+        const std::string &displayName() const;
         /*! \brief
          * Returns the full command line used to invoke the binary.
          *
index c4d21abe5efa63abdc6bfc023448db80451013f7..2661139986a7a347eef87ed3850ad2722807209e 100644 (file)
 int
 main(int argc, char *argv[])
 {
-    const gmx::ProgramInfo &info =
-        gmx::ProgramInfo::init("gmx", argc, argv);
+    gmx::ProgramInfo &info = gmx::ProgramInfo::init("gmx", argc, argv);
     try
     {
-        gmx::CommandLineModuleManager manager(info);
+        gmx::CommandLineModuleManager manager(&info);
         registerTrajectoryAnalysisModules(&manager);
         registerLegacyModules(&manager);
         manager.addHelpTopic(gmx::SelectionCollection::createDefaultHelpTopic());