Improve gmx help -export Sphinx rebuild behavior
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 29 Jun 2015 10:43:11 +0000 (13:43 +0300)
committerKasson <kasson@gmail.com>
Sun, 5 Jul 2015 21:28:21 +0000 (23:28 +0200)
Make 'gmx help -export rst' only touch those files whose contents have
actually changed.  This means that rerunning Sphinx is much faster when,
e.g., checking the help text for a single tool after fixes.

Use the file output redirection mechanism to capture all output into
intermediate buffers, and only write it to a file if that file is
missing or has incorrect contents.

Update the reference data to avoid future confusion, as the files are
now written out in a different order (but the tests pass irrespective of
the order of the stuff in the reference data).

Change-Id: I41d764e16aa68a5aaa7da879f4b600e268ca70f2

src/gromacs/commandline/cmdlinehelpmodule.cpp
src/gromacs/commandline/tests/refdata/CommandLineHelpModuleTest_ExportsHelp.xml

index 0ebad1ecfcf51e147bf67de079dbe101e52ac162..3d0020d3cdfc6671c5d88569b712408055cc8d5c 100644 (file)
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fileredirector.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/path.h"
 #include "gromacs/utility/programcontext.h"
+#include "gromacs/utility/stringstream.h"
 #include "gromacs/utility/stringutil.h"
 #include "gromacs/utility/textreader.h"
+#include "gromacs/utility/textstream.h"
 #include "gromacs/utility/textwriter.h"
 
 #include "shellcompletions.h"
@@ -491,8 +494,9 @@ class HelpExportReStructuredText : public HelpExportInterface
 {
     public:
         //! Initializes reST exporter.
-        explicit HelpExportReStructuredText(
-            const CommandLineHelpModuleImpl &helpModule);
+        HelpExportReStructuredText(
+            const CommandLineHelpModuleImpl &helpModule,
+            FileOutputRedirectorInterface   *outputRedirector);
 
         virtual void startModuleExport();
         virtual void exportModuleHelp(
@@ -517,8 +521,9 @@ class HelpExportReStructuredText : public HelpExportInterface
 };
 
 HelpExportReStructuredText::HelpExportReStructuredText(
-        const CommandLineHelpModuleImpl &helpModule)
-    : outputRedirector_(helpModule.outputRedirector_),
+        const CommandLineHelpModuleImpl &helpModule,
+        FileOutputRedirectorInterface   *outputRedirector)
+    : outputRedirector_(outputRedirector),
       binaryName_(helpModule.binaryName_),
       links_(eHelpOutputFormat_Rst)
 {
@@ -554,8 +559,6 @@ void HelpExportReStructuredText::exportModuleHelp(
         const std::string                &tag,
         const std::string                &displayName)
 {
-    // TODO: Ideally, the file would only be touched if it really changes.
-    // This would make Sphinx reruns much faster.
     TextOutputStreamPointer file
         = outputRedirector_->openTextOutputFile("onlinehelp/" + tag + ".rst");
     TextWriter              writer(file);
@@ -783,6 +786,76 @@ void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter)
     rootTopic_->exportHelp(exporter);
 }
 
+namespace
+{
+
+/********************************************************************
+ * ModificationCheckingFileOutputStream
+ */
+
+class ModificationCheckingFileOutputStream : public TextOutputStream
+{
+    public:
+        ModificationCheckingFileOutputStream(
+            const char                    *path,
+            FileOutputRedirectorInterface *redirector)
+            : path_(path), redirector_(redirector)
+        {
+        }
+
+        virtual void write(const char *str) { contents_.write(str); }
+        virtual void close()
+        {
+            const std::string &newContents = contents_.toString();
+            // TODO: Redirect these for unit tests.
+            if (File::exists(path_))
+            {
+                const std::string originalContents_
+                    = TextReader::readFileToString(path_);
+                if (originalContents_ == newContents)
+                {
+                    return;
+                }
+            }
+            TextWriter writer(redirector_->openTextOutputFile(path_));
+            writer.writeString(newContents);
+        }
+
+    private:
+        std::string                     path_;
+        StringOutputStream              contents_;
+        FileOutputRedirectorInterface  *redirector_;
+};
+
+/********************************************************************
+ * ModificationCheckingFileOutputRedirector
+ */
+
+class ModificationCheckingFileOutputRedirector : public FileOutputRedirectorInterface
+{
+    public:
+        explicit ModificationCheckingFileOutputRedirector(
+            FileOutputRedirectorInterface *redirector)
+            : redirector_(redirector)
+        {
+        }
+
+        virtual TextOutputStream &standardOutput()
+        {
+            return redirector_->standardOutput();
+        }
+        virtual TextOutputStreamPointer openTextOutputFile(const char *filename)
+        {
+            return TextOutputStreamPointer(
+                    new ModificationCheckingFileOutputStream(filename, redirector_));
+        }
+
+    private:
+        FileOutputRedirectorInterface  *redirector_;
+};
+
+}   // namespace
+
 /********************************************************************
  * CommandLineHelpModule
  */
@@ -841,10 +914,11 @@ int CommandLineHelpModule::run(int argc, char *argv[])
     CommandLineParser(&options).parse(&argc, argv);
     if (!exportFormat.empty())
     {
-        boost::scoped_ptr<HelpExportInterface> exporter;
+        ModificationCheckingFileOutputRedirector redirector(impl_->outputRedirector_);
+        boost::scoped_ptr<HelpExportInterface>   exporter;
         if (exportFormat == "rst")
         {
-            exporter.reset(new HelpExportReStructuredText(*impl_));
+            exporter.reset(new HelpExportReStructuredText(*impl_, &redirector));
         }
         else if (exportFormat == "completion")
         {
index 40c8fb826d058692cc38007f8acca1a4a5decf11..df3572fa4125dcb88d65cbd597b8251af100708e 100644 (file)
@@ -1,20 +1,6 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
-  <String Name="fragments/byname.rst"><![CDATA[
-* :doc:`test </onlinehelp/test>` - molecular dynamics simulation suite
-* :doc:`test help </onlinehelp/test-help>` - Print help information
-* :doc:`test module </onlinehelp/test-module>` - First module
-* :doc:`test other </onlinehelp/test-other>` - Second module
-]]></String>
-  <String Name="conf-man.py"><![CDATA[
-man_pages = [
-    ('onlinehelp/test-help', 'test-help', "Print help information", '', 1),
-    ('onlinehelp/test-module', 'test-module', "First module", '', 1),
-    ('onlinehelp/test-other', 'test-other', "Second module", '', 1),
-    ('onlinehelp/test', 'test', 'molecular dynamics simulation suite', '', 1)
-]
-]]></String>
   <String Name="onlinehelp/test-help.rst"><![CDATA[
 .. _test help:
 
@@ -83,6 +69,20 @@ Synopsis
    :manpage:`test(1)`
 
    More information about |Gromacs| is available at <http://www.gromacs.org/>.
+]]></String>
+  <String Name="fragments/byname.rst"><![CDATA[
+* :doc:`test </onlinehelp/test>` - molecular dynamics simulation suite
+* :doc:`test help </onlinehelp/test-help>` - Print help information
+* :doc:`test module </onlinehelp/test-module>` - First module
+* :doc:`test other </onlinehelp/test-other>` - Second module
+]]></String>
+  <String Name="conf-man.py"><![CDATA[
+man_pages = [
+    ('onlinehelp/test-help', 'test-help', "Print help information", '', 1),
+    ('onlinehelp/test-module', 'test-module', "First module", '', 1),
+    ('onlinehelp/test-other', 'test-other', "Second module", '', 1),
+    ('onlinehelp/test', 'test', 'molecular dynamics simulation suite', '', 1)
+]
 ]]></String>
   <String Name="fragments/bytopic.rst"><![CDATA[
 Group 1