]> Creatis software - bbtk.git/commitdiff
Feature #2042 bbpConfigurator
authorDaniel Gonzalez <daniel.gonzalez@creatis.insa-lyon.fr>
Wed, 19 Jun 2013 15:08:36 +0000 (17:08 +0200)
committerDaniel Gonzalez <daniel.gonzalez@creatis.insa-lyon.fr>
Wed, 19 Jun 2013 15:08:36 +0000 (17:08 +0200)
This application should replace the macro BBTK_CREATE_PACKAGE_INCLUDE_SCRIPT in order to organize the includes so the dependecies are taken into account.

It takes the path of the bbs's, the package name, and the output bbp path.

Creates a dependency graph and checks for cycles and orders the includes by their dependency level.

kernel/appli/bbpConfigurator/bbpConfigurator.cpp
kernel/src/bbtkBBPInterpreter.cxx [new file with mode: 0644]
kernel/src/bbtkBBPInterpreter.h [new file with mode: 0644]

index 7a1df7986685f31b7eda805fc65b339c3c56b1f5..50c41635bdc86f77e91ce1c588888de55568bcb0 100644 (file)
 #include <fstream>
 #include <iostream>
 #include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
 #include "boost/filesystem.hpp"
 //#include "boost/filesystem/operations.hpp"
 //#include "boost/filesystem/path.hpp"
+#include "bbtkBBPInterpreter.h"
 
 namespace bf = boost::filesystem;
+typedef std::vector<std::vector<int> > Graph;
 
-//using namespace bbtk;
+typedef std::set<std::string> Dependency;
+typedef std::vector<Dependency> Dependencies;
+typedef std::vector<std::string> Boxes;
+
+bool isCycle(const Graph& g);
+bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v);
+
+void setPriorities(const Graph& g, std::vector<int>& p);
+void setPriority(const Graph& g, const int i, std::vector<int>& p);
 
 int main(int argc, char **argv)
 {
+  // Check arguments
   if (argc != 4)
   {
     std::cout << "usage : bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
@@ -48,6 +62,7 @@ int main(int argc, char **argv)
   std::string package_name(argv[2]);
   std::string path_out(argv[3]);
   
+  // Get bbs files in path_bbs
   std::vector<bf::path> files;
 
   bf::path pth(path_bbs.c_str());
@@ -61,7 +76,7 @@ int main(int argc, char **argv)
         std::string nm(itr->path().filename().string());
         if(nm.substr(nm.size()-4) == ".bbs")
         {
-          std::cout << itr->path().filename().string() << std::endl;
+          //std::cout << itr->path().filename().string() << std::endl;
           files.push_back(itr->path());
         }
       }
@@ -73,6 +88,7 @@ int main(int argc, char **argv)
     return 1;
   }
 
+  // Order files by name
   for (int i = 0; i < (int)files.size()-1; ++i) {
     for (int j = i+1; j < (int)files.size(); ++j) {
       if(files[j].filename().string() < files[i].filename().string())
@@ -84,37 +100,189 @@ int main(int argc, char **argv)
     }
   }
 
