]> Creatis software - bbtk.git/blob - kernel/appli/bbpConfigurator/bbpConfigurator.cpp
fdabc26ed99cb56165e7c89f98c9e556baabac82
[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     bbtk::BBPInterpreter::Pointer I = bbtk::BBPInterpreter::New();
111     I->InterpretFile(files[i].string());
112     boxs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
113     deps.push_back( ((bbtk::BBPInterpreter*)(I.get()))->dependencies );
114
115     //print box name and dependencies
116 //    std::cout << ((bbtk::BBPInterpreter*)(I.get()))->boxName << ": ";
117 //    for(
118 //      Dependencies::iterator it = ((bbtk::BBPInterpreter*)(I.get()))->dependencies.begin();
119 //      it != ((bbtk::BBPInterpreter*)(I.get()))->dependencies.end();
120 //      it++) {
121 //      std::cout << *it << ", ";
122 //    }
123 //    std::cout << std::endl;
124
125   }
126
127   // Only keep dependencies from package
128   Dependencies boxNamesSet(boxs.begin(), boxs.end());
129
130   //std::cout << "after: " << std::endl;
131   for (DependenciesVector::iterator it = deps.begin(); it != deps.end(); it++) {
132     BoxesVector tmp;
133     std::set_intersection(it->begin(), it->end(), boxNamesSet.begin(), boxNamesSet.end(),std::back_inserter(tmp));
134     Dependencies tmp1(tmp.begin(),tmp.end());
135     it->swap( tmp1 );
136     //print clean dependencies
137 //    for(
138 //      Dependencies::iterator it1 = it->begin();
139 //      it1 != it->end();
140 //      it1++) {
141 //      std::cout << *it1 << ", ";
142 //    }
143 //    std::cout << std::endl;
144
145   }
146
147   // Create dependencies graph
148   std::vector<std::vector<int> > g(boxs.size(), std::vector<int>());
149   std::map<std::string, int> idxs;
150
151
152   for (int i = 0; i < (int)boxs.size(); ++i)
153   {
154     idxs[boxs[i]] = i;
155   }
156
157   int boxit = 0;
158   for (DependenciesVector::iterator dit = deps.begin(); dit != deps.end(); dit++, boxit++)
159   {
160     for (Dependencies::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
161     {
162       g[boxit].push_back(idxs[*ddit]);
163     }
164   }
165
166   // Check there are no cycles in graph
167   if(isCycle(g))
168   {
169     std::cout << "bbpConfigurator: There are dependency cycles, please check your scripts in '" <<
170         path_bbs << "'. No bbp file created." << std::endl;
171     return 2;
172   }
173   else
174   {
175     std::cout << "bbpConfigurator: No cycles detected in dependency graph." << std::endl;
176     std::vector<int> priorities(boxs.size(), -1);
177     setPriorities(g, priorities);
178 //    for (int i = 0; i < (int)priorities.size(); i++)
179 //    {
180 //      std::cout << priorities[i] << " ";
181 //    }
182 //    std::cout << std::endl;
183
184     // Write results to bbp file
185   #ifdef WIN32
186     std::string fname = path_out + "\\" + package_name + ".bbp";
187   #else
188     std::string fname = path_out + "/" + package_name + ".bbp";
189   #endif
190
191     std::ofstream out(fname.c_str());
192     out << "#-----------------------------------------" << std::endl;
193     out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
194     out << "# Automatically generated by bbpConfigurator" << std::endl;
195     out << "#-----------------------------------------" << std::endl;
196     out << "load "<< package_name << std::endl;
197     out << "#-----------------------------------------" << std::endl;
198     out << "package "<< package_name << std::endl;
199     out << "#-----------------------------------------" << std::endl;
200
201     //each bbs file ordered.
202     //include [package_name]/boxes/[file_bbs]
203     //#-----------------------------------------
204
205   //  for (int i = 0; i < (int)files.size(); ++i) {
206   //    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
207   //    out << "#-----------------------------------------" << std::endl;
208   //  }
209
210     // find max priority level
211     int mx_priority = 0;
212     for (int i = 0; i < (int)priorities.size(); i++)
213       mx_priority = std::max(mx_priority, priorities[i]);
214
215     // for each priority level print scripts in that level.
216     for (int i = 0; i <= mx_priority; i++)
217     {
218       for (int j = 0; j < (int)priorities.size(); j++)
219       {
220         if(priorities[j] == i)
221         {
222           out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
223           out << "#-----------------------------------------" << std::endl;
224         }
225       }
226     }
227     out << "endpackage" << std::endl;
228     out << "#-- EOF ----------------------------------" << std::endl;
229   
230     out.close();
231
232     std::cout << "bbpConfigurator: bbp file created at '" << fname << "'." << std::endl;
233   }
234   return 0;
235 }
236 //==========================================================================
237
238 // extract of the tarjan's algorithm for strongly connected components
239 bool isCycle(const Graph& g)
240 {
241   for (int it = 0; it < (int)g.size(); ++it) {
242     std::vector<bool> visited (g.size(), false);
243     if (checkCycle(g, it, visited))
244     {
245       //std::cout << "At " << it << std::endl;
246       return true;
247     }
248   }
249   return false;
250 }
251
252 //==========================================================================
253
254 // dfs search to check cycles.
255 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v)
256 {
257
258   v[i] = true;
259   for(int dit = 0; dit < (int)g[i].size(); dit++)
260   {
261     int d = g[i][dit];
262     if(d < 0 || d >= (int)g.size() || v[d])
263     {
264       //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
265       return true;
266     }
267     if(checkCycle(g,d,v))
268       return true;
269   }
270   v[i] = false;
271   return false;
272 }
273
274 //==========================================================================
275
276 // 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.
277 void setPriorities(const Graph& g, std::vector<int>& p)
278 {
279   for(int i = 0; i < (int)g.size(); i++)
280   {
281     if(p[i] == -1)
282       setPriority(g, i, p);
283   }
284 }
285
286 //==========================================================================
287
288 // dfs search to find dependencies
289 void setPriority(const Graph& g, const int i, std::vector<int>& p)
290 {
291   int pi = -1;
292   for(int j = 0; j < (int)g[i].size(); j++)
293   {
294     setPriority(g, g[i][j], p);
295     pi = std::max(pi, p[g[i][j]]);
296   }
297   p[i]=pi+1;
298 }
299
300 //==========================================================================
301
302 std::vector<bf::path> getFileList(const std::string& path)
303 {
304   std::vector<bf::path> files;
305
306   bf::path pth(path.c_str());
307   if(bf::exists(pth) && bf::is_directory(pth))
308   {
309     bf::directory_iterator end_itr;
310     for(bf::directory_iterator itr(pth); itr != end_itr; ++itr)
311     {
312       if(!is_directory(itr->status()))
313       {
314         std::string nm(itr->path().filename().string());
315         if(nm.substr(nm.size()-4) == ".bbs")
316         {
317           //std::cout << itr->path().filename().string() << std::endl;
318           files.push_back(itr->path());
319         }
320       }
321     }
322   }
323   else
324   {
325     std::cout<< "bbpConfigurator: The path to the bbs's doesn't exist or is not a folder. ('" << path << "')" << std::endl;
326     return files;
327   }
328
329   // Order files by name
330   for (int i = 0; i < (int)files.size()-1; ++i) {
331     for (int j = i+1; j < (int)files.size(); ++j) {
332       if(files[j].filename().string() < files[i].filename().string())
333       {
334         bf::path tmp = files[i];
335         files[i] = files[j];
336         files[j] = tmp;
337       }
338     }
339   }
340
341   return files;
342 }