Imported Upstream version 17.20.0
[platform/upstream/libzypp.git] / zypp / RepoStatus.cc
index fdea7a5..7a2ca5f 100644 (file)
 */
 #include <iostream>
 #include <sstream>
-#include <vector>
-#include <algorithm>
 #include <fstream>
-//#include "zypp/base/Logger.h"
+#include "zypp/base/Logger.h"
 #include "zypp/base/String.h"
 #include "zypp/RepoStatus.h"
 #include "zypp/PathInfo.h"
@@ -32,17 +30,42 @@ namespace zypp
   /** RepoStatus implementation. */
   struct RepoStatus::Impl
   {
-
   public:
-    
-    string checksum;
-    Date timestamp;
-    
-    /** Offer default Impl. */
-    static shared_ptr<Impl> nullimpl()
+    string _checksum;
+    Date _timestamp;
+
+    // NOTE: Changing magic will at once invalidate all solv file caches.
+    // Helpfull if solv file content must be refreshed (e.g. due to different
+    // repo2* arguments) even if raw metadata are unchanged.
+    // Only values set from a RepoStatus ctor need magic to be added.
+    void assignFromCtor( std::string && checksum_r, Date && timestamp_r )
     {
-      static shared_ptr<Impl> _nullimpl( new Impl );
-      return _nullimpl;
+      _checksum = std::move(checksum_r);
+      _timestamp = std::move(timestamp_r);
+      if ( !_checksum.empty() )
+      {
+       static const std::string magic( "43" );
+       _checksum += magic;
+      }
+    }
+
+    /** Recursive computation of max dir timestamp. */
+    static void recursive_timestamp( const Pathname & dir_r, time_t & max_r )
+    {
+      std::list<std::string> dircontent;
+      if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
+       return; // readdir logged the error
+
+      for_( it, dircontent.begin(), dircontent.end() )
+      {
+       PathInfo pi( dir_r + *it, PathInfo::LSTAT );
+       if ( pi.isDir() )
+       {
+         if ( pi.mtime() > max_r )
+           max_r = pi.mtime();
+         recursive_timestamp( pi.path(), max_r );
+       }
+      }
     }
 
   private:
@@ -55,9 +78,7 @@ namespace zypp
 
   /** \relates RepoStatus::Impl Stream output */
   inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj )
-  {
-    return str << obj.checksum << " " << obj.timestamp;
-  }
+  { return str << obj._checksum << " " << (time_t)obj._timestamp; }
 
   ///////////////////////////////////////////////////////////////////
   //
@@ -65,112 +86,98 @@ namespace zypp
   //
   ///////////////////////////////////////////////////////////////////
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : RepoStatus::RepoStatus
-  //   METHOD TYPE : Ctor
-  //
   RepoStatus::RepoStatus()
     : _pimpl( new Impl() )
   {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : RepoStatus::~RepoStatus
-  //   METHOD TYPE : Dtor
-  //
+  RepoStatus::RepoStatus( const Pathname & path_r )
+    : _pimpl( new Impl() )
+  {
+    PathInfo info( path_r );
+    if ( info.isExist() )
+    {
+      if ( info.isFile() )
+      {
+       _pimpl->assignFromCtor( filesystem::sha1sum( path_r ), Date( info.mtime() ) );
+      }
+      else if ( info.isDir() )
+      {
+       time_t t = info.mtime();
+       Impl::recursive_timestamp( path_r, t );
+       _pimpl->assignFromCtor( CheckSum::sha1FromString( str::numstring( t ) ).checksum(), Date( t ) );
+      }
+    }
+  }
+
+  RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r )
+  : _pimpl( new Impl() )
+  {
+    _pimpl->assignFromCtor( std::move(checksum_r), std::move(timestamp_r) );
+  }
+
   RepoStatus::~RepoStatus()
   {}
 
