Squashed commit of the following:
authorDuncan Mac-Vicar P <dmacvicar@suse.de>
Thu, 9 Aug 2007 12:24:34 +0000 (12:24 +0000)
committerDuncan Mac-Vicar P <dmacvicar@suse.de>
Thu, 9 Aug 2007 12:24:34 +0000 (12:24 +0000)
commit fb2dba632df53d074600eecb7bd1d19767acda21
Author: Duncan Mac-Vicar P <dmacvicar@suse.de>
Date:   Thu Aug 9 12:39:10 2007 +0200

    - check for vendors in candidates
    - check that the resolvables are not empty before calling vendor()

commit 173588f356356c129dab39fb32b8cf802dfaae78
Author: Duncan Mac-Vicar P <dmacvicar@suse.de>
Date:   Wed Aug 8 14:02:06 2007 +0200

    - typo
    - trustedVendors file location

commit cc8b757dc0dd8ef1616c5e0404e7894a7802d39c
Author: Duncan Mac-Vicar P <dmacvicar@suse.de>
Date:   Wed Aug 8 13:53:59 2007 +0200

    Implementation of a saner locking solution:
    - no automatic inter-vendor upgrades
    - no automatic untrusted vendor protection
    - user defined locks from /etc/zypp/locks

zypp/CMakeLists.txt
zypp/Locks.cc [new file with mode: 0644]
zypp/Locks.h [new file with mode: 0644]
zypp/VendorAttr.cc
zypp/ZConfig.cc
zypp/ZConfig.h
zypp/solver/detail/Helper.cc
zypp/solver/detail/QueueItemRequire.cc
zypp/solver/detail/ResolverUpgrade.cc

index 7077c73..ef789d9 100644 (file)
@@ -87,6 +87,7 @@ SET( zypp_SRCS
   RepoStatus.cc
   RepoManager.cc
   MediaProducts.cc
+  Locks.cc
 )
 
 SET( zypp_HEADERS
@@ -184,6 +185,7 @@ SET( zypp_HEADERS
   RepoStatus.h
   RepoManager.h
   MediaProducts.h
+  Locks.h
 )
 
 INSTALL(  FILES ${zypp_HEADERS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/zypp" )
diff --git a/zypp/Locks.cc b/zypp/Locks.cc
new file mode 100644 (file)
index 0000000..9651319
--- /dev/null
@@ -0,0 +1,254 @@
+
+
+
+
+
+
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#include <set>
+#include <fstream>
+#include <boost/regex.hpp>
+#include <boost/function.hpp>
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/IOStream.h"
+#include "zypp/PoolItem.h"
+#include "zypp/CapFactory.h"
+#include "zypp/CapMatchHelper.h"
+#include "zypp/capability/Capabilities.h"
+
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "locks"
+
+#include "zypp/Locks.h"
+#include "zypp/PathInfo.h"
+
+using namespace std;
+using namespace zypp;
+using namespace boost;
+using boost::regex;
+
+namespace zypp
+{
+namespace locks
+{
+
+//
+// collect matching names
+//
+// called by regexp matching, see 'Match' below
+//
+
+struct NameMatchCollectorFunc
+{
+  set<string> matches;
+
+  bool operator()( const PoolItem &item )
+  {
+    matches.insert( item.resolvable()->name() );
+    return true;
+  }
+};
+
+
+// taken from zypper
+struct Match
+{
+  const regex * _regex;
+
+  Match(const regex & regex ) :
+    _regex(&regex)
+  {}
+
+  bool operator()(const zypp::PoolItem & pi) const
+  {
+    return
+    // match resolvable name
+    regex_match(pi.resolvable()->name(), *_regex);
+  }
+};
+
+
+string
+wildcards2regex(const string & str)
+{
+  string regexed;
+
+  regex all("\\*"); // regex to search for '*'
+  regex one("\\?"); // regex to search for '?'
+  string r_all(".*"); // regex equivalent of '*'
+  string r_one(".");  // regex equivalent of '?'
+
+  // replace all "*" in input with ".*"
+  regexed = regex_replace(str, all, r_all);
+  MIL << "wildcards2regex: " << str << " -> " << regexed;
+
+  // replace all "?" in input with "."
+  regexed = regex_replace(regexed, one, r_one);
+  MIL << " -> " << regexed << endl;
+
+  return regexed;
+}
+
+
+//
+// assign Lock to installed pool item
+//
+
+struct ItemLockerFunc
+{
+  ItemLockerFunc( const string lock_str )
+    : _lock_str(lock_str)
+  {}
+
+  bool operator()( const CapAndItem &cai_r )
+  {
+    PoolItem_Ref item(cai_r.item);
+    MIL << "Locking " << cai_r.item << "(matched by " << _lock_str << ")" << endl;
+    item.status().setLock( true, ResStatus::USER);
+    return true;
+  }
+
+  string _lock_str;
+};
+
+struct AddLockToPool
+{
+  AddLockToPool( const ResPool &pool )
+  : _pool(pool)
+  , _count(0)
+  {
+  
+  }
+  
+  bool operator()( const std::string & str_r )
+  {
+    CapFactory cap_factory;
+    
+    std::string line( str::trim( str_r ) );
+    
+    if ( line.empty() || line[0] != '#')
+      return true;
+    
+    // zypp does not provide wildcard or regex support in the Capability matching helpers
+    // but it still parses the index if it contains wildcards.
+    // so we decompose the capability, and keep the op and edition, while, the name
+    // is converted to a regexp and matched against all possible names in the _pool
+    // Then these names are combined with the original edition and relation and we
+    // got a new capability for matching wildcard to use with the capability match
+    // helpers
+
+    Rel rel;
+    Edition edition;
+    string name;
+
+    try
+    {
+      Capability capability = cap_factory.parse( ResTraits<zypp::Package>::kind, line );
+      
+      capability::NamedCap::constPtr named = capability::asKind<capability::NamedCap>(capability);
+      if ( named )
+      {
+        rel = named->op();
+        edition = named->edition();
+        name = named->index();
+      }
+      else
+      {
+        ERR << "Not a named capability in: '" << line << "' skipping" << std::endl;
+        return true;
+      }
+    }
+    catch ( const Exception &e )
+    {
+      ERR << "Can't parse capability in: '" << line << "' (" << e.msg() << ") skipping" << std::endl;
+      return true;
+    }
+
+    // Operator NONE is not allowed in Capability
+    if (rel == Rel::NONE) rel = Rel::ANY;
+
+    NameMatchCollectorFunc nameMatchFunc;
+
+    // regex flags
+    unsigned int flags = regex::normal;
+    flags |= regex_constants::icase;
+    regex reg;
+
+    // create regex object
+    string regstr( wildcards2regex( name ) );
+    MIL << "regstr '" << regstr << "'" << endl;
+    try
+    {
+      reg.assign( regstr, flags );
+    }
+    catch (regex_error & e)
+    {
+      ERR << "locks: " << regstr << " is not a valid regular expression: \"" << e.what() << "\"" << endl;
+      ERR << "This is a bug, please file a bug report against libzypp-zmd-backend" << endl;
+      // ignore this lock and continue
+      return true;;
+    }
+
+    invokeOnEach( _pool.begin(), _pool.end(), Match(reg), functor::functorRef<bool, const PoolItem &>(nameMatchFunc) );
+
+    MIL << "Found " << nameMatchFunc.matches.size() << " matches." << endl;
+
+    // now we have all the names matching
+
+    // for each name matching try to match a capability
+
+    ItemLockerFunc lockItemFunc( line );
+
+    for ( set<string>::const_iterator it = nameMatchFunc.matches.begin(); it != nameMatchFunc.matches.end(); ++it )
+    {
+      string matched_name = *it;
+
+      try
+      {
+        Capability capability = cap_factory.parse( ResTraits<zypp::Package>::kind, matched_name, rel, edition );
+        MIL << "Locking capability " << capability << endl;
+        forEachMatchIn( _pool, Dep::PROVIDES, capability, functor::functorRef<bool, const CapAndItem &>(lockItemFunc) );
+      }
+      catch ( const Exception &e )
+      {
+        ERR << "Invalid lock: " << e.msg() << std::endl;
+      }
+      ++_count;
+    }
+    return true;
+  } // end operator()()
+        
+  ResPool _pool;
+  int _count;
+};
+
+//
+// read 'locks' table, evaluate 'glob' column, assign locks to pool
+//
+int
+readLocks(const ResPool & pool, const Pathname &file )
+{
+  PathInfo lockrc( file );
+  if ( lockrc.isFile() )
+  {
+    MIL << "Reading " << lockrc << endl;
+    ifstream inp( file.c_str() );
+    AddLockToPool addlock(pool);
+    iostr::forEachLine( inp, addlock);
+    MIL << addlock._count << " locks." << endl;
+    return addlock._count;
+  }
+  return 0;
+}
+
+} // ns locks
+} // ns zypp
diff --git a/zypp/Locks.h b/zypp/Locks.h
new file mode 100644 (file)
index 0000000..f3789d3
--- /dev/null
@@ -0,0 +1,17 @@
+
+#ifndef ZYPP_LOCKS_H
+#define ZYPP_LOCKS_H
+
+#include "zypp/ResPool.h"
+#include "zypp/Pathname.h"
+
+namespace zypp
+{
+  namespace locks
+  {
+
+    int readLocks(const ResPool & pool, const Pathname &file );
+  }
+}
+    
+#endif
\ No newline at end of file
index 8c49a2f..a8d7bc2 100644 (file)
@@ -29,6 +29,8 @@
 #include "zypp/VendorAttr.h"
 #include "zypp/ZYppFactory.h"
 
+#include "zypp/ZConfig.h"
+
 using namespace std;
 
 #undef  ZYPP_BASE_LOGGER_LOGGROUP
@@ -80,9 +82,6 @@ namespace zypp
         }
       return res.first->second;
     }
-
-    bool applyAutoProtection = true;
-
     /////////////////////////////////////////////////////////////////
   } // namespace
   ///////////////////////////////////////////////////////////////////
@@ -107,7 +106,7 @@ namespace zypp
     };
     _trustedVendors.insert( vendors, vendors+(sizeof(vendors)/sizeof(const char *)) );
 
-    Pathname vendorrcPath( getZYpp()->homePath() / "db/trustedVendors" );
+    Pathname vendorrcPath( "/etc/zypp/trustedVendors" );
     try
       {
         Target_Ptr trg( getZYpp()->target() );
@@ -131,14 +130,14 @@ namespace zypp
 
   void VendorAttr::enableAutoProtect()
   {
-    MIL << "Foreign vendor auto protection enabled." << endl;
-    applyAutoProtection = true;
+    MIL << "FIXME: Not implemented." << endl;
+    // FIXME use ZConfig
   }
 
   void VendorAttr::disableAutoProtect()
   {
-    MIL << "Foreign vendor auto protection disabled." << endl;
-    applyAutoProtection = false;
+    MIL << "FIXME: Not implemented." << endl;
+    // FIXME use ZConfig
   }
 
   bool VendorAttr::isKnown( const Vendor & vendor_r ) const
@@ -146,7 +145,7 @@ namespace zypp
 
 
   bool VendorAttr::autoProtect( const Vendor & vendor_r ) const
-  { return( applyAutoProtection && ! trusted( vendor_r ) ); }
+  { return( ZConfig::instance().autolock_untrustedvendor() && ! trusted( vendor_r ) ); }
 
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
index a31666d..f83c88f 100644 (file)
@@ -37,6 +37,7 @@ namespace zypp
     public:
       Impl()
         : repo_add_probe(false)
+        , autolock_untrustedvendor(false)
       {
         MIL << "ZConfig singleton created." << endl;
         Pathname confpath("/etc/zypp/zypp.conf");
@@ -86,6 +87,10 @@ namespace zypp
                 repo_add_probe = (value == "1");
               }
             }
+            else if ( section == "locking" )
+            {
+              autolock_untrustedvendor = ( value == "1" );
+            }
             
           }
         }
@@ -106,6 +111,9 @@ namespace zypp
     
     bool repo_add_probe;
     
+    // [locking]
+    bool autolock_untrustedvendor;
+    
   };
   ///////////////////////////////////////////////////////////////////
 
@@ -192,6 +200,11 @@ namespace zypp
     return _pimpl->repo_add_probe;
   }
   
+  bool ZConfig::autolock_untrustedvendor() const
+  {
+    return _pimpl->autolock_untrustedvendor;
+  }
+  
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////
index 79ef4c0..533b7de 100644 (file)
@@ -80,6 +80,13 @@ namespace zypp
        */
       bool repo_add_probe() const;
       
+      /**
+       * Whether untrusted vendor should be autolocked
+       / config option
+       * repo.add.probe
+       */
+      bool autolock_untrustedvendor() const;
+      
     public:
       class Impl;
       /** Dtor */
index 1705b93..9cfd8f8 100644 (file)
@@ -124,10 +124,30 @@ class LookForUpdate : public resfilter::PoolItemFilterFunctor
 
     bool operator()( PoolItem_Ref provider )
     {
+        MIL << "comparing: " << endl << provider << endl << uninstalled << endl;
+        
+        // is valid
+        if ( ! provider.resolvable() )
+        {
+          MIL << "Warning: '" << provider << "' not valid" << endl;
+          return true;
+        }
+        
+        if ( uninstalled.resolvable() )
+        {
+          if ( uninstalled->vendor() != provider->vendor() )
+          {
+            MIL << "Discarding '" << provider << "' from vendor '"
+                << provider->vendor() << "' different to uninstalled '"
+                << uninstalled->vendor() << "' vendor." << endl;
+            return true;
+          }
+        }
+        
        if ((!uninstalled                                                       // none yet
            || (uninstalled->edition().compare( provider->edition() ) < 0)      // or a better edition
-           || (uninstalled->arch().compare( provider->arch() ) < 0) )          // or a better architecture
-           && !provider.status().isLocked()                                  // is not locked
+           || (uninstalled->arch().compare( provider->arch() ) < 0) ) // or a better architecture
+           && !provider.status().isLocked() )                                  // is not locked
        {
            uninstalled = provider;                                             // store 
        }
index 9f213b8..724dc6c 100644 (file)
@@ -220,6 +220,7 @@ struct RequireProcess
            && ! _context->isParallelInstall( provider )
            && _context->itemIsPossible( provider )
            && ! provider.status().isLocked()
+            && ( (!provider || !upgrades) || (provider->vendor() == upgrades->vendor()) )
            && ! (provider.status().isKept()
                  &&provider.status().isByUser())
            ) {
index b2f1d26..c68b8c4 100644 (file)
@@ -357,7 +357,8 @@ Resolver::doUpgrade( UpgradeStatistics & opt_stats_r )
        if (cand_it == candidatemap.end()                                               // not in map yet
            || (cand_it->second->arch().compare( candidate->arch() ) < 0)               // or the new has better architecture
            || ((cand_it->second->arch().compare( candidate->arch() ) == 0)             // or the new has the same architecture
-               && (cand_it->second->edition().compare( candidate->edition() ) < 0) ) ) //   and a better edition (-> 157501)
+               && (cand_it->second->edition().compare( candidate->edition() ) < 0)     //   and a better edition (-> 157501)
+                && (cand_it->second->vendor() == candidate->vendor() ) ) )//   and same vendor
        {
            candidatemap[installed] = candidate;                                // put it in !
        }