]> 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 "boost/filesystem/operations.hpp"
36 //#include "boost/filesystem/path.hpp"
37 #include "bbtkBBPInterpreter.h"
38
39 namespace bf = boost::filesystem;
40 typedef std::vector<std::vector<int> > Graph;
41
42 typedef std::set<std::string> Dependency;
43 typedef std::vector<Dependency> Dependencies;
44 typedef std::vector<std::string> Boxes;
45
46 bool isCycle(const Graph& g);
47 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v);
48
49 void setPriorities(const Graph& g, std::vector<int>& p);
50 void setPriority(const Graph& g, const int i, std::vector<int>& p);
51
52 int main(int argc, char **argv)
53 {
54   // Check arguments
55   if (argc != 4)
56   {
57     std::cout << "usage : bbConfigurator <path_to_bbs> <package_name> <output_path>" << std::endl;
58     return 1;
59   }
60
61   std::string path_bbs(argv[1]);
62   std::string package_name(argv[2]);
63   std::string path_out(argv[3]);
64   
65   // Get bbs files in path_bbs
66   std::vector<bf::path> files;
67
68   bf::path pth(path_bbs.c_str());
69   if(bf::exists(pth) && bf::is_directory(pth))
70   {
71     bf::directory_iterator end_itr;
72     for(bf::directory_iterator itr(pth); itr != end_itr; ++itr)
73     {
74       if(!is_directory(itr->status()))
75       {
76         std::string nm(itr->path().filename().string());
77         if(nm.substr(nm.size()-4) == ".bbs")
78         {
79           //std::cout << itr->path().filename().string() << std::endl;
80           files.push_back(itr->path());
81         }
82       }
83     }
84   }
85   else
86   {
87     std::cout<< "the path to the bbs's should be a folder and not a file.";
88     return 1;
89   }
90
91   // Order files by name
92   for (int i = 0; i < (int)files.size()-1; ++i) {
93     for (int j = i+1; j < (int)files.size(); ++j) {
94       if(files[j].filename().string() < files[i].filename().string())
95       {
96         bf::path tmp = files[i];
97         files[i] = files[j];
98         files[j] = tmp;
99       }
100     }
101   }
102
103   // Order files by dependencies
104   //  Get Dependencies and Box Names
105   Dependencies ds;
106   Boxes bs;
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     bs.push_back( ((bbtk::BBPInterpreter*)(I.get()))->boxName );
113     ds.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       dep::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   // Only keep dependencies from package
127   Dependency boxesNamesSet(bs.begin(), bs.end());
128
129   //std::cout << "after: " << std::endl;
130   for (Dependencies::iterator it = ds.begin(); it != ds.end(); it++) {
131     Boxes tmp;
132     std::set_intersection(it->begin(), it->end(), boxesNamesSet.begin(), boxesNamesSet.end(),std::back_inserter(tmp));
133     Dependency tmp1(tmp.begin(),tmp.end());
134     it->swap( tmp1 );
135     //print clean dependencies
136 /*    for(
137       dep::iterator it1 = it->begin();
138       it1 != it->end();
139       it1++) {
140       std::cout << *it1 << ", ";
141     }
142     std::cout << std::endl;
143 */
144   }
145
146   // Check there are no cycles in graph
147   std::vector<std::vector<int> > g(bs.size(), std::vector<int>());
148   std::map<std::string, int> idxs;
149
150
151   for (int i = 0; i < (int)bs.size(); ++i)
152   {
153     idxs[bs[i]] = i;
154   }
155
156   int boxit = 0;
157   for (Dependencies::iterator dit = ds.begin(); dit != ds.end(); dit++, boxit++)
158   {
159     for (Dependency::iterator ddit = dit->begin(); ddit != dit->end(); ddit++)
160     {
161       g[boxit].push_back(idxs[*ddit]);
162     }
163   }
164
165   if(isCycle(g))
166   {
167     std::cout << "there are dependency cycles, please check your scripts." << std::endl;
168     return 2;
169   }
170   else
171   {
172     std::cout << "no cycles, we keep going." << std::endl;
173     std::vector<int> dep_priority(bs.size(), -1);
174     setPriorities(g, dep_priority);
175 //    for (int i = 0; i < (int)dep_priority.size(); i++)
176 //    {
177 //      std::cout << dep_priority[i] << " ";
178 //    }
179 //    std::cout << std::endl;
180
181     // Write results to bbp file
182   #ifdef WIN32
183     std::string fname = path_out + "\\" + package_name + ".bbp";
184   #else
185     std::string fname = path_out + "/" + package_name + ".bbp";
186   #endif
187
188     std::ofstream out(fname.c_str());
189     out << "#-----------------------------------------" << std::endl;
190     out << "# Include script for bbtk package '" << package_name << "'" << std::endl;
191     out << "# Automatically generated by bbpConfigurator" << std::endl;
192     out << "#-----------------------------------------" << std::endl;
193     out << "load "<< package_name << std::endl;
194     out << "#-----------------------------------------" << std::endl;
195     out << "package "<< package_name << std::endl;
196     out << "#-----------------------------------------" << std::endl;
197
198     //each bbs file ordered.
199     //include [package_name]/boxes/[file_bbs]
200     //#-----------------------------------------
201
202   //  for (int i = 0; i < (int)files.size(); ++i) {
203   //    out << "include " << package_name << "/boxes/" << files[i].filename().string() << std::endl;
204   //    out << "#-----------------------------------------" << std::endl;
205   //  }
206
207     // for each priority level print scripts in that level.
208     int m_priority = 0;
209     for (int i = 0; i < (int)dep_priority.size(); i++)
210       m_priority = std::max(m_priority, dep_priority[i]);
211
212     for (int i = 0; i <= m_priority; i++)
213     {
214       for (int j = 0; j < (int)dep_priority.size(); j++)
215       {
216         if(dep_priority[j] == i)
217         {
218           out << "include " << package_name << "/boxes/" << files[j].filename().string() << std::endl;
219           out << "#-----------------------------------------" << std::endl;
220         }
221       }
222     }
223     out << "endpackage" << std::endl;
224     out << "#-- EOF ----------------------------------" << std::endl;
225   
226     out.close();
227   }
228   return 0;
229 }
230 //==========================================================================
231
232 // extract of the tarjan's algorithm for strongly connected components
233 bool isCycle(const Graph& g)
234 {
235   for (int it = 0; it < (int)g.size(); ++it) {
236     std::vector<bool> visited (g.size(), false);
237     if (checkCycle(g, it, visited))
238     {
239       //std::cout << "At " << it << std::endl;
240       return true;
241     }
242   }
243   return false;
244 }
245
246 //==========================================================================
247
248 bool checkCycle(const Graph& g, const int& i, std::vector<bool>& v)
249 {
250
251   v[i] = true;
252   for(int dit = 0; dit < (int)g[i].size(); dit++)
253   {
254     int d = g[i][dit];
255     if(d < 0 || d >= (int)g[i].size() || v[d])
256     {
257       //std::cout << "Checking " << i << " dependency " << dit << "=" << d << std::endl;
258       return true;
259     }
260     if(checkCycle(g,d,v))
261       return true;
262   }
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 void setPriority(const Graph& g, const int i, std::vector<int>& p)
280 {
281   int pi = -1;
282   for(int j = 0; j < (int)g[i].size(); j++)
283   {
284     setPriority(g, g[i][j], p);
285     pi = std::max(pi, p[g[i][j]]);
286   }
287   p[i]=pi+1;
288 }