From 0b545a71f0da57d48b476a16da61ce3607c4c4fc Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Wed, 19 Jun 2013 17:08:36 +0200 Subject: [PATCH] Feature #2042 bbpConfigurator 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. --- .../appli/bbpConfigurator/bbpConfigurator.cpp | 220 +++++++++++++++--- kernel/src/bbtkBBPInterpreter.cxx | 158 +++++++++++++ kernel/src/bbtkBBPInterpreter.h | 100 ++++++++ 3 files changed, 452 insertions(+), 26 deletions(-) create mode 100644 kernel/src/bbtkBBPInterpreter.cxx create mode 100644 kernel/src/bbtkBBPInterpreter.h diff --git a/kernel/appli/bbpConfigurator/bbpConfigurator.cpp b/kernel/appli/bbpConfigurator/bbpConfigurator.cpp index 7a1df79..50c4163 100644 --- a/kernel/appli/bbpConfigurator/bbpConfigurator.cpp +++ b/kernel/appli/bbpConfigurator/bbpConfigurator.cpp @@ -28,16 +28,30 @@ #include #include #include +#include +#include +#include #include "boost/filesystem.hpp" //#include "boost/filesystem/operations.hpp" //#include "boost/filesystem/path.hpp" +#include "bbtkBBPInterpreter.h" namespace bf = boost::filesystem; +typedef std::vector > Graph; -//using namespace bbtk; +typedef std::set Dependency; +typedef std::vector Dependencies; +typedef std::vector Boxes; + +bool isCycle(const Graph& g); +bool checkCycle(const Graph& g, const int& i, std::vector& v); + +void setPriorities(const Graph& g, std::vector& p); +void setPriority(const Graph& g, const int i, std::vector& p); int main(int argc, char **argv) { + // Check arguments if (argc != 4) { std::cout << "usage : bbConfigurator " << 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 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 > g(bs.size(), std::vector()); + std::map 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 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 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& 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& 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& 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 index 0000000..a9f246c --- /dev/null +++ b/kernel/src/bbtkBBPInterpreter.cxx @@ -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 index 0000000..3e98a96 --- /dev/null +++ b/kernel/src/bbtkBBPInterpreter.h @@ -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 +#include + + +//#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 dependencies; + + private: + + //Private Attributes + + //Private Methods + + protected: + + //Protected Attributes + + //Protected methods + + }; +} +// namespace bbtk +#endif + -- 2.45.1