-  RepoStatus RepoStatus::fromCookieFile( const Pathname &cookiefile )
+  RepoStatus RepoStatus::fromCookieFile( const Pathname & path_r )
   {
-    RepoStatus status;
-    
-    std::ifstream file(cookiefile.c_str());
-    if (!file) {
-      ZYPP_THROW (Exception( "Can't open " + cookiefile.asString() ) );
+    RepoStatus ret;
+    std::ifstream file( path_r.c_str() );
+    if ( !file )
+    {
+      WAR << "No cookie file " << path_r << endl;
     }
-
-    std::string buffer;
-    while(file && !file.eof()) {
-      getline(file, buffer);
+    else
+    {
+      // line := "[checksum] time_t"
+      std::string line( str::getline( file ) );
+      ret._pimpl->_timestamp = Date( str::strtonum<time_t>( str::stripLastWord( line ) ) );
+      ret._pimpl->_checksum = line;
     }
-
-    std::vector<std::string> words;
-    if ( str::split( buffer, std::back_inserter(words) ) != 2 )
-      ZYPP_THROW (Exception( "bad cookie file " + cookiefile.asString() ) );
-
-    status.setTimestamp(Date(str::strtonum<time_t>(words[1])));
-    status.setChecksum(words[0]);
-    return status;
+    return ret;
   }
 
-  void RepoStatus::saveToCookieFile( const Pathname &cookiefile )
+  void RepoStatus::saveToCookieFile( const Pathname & path_r ) const
   {
-    std::ofstream file(cookiefile.c_str());
+    std::ofstream file(path_r.c_str());
     if (!file) {
-      ZYPP_THROW (Exception( "Can't open " + cookiefile.asString() ) );
+      ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
     }
-    file << *(this);
+    file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl;
     file.close();
   }
 
-  RepoStatus::RepoStatus( const Pathname &path )
-    : _pimpl( new Impl() )
-  {
-      PathInfo info(path);
-      if ( info.isExist() )
-      {
-        _pimpl->checksum = filesystem::sha1sum(path);
-        _pimpl->timestamp = Date(info.mtime());
-      }
-  }
-  
   bool RepoStatus::empty() const
-  {
-    return _pimpl->checksum.empty();
-  }
+  { return _pimpl->_checksum.empty(); }
 
-  RepoStatus & RepoStatus::setChecksum( const string &checksum )
-  {
-    _pimpl->checksum = checksum;
-    return *this;
-  }
+  Date RepoStatus::timestamp() const
+  { return _pimpl->_timestamp; }
 
-  RepoStatus & RepoStatus::setTimestamp( const Date &timestamp )
-  {
-    _pimpl->timestamp = timestamp;
-    return *this;
-  }
-  
-  string RepoStatus::checksum() const
-  { return _pimpl->checksum; }
+  std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
+  { return str << *obj._pimpl; }
 
-  Date RepoStatus::timestamp() const
-  { return _pimpl->timestamp; }
-  
-  RepoStatus operator&&( const RepoStatus &lhs, const RepoStatus &rhs )
+  RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
   {
     RepoStatus result;
-    string combinedcs = (lhs.checksum() + rhs.checksum());
-    stringstream ss(combinedcs);
-    CheckSum newcs(CheckSum::sha1(ss));
-    result.setChecksum(newcs.checksum());
-    result.setTimestamp(lhs.timestamp());
-    if ( rhs.timestamp() > lhs.timestamp() )
-      result.setTimestamp(rhs.timestamp());
+
+    if ( lhs.empty() )
+      result = rhs;
+    else if ( rhs.empty() )
+      result = lhs;
+    else
+    {
+      // order strings to assert && is kommutativ
+      std::string lchk( lhs._pimpl->_checksum );
+      std::string rchk( rhs._pimpl->_checksum );
+      stringstream ss( lchk < rchk ? lchk+rchk : rchk+lchk );
+
+      result._pimpl->_checksum = CheckSum::sha1(ss).checksum();
+      result._pimpl->_timestamp = std::max( lhs._pimpl->_timestamp, rhs._pimpl->_timestamp );
+    }
     return result;
   }
 
-  /******************************************************************
-  **
-  **   FUNCTION NAME : operator<<
-  **   FUNCTION TYPE : std::ostream &
-  */
-  std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
-  {
-    return str << *obj._pimpl;
-  }
+  bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
+  { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; }
 
   /////////////////////////////////////////////////////////////////
 } // namespace zypp