Browse Source

[add][WIP][Refs #29] UNTESTED/undocumented diff tools

B Thibault 9 years ago
parent
commit
9f1158f32d
6 changed files with 214 additions and 6 deletions
  1. 1 0
      CMakeLists.txt
  2. 40 0
      include/diffCmd.hh
  3. 10 1
      include/params.hh
  4. 67 0
      src/diffCmd.cpp
  5. 72 1
      src/main.cpp
  6. 24 4
      src/params.cpp

+ 1 - 0
CMakeLists.txt

@@ -14,6 +14,7 @@ include_directories(include ${CURSES_INCLUDE_DIRS})
 # jsonstroll
 # jsonstroll
 add_executable(jsonstroll
 add_executable(jsonstroll
     src/warning.cpp
     src/warning.cpp
+    src/diffCmd.cpp
     src/params.cpp
     src/params.cpp
 
 
     src/curseOutput.cpp
     src/curseOutput.cpp

+ 40 - 0
include/diffCmd.hh

@@ -0,0 +1,40 @@
+#pragma once
+
+#include <string>
+#include <deque>
+
+class DiffCmd
+{
+    public:
+        DiffCmd();
+        ~DiffCmd();
+
+        /**
+         * Append parameter to cmd params
+        **/
+        void add(const std::string &param);
+
+        /**
+         * file to pass to execvp to construct executable path from PATH or ./
+        **/
+        std::string getFile() const;
+        /**
+         * get args to pass to execvp
+        **/
+        std::deque<std::string> getArgv() const;
+
+        /**
+         * lazy-compute char*argv[] from File &a and File &b
+        **/
+        char **computeArgv(const std::deque<std::string> &inputFiles);
+
+        /**
+         * Hash string
+        **/
+        static unsigned long long hashString(const std::string &s);
+
+    private:
+        std::deque<std::string> argv;
+        char **allocatedArgv;
+};
+

+ 10 - 1
include/params.hh

@@ -12,9 +12,12 @@
 #include <utility>
 #include <utility>
 #include <istream>
 #include <istream>
 #include "fifoMap.hpp"
 #include "fifoMap.hpp"
+#include "optional.hpp"
 
 
 typedef fifoMap<std::string, std::basic_istream<char> *> IndexedDeque;
 typedef fifoMap<std::string, std::basic_istream<char> *> IndexedDeque;
 
 
+class DiffCmd;
+
 class AParams
 class AParams
 {
 {
     public:
     public:
@@ -30,7 +33,6 @@ class AParams
          * true if --color match conditions
          * true if --color match conditions
         **/
         **/
         virtual bool colorEnabled() const =0;
         virtual bool colorEnabled() const =0;
-
         /**
         /**
          * true if need sorted object
          * true if need sorted object
         **/
         **/
@@ -76,6 +78,11 @@ class Params: public AParams
         **/
         **/
         const std::string &getProgName() const;
         const std::string &getProgName() const;
 
 
+        /**
+         * return diff command helper (or nullptr if none)
+        **/
+        DiffCmd *getExternalDiff() const;
+
         /**
         /**
          * flags
          * flags
         **/
         **/
@@ -102,5 +109,7 @@ class Params: public AParams
         bool diffMode;
         bool diffMode;
         bool sorted;
         bool sorted;
         bool compressMode;
         bool compressMode;
+
+        DiffCmd *diffCmd;
 };
 };
 
 

+ 67 - 0
src/diffCmd.cpp

@@ -0,0 +1,67 @@
+#include <string.h>
+#include "diffCmd.hh"
+
+DiffCmd::DiffCmd(): allocatedArgv(nullptr)
+{ }
+
+DiffCmd::~DiffCmd()
+{
+    char **av = allocatedArgv;
+
+    if (av)
+    {
+        while (*av)
+        {
+            free(*av);
+            av++;
+        }
+        delete[] allocatedArgv;
+    }
+}
+
+void DiffCmd::add(const std::string &str)
+{ argv.push_back(str); }
+
+std::string DiffCmd::getFile() const
+{ return argv[0]; }
+
+std::deque<std::string> DiffCmd::getArgv() const
+{ return argv; }
+
+char **DiffCmd::computeArgv(const std::deque<std::string> &inputFiles)
+{
+    if (allocatedArgv)
+        return allocatedArgv;
+    unsigned int nbParams = 0,
+                 currentParam = 0;
+
+    for (std::string &i : argv)
+    {
+        if (i == "{}")
+            nbParams += inputFiles.size();
+        else
+            nbParams++;
+    }
+    allocatedArgv = new char*[nbParams +1];
+    for (std::string &i : argv)
+    {
+        if (i == "{}")
+            for(std::string input: inputFiles)
+                allocatedArgv[currentParam++] = strdup(input.c_str());
+        else
+            allocatedArgv[currentParam++] = strdup(i.c_str());
+    }
+    allocatedArgv[currentParam] = nullptr;
+    return allocatedArgv;
+}
+
+unsigned long long DiffCmd::hashString(const std::string &s)
+{
+    unsigned long long hash =0;
+
+    for (char c: s)
+        hash = (hash << 5) + c;
+
+    return hash;
+}
+

+ 72 - 1
src/main.cpp

@@ -5,6 +5,9 @@
 **/
 **/
 
 
 #include <iostream>
 #include <iostream>
+#include <sstream>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <locale.h>
 #include <locale.h>
 #include "curseSimpleOutput.hh"
 #include "curseSimpleOutput.hh"
@@ -12,6 +15,7 @@
 #include "streamConsumer.hh"
 #include "streamConsumer.hh"
 #include "jsonException.hh"
 #include "jsonException.hh"
 #include "simpleOutput.hh"
 #include "simpleOutput.hh"
+#include "diffCmd.hh"
 #include "params.hh"
 #include "params.hh"
 
 
 void displayException(const std::string &filename, const Params &params, const std::string &type, const JsonException &e)
 void displayException(const std::string &filename, const Params &params, const std::string &type, const JsonException &e)
@@ -60,6 +64,71 @@ StreamConsumer *readOneFile(std::pair<std::string, std::basic_istream<char>*> in
     return stream;
     return stream;
 }
 }
 
 
+std::ofstream getOutputFile(const std::string iname, std::string &outfile)
+{
+    unsigned long long hash = DiffCmd::hashString(iname);
+    unsigned int i = 0;
+    std::ofstream fout;
+    std::stringstream ss;
+
+    do {
+        ss = std::stringstream("");
+        ss << "/tmp/jsondifftmp" << hash << '.' << i << ".tmp";
+        outfile = ss.str();
+        fout.open(outfile);
+    } while (!fout.is_open() && i  < 1000);
+    return fout;
+}
+
+/**
+ * run command, and return once finished to let parent clean files and GC
+**/
+std::deque<std::string> doRunExternalDiff(const Params &p)
+{
+    std::deque<std::string> inputsFilenames;
+    IndexedDeque inputs = p.getInputs();
+    std::deque<Warning> warns;
+
+    for (std::pair<std::string, std::basic_istream<char>*> input : inputs)
+    {
+        std::string fname;
+        StreamConsumer *stream = readOneFile(input, p, warns);
+
+        if (!stream)
+            return inputsFilenames;
+        std::ofstream fout = getOutputFile(input.first, fname);
+        inputsFilenames.push_back(fname);
+        SimpleOutput::display(fout, stream->getRoot(), p);
+        delete stream;
+    }
+    for (Warning w : warns)
+    {
+        std::cerr << "Warning: ";
+        displayException(w.filename(), p, w.getType(), w());
+    }
+
+    char **av = p.getExternalDiff()->computeArgv(inputsFilenames);
+    int fk = fork();
+    int status;
+
+    if (fk == -1)
+        return inputsFilenames;
+    else if (fk == 0)
+        execvp(*av, av);
+    // Wait for child to terminate
+    do {
+        waitpid(fk, &status, 0);
+    } while (!WIFEXITED(status));
+    return inputsFilenames;
+}
+
+void runExternalDiff(const Params &p)
+{
+    std::deque<std::string> files = doRunExternalDiff(p);
+    for (std::string &fname: files)
+        unlink(fname.c_str());
+}
+
 void runDiff(const Params &params)
 void runDiff(const Params &params)
 {
 {
     const IndexedDeque inputs = params.getInputs();
     const IndexedDeque inputs = params.getInputs();
@@ -162,7 +231,9 @@ int main(int ac, char **av)
     {
     {
         if (!params->isIgnoringUnicode())
         if (!params->isIgnoringUnicode())
             setlocale(LC_ALL, "");
             setlocale(LC_ALL, "");
-        if (params->isDiff())
+        if (params->getExternalDiff())
+            runExternalDiff(*params);
+        else if (params->isDiff())
             runDiff(*params);
             runDiff(*params);
         else
         else
         {
         {

+ 24 - 4
src/params.cpp

@@ -9,11 +9,11 @@
 #include <sstream>
 #include <sstream>
 #include <curses.h>
 #include <curses.h>
 #include <unistd.h>
 #include <unistd.h>
+#include "diffCmd.hh"
 #include "params.hh"
 #include "params.hh"
-
 #include "config.h"
 #include "config.h"
 
 
-Params::Params(char **av): progName(*av), strict(true), diffMode(false)
+Params::Params(char **av): progName(*av), strict(true), diffMode(false), diffCmd(nullptr)
 {
 {
     av++;
     av++;
     while (*av)
     while (*av)
@@ -27,11 +27,14 @@ Params::~Params()
 {
 {
     for (std::pair<std::string, std::basic_istream<char>*> in : inputs)
     for (std::pair<std::string, std::basic_istream<char>*> in : inputs)
         delete in.second;
         delete in.second;
+    if (diffCmd)
+        delete diffCmd;
 }
 }
 
 
 bool Params::read()
 bool Params::read()
 {
 {
-    bool written = false;
+    bool written = false,
+         inDiff = false;
     std::stringstream *input = nullptr;
     std::stringstream *input = nullptr;
     ignoreUnicode = false;
     ignoreUnicode = false;
     colorMode = sorted = true;
     colorMode = sorted = true;
@@ -40,7 +43,7 @@ bool Params::read()
     for (std::list<std::string>::const_iterator i = params.cbegin(); i != params.cend(); i++)
     for (std::list<std::string>::const_iterator i = params.cbegin(); i != params.cend(); i++)
     {
     {
         std::string tmp(*i);
         std::string tmp(*i);
-        if (!input)
+        if (!input && !inDiff)
         {
         {
             if (tmp == "--")
             if (tmp == "--")
                 inputs["ARGS"] = input = new std::stringstream();
                 inputs["ARGS"] = input = new std::stringstream();
@@ -66,6 +69,13 @@ bool Params::read()
             }
             }
             else if (tmp == "--keep-order")
             else if (tmp == "--keep-order")
                 sorted = false;
                 sorted = false;
+            else if (tmp == "--diff-cmd")
+            {
+                if (diffCmd)
+                    throw std::runtime_error("Invalid double usage of --diff-cmd");
+                inDiff = true;
+                diffCmd = new DiffCmd();
+            }
             else if (tmp.find("--color=") == 0)
             else if (tmp.find("--color=") == 0)
             {
             {
                 std::string mode = tmp.substr(8);
                 std::string mode = tmp.substr(8);
@@ -95,6 +105,13 @@ bool Params::read()
                     inputs[tmp] = in;
                     inputs[tmp] = in;
             }
             }
         }
         }
+        else if (inDiff)
+        {
+            if (tmp == ";")
+                inDiff = false;
+            else
+                diffCmd->add(tmp);
+        }
         else
         else
         {
         {
             if (written)
             if (written)
@@ -193,3 +210,6 @@ bool Params::compressed() const
 bool Params::isDiff() const
 bool Params::isDiff() const
 { return diffMode; }
 { return diffMode; }
 
 
+DiffCmd *Params::getExternalDiff() const
+{ return diffCmd; }
+