inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_upgrader 00005 #define inlib_upgrader 00006 00007 #include "sys/dir" 00008 #include "sys/file" 00009 #include "smanip" 00010 #include "system" 00011 #include "file" 00012 00013 namespace inlib { 00014 00015 class upgrader { 00016 private: 00017 class upgrade_visitor : public virtual dir::visitor { 00018 public: 00019 virtual bool directory(const std::string& aString,bool& aProcess) { 00020 aProcess = true; 00021 std::string p,n,s; 00022 path_name_suffix(aString,p,n,s); 00023 if((n=="CVS")||(n==".svn")) aProcess = false; 00024 return true; 00025 } 00026 virtual bool file(const std::string& aString) { 00027 return m_upgrader.upgrade_file(aString); 00028 } 00029 public: 00030 upgrade_visitor(upgrader& a_upgrader):m_upgrader(a_upgrader){} 00031 virtual ~upgrade_visitor() {} 00032 public: 00033 upgrade_visitor(const upgrade_visitor& a_from) 00034 : dir::visitor(a_from) 00035 ,m_upgrader(a_from.m_upgrader) 00036 {} 00037 upgrade_visitor& operator=(const upgrade_visitor&){return *this;} 00038 private: 00039 upgrader& m_upgrader; 00040 }; 00041 00042 public: 00043 upgrader(std::ostream& a_out,bool a_verbose,const std::string& a_upfile,const std::string& aFilter) 00044 :m_out(a_out) 00045 ,m_verbose(a_verbose) 00046 ,m_filter(aFilter) 00047 { 00048 if(m_verbose) { 00049 m_out << "upgrader::upgrader :" 00050 << " upgrade file is " << inlib::sout(a_upfile) 00051 << std::endl; 00052 } 00053 std::string _a_upfile; 00054 file_name(a_upfile,_a_upfile); 00055 if(!inlib::file::read(_a_upfile,m_orders)) { 00056 m_out << "upgrader::upgrader :" 00057 << " can't read upgrade file." 00058 << std::endl; 00059 } 00060 00061 // include files : 00062 bool hasIncs = true; 00063 while(hasIncs) { 00064 hasIncs = false; 00065 std::vector<std::string> orders; 00066 unsigned int ordern = m_orders.size(); 00067 for(unsigned int index=0;index<ordern;index++) { 00068 std::vector<std::string> wrds = words(m_orders[index],"\\n"); 00069 if( (wrds.size()==2) && (wrds[0]=="include")) { 00070 const std::string& file = wrds[1]; 00071 if(m_verbose) { 00072 m_out << "upgrader::upgrade_file :" 00073 << " include " << inlib::sout(file) 00074 << std::endl; 00075 } 00076 std::vector<std::string> incs; 00077 std::string _file; 00078 file_name(file,_file); 00079 if(!inlib::file::read(_file,incs)) { 00080 m_out << "upgrader::upgrader :" 00081 << " can't read include upgrade file " 00082 << inlib::sout(file) << "." 00083 << std::endl; 00084 m_orders.clear(); 00085 return; 00086 } 00087 unsigned int incn = incs.size(); 00088 for(unsigned int inci=0;inci<incn;inci++) { 00089 hasIncs = true; 00090 orders.push_back(incs[inci]); 00091 } 00092 } else { 00093 orders.push_back(m_orders[index]); 00094 } 00095 } 00096 m_orders = orders; 00097 } 00098 } 00099 00100 virtual ~upgrader(){} 00101 00102 public: 00103 upgrader(const upgrader& a_from) 00104 :m_out(a_from.m_out) 00105 ,m_verbose(a_from.m_verbose) 00106 ,m_orders(a_from.m_orders) 00107 ,m_filter(a_from.m_filter) 00108 {} 00109 upgrader& operator=(const upgrader& a_from){ 00110 m_verbose = a_from.m_verbose; 00111 m_orders = a_from.m_orders; 00112 m_filter = a_from.m_filter; 00113 return *this; 00114 } 00115 public: 00116 bool verbose() const {return m_verbose;} 00117 00118 bool upgrade(const std::string& a_string) { 00119 if(!m_orders.size()) return true; //Nothing to do. 00120 bool value; 00121 if(!dir::is_a(a_string,value)) return false; 00122 if(value) return upgrade_dir(a_string); 00123 else return upgrade_file(a_string); 00124 } 00125 00126 bool upgrade_file(const std::string& a_file) { 00127 if(m_verbose) { 00128 m_out << "upgrader::upgrade_file :" 00129 << " upgrade file " << inlib::sout(a_file) << "..." 00130 << std::endl; 00131 } 00132 if(m_filter.size()) { 00133 if(!match(a_file,m_filter)) return true; 00134 } 00135 unsigned int ordern = m_orders.size(); 00136 for(unsigned int index=0;index<ordern;index++) { 00137 std::vector<std::string> wrds = 00138 words(m_orders[index],"\\n",true); //true = take empty. 00139 if(m_orders[index].size()<=0) { 00140 } else if( (m_orders[index].size()>=1) && (m_orders[index][0]=='#') ) { 00141 00142 } else if( (wrds.size()==3) && (wrds[0]=="replace")) { 00143 if(m_verbose) { 00144 m_out << "upgrader::upgrade_file :" 00145 << " replace " << inlib::sout(wrds[1]) 00146 << " by " << inlib::sout(wrds[2]) 00147 << std::endl; 00148 } 00149 std::vector<std::string> changes; 00150 if(!replace(a_file,wrds[1],wrds[2],changes)) { 00151 m_out << "upgrader::upgrade_file :" 00152 << " upgrade of file " << inlib::sout(a_file) << " fails." 00153 << std::endl; 00154 return false; 00155 } 00156 unsigned int changen = changes.size(); 00157 for(unsigned int count=0;count<changen;count+=2) { 00158 m_out << ">>>>>>>>>>>>> In file " << inlib::sout(a_file) 00159 << ", line changed : " << std::endl; 00160 m_out << changes[count] << std::endl; 00161 m_out << changes[count+1] << std::endl; 00162 } 00163 00164 } else if( (wrds.size()==4) && (wrds[0]=="replace_if")) { 00165 if(m_verbose) { 00166 m_out << "upgrader::upgrade_file :" 00167 << " if " << inlib::sout(wrds[1]) 00168 << " replace " << inlib::sout(wrds[2]) 00169 << " by " << inlib::sout(wrds[3]) 00170 << std::endl; 00171 } 00172 std::vector<std::string> changes; 00173 if(!replace_if(a_file,wrds[1],wrds[2],wrds[3],changes)) { 00174 m_out << "upgrader::upgrade_file :" 00175 << " upgrade of file " << inlib::sout(a_file) << " fails." 00176 << std::endl; 00177 return false; 00178 } 00179 unsigned int changen = changes.size(); 00180 for(unsigned int count=0;count<changen;count+=2) { 00181 m_out << ">>>>>>>>>>>>> In file " << inlib::sout(a_file) 00182 << ", line changed : " << std::endl; 00183 m_out << changes[count] << std::endl; 00184 m_out << changes[count+1] << std::endl; 00185 } 00186 00187 } else if( (wrds.size()==2) && (wrds[0]=="remove_line")) { 00188 if(m_verbose) { 00189 m_out << "upgrader::upgrade_file :" 00190 << " remove_line " << inlib::sout(wrds[1]) 00191 << std::endl; 00192 } 00193 if(!remove_lines(a_file,wrds[1])) { 00194 m_out << "upgrader::upgrade_file :" 00195 << " upgrade of file " << inlib::sout(a_file) << " fails." 00196 << std::endl; 00197 return false; 00198 } 00199 00200 } else if( (wrds.size()==2) && (wrds[0]=="remove_if")) { 00201 if(m_verbose) { 00202 m_out << "upgrader::upgrade_file :" 00203 << " remove_if " << inlib::sout(wrds[1]) 00204 << std::endl; 00205 } 00206 if(!remove_if(a_file,wrds[1])) { 00207 m_out << "upgrader::upgrade_file :" 00208 << " upgrade of file " << inlib::sout(a_file) << " fails." 00209 << std::endl; 00210 return false; 00211 } 00212 00213 } else if( (wrds.size()==3) && (wrds[0]=="if_rm_eol")) { 00214 if(m_verbose) { 00215 m_out << "upgrader::upgrade_file :" 00216 << " if_rm_eol " << inlib::sout(wrds[1]) 00217 << std::endl; 00218 } 00219 std::vector<std::string> changes; 00220 if(!if_rm_eol(a_file,wrds[1],wrds[2],changes)) { 00221 m_out << "upgrader::upgrade_file :" 00222 << " upgrade of file " << inlib::sout(a_file) << " fails." 00223 << std::endl; 00224 return false; 00225 } 00226 unsigned int changen = changes.size(); 00227 for(unsigned int count=0;count<changen;count+=2) { 00228 m_out << ">>>>>>>>>>>>> In file " << inlib::sout(a_file) 00229 << ", line changed : " << std::endl; 00230 m_out << changes[count] << std::endl; 00231 m_out << changes[count+1] << std::endl; 00232 } 00233 00234 } else if( (wrds.size()==3) && (wrds[0]=="warn")) { 00235 std::vector<std::string> found; 00236 if(!file::found(a_file,wrds[1],found)) { 00237 m_out << "upgrader::upgrade_file :" 00238 << " upgrade of file " << inlib::sout(a_file) << " fails." 00239 << std::endl; 00240 return false; 00241 } 00242 unsigned int foundn = found.size(); 00243 for(unsigned int count=0;count<foundn;count++) { 00244 m_out << ">>>>>>>>>>>>> In file " << inlib::sout(a_file) 00245 << ", have to upgrade by hand line :" 00246 << std::endl; 00247 m_out << found[count] << std::endl; 00248 m_out << "Action being :" << std::endl; 00249 m_out << wrds[2] << std::endl; 00250 } 00251 } else { 00252 m_out << "upgrader::upgrade_file :" 00253 << " bad formed or unknown request " << inlib::sout(m_orders[index]) 00254 << std::endl; 00255 } 00256 } 00257 return true; 00258 } 00259 00260 bool upgrade_dir(const std::string& aPath) { 00261 if(!m_orders.size()) return true; //Nothing to do. 00262 if(m_verbose) { 00263 m_out << "upgrader::upgrade_dir :" 00264 << " upgrade directory " << inlib::sout(aPath) << "..." 00265 << std::endl; 00266 } 00267 dir::tree tree(m_out); 00268 tree.set_path(aPath); 00269 if(!tree.build()) { 00270 m_out << "upgrader::upgrade_dir :" 00271 << "Can't get files of " << inlib::sout(aPath) << std::endl; 00272 return false; 00273 } 00274 upgrade_visitor visitor(*this); 00275 return tree.visit(visitor); 00276 } 00277 private: 00278 static bool replace(const std::string& a_file,const std::string& a_old,const std::string& a_new,std::vector<std::string>& a_changes){ 00279 a_changes.clear(); 00280 std::vector<std::string> text; 00281 if(!file::read(a_file,text)) return false; 00282 // Replace : 00283 bool touched = false; 00284 {std::vector<std::string>::iterator it; 00285 for(it=text.begin();it!=text.end();++it) { 00286 std::string old = *it; 00287 if(inlib::replace(*it,a_old,a_new)) { 00288 a_changes.push_back(old); 00289 a_changes.push_back(*it); 00290 touched = true; 00291 } 00292 }} 00293 if(!touched) return true; 00294 // Create temporary file : 00295 //NOTE : have a tmpname in current directory so that the below 00296 // rename works. (Else we should do a move). 00297 std::string tmp_name; 00298 if(!tmpname(".","inlib_","",tmp_name)) return false; 00299 FILE* file = ::fopen(tmp_name.c_str(),"wb"); 00300 if(!file) return false; 00301 {std::vector<std::string>::iterator it; 00302 for(it=text.begin();it!=text.end();++it) { 00303 if(::fprintf(file,"%s\n",(*it).c_str())<0) { 00304 ::fclose(file); 00305 ::remove(tmp_name.c_str()); 00306 return false; 00307 } 00308 }} 00309 ::fclose(file); 00310 if(::remove(a_file.c_str())!=0) return false; 00311 //NOTE : tmp_name, a_file must not be a path ! 00312 // Darwin is ok with a path but not Linux ! 00313 // For example : 00314 // ::rename("/tmp/tmp01"."x"); 00315 // return -1 on Linux. 00316 // To do the upper then someone must use move. 00317 // But there is no move in the standard lib C ! 00318 if(::rename(tmp_name.c_str(),a_file.c_str())!=0) return false; 00319 return true; 00320 } 00321 00322 static bool replace_if(const std::string& a_file,const std::string& a_if,const std::string& a_old,const std::string& a_new,std::vector<std::string>& a_changes){ 00323 a_changes.clear(); 00324 std::vector<std::string> text; 00325 if(!file::read(a_file,text)) return false; 00326 // Replace : 00327 bool touched = false; 00328 {std::vector<std::string>::iterator it; 00329 for(it=text.begin();it!=text.end();++it) { 00330 std::string old = *it; 00331 if(old.find(a_if)!=std::string::npos) { 00332 if(inlib::replace(*it,a_old,a_new)) { 00333 a_changes.push_back(old); 00334 a_changes.push_back(*it); 00335 touched = true; 00336 } 00337 } 00338 }} 00339 if(!touched) return true; 00340 // Create temporary file : 00341 //NOTE : have a tmpname in current directory so that the below 00342 // rename works. (Else we should do a move). 00343 std::string tmp_name; 00344 if(!tmpname(".","inlib_","",tmp_name)) return false; 00345 FILE* file = ::fopen(tmp_name.c_str(),"wb"); 00346 if(!file) return false; 00347 {std::vector<std::string>::iterator it; 00348 for(it=text.begin();it!=text.end();++it) { 00349 if(::fprintf(file,"%s\n",(*it).c_str())<0) { 00350 ::fclose(file); 00351 ::remove(tmp_name.c_str()); 00352 return false; 00353 } 00354 }} 00355 ::fclose(file); 00356 if(::remove(a_file.c_str())!=0) return false; 00357 if(::rename(tmp_name.c_str(),a_file.c_str())!=0) return false; 00358 return true; 00359 } 00360 00361 static bool if_rm_eol(const std::string& a_file,const std::string& a_if,const std::string& a_rm,std::vector<std::string>& a_changes){ 00362 a_changes.clear(); 00363 std::vector<std::string> text; 00364 if(!file::read(a_file,text)) return false; 00365 bool touched = false; 00366 {std::vector<std::string>::iterator it; 00367 for(it=text.begin();it!=text.end();++it) { 00368 std::string old = *it; 00369 std::string& line = (*it); 00370 if(line.find(a_if)!=std::string::npos) { 00371 std::string::size_type pos = line.find(a_rm); 00372 if(pos!=std::string::npos) { 00373 line = line.substr(0,pos); 00374 a_changes.push_back(old); 00375 a_changes.push_back(line); 00376 touched = true; 00377 } 00378 } 00379 }} 00380 if(!touched) return true; 00381 // Create temporary file : 00382 //NOTE : have a tmpname in current directory so that the below 00383 // rename works. (Else we should do a move). 00384 std::string tmp_name; 00385 if(!tmpname(".","inlib_","",tmp_name)) return false; 00386 FILE* file = ::fopen(tmp_name.c_str(),"wb"); 00387 if(!file) return false; 00388 {std::vector<std::string>::iterator it; 00389 for(it=text.begin();it!=text.end();++it) { 00390 if(::fprintf(file,"%s\n",(*it).c_str())<0) { 00391 ::fclose(file); 00392 ::remove(tmp_name.c_str()); 00393 return false; 00394 } 00395 }} 00396 ::fclose(file); 00397 if(::remove(a_file.c_str())!=0) return false; 00398 if(::rename(tmp_name.c_str(),a_file.c_str())!=0) return false; 00399 return true; 00400 } 00401 00402 static bool remove_lines(const std::string& a_file,const std::string& a_to_remove){ 00403 std::vector<std::string> text; 00404 if(!file::read(a_file,text)) return false; 00405 bool touched = false; 00406 {std::vector<std::string>::iterator it; 00407 for(it=text.begin();it!=text.end();) { 00408 std::string line = *it; 00409 if(line==a_to_remove) { 00410 it = text.erase(it); 00411 touched = true; 00412 } else { 00413 it++; 00414 } 00415 }} 00416 if(!touched) return true; 00417 // Create temporary file : 00418 //NOTE : have a tmpname in current directory so that the below 00419 // rename works. (Else we should do a move). 00420 std::string tmp_name; 00421 if(!tmpname(".","inlib_","",tmp_name)) return false; 00422 FILE* file = ::fopen(tmp_name.c_str(),"wb"); 00423 if(!file) return false; 00424 {std::vector<std::string>::iterator it; 00425 for(it=text.begin();it!=text.end();++it) { 00426 if(::fprintf(file,"%s\n",(*it).c_str())<0) { 00427 ::fclose(file); 00428 ::remove(tmp_name.c_str()); 00429 return false; 00430 } 00431 }} 00432 ::fclose(file); 00433 if(::remove(a_file.c_str())!=0) return false; 00434 if(::rename(tmp_name.c_str(),a_file.c_str())!=0) return false; 00435 return true; 00436 } 00437 00438 static bool remove_if(const std::string& a_file,const std::string& a_if){ 00439 std::vector<std::string> text; 00440 if(!file::read(a_file,text)) return false; 00441 bool touched = false; 00442 {std::vector<std::string>::iterator it; 00443 for(it=text.begin();it!=text.end();) { 00444 std::string line = *it; 00445 if(line.find(a_if)!=std::string::npos) { 00446 it = text.erase(it); 00447 touched = true; 00448 } else { 00449 it++; 00450 } 00451 }} 00452 if(!touched) return true; 00453 // Create temporary file : 00454 //NOTE : have a tmpname in current directory so that the below 00455 // rename works. (Else we should do a move). 00456 std::string tmp_name; 00457 if(!tmpname(".","inlib_","",tmp_name)) return false; 00458 FILE* file = ::fopen(tmp_name.c_str(),"wb"); 00459 if(!file) return false; 00460 {std::vector<std::string>::iterator it; 00461 for(it=text.begin();it!=text.end();++it) { 00462 if(::fprintf(file,"%s\n",(*it).c_str())<0) { 00463 ::fclose(file); 00464 ::remove(tmp_name.c_str()); 00465 return false; 00466 } 00467 }} 00468 ::fclose(file); 00469 if(::remove(a_file.c_str())!=0) return false; 00470 if(::rename(tmp_name.c_str(),a_file.c_str())!=0) return false; 00471 return true; 00472 } 00473 00474 private: 00475 std::ostream& m_out; 00476 bool m_verbose; 00477 std::vector<std::string> m_orders; 00478 std::string m_filter; 00479 }; 00480 00481 } 00482 00483 #endif