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