#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;
-//using namespace bbtk;
+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 << "usage : bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
+ std::cout << "bbpConfigurator usage: bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
return 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)
+ {
+ out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
+ 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_bbs.c_str());
+ bf::path pth(path.c_str());
if(bf::exists(pth) && bf::is_directory(pth))
{
bf::directory_iterator end_itr;
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());
}
}
}
else
{
- std::cout<< "the path to the bbs's should be a folder and not a file.";
- return 1;
+ 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) {
if(files[j].filename().string() < files[i].filename().string())
}
}
-#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;
- }
-
- out << "endpackage" << std::endl;
- out << "#-- EOF ----------------------------------" << std::endl;
-
- out.close();
-
- return 0;
+ return files;
}
-//==========================================================================
-
-