-#ifdef WIN32
-  std::string fname = path_out + "\\" + package_name + ".bbp";
-#else
-  std::string fname = path_out + "/" + package_name + ".bbp";
-#endif
-  
-  std::ofstream out(fname.c_str());
-  out << "#-----------------------------------------" << std::endl;
-  out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
-  out << "# Automatically generated by bbpConfigurator" << std::endl;
-  out << "#-----------------------------------------" << std::endl;
-  out << "load "<< package_name << std::endl;
-  out << "#-----------------------------------------" << std::endl;
-  out << "package "<< package_name << std::endl;
-  out << "#-----------------------------------------" << std::endl;
-
-  //each bbs file ordered.
-  //include [package_name]/boxes/[file_bbs]
-  //#-----------------------------------------
+  // Order files by dependencies
+  //  Get Dependencies and Box Names
+  Dependencies ds;
+  Boxes bs;
+
+
   for (int i = 0; i < (int)files.size(); ++i) {
-    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
-    out << "#-----------------------------------------" << std::endl;
+    bbtk::BBPInterpreter::Pointer I = bbtk::BBPInterpreter::New();
+    I->InterpretFile(files[i].string());
+    bs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
+    ds.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies );
+
+    //print box name and dependencies
+/*    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
+    for(
+      dep::iterator it = ((bbtk::BBPInterpreter*)(I.get()))->dependencies.begin();
+      it != ((bbtk::BBPInterpreter*)(I.get()))->dependencies.end();
+      it++) {
+      std::cout << *it << ", ";
+    }
+    std::cout << std::endl;
+*/
+  }
+  // Only keep dependencies from package
+  Dependency boxesNamesSet(bs.begin(), bs.end());
+
+  //std::cout << "after: " << std::endl;
+  for (Dependencies::iterator it = ds.begin(); it != ds.end(); it++) {
+    Boxes tmp;
+    std::set_intersection(it->begin(), it->end(), boxesNamesSet.begin(), boxesNamesSet.end(),std::back_inserter(tmp));
+    Dependency tmp1(tmp.begin(),tmp.end());
+    it->swap( tmp1 );
+    //print clean dependencies
+/*    for(
+      dep::iterator it1 = it->begin();
+      it1 != it->end();
+      it1++) {
+      std::cout << *it1 << ", ";
+    }
+    std::cout << std::endl;
+*/
+  }
+
+  // Check there are no cycles in graph
+  std::vector<std::vector<int> > g(bs.size(), std::vector<int>());
+  std::map<std::string, int> idxs;
+
+
+  for (int i = 0; i < (int)bs.size(); ++i)
+  {
+    idxs[bs[i]] = i;
+  }
+
+  int boxit = 0;
+  for (Dependencies::iterator dit = ds.begin(); dit != ds.end(); dit++, boxit++)
+  {
+    for (Dependency::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
+    {
+      g[boxit].push_back(idxs[*ddit]);
+    }
   }
 
-  out << "endpackage" << std::endl;
-  out << "#-- EOF ----------------------------------" << std::endl;
+  if(isCycle(g))
+  {
+    std::cout << "there are dependency cycles, please check your scripts." << std::endl;
+    return 2;
+  }
+  else
+  {
+    std::cout << "no cycles, we keep going." << std::endl;
+    std::vector<int> dep_priority(bs.size(), -1);
+    setPriorities(g, dep_priority);
+//    for (int i = 0; i < (int)dep_priority.size(); i++)
+//    {
+//      std::cout << dep_priority[i] << " ";
+//    }
+//    std::cout << std::endl;
 
-  out.close();
+    // Write results to bbp file
+  #ifdef WIN32
+    std::string fname = path_out + "\\" + package_name + ".bbp";
+  #else
+    std::string fname = path_out + "/" + package_name + ".bbp";
+  #endif
 
+    std::ofstream out(fname.c_str());
+    out << "#-----------------------------------------" << std::endl;
+    out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
+    out << "# Automatically generated by bbpConfigurator" << std::endl;
+    out << "#-----------------------------------------" << std::endl;
+    out << "load "<< package_name << std::endl;
+    out << "#-----------------------------------------" << std::endl;
+    out << "package "<< package_name << std::endl;
+    out << "#-----------------------------------------" << std::endl;
+
+    //each bbs file ordered.
+    //include [package_name]/boxes/[file_bbs]
+    //#-----------------------------------------
+
+  //  for (int i = 0; i < (int)files.size(); ++i) {
+  //    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
+  //    out << "#-----------------------------------------" << std::endl;
+  //  }
+
+    // for each priority level print scripts in that level.
+    int m_priority = 0;
+    for (int i = 0; i < (int)dep_priority.size(); i++)
+      m_priority = std::max(m_priority, dep_priority[i]);
+
+    for (int i = 0; i <= m_priority; i++)
+    {
+      for (int j = 0; j < (int)dep_priority.size(); j++)
+      {
+        if(dep_priority[j] == i)
+        {
+          out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
+          out << "#-----------------------------------------" << std::endl;
+        }
+      }
+    }
+    out << "endpackage" << std::endl;
+    out << "#-- EOF ----------------------------------" << std::endl;
+  
+    out.close();
+  }
   return 0;
 }
 //==========================================================================
 
