inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/upgrader
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines