]> Creatis software - bbtk.git/blobdiff - kernel/appli/bbpConfigurator/bbpConfigurator.cpp
#3120 BBTK Bug New Normal - merge branch changestoITK3and4 FROM master
[bbtk.git] / kernel / appli / bbpConfigurator / bbpConfigurator.cpp
diff --git a/kernel/appli/bbpConfigurator/bbpConfigurator.cpp b/kernel/appli/bbpConfigurator/bbpConfigurator.cpp
new file mode 100644 (file)
index 0000000..a4fa7ac
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ # ---------------------------------------------------------------------
+ #
+ # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
+ #                        pour la SantÈ)
+ # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
+ # Previous Authors : Laurent Guigues, Jean-Pierre Roux
+ # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
+ #
+ #  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.
+ # ------------------------------------------------------------------------ */
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
+#include "boost/filesystem.hpp"
+#include "bbtkBBPInterpreter.h"
+
+namespace bf = boost::filesystem;
+
+typedef std::vector<std::vector<int> > Graph;
+
+typedef std::set<std::string> Dependencies;
+typedef std::vector<Dependencies> DependenciesVector;
+typedef std::vector<std::string> BoxesVector;
+
+std::vector<bf::path> getFileList(const std::string& path);
+
+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 << "bbpConfigurator usage: bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
+    return 1;
+  }
+
+  std::string path_bbs(argv[1]);
+  std::string package_name(argv[2]);
+  std::string path_out(argv[3]);
+  
+  std::cout << "bbpConfigurator launched with bbs path: '" << path_bbs <<
+      "', package: '" << package_name <<
+      "', output path: '" << path_out << "'." << std::endl;
+
+  // Get bbs files in path_bbs
+  std::vector<bf::path> files = getFileList(path_bbs);
+  if(files.size() == 0)
+  {
+    std::cout << "bbpConfigurator: No files to check in bbs path. "
+        "An empty bbp will be created for the package '" << package_name << "'." << std::endl;
+
+    // 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;
+      out << "endpackage" << std::endl;
+      out << "#-- EOF ----------------------------------" << std::endl;
+
+      out.close();
+
+
+    return 0;
+  }
+
+
+  // Order files by dependencies
+  //  Get DependenciesVector and Box Names
+  DependenciesVector deps;
+  BoxesVector boxs;
+
+
+  for (int i = 0; i < (int)files.size(); ++i) 
+  {
+    bbtk::BBPInterpreter::Pointer I = bbtk::BBPInterpreter::New();
+    I->InterpretFile(files[i].string());
+
+
+    boxs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
+
+// EED 2016/02/19
+//    deps.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies );
+ //-->  Cleanning string package:boxname -> boxname
+    std::set<std::string> tmpDependencies1=  ((bbtk::BBPInterpreter*)(I.get()))->dependencies  ;
+    std::set<std::string> tmpDependencies2;
+    std::set<std::string>::const_iterator sit(tmpDependencies1.begin()), send(tmpDependencies1.end()); 
+       int pos;
+       std::string tmpStr;
+//    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
+    for(;sit!=send;++sit)
+    { 
+               pos=(*sit).find(":");   
+               if (pos== std::string::npos ) 
+               { 
+                       tmpDependencies2.insert( *sit );
+//                     std::cout << *sit << ' ';
+               } else {
+                       tmpStr=(*sit).substr(pos+1);
+                       tmpDependencies2.insert( tmpStr );
+//                     std::cout << tmpStr << ' ';
+               } // if
+
+    } // for
+//    std::cout << std::endl;
+    deps.push_back( tmpDependencies2 );
+ //<--
+
+
+
+//    //print box name and dependencies  OLD VERSION
+//    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
+//   for(
+//      Dependencies::iterator it = ((bbtk::BBPInterpreter*)(I.get()))->dependencies.begin();
+//      it != ((bbtk::BBPInterpreter*)(I.get()))->dependencies.end();
+//      it++) {
+//      std::cout << *it << ", ";
+//    }
+//    std::cout << std::endl;
+
+  } // for i
+
+  // Only keep dependencies from package
+  Dependencies boxNamesSet(boxs.begin(), boxs.end());
+
+//std::cout << "after: " << std::endl;
+  for (DependenciesVector::iterator it = deps.begin(); it != deps.end(); it++) 
+  {
+    BoxesVector tmp;
+    std::set_intersection(it->begin(), it->end(), boxNamesSet.begin(), boxNamesSet.end(),std::back_inserter(tmp));
+    Dependencies tmp1(tmp.begin(),tmp.end());
+    it->swap( tmp1 );
+//    //print clean dependencies
+//    for( Dependencies::iterator it1 = it->begin();  it1 != it->end(); it1++) 
+//    {
+//      std::cout << *it1 << ", ";
+//    }
+//    std::cout << std::endl;
+
+  }
+
+  // Create dependencies graph
+  std::vector<std::vector<int> > g(boxs.size(), std::vector<int>());
+  std::map<std::string, int> idxs;
+
+
+  for (int i = 0; i < (int)boxs.size(); ++i)
+  {
+    idxs[boxs[i]] = i;
+  }
+
+  int boxit = 0;
+  for (DependenciesVector::iterator dit = deps.begin(); dit != deps.end(); dit++, boxit++)
+  {
+    for (Dependencies::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
+    {
+      g[boxit].push_back(idxs[*ddit]);
+    }
+  }
+
+  // Check there are no cycles in graph
+  if(isCycle(g))
+  {
+    std::cout << "bbpConfigurator: There are dependency cycles, please check your scripts in '" <<
+        path_bbs << "'. No bbp file created." << std::endl;
+    return 2;
+  }
+  else
+  {
+    std::cout << "bbpConfigurator: No cycles detected in dependency graph." << std::endl;
+    std::vector<int> priorities(boxs.size(), -1);
+    setPriorities(g, priorities);
+//    for (int i = 0; i < (int)priorities.size(); i++)
+//    {
+//      std::cout << priorities[i] << " ";
+//    }
+//    std::cout << std::endl;
+
+    // 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;
+  //  }
+
+    // find max priority level
+    int mx_priority = 0;
+    for (int i = 0; i < (int)priorities.size(); i++)
+    {
+      mx_priority = std::max(mx_priority, priorities[i]);
+    }
+
+    // for each priority level print scripts in that level.
+    for (int i = 0; i <= mx_priority; i++)
+    {
+      for (int j = 0; j < (int)priorities.size(); j++)
+      {
+        if(priorities[j] == i)
+        {
+//EED 2017-03-28
+#if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
+          out << "include " << package_name << "/boxes/" << files[j].filename() << std::endl;
+#else
+          out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
+#endif
+
+          out << "#-----------------------------------------" << std::endl;
+        }
+      }
+    }
+    out << "endpackage" << std::endl;
+    out << "#-- EOF ----------------------------------" << std::endl;
+  
+    out.close();
+
+    std::cout << "bbpConfigurator: bbp file created at '" << fname << "'." << std::endl;
+  }
+  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;
+}
+
+//==========================================================================
+
+// dfs search to check cycles.
+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.size() || v[d])
+    {
+      //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
+      return true;
+    }
+    if(checkCycle(g,d,v))
+      return true;
+  }
+  v[i] = false;
+  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);
+  }
+}
+
+//==========================================================================
+
+// dfs search to find dependencies
+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;
+}
+
+//==========================================================================
+
+std::vector<bf::path> getFileList(const std::string& path)
+{
+  std::vector<bf::path> files;
+
+  bf::path pth(path.c_str());
+  if(bf::exists(pth) && bf::is_directory(pth))
+  {
+    bf::directory_iterator end_itr;
+    bf::directory_iterator itr(pth);
+    for(itr; itr != end_itr; ++itr)
+    {
+      if(!is_directory(itr->status()))
+      {
+//EED 2017-03-28
+#if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
+        std::string nm(itr->path().filename());
+#else
+        std::string nm(itr->path().filename().string());
+#endif
+        if(nm.substr(nm.size()-4) == ".bbs")
+        {
+          //std::cout << itr->path().filename().string() << std::endl;
+          files.push_back(itr->path());
+        }
+      }
+    }
+  }
+  else
+  {
+    std::cout<< "bbpConfigurator: The path to the bbs's doesn't exist or is not a folder. ('" << path << "')" << std::endl;
+    return files;
+  }
+
+  // Order files by name
+  for (int i = 0; i < (int)files.size()-1; ++i) {
+    for (int j = i+1; j < (int)files.size(); ++j) {
+
+//EED 2017-03-28
+#if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
+      if(files[j].filename() < files[i].filename())
+#else
+      if(files[j].filename().string() < files[i].filename().string())
+#endif
+
+      {
+        bf::path tmp = files[i];
+        files[i] = files[j];
+        files[j] = tmp;
+      }
+    }
+  }
+
+  return files;
+}