/* # --------------------------------------------------------------------- # # 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 #include #include #include #include #include #include #include "boost/filesystem.hpp" #include "bbtkBBPInterpreter.h" namespace bf = boost::filesystem; typedef std::vector > Graph; typedef std::set Dependencies; typedef std::vector DependenciesVector; typedef std::vector BoxesVector; std::vector getFileList(const std::string& path); 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; return 1; } std::string path_bbs(argv[1]); std::string package_name(argv[2]); std::string path_out(argv[3]); // Get bbs files in path_bbs std::vector files = getFileList(path_bbs); if(files.size() == 0) { std::cout << "No files to check." << 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 ); deps.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies ); //print box name and dependencies // 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; } // 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 > g(boxs.size(), std::vector()); std::map 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 << "there are dependency cycles, please check your scripts." << std::endl; return 2; } else { std::cout << "no cycles, we keep going." << std::endl; std::vector 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) { 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; } //========================================================================== // dfs search to check cycles. 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.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& 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& 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 getFileList(const std::string& path) { std::vector files; bf::path pth(path.c_str()); if(bf::exists(pth) && bf::is_directory(pth)) { bf::directory_iterator end_itr; for(bf::directory_iterator itr(pth); itr != end_itr; ++itr) { if(!is_directory(itr->status())) { std::string nm(itr->path().filename().string()); if(nm.substr(nm.size()-4) == ".bbs") { //std::cout << itr->path().filename().string() << std::endl; files.push_back(itr->path()); } } } } else { std::cout<< "the path to the bbs's should be a folder and not a file."; 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) { if(files[j].filename().string() < files[i].filename().string()) { bf::path tmp = files[i]; files[i] = files[j]; files[j] = tmp; } } } return files; }