*/
#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"
/** 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:
/** \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; }
///////////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////
- //
- // 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 ×tamp )
- {
- _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