+// extract of the tarjan's algorithm for strongly connected components
+bool isCycle(const Graph& g)
+{
+  for (int it = 0; it < (int)g.size(); ++it) {
+    std::vector<bool> visited (g.size(), false);
+    if (checkCycle(g, it, visited))
+    {
+      //std::cout << "At " << it << std::endl;
+      return true;
+    }
+  }
+  return false;
+}
+
+//==========================================================================
+
+bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v)
+{
+
+  v[i] = true;
+  for(int dit = 0; dit < (int)g[i].size(); dit++)
+  {
+    int d = g[i][dit];
+    if(d < 0 || d >= (int)g[i].size() || v[d])
+    {
+      //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
+      return true;
+    }
+    if(checkCycle(g,d,v))
+      return true;
+  }
+  return false;
+}
+
+//==========================================================================
+
+// find precedence in graph. 0 are the boxes that have no deps, 1 boxes that have deps from 0 or less, 2 boxes that have deps from 1 or less, etc.
+void setPriorities(const Graph& g, std::vector<int>& p)
+{
+  for(int i = 0; i < (int)g.size(); i++)
+  {
+    if(p[i] == -1)
+      setPriority(g, i, p);
+  }
+}
 
+//==========================================================================
+void setPriority(const Graph& g, const int i, std::vector<int>& p)
+{
+  int pi = -1;
+  for(int j = 0; j < (int)g[i].size(); j++)
+  {
+    setPriority(g, g[i][j], p);
+    pi = std::max(pi, p[g[i][j]]);
+  }
+  p[i]=pi+1;
+}
diff --git a/kernel/src/bbtkBBPInterpreter.cxx b/kernel/src/bbtkBBPInterpreter.cxx
new file mode 100644 (file)
index 0000000..a9f246c
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+# ---------------------------------------------------------------------
+#
+# Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
+#                        pour la Santé)
+# Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
+#
+#  This software is governed by the CeCILL-B license under French law and
+#  abiding by the rules of distribution of free software. You can  use,
+#  modify and/ or redistribute the software under the terms of the CeCILL-B
+#  license as circulated by CEA, CNRS and INRIA at the following URL
+#  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+#  or in the file LICENSE.txt.
+#
+#  As a counterpart to the access to the source code and  rights to copy,
+#  modify and redistribute granted by the license, users are provided only
+#  with a limited warranty  and the software's author,  the holder of the
+#  economic rights,  and the successive licensors  have only  limited
+#  liability.
+#
+#  The fact that you are presently reading this means that you have had
+#  knowledge of the CeCILL-B license and that you accept its terms.
+# ------------------------------------------------------------------------
+ */
+
+/*=========================================================================
+Program:   bbtk
+Module:    $RCSfile$
+Language:  C++
+Date:      $Date$
+Version:   $Revision$
+=========================================================================*/
+
+
+/**
+ *  \file
+ *  \brief Class bbtk::BBPInterpreter
+ */
+
+
+#include "bbtkBBPInterpreter.h"
+
+#include "bbtkExecuter.h"
+#include "bbtkMessageManager.h"
+#include "bbtkFactory.h"
+#include "bbtkUtilities.h"
+
+namespace bbtk
+{
+
+  //=========================================================================
+  BBPInterpreter::Pointer BBPInterpreter::New()
+  {
+    return MakePointer( new BBPInterpreter() );
+  }
+  //=========================================================================
+
+
+
+  //=========================================================================
+  BBPInterpreter::BBPInterpreter()
+  {
+    bbtk::InterpreterVirtual::Init();
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  BBPInterpreter::~BBPInterpreter()
+  {
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  /// Creates a new black box in current complex box
+  void BBPInterpreter::commandNew( const std::string& boxType, const std::string& boxName) // virtual
+  {
+    this->dependencies.insert(boxType);
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  /// Connects the output boxOutput to the input boxInput
+  void BBPInterpreter::commandConnection (const std::string &boxfrom,
+      const std::string &output,
+      const std::string &boxto,
+      const std::string &input)                        // virtual
+  {
+  }
+  //=========================================================================
+
+  //=========================================================================
+  void BBPInterpreter::commandInput(const std::string &name,const std::string &box,const std::string &input,const std::string  &help)
+  {
+  }
+  //=========================================================================
+
+  //=========================================================================
+  void BBPInterpreter::commandOutput(const std::string &name,const std::string &box,const std::string &output,const std::string  &help)
+  {
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  /// sets the input of the box with the value
+  void BBPInterpreter::commandSet(const std::string &box,const std::string &input,const std::string &value) // virtual
+  {
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  void BBPInterpreter::commandDefine(const std::string &name,const std::string &pack,const std::string &scriptfilename) // virtual
+  {
+    this->boxName = name;
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  void BBPInterpreter::commandEndDefine() // virtual
+  {
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  void BBPInterpreter::commandExec(const std::string &word) // virtual
+  {
+  }
+  //=========================================================================
+
+
+  //=========================================================================
+  void BBPInterpreter::commandAuthor(const std::string &author)  // virtual
+  {
+  }
+  //=========================================================================
+
+  //=========================================================================
+  void BBPInterpreter::commandCategory(const std::string &categorytype)  // virtual
+  {
+  }
+  //=========================================================================
+
+  //=========================================================================
+  void BBPInterpreter::commandDescription(const std::string &description)  // virtual
+  {
+  }
+  //=========================================================================
+
+}  // EO namespace bbtk
+
+// EOF
+
diff --git a/kernel/src/bbtkBBPInterpreter.h b/kernel/src/bbtkBBPInterpreter.h
new file mode 100644 (file)
index 0000000..3e98a96
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+# ---------------------------------------------------------------------
+#
+# Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
+#                        pour la Santé)
+# Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
+#
+#  This software is governed by the CeCILL-B license under French law and
+#  abiding by the rules of distribution of free software. You can  use,
+#  modify and/ or redistribute the software under the terms of the CeCILL-B
+#  license as circulated by CEA, CNRS and INRIA at the following URL
+#  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+#  or in the file LICENSE.txt.
+#
+#  As a counterpart to the access to the source code and  rights to copy,
+#  modify and redistribute granted by the license, users are provided only
+#  with a limited warranty  and the software's author,  the holder of the
+#  economic rights,  and the successive licensors  have only  limited
+#  liability.
+#
+#  The fact that you are presently reading this means that you have had
+#  knowledge of the CeCILL-B license and that you accept its terms.
+# ------------------------------------------------------------------------
+*/
+
+/*=========================================================================
+Program:   bbtk
+Module:    $RCSfile$
+Language:  C++
+Date:      $Date$
+Version:   $Revision$
+=========================================================================*/
+
+
+#ifndef __bbtkBBPInterpreter_h__
+#define __bbtkBBPInterpreter_h__
+
+//Includes bbtk
+#include "bbtkInterpreterVirtual.h"
+
+//Includes std
+#include <iostream>
+#include <set>
+
+
+//#include "bbtkSystem.h"
+//#include "bbtkComplexBlackBox.h"
+
+namespace bbtk
+{
+  class BBPInterpreter : public InterpreterVirtual
+  {
+  public:
+    static Pointer New();
+    BBPInterpreter();
+    ~BBPInterpreter();
+
+    //Public methods
+
+    virtual void commandNew( const std::string& boxType, const std::string& boxName);
+
+    virtual void commandConnection (const std::string &boxfrom,
+                       const std::string &output,
+                       const std::string &boxto,
+                       const std::string &input);
+    virtual void commandSet(const std::string &box,const std::string &input,const std::string &value);
+
+
+    virtual void commandDefine(const std::string &name,const std::string &pack,const std::string &scriptfilename);
+    virtual void commandEndDefine();
+
+    virtual void commandExec(const std::string &word);
+
+    virtual void commandAuthor(const std::string &author);
+    virtual void commandCategory(const std::string &categorytype);
+    virtual void commandDescription(const std::string &description);
+
+    virtual void commandInput(const std::string &name,const std::string &box,const std::string &input,const std::string  &help);
+    virtual void commandOutput(const std::string &name,const std::string &box,const std::string &output,const std::string  &help);
+
+    std::string boxName;
+    std::set<std::string> dependencies;
+
+  private:
+
+    //Private Attributes
+
+    //Private Methods
+
+  protected:
+
+    //Protected Attributes
+
+    //Protected methods
+
+  };
+}
+// namespace bbtk
+#endif
+