]> Creatis software - bbtk.git/blob - kernel/appli/bbpConfigurator/bbpConfigurator.cpp
#3512 clean bbs2 python version
[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 << "bbpConfigurator 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   std::cout << "bbpConfigurator launched with bbs path: '" << path_bbs <<
67       "', package: '" << package_name <<
68       "', output path: '" << path_out << "'." << std::endl;
69
70   // Get bbs files in path_bbs
71   std::vector<bf::path> files = getFileList(path_bbs);
72   if(files.size() == 0)
73   {
74     std::cout << "bbpConfigurator: No files to check in bbs path. "
75         "An empty bbp will be created for the package '" << package_name << "'." << std::endl;
76
77     // Write results to bbp file
78     #ifdef WIN32
79       std::string fname = path_out + "\\" + package_name + ".bbp";
80     #else
81       std::string fname = path_out + "/" + package_name + ".bbp";
82     #endif
83
84       std::ofstream out(fname.c_str());
85       out << "#-----------------------------------------" << std::endl;
86       out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
87       out << "# Automatically generated by bbpConfigurator" << std::endl;
88       out << "#-----------------------------------------" << std::endl;
89       out << "load "<< package_name << std::endl;
90       out << "#-----------------------------------------" << std::endl;
91       out << "package "<< package_name << std::endl;
92       out << "#-----------------------------------------" << std::endl;
93       out << "endpackage" << std::endl;
94       out << "#-- EOF ----------------------------------" << std::endl;
95
96       out.close();
97
98
99     return 0;
100   }
101
102
103   // Order files by dependencies
104   //  Get DependenciesVector and Box Names
105   DependenciesVector deps;
106   BoxesVector boxs;
107
108
109   for (int i = 0; i < (int)files.size(); ++i) 
110   {
111     bbtk::BBPInterpreter::Pointer I = bbtk::BBPInterpreter::New();
112     I->InterpretFile(files[i].string());
113
114
115     boxs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
116
117 // EED 2016/02/19
118 //    deps.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies );
119  //-->  Cleanning string package:boxname -> boxname
120     std::set<std::string> tmpDependencies1=  ((bbtk::BBPInterpreter*)(I.get()))->dependencies  ;
121     std::set<std::string> tmpDependencies2;
122     std::set<std::string>::const_iterator sit(tmpDependencies1.begin()), send(tmpDependencies1.end()); 
123         int pos;
124         std::string tmpStr;
125 //    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
126     for(;sit!=send;++sit)
127     { 
128                 pos=(*sit).find(":");   
129                 if (pos== std::string::npos ) 
130                 { 
131                         tmpDependencies2.insert( *sit );
132 //                      std::cout << *sit << ' ';
133                 } else {
134                         tmpStr=(*sit).substr(pos+1);
135                         tmpDependencies2.insert( tmpStr );
136 //                      std::cout << tmpStr << ' ';
137                 } // if
138
139     } // for
140 //    std::cout << std::endl;
141     deps.push_back( tmpDependencies2 );
142  //<--
143
144
145
146 //    //print box name and dependencies  OLD VERSION
147 //    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
148 //   for(
149 //      Dependencies::iterator it = ((bbtk::BBPInterpreter*)(I.get()))->dependencies.begin();
150 //      it != ((bbtk::BBPInterpreter*)(I.get()))->dependencies.end();
151 //      it++) {
152 //      std::cout << *it << ", ";
153 //    }
154 //    std::cout << std::endl;
155
156   } // for i
157
158   // Only keep dependencies from package
159   Dependencies boxNamesSet(boxs.begin(), boxs.end());
160
161 //std::cout << "after: " << std::endl;
162   for (DependenciesVector::iterator it = deps.begin(); it != deps.end(); it++) 
163   {
164     BoxesVector tmp;
165     std::set_intersection(it->begin(), it->end(), boxNamesSet.begin(), boxNamesSet.end(),std::back_inserter(tmp));
166     Dependencies tmp1(tmp.begin(),tmp.end());
167     it->swap( tmp1 );
168 //    //print clean dependencies
169 //    for( Dependencies::iterator it1 = it->begin();  it1 != it->end(); it1++) 
170 //    {
171 //      std::cout << *it1 << ", ";
172 //    }
173 //    std::cout << std::endl;
174
175   }
176
177   // Create dependencies graph
178   std::vector<std::vector<int> > g(boxs.size(), std::vector<int>());
179   std::map<std::string, int> idxs;
180
181
182   for (int i = 0; i < (int)boxs.size(); ++i)
183   {
184     idxs[boxs[i]] = i;
185   }
186
187   int boxit = 0;
188   for (DependenciesVector::iterator dit = deps.begin(); dit != deps.end(); dit++, boxit++)
189   {
190     for (Dependencies::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
191     {
192       g[boxit].push_back(idxs[*ddit]);
193     }
194   }
195
196   // Check there are no cycles in graph
197   if(isCycle(g))
198   {
199     std::cout << "bbpConfigurator: There are dependency cycles, please check your scripts in '" <<
200         path_bbs << "'. No bbp file created." << std::endl;
201     return 2;
202   }
203   else
204   {
205     std::cout << "bbpConfigurator: No cycles detected in dependency graph." << std::endl;
206     std::vector<int> priorities(boxs.size(), -1);
207     setPriorities(g, priorities);
208 //    for (int i = 0; i < (int)priorities.size(); i++)
209 //    {
210 //      std::cout << priorities[i] << " ";
211 //    }
212 //    std::cout << std::endl;
213
214     // Write results to bbp file
215   #ifdef WIN32
216     std::string fname = path_out + "\\" + package_name + ".bbp";
217   #else
218     std::string fname = path_out + "/" + package_name + ".bbp";
219   #endif
220
221     std::ofstream out(fname.c_str());
222     out << "#-----------------------------------------" << std::endl;
223     out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
224     out << "# Automatically generated by bbpConfigurator" << std::endl;
225     out << "#-----------------------------------------" << std::endl;
226     out << "load "<< package_name << std::endl;
227     out << "#-----------------------------------------" << std::endl;
228     out << "package "<< package_name << std::endl;
229     out << "#-----------------------------------------" << std::endl;
230
231     //each bbs file ordered.
232     //include [package_name]/boxes/[file_bbs]
233     //#-----------------------------------------
234
235   //  for (int i = 0; i < (int)files.size(); ++i) {
236   //    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
237   //    out << "#-----------------------------------------" << std::endl;
238   //  }
239
240     // find max priority level
241     int mx_priority = 0;
242     for (int i = 0; i < (int)priorities.size(); i++)
243     {
244       mx_priority = std::max(mx_priority, priorities[i]);
245     }
246
247     // for each priority level print scripts in that level.
248     for (int i = 0; i <= mx_priority; i++)
249     {
250       for (int j = 0; j < (int)priorities.size(); j++)
251       {
252         if(priorities[j] == i)
253         {
254 //EED 2017-03-28
255 #if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
256           out << "include " << package_name << "/boxes/" << files[j].filename() << std::endl;
257 #else
258           out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
259 #endif
260
261           out << "#-----------------------------------------" << std::endl;
262         }
263       }
264     }
265     out << "endpackage" << std::endl;
266     out << "#-- EOF ----------------------------------" << std::endl;
267   
268     out.close();
269
270     std::cout << "bbpConfigurator: bbp file created at '" << fname << "'." << std::endl;
271   }
272   return 0;
273 }
274 //==========================================================================
275
276 // extract of the tarjan's algorithm for strongly connected components
277 bool isCycle(const Graph& g)
278 {
279   for (int it = 0; it < (int)g.size(); ++it) {
280     std::vector<bool> visited (g.size(), false);
281     if (checkCycle(g, it, visited))
282     {
283       //std::cout << "At " << it << std::endl;
284       return true;
285     }
286   }
287   return false;
288 }
289
290 //==========================================================================
291
292 // dfs search to check cycles.
293 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v)
294 {
295
296   v[i] = true;
297   for(int dit = 0; dit < (int)g[i].size(); dit++)
298   {
299     int d = g[i][dit];
300     if(d < 0 || d >= (int)g.size() || v[d])
301     {
302       //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
303       return true;
304     }
305     if(checkCycle(g,d,v))
306       return true;
307   }
308   v[i] = false;
309   return false;
310 }
311
312 //==========================================================================
313
314 // 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.
315 void setPriorities(const Graph& g, std::vector<int>& p)
316 {
317   for(int i = 0; i < (int)g.size(); i++)
318   {
319     if(p[i] == -1)
320       setPriority(g, i, p);
321   }
322 }
323
324 //==========================================================================
325
326 // dfs search to find dependencies
327 void setPriority(const Graph& g, const int i, std::vector<int>& p)
328 {
329   int pi = -1;
330   for(int j = 0; j < (int)g[i].size(); j++)
331   {
332     setPriority(g, g[i][j], p);
333     pi = std::max(pi, p[g[i][j]]);
334   }
335   p[i]=pi+1;
336 }
337
338 //==========================================================================
339
340 std::vector<bf::path> getFileList(const std::string& path)
341 {
342   std::vector<bf::path> files;
343
344   bf::path pth(path.c_str());
345   if(bf::exists(pth) && bf::is_directory(pth))
346   {
347     bf::directory_iterator end_itr;
348     bf::directory_iterator itr(pth);
349     for(itr; itr != end_itr; ++itr)
350     {
351       if(!is_directory(itr->status()))
352       {
353 //EED 2017-03-28
354 #if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
355         std::string nm(itr->path().filename());
356 #else
357         std::string nm(itr->path().filename().string());
358 #endif
359         if(nm.substr(nm.size()-4) == ".bbs")
360         {
361           //std::cout << itr->path().filename().string() << std::endl;
362           files.push_back(itr->path());
363         }
364       }
365     }
366   }
367   else
368   {
369     std::cout<< "bbpConfigurator: The path to the bbs's doesn't exist or is not a folder. ('" << path << "')" << std::endl;
370     return files;
371   }
372
373   // Order files by name
374   for (int i = 0; i < (int)files.size()-1; ++i) {
375     for (int j = i+1; j < (int)files.size(); ++j) {
376
377 //EED 2017-03-28
378 #if BOOST_MAJOR_VERSION <= 1 && BOOST_MINOR_VERSION <=41 
379       if(files[j].filename() < files[i].filename())
380 #else
381       if(files[j].filename().string() < files[i].filename().string())
382 #endif
383
384       {
385         bf::path tmp = files[i];
386         files[i] = files[j];
387         files[j] = tmp;
388       }
389     }
390   }
391
392   return files;
393 }