]> Creatis software - bbtk.git/blob - kernel/appli/bbpConfigurator/bbpConfigurator.cpp
Feature #2042 bbpConfigurator
[bbtk.git] / kernel / appli / bbpConfigurator / bbpConfigurator.cpp
1 /*
2  # ---------------------------------------------------------------------
3  #
4  # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
5  #                        pour la SantÈ)
6  # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
7  # Previous Authors : Laurent Guigues, Jean-Pierre Roux
8  # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
9  #
10  #  This software is governed by the CeCILL-B license under French law and
11  #  abiding by the rules of distribution of free software. You can  use,
12  #  modify and/ or redistribute the software under the terms of the CeCILL-B
13  #  license as circulated by CEA, CNRS and INRIA at the following URL
14  #  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
15  #  or in the file LICENSE.txt.
16  #
17  #  As a counterpart to the access to the source code and  rights to copy,
18  #  modify and redistribute granted by the license, users are provided only
19  #  with a limited warranty  and the software's author,  the holder of the
20  #  economic rights,  and the successive licensors  have only  limited
21  #  liability.
22  #
23  #  The fact that you are presently reading this means that you have had
24  #  knowledge of the CeCILL-B license and that you accept its terms.
25  # ------------------------------------------------------------------------ */
26
27 #include <cstdlib>
28 #include <fstream>
29 #include <iostream>
30 #include <vector>
31 #include <set>
32 #include <map>
33 #include <algorithm>
34 #include "boost/filesystem.hpp"
35 #include "bbtkBBPInterpreter.h"
36
37 namespace bf = boost::filesystem;
38
39 typedef std::vector<std::vector<int> > Graph;
40
41 typedef std::set<std::string> Dependencies;
42 typedef std::vector<Dependencies> DependenciesVector;
43 typedef std::vector<std::string> BoxesVector;
44
45 std::vector<bf::path> getFileList(const std::string& path);
46
47 bool isCycle(const Graph& g);
48 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v);
49
50 void setPriorities(const Graph& g, std::vector<int>& p);
51 void setPriority(const Graph& g, const int i, std::vector<int>& p);
52
53 int main(int argc, char **argv)
54 {
55   // Check arguments
56   if (argc != 4)
57   {
58     std::cout << "usage : bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
59     return 1;
60   }
61
62   std::string path_bbs(argv[1]);
63   std::string package_name(argv[2]);
64   std::string path_out(argv[3]);
65   
66   // Get bbs files in path_bbs
67   std::vector<bf::path> files = getFileList(path_bbs);
68   if(files.size() == 0)
69   {
70     std::cout << "No files to check." << std::endl;
71
72     // Write results to bbp file
73     #ifdef WIN32
74       std::string fname = path_out + "\\" + package_name + ".bbp";
75     #else
76       std::string fname = path_out + "/" + package_name + ".bbp";
77     #endif
78
79       std::ofstream out(fname.c_str());
80       out << "#-----------------------------------------" << std::endl;
81       out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
82       out << "# Automatically generated by bbpConfigurator" << std::endl;
83       out << "#-----------------------------------------" << std::endl;
84       out << "load "<< package_name << std::endl;
85       out << "#-----------------------------------------" << std::endl;
86       out << "package "<< package_name << std::endl;
87       out << "#-----------------------------------------" << std::endl;
88       out << "endpackage" << std::endl;
89       out << "#-- EOF ----------------------------------" << std::endl;
90
91       out.close();
92
93
94     return 0;
95   }
96
97
98   // Order files by dependencies
99   //  Get DependenciesVector and Box Names
100   DependenciesVector deps;
101   BoxesVector boxs;
102
103
104   for (int i = 0; i < (int)files.size(); ++i) {
105     bbtk::BBPInterpreter::Pointer I = bbtk::BBPInterpreter::New();
106     I->InterpretFile(files[i].string());
107     boxs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
108     deps.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies );
109
110     //print box name and dependencies
111 //    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
112 //    for(
113 //      Dependencies::iterator it = ((bbtk::BBPInterpreter*)(I.get()))->dependencies.begin();
114 //      it != ((bbtk::BBPInterpreter*)(I.get()))->dependencies.end();
115 //      it++) {
116 //      std::cout << *it << ", ";
117 //    }
118 //    std::cout << std::endl;
119
120   }
121
122   // Only keep dependencies from package
123   Dependencies boxNamesSet(boxs.begin(), boxs.end());
124
125   //std::cout << "after: " << std::endl;
126   for (DependenciesVector::iterator it = deps.begin(); it != deps.end(); it++) {
127     BoxesVector tmp;
128     std::set_intersection(it->begin(), it->end(), boxNamesSet.begin(), boxNamesSet.end(),std::back_inserter(tmp));
129     Dependencies tmp1(tmp.begin(),tmp.end());
130     it->swap( tmp1 );
131     //print clean dependencies
132 //    for(
133 //      Dependencies::iterator it1 = it->begin();
134 //      it1 != it->end();
135 //      it1++) {
136 //      std::cout << *it1 << ", ";
137 //    }
138 //    std::cout << std::endl;
139
140   }
141
142   // Create dependencies graph
143   std::vector<std::vector<int> > g(boxs.size(), std::vector<int>());
144   std::map<std::string, int> idxs;
145
146
147   for (int i = 0; i < (int)boxs.size(); ++i)
148   {
149     idxs[boxs[i]] = i;
150   }
151
152   int boxit = 0;
153   for (DependenciesVector::iterator dit = deps.begin(); dit != deps.end(); dit++, boxit++)
154   {
155     for (Dependencies::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
156     {
157       g[boxit].push_back(idxs[*ddit]);
158     }
159   }
160
161   // Check there are no cycles in graph
162   if(isCycle(g))
163   {
164     std::cout << "there are dependency cycles, please check your scripts." << std::endl;
165     return 2;
166   }
167   else
168   {
169     std::cout << "no cycles, we keep going." << std::endl;
170     std::vector<int> priorities(boxs.size(), -1);
171     setPriorities(g, priorities);
172 //    for (int i = 0; i < (int)priorities.size(); i++)
173 //    {
174 //      std::cout << priorities[i] << " ";
175 //    }
176 //    std::cout << std::endl;
177
178     // Write results to bbp file
179   #ifdef WIN32
180     std::string fname = path_out + "\\" + package_name + ".bbp";
181   #else
182     std::string fname = path_out + "/" + package_name + ".bbp";
183   #endif
184
185     std::ofstream out(fname.c_str());
186     out << "#-----------------------------------------" << std::endl;
187     out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
188     out << "# Automatically generated by bbpConfigurator" << std::endl;
189     out << "#-----------------------------------------" << std::endl;
190     out << "load "<< package_name << std::endl;
191     out << "#-----------------------------------------" << std::endl;
192     out << "package "<< package_name << std::endl;
193     out << "#-----------------------------------------" << std::endl;
194
195     //each bbs file ordered.
196     //include [package_name]/boxes/[file_bbs]
197     //#-----------------------------------------
198
199   //  for (int i = 0; i < (int)files.size(); ++i) {
200   //    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
201   //    out << "#-----------------------------------------" << std::endl;
202   //  }
203
204     // find max priority level
205     int mx_priority = 0;
206     for (int i = 0; i < (int)priorities.size(); i++)
207       mx_priority = std::max(mx_priority, priorities[i]);
208
209     // for each priority level print scripts in that level.
210     for (int i = 0; i <= mx_priority; i++)
211     {
212       for (int j = 0; j < (int)priorities.size(); j++)
213       {
214         if(priorities[j] == i)
215         {
216           out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
217           out << "#-----------------------------------------" << std::endl;
218         }
219       }
220     }
221     out << "endpackage" << std::endl;
222     out << "#-- EOF ----------------------------------" << std::endl;
223   
224     out.close();
225   }
226   return 0;
227 }
228 //==========================================================================
229
230 // extract of the tarjan's algorithm for strongly connected components
231 bool isCycle(const Graph& g)
232 {
233   for (int it = 0; it < (int)g.size(); ++it) {
234     std::vector<bool> visited (g.size(), false);
235     if (checkCycle(g, it, visited))
236     {
237       //std::cout << "At " << it << std::endl;
238       return true;
239     }
240   }
241   return false;
242 }
243
244 //==========================================================================
245
246 // dfs search to check cycles.
247 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v)
248 {
249
250   v[i] = true;
251   for(int dit = 0; dit < (int)g[i].size(); dit++)
252   {
253     int d = g[i][dit];
254     if(d < 0 || d >= (int)g.size() || v[d])
255     {
256       //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
257       return true;
258     }
259     if(checkCycle(g,d,v))
260       return true;
261   }
262   v[i] = false;
263   return false;
264 }
265
266 //==========================================================================
267
268 // 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.
269 void setPriorities(const Graph& g, std::vector<int>& p)
270 {
271   for(int i = 0; i < (int)g.size(); i++)
272   {
273     if(p[i] == -1)
274       setPriority(g, i, p);
275   }
276 }
277
278 //==========================================================================
279
280 // dfs search to find dependencies
281 void setPriority(const Graph& g, const int i, std::vector<int>& p)
282 {
283   int pi = -1;
284   for(int j = 0; j < (int)g[i].size(); j++)
285   {
286     setPriority(g, g[i][j], p);
287     pi = std::max(pi, p[g[i][j]]);
288   }
289   p[i]=pi+1;
290 }
291
292 //==========================================================================
293
294 std::vector<bf::path> getFileList(const std::string& path)
295 {
296   std::vector<bf::path> files;
297
298   bf::path pth(path.c_str());
299   if(bf::exists(pth) && bf::is_directory(pth))
300   {
301     bf::directory_iterator end_itr;
302     for(bf::directory_iterator itr(pth); itr != end_itr; ++itr)
303     {
304       if(!is_directory(itr->status()))
305       {
306         std::string nm(itr->path().filename().string());
307         if(nm.substr(nm.size()-4) == ".bbs")
308         {
309           //std::cout << itr->path().filename().string() << std::endl;
310           files.push_back(itr->path());
311         }
312       }
313     }
314   }
315   else
316   {
317     std::cout<< "the path to the bbs's should be a folder and not a file.";
318     return files;
319   }
320
321   // Order files by name
322   for (int i = 0; i < (int)files.size()-1; ++i) {
323     for (int j = i+1; j < (int)files.size(); ++j) {
324       if(files[j].filename().string() < files[i].filename().string())
325       {
326         bf::path tmp = files[i];
327         files[i] = files[j];
328         files[j] = tmp;
329       }
330     }
331   }
332
333   return files;
334 }