Locks.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00009 
00010 #include <set>
00011 #include <fstream>
00012 #include <boost/function.hpp>
00013 
00014 #include <zypp/base/Regex.h>
00015 #include <zypp/base/String.h>
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/base/IOStream.h"
00018 #include "zypp/PoolItem.h"
00019 #include "zypp/CapFactory.h"
00020 #include "zypp/CapMatchHelper.h"
00021 #include "zypp/capability/Capabilities.h"
00022 
00023 #undef ZYPP_BASE_LOGGER_LOGGROUP
00024 #define ZYPP_BASE_LOGGER_LOGGROUP "locks"
00025 
00026 #include "zypp/Locks.h"
00027 #include "zypp/PathInfo.h"
00028 
00029 using namespace std;
00030 using namespace zypp;
00031 using namespace zypp::str;
00032 
00033 namespace zypp
00034 {
00035 namespace locks
00036 {
00037 
00038 //
00039 // collect matching names
00040 //
00041 // called by regexp matching, see 'Match' below
00042 //
00043 
00044 struct NameMatchCollectorFunc
00045 {
00046   set<string> matches;
00047 
00048   bool operator()( const PoolItem &item )
00049   {
00050     matches.insert( item.resolvable()->name() );
00051     return true;
00052   }
00053 };
00054 
00055 
00056 // taken from zypper
00057 struct Match
00058 {
00059   const regex * _regex;
00060 
00061   Match(const regex & regex ) :
00062     _regex(&regex)
00063   {}
00064 
00065   bool operator()(const zypp::PoolItem & pi) const
00066   {
00067     return
00068     // match resolvable name
00069     regex_match(pi.resolvable()->name(), *_regex);
00070   }
00071 };
00072 
00073 
00074 string
00075 wildcards2regex(const string & str)
00076 {
00077   string regexed;
00078 
00079   string all("*"); // regex to search for '*'
00080   string one("?"); // regex to search for '?'
00081   string r_all(".*"); // regex equivalent of '*'
00082   string r_one(".");  // regex equivalent of '?'
00083 
00084   // replace all "*" in input with ".*"
00085   regexed = str::gsub( str, all, r_all );
00086   MIL << "wildcards2regex: " << str << " -> " << regexed;
00087 
00088   // replace all "?" in input with "."
00089    regexed = str::gsub(regexed, one, r_one);
00090    MIL << " -> " << regexed << endl;
00091 
00092   return regexed;
00093 }
00094 
00095 
00096 //
00097 // assign Lock to installed pool item
00098 //
00099 
00100 struct ItemLockerFunc
00101 {
00102   ItemLockerFunc( const string lock_str )
00103     : _lock_str(lock_str)
00104   {}
00105 
00106   bool operator()( const CapAndItem &cai_r )
00107   {
00108     PoolItem_Ref item(cai_r.item);
00109     MIL << "Locking " << cai_r.item << "(matched by " << _lock_str << ")" << endl;
00110     item.status().setLock( true, ResStatus::USER);
00111     return true;
00112   }
00113 
00114   string _lock_str;
00115 };
00116 
00117 struct AddLockToPool
00118 {
00119   AddLockToPool( const ResPool &pool )
00120   : _pool(pool)
00121   , _count(0)
00122   {
00123   
00124   }
00125   
00126   bool operator()( const std::string & str_r )
00127   {
00128     CapFactory cap_factory;
00129     
00130     std::string line( str::trim( str_r ) );
00131     
00132     if ( line.empty() || line[0] == '#')
00133       return true;
00134     
00135     MIL << "Applying locks from pattern '" << str_r << "'" << endl;
00136     
00137     // zypp does not provide wildcard or regex support in the Capability matching helpers
00138     // but it still parses the index if it contains wildcards.
00139     // so we decompose the capability, and keep the op and edition, while, the name
00140     // is converted to a regexp and matched against all possible names in the _pool
00141     // Then these names are combined with the original edition and relation and we
00142     // got a new capability for matching wildcard to use with the capability match
00143     // helpers
00144 
00145     Rel rel;
00146     Edition edition;
00147     string name;
00148 
00149     try
00150     {
00151       Capability capability = cap_factory.parse( ResTraits<zypp::Package>::kind, line );
00152       
00153       capability::NamedCap::constPtr named = capability::asKind<capability::NamedCap>(capability);
00154       if ( named )
00155       {
00156         rel = named->op();
00157         edition = named->edition();
00158         name = named->index();
00159       }
00160       else
00161       {
00162         ERR << "Not a named capability in: '" << line << "' skipping" << std::endl;
00163         return true;
00164       }
00165     }
00166     catch ( const Exception &e )
00167     {
00168       ERR << "Can't parse capability in: '" << line << "' (" << e.msg() << ") skipping" << std::endl;
00169       return true;
00170     }
00171 
00172     // Operator NONE is not allowed in Capability
00173     if (rel == Rel::NONE) rel = Rel::ANY;
00174 
00175     NameMatchCollectorFunc nameMatchFunc;
00176 
00177     // regex flags
00178     unsigned int flags = regex::normal;
00179     flags |= regex::icase;
00180     regex reg;
00181 
00182     // create regex object
00183     string regstr( wildcards2regex( name ) );
00184     MIL << "regstr '" << regstr << "'" << endl;
00185     try
00186     {
00187       reg.assign( regstr, flags );
00188     }
00189     catch (regex_error & e)
00190     {
00191       ERR << "locks: " << regstr << " is not a valid regular expression: \"" << e.msg() << "\"" << endl;
00192       ERR << "This is a bug, please file a bug report against libzypp" << endl;
00193       // ignore this lock and continue
00194       return true;;
00195     }
00196 
00197     invokeOnEach( _pool.begin(), _pool.end(), Match(reg), functor::functorRef<bool, const PoolItem &>(nameMatchFunc) );
00198 
00199     MIL << "Found " << nameMatchFunc.matches.size() << " matches." << endl;
00200 
00201     // now we have all the names matching
00202 
00203     // for each name matching try to match a capability
00204 
00205     ItemLockerFunc lockItemFunc( line );
00206 
00207     for ( set<string>::const_iterator it = nameMatchFunc.matches.begin(); it != nameMatchFunc.matches.end(); ++it )
00208     {
00209       string matched_name = *it;
00210 
00211       try
00212       {
00213         Capability capability = cap_factory.parse( ResTraits<zypp::Package>::kind, matched_name, rel, edition );
00214         MIL << "Locking capability " << capability << endl;
00215         forEachMatchIn( _pool, Dep::PROVIDES, capability, functor::functorRef<bool, const CapAndItem &>(lockItemFunc) );
00216       }
00217       catch ( const Exception &e )
00218       {
00219         ERR << "Invalid lock: " << e.msg() << std::endl;
00220       }
00221       ++_count;
00222     }
00223     return true;
00224   } // end operator()()
00225         
00226   ResPool _pool;
00227   int _count;
00228 };
00229 
00230 //
00231 // read 'locks' table, evaluate 'glob' column, assign locks to pool
00232 //
00233 int
00234 readLocks(const ResPool & pool, const Pathname &file )
00235 {
00236   PathInfo lockrc( file );
00237   if ( lockrc.isFile() )
00238   {
00239     MIL << "Reading " << lockrc << endl;
00240     ifstream inp( file.c_str() );
00241     AddLockToPool addlock(pool);
00242     iostr::forEachLine( inp, addlock);
00243     MIL << addlock._count << " locks." << endl;
00244     return addlock._count;
00245   }
00246   return 0;
00247 }
00248 
00249 } // ns locks
00250 } // ns zypp

Generated on Tue Sep 25 19:23:01 2007 for libzypp by  doxygen 1.5.3