1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/RepoStatus.cc
16 #include <zypp/base/Logger.h>
17 #include <zypp/base/String.h>
18 #include <zypp/RepoStatus.h>
19 #include <zypp/RepoInfo.h>
20 #include <zypp/PathInfo.h>
24 ///////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////
30 /** Recursive computation of max dir timestamp. */
31 void recursiveTimestamp( const Pathname & dir_r, time_t & max_r )
33 std::list<std::string> dircontent;
34 if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
35 return; // readdir logged the error
37 for_( it, dircontent.begin(), dircontent.end() )
39 PathInfo pi( dir_r + *it, PathInfo::LSTAT );
42 if ( pi.mtime() > max_r )
44 recursiveTimestamp( pi.path(), max_r );
49 ///////////////////////////////////////////////////////////////////
51 ///////////////////////////////////////////////////////////////////
53 // CLASS NAME : RepoStatus::Impl
55 /** RepoStatus implementation. */
56 struct RepoStatus::Impl
58 using Checksums = std::set<std::string>;
61 /** Assign data called from RepoStatus ctor (adds magic).
63 * \Note Changing magic will at once invalidate all solv file caches.
64 * Helpfull if solv file content must be refreshed (e.g. due to different
65 * repo2solv arguments) even if raw metadata are unchanged. Only values
66 * set from a RepoStatus ctor need magic to be added!
68 void assignFromCtor( std::string && checksum_r, Date && timestamp_r )
70 if ( !checksum_r.empty() ) {
71 static const std::string magic( "43" );
73 _checksums.insert( std::move(checksum_r) );
75 _timestamp = std::move(timestamp_r);
78 /** Inject raw data (no magic added). */
79 void inject( std::string && checksum_r, Date && timestamp_r )
81 if ( !checksum_r.empty() ) {
82 _checksums.insert( std::move(checksum_r) );
83 _cachedchecksum.reset();
86 if ( timestamp_r > _timestamp )
87 _timestamp = timestamp_r;
90 /** Inject the raw data from rhs */
91 void injectFrom( const Impl & rhs )
93 if ( &rhs == this ) // no self insert
96 if ( !rhs._checksums.empty() ) {
97 _checksums.insert( rhs._checksums.begin(), rhs._checksums.end() );
98 _cachedchecksum.reset();
101 if ( rhs._timestamp > _timestamp )
102 _timestamp = rhs._timestamp;
106 { return _checksums.empty(); }
108 std::string checksum() const
111 if ( _checksums.empty() )
114 if ( _checksums.size() == 1 )
115 ret = *_checksums.begin();
117 if ( !_cachedchecksum ) {
118 std::stringstream ss;
119 for ( std::string_view c : _checksums )
121 _cachedchecksum = CheckSum::sha1(ss).checksum();
123 ret = *_cachedchecksum;
128 Date timestamp() const
129 { return _timestamp; }
131 /** Dump to log file (not to/from CookieFile). */
132 std::ostream & dumpOn( std::ostream & str ) const
133 { return str << ( empty() ? "NO_REPOSTATUS" : checksum() ) << " " << time_t(_timestamp); }
136 Checksums _checksums;
139 mutable std::optional<std::string> _cachedchecksum;
142 friend Impl * rwcowClone<Impl>( const Impl * rhs );
143 /** clone for RWCOW_pointer */
145 { return new Impl( *this ); }
147 ///////////////////////////////////////////////////////////////////
149 ///////////////////////////////////////////////////////////////////
151 // CLASS NAME : RepoStatus
153 ///////////////////////////////////////////////////////////////////
155 RepoStatus::RepoStatus()
156 : _pimpl( new Impl() )
159 RepoStatus::RepoStatus( const Pathname & path_r )
160 : _pimpl( new Impl() )
162 PathInfo info( path_r );
163 if ( info.isExist() )
167 _pimpl->assignFromCtor( filesystem::sha1sum( path_r ), Date( info.mtime() ) );
169 else if ( info.isDir() )
171 time_t t = info.mtime();
172 recursiveTimestamp( path_r, t );
173 _pimpl->assignFromCtor( CheckSum::sha1FromString( str::numstring( t ) ).checksum(), Date( t ) );
178 RepoStatus::RepoStatus( const RepoInfo & info_r )
179 : _pimpl( new Impl() )
181 _pimpl->assignFromCtor( CheckSum::sha1FromString( info_r.url().asString() ).checksum(), Date() );
184 RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r )
185 : _pimpl( new Impl() )
187 _pimpl->assignFromCtor( std::move(checksum_r), std::move(timestamp_r) );
190 RepoStatus::~RepoStatus()
193 RepoStatus RepoStatus::fromCookieFile( const Pathname & path_r )
196 std::ifstream file( path_r.c_str() );
199 WAR << "No cookie file " << path_r << endl;
203 // line := "[checksum] time_t" !!! strip time from line
204 std::string line { str::getline( file ) };
205 Date stmp { str::strtonum<time_t>( str::stripLastWord( line ) ) };
206 ret._pimpl->inject( std::move(line), std::move(stmp) ); // raw inject to avoid magic being added
211 void RepoStatus::saveToCookieFile( const Pathname & path_r ) const
213 std::ofstream file(path_r.c_str());
215 ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
217 file << _pimpl->checksum() << " " << time_t(_pimpl->timestamp()) << endl;
221 bool RepoStatus::empty() const
222 { return _pimpl->empty(); }
224 Date RepoStatus::timestamp() const
225 { return _pimpl->timestamp(); }
227 std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
228 { return obj._pimpl->dumpOn( str ); }
230 RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
232 RepoStatus result { lhs };
233 result._pimpl->injectFrom( *rhs._pimpl );
237 bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
238 { return lhs._pimpl->checksum() == rhs._pimpl->checksum(); }
240 /////////////////////////////////////////////////////////////////
242 ///////////////////////////////////////////////////////////////////