bookmaker report only changed files

Change bookmaker to omit files written with unchanged
values. Temporary copies of fiddleout.json and catalog.htm
are written, and if the same as the existing copies, are
silently deleted.

Update stdout from examples in SkColor4f_Reference that
have changed to keep up with the latest checkin.

TBR=brianosman@google.com

Docs-Preview: https://skia.org/?cl=150146
Bug: skia:6898
Change-Id: I14e326bdd53baec92853d265edbe160c84583381
Reviewed-on: https://skia-review.googlesource.com/150146
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
diff --git a/docs/SkColor4f_Reference.bmh b/docs/SkColor4f_Reference.bmh
index 19d4b5d..251145d 100644
--- a/docs/SkColor4f_Reference.bmh
+++ b/docs/SkColor4f_Reference.bmh
@@ -111,8 +111,8 @@
     const float* array = color.vec();

     SkDebugf("[0]=%g [1]=%g [2]=%g [3]=%g\n", array[0], array[1], array[2], array[3]);

 #StdOut
-red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333

-[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=0.533333
+red=0.266667 green=0.533333 blue=0.8 alpha=0.533333

+[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=0.533333
 ##
 ##
 
@@ -137,8 +137,8 @@
     array[3] = 1;

     SkDebugf("[0]=%g [1]=%g [2]=%g [3]=%g\n", array[0], array[1], array[2], array[3]);
 #StdOut
-red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333

-[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=1
+red=0.266667 green=0.533333 blue=0.8 alpha=0.533333

+[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=1
 ##
 ##
 
@@ -208,7 +208,7 @@
     SkDebugf("red=%d green=%d blue=%d alpha=%d\n", SkColorGetR(fromColor4f),

              SkColorGetG(fromColor4f), SkColorGetB(fromColor4f), SkColorGetA(fromColor4f));
 #StdOut
-red=0.0742136 green=0.130136 blue=0.318547 alpha=0.168627

+red=0.301961 green=0.396078 blue=0.6 alpha=0.168627

 red=77 green=101 blue=153 alpha=43
 ##
 ##
@@ -237,8 +237,8 @@
     SkDebugf("red=%g green=%g blue=%g alpha=%g\n", fromSkColor.fR, fromSkColor.fG,

                                                    fromSkColor.fB, fromSkColor.fA);

 #StdOut

-red=75 green=101 blue=153 alpha=43

-red=0.0703601 green=0.130136 blue=0.318547 alpha=0.168627

+red=18 green=33 blue=82 alpha=43

+red=0.0705882 green=0.129412 blue=0.321569 alpha=0.168627

 ##

 ##
 
diff --git a/site/user/api/SkColor4f_Reference.md b/site/user/api/SkColor4f_Reference.md
index 569236a..4e2c59c 100644
--- a/site/user/api/SkColor4f_Reference.md
+++ b/site/user/api/SkColor4f_Reference.md
@@ -242,8 +242,8 @@
 #### Example Output
 
 ~~~~
-red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333
-[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=0.533333
+red=0.266667 green=0.533333 blue=0.8 alpha=0.533333
+[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=0.533333
 ~~~~
 
 </fiddle-embed></div>
@@ -273,8 +273,8 @@
 #### Example Output
 
 ~~~~
-red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333
-[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=1
+red=0.266667 green=0.533333 blue=0.8 alpha=0.533333
+[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=1
 ~~~~
 
 </fiddle-embed></div>
@@ -351,7 +351,7 @@
 #### Example Output
 
 ~~~~
-red=0.0742136 green=0.130136 blue=0.318547 alpha=0.168627
+red=0.301961 green=0.396078 blue=0.6 alpha=0.168627
 red=77 green=101 blue=153 alpha=43
 ~~~~
 
@@ -383,8 +383,8 @@
 #### Example Output
 
 ~~~~
-red=75 green=101 blue=153 alpha=43
-red=0.0703601 green=0.130136 blue=0.318547 alpha=0.168627
+red=18 green=33 blue=82 alpha=43
+red=0.0705882 green=0.129412 blue=0.321569 alpha=0.168627
 ~~~~
 
 </fiddle-embed></div>
diff --git a/site/user/api/catalog.htm b/site/user/api/catalog.htm
index 610aba1..d85d583 100644
--- a/site/user/api/catalog.htm
+++ b/site/user/api/catalog.htm
@@ -579,7 +579,7 @@
     "hash": "33b029064e8d1928e42a587c953d0e4e",
     "file": "SkColor4f_Reference",
     "name": "SkColor4f::FromColor",
-        "stdout": "red=0.0742136 green=0.130136 blue=0.318547 alpha=0.168627\\nred=77 green=101 blue=153 alpha=43\\n"
+        "stdout": "red=0.301961 green=0.396078 blue=0.6 alpha=0.168627\\nred=77 green=101 blue=153 alpha=43\\n"
     },
         "SkColor4f_equal1_operator": {
     "code": "void draw(SkCanvas* canvas) {\n    SkColor4f colorRed = { 1, 0, 0, 1 };\n    SkColor4f colorNamedRed = SkColor4f::FromColor(SK_ColorRED);\n    SkDebugf(\"colorRed %c= colorNamedRed\", colorRed == colorNamedRed ? '=' : '!');\n}",
@@ -600,21 +600,21 @@
     "hash": "edc5fd18d961f7607d2bcbf7f7d427e5",
     "file": "SkColor4f_Reference",
     "name": "SkColor4f::toSkColor",
-        "stdout": "red=75 green=101 blue=153 alpha=43\\nred=0.0703601 green=0.130136 blue=0.318547 alpha=0.168627\\n"
+        "stdout": "red=18 green=33 blue=82 alpha=43\\nred=0.0705882 green=0.129412 blue=0.321569 alpha=0.168627\\n"
     },
         "SkColor4f_vec": {
     "code": "void draw(SkCanvas* canvas) {\n    SkColor4f color = SkColor4f::FromColor(0x884488CC);\n    SkDebugf(\"red=%g green=%g blue=%g alpha=%g\\n\", color.fR, color.fG, color.fB, color.fA);\n    const float* array = color.vec();\n    SkDebugf(\"[0]=%g [1]=%g [2]=%g [3]=%g\\n\", array[0], array[1], array[2], array[3]);\n}",
     "hash": "229057023515224358a36acf15508cf6",
     "file": "SkColor4f_Reference",
     "name": "SkColor4f::vec()",
-        "stdout": "red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333\\n[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=0.533333\\n"
+        "stdout": "red=0.266667 green=0.533333 blue=0.8 alpha=0.533333\\n[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=0.533333\\n"
     },
         "SkColor4f_vec_2": {
     "code": "void draw(SkCanvas* canvas) {\n    SkColor4f color = SkColor4f::FromColor(0x884488CC);\n    SkDebugf(\"red=%g green=%g blue=%g alpha=%g\\n\", color.fR, color.fG, color.fB, color.fA);\n    float* array = color.vec();\n    array[3] = 1;\n    SkDebugf(\"[0]=%g [1]=%g [2]=%g [3]=%g\\n\", array[0], array[1], array[2], array[3]);\n}",
     "hash": "7420bf0a7cae5c6577c4c4a4613e7e7e",
     "file": "SkColor4f_Reference",
     "name": "SkColor4f::vec_2",
-        "stdout": "red=0.0578054 green=0.246201 blue=0.603827 alpha=0.533333\\n[0]=0.0578054 [1]=0.246201 [2]=0.603827 [3]=1\\n"
+        "stdout": "red=0.266667 green=0.533333 blue=0.8 alpha=0.533333\\n[0]=0.266667 [1]=0.533333 [2]=0.8 [3]=1\\n"
     },
         "SkIPoint_Make": {
     "code": "void draw(SkCanvas* canvas) {\n    SkIPoint pt1 = {45, 66};\n    SkIPoint pt2 = SkIPoint::Make(45, 66);\n    SkDebugf(\"pt1 %c= pt2\\n\", pt1 == pt2 ? '=' : '!');\n}",
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index c173c09..c1a0569 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -976,9 +976,12 @@
 }
 
 bool BmhParser::dumpExamples(const char* fiddleJsonFileName) const {
-    FILE* fiddleOut = fopen(fiddleJsonFileName, "wb");
+    string oldFiddle(fiddleJsonFileName);
+    string newFiddle(fiddleJsonFileName);
+    newFiddle += "_new";
+    FILE* fiddleOut = fopen(newFiddle.c_str(), "wb");
     if (!fiddleOut) {
-        SkDebugf("could not open output file %s\n", fiddleJsonFileName);
+        SkDebugf("could not open output file %s\n", newFiddle.c_str());
         return false;
     }
     fprintf(fiddleOut, "{\n");
@@ -991,7 +994,10 @@
     }
     fprintf(fiddleOut, "\n}\n");
     fclose(fiddleOut);
-    SkDebugf("wrote %s\n", fiddleJsonFileName);
+    if (ParserCommon::WrittenFileDiffers(oldFiddle, newFiddle)) {
+        ParserCommon::CopyToFile(oldFiddle, newFiddle);
+        SkDebugf("wrote %s\n", fiddleJsonFileName);
+    }
     return true;
 }
 
@@ -1555,7 +1561,7 @@
     this->topicIter(root);
     fprintf(fOut, "%.*s", (int) (fEnd - fChar), fChar);
     fclose(fOut);
-    if (this->writtenFileDiffers(filename, root->fFileName)) {
+    if (ParserCommon::WrittenFileDiffers(filename, root->fFileName)) {
         SkDebugf("wrote %s\n", filename.c_str());
     } else {
         remove(filename.c_str());
@@ -2698,16 +2704,16 @@
     if (!done && FLAGS_catalog && FLAGS_examples.isEmpty()) {
         Catalog cparser(&bmhParser);
         cparser.fDebugOut = FLAGS_stdout;
-        if (!FLAGS_bmh.isEmpty() && !cparser.openCatalog(FLAGS_bmh[0], FLAGS_ref[0])) {
+        if (!FLAGS_bmh.isEmpty() && !cparser.openCatalog(FLAGS_bmh[0])) {
             return -1;
         }
-        if (!FLAGS_status.isEmpty() && !cparser.openStatus(FLAGS_status[0], FLAGS_ref[0])) {
+        if (!FLAGS_status.isEmpty() && !cparser.openStatus(FLAGS_status[0])) {
             return -1;
         }
         if (!cparser.parseFile(FLAGS_fiddle[0], ".txt", ParserCommon::OneFile::kNo)) {
             return -1;
         }
-        if (!cparser.closeCatalog()) {
+        if (!cparser.closeCatalog(FLAGS_ref[0])) {
             return -1;
         }
         bmhParser.fWroteOut = true;
diff --git a/tools/bookmaker/bookmaker.h b/tools/bookmaker/bookmaker.h
index 04b1c0f..e16e4b5 100644
--- a/tools/bookmaker/bookmaker.h
+++ b/tools/bookmaker/bookmaker.h
@@ -1150,7 +1150,9 @@
         fParent = def;
     }
 
-    char* FindDateTime(char* buffer, int size);
+    static void CopyToFile(string oldFile, string newFile);
+
+    static char* FindDateTime(char* buffer, int size);
 
     void indentIn(IndentKind kind) {
         fIndent += 4;
@@ -1220,7 +1222,7 @@
         fParent = fParent->fParent;
     }
 
-    char* ReadToBuffer(string filename, int* size);
+    static char* ReadToBuffer(string filename, int* size);
 
     virtual void reset() = 0;
 
@@ -1298,7 +1300,7 @@
         this->writeString(str.c_str());
     }
 
-    bool writtenFileDiffers(string filename, string readname);
+    static bool WrittenFileDiffers(string filename, string readname);
 
     unordered_map<string, sk_sp<SkData>> fRawData;
     unordered_map<string, vector<char>> fLFOnly;
@@ -2164,9 +2166,9 @@
     Catalog(BmhParser* bmh) : FiddleBase(bmh) {}
 
     bool appendFile(string path);
-    bool closeCatalog();
-    bool openCatalog(const char* inDir, const char* outDir);
-    bool openStatus(const char* inDir, const char* outDir);
+    bool closeCatalog(const char* outDir);
+    bool openCatalog(const char* inDir);
+    bool openStatus(const char* inDir);
 
     bool parseFromFile(const char* path) override ;
 private:
diff --git a/tools/bookmaker/cataloger.cpp b/tools/bookmaker/cataloger.cpp
index c6aae74..5689813 100644
--- a/tools/bookmaker/cataloger.cpp
+++ b/tools/bookmaker/cataloger.cpp
@@ -10,6 +10,8 @@
 #include "SkOSFile.h"
 #include "SkOSPath.h"
 
+const string kCatalogFileName("catalog.htm");
+
 bool Catalog::appendFile(string path) {
     FILE* file = fopen(path.c_str(), "r");
     if (!file) {
@@ -27,19 +29,15 @@
     return true;
 }
 
-bool Catalog::openCatalog(const char* inDir, const char* outDir) {
+bool Catalog::openCatalog(const char* inDir) {
     fDocsDir = inDir;
     if ('/' != fDocsDir.back()) {
         fDocsDir += '/';
     }
-    string outie = outDir;
-    if ('/' != outie.back()) {
-        outie += '/';
-    }
-    fFullName = outie + "catalog.htm";
-    fOut = fopen(fFullName.c_str(), "wb");
+    fOut = fopen(kCatalogFileName.c_str(), "wb");
+    fFullName = kCatalogFileName;
     if (!fOut) {
-        SkDebugf("could not open output file %s\n", fFullName.c_str());
+        SkDebugf("could not open output file %s\n", kCatalogFileName.c_str());
         return false;
     }
     fContinuation = false;
@@ -47,10 +45,11 @@
         return false;
     }
     this->lf(1);
+
     return true;
 }
 
-bool Catalog::openStatus(const char* statusFile, const char* outDir) {
+bool Catalog::openStatus(const char* statusFile) {
     StatusIter iter(statusFile, ".bmh", StatusFilter::kInProgress);
     string unused;
     // FIXME: iterate through only chosen files by setting fDocsDir to iter
@@ -58,10 +57,10 @@
     if (!iter.next(&unused)) {
         return false;
     }
-    return openCatalog(iter.baseDir().c_str(), outDir);
+    return openCatalog(iter.baseDir().c_str());
 }
 
-bool Catalog::closeCatalog() {
+bool Catalog::closeCatalog(const char* outDir) {
     if (fOut) {
         this->lf(1);
         this->writeString("}");
@@ -72,7 +71,15 @@
         this->lf(1);
         this->writePending();
         fclose(fOut);
-        SkDebugf("wrote %s\n", fFullName.c_str());
+        string outie = outDir;
+        if ('/' != outie.back()) {
+            outie += '/';
+        }
+        string fullName = outie + kCatalogFileName;
+        if (ParserCommon::WrittenFileDiffers(fullName, kCatalogFileName)) {
+            ParserCommon::CopyToFile(fullName, kCatalogFileName);
+            SkDebugf("wrote %s\n", fullName.c_str());
+        }
         fOut = nullptr;
     }
     return true;
diff --git a/tools/bookmaker/includeWriter.cpp b/tools/bookmaker/includeWriter.cpp
index 1ffd60c..e9ab8b9 100644
--- a/tools/bookmaker/includeWriter.cpp
+++ b/tools/bookmaker/includeWriter.cpp
@@ -2113,7 +2113,7 @@
         }
         string dir = fFileName.substr(0, SkTMax(slash, back) + 1);
         string readname = dir + fileName;
-        if (this->writtenFileDiffers(fileName, readname)) {
+        if (ParserCommon::WrittenFileDiffers(fileName, readname)) {
             SkDebugf("wrote updated %s\n", fileName.c_str());
         } else {
             remove(fileName.c_str());
diff --git a/tools/bookmaker/mdOut.cpp b/tools/bookmaker/mdOut.cpp
index c3a985c..247c729 100644
--- a/tools/bookmaker/mdOut.cpp
+++ b/tools/bookmaker/mdOut.cpp
@@ -621,7 +621,7 @@
         this->writePending();
         fclose(fOut);
         fflush(fOut);
-        if (this->writtenFileDiffers(filename, fullName)) {
+        if (ParserCommon::WrittenFileDiffers(filename, fullName)) {
             fOut = fopen(fullName.c_str(), "wb");
             int writtenSize;
             const char* written = ReadToBuffer(filename, &writtenSize);
diff --git a/tools/bookmaker/parserCommon.cpp b/tools/bookmaker/parserCommon.cpp
index fb00b16..edeec02 100644
--- a/tools/bookmaker/parserCommon.cpp
+++ b/tools/bookmaker/parserCommon.cpp
@@ -14,6 +14,19 @@
     SkDebugf("%.*s", len, data);
 }
 
+void ParserCommon::CopyToFile(string oldFile, string newFile) {
+    int bufferSize;
+    char* buffer = ParserCommon::ReadToBuffer(newFile, &bufferSize);
+    FILE* oldOut = fopen(oldFile.c_str(), "wb");
+    if (!oldOut) {
+        SkDebugf("could not open file %s\n", oldFile.c_str());
+        return;
+    }
+    fwrite(buffer, 1, bufferSize, oldOut);
+    fclose(oldOut);
+    remove(newFile.c_str());
+}
+
 bool ParserCommon::parseFile(const char* fileOrPath, const char* suffix, OneFile oneFile) {
     if (!sk_isdir(fileOrPath)) {
         if (!this->parseFromFile(fileOrPath)) {
@@ -275,13 +288,13 @@
     return &buffer[index];
 }
 
-bool ParserCommon::writtenFileDiffers(string filename, string readname) {
+bool ParserCommon::WrittenFileDiffers(string filename, string readname) {
     int writtenSize, readSize;
-    char* written = ReadToBuffer(filename, &writtenSize);
+    char* written = ParserCommon::ReadToBuffer(filename, &writtenSize);
     if (!written) {
         return true;
     }
-    char* read = ReadToBuffer(readname, &readSize);
+    char* read = ParserCommon::ReadToBuffer(readname, &readSize);
     if (!read) {
         delete[] written;
         return true;