SET(LIBZYPP_MAJOR "17")
SET(LIBZYPP_COMPATMINOR "22")
SET(LIBZYPP_MINOR "25")
-SET(LIBZYPP_PATCH "2")
+SET(LIBZYPP_PATCH "3")
#
-# LAST RELEASED: 17.25.2 (22)
+# LAST RELEASED: 17.25.3 (22)
# (The number in parenthesis is LIBZYPP_COMPATMINOR)
#=======
#include <zypp/sat/LookupAttr.h>
#include <zypp/PoolQuery.h>
-#include <zypp/sat/AttrMatcher.h>
static const Pathname sysRoot( "/tmp/ToolScanRepos" );
-------------------------------------------------------------------
+Fri Nov 27 10:17:50 CET 2020 - ma@suse.de
+
+- RepoManager: Carefully tidy up the caches. Remove non-directory
+ entries. (bsc#1178966)
+- RpmDb: If no database exists use the _dbpath configured in rpm.
+ Still makes sure a compat symlink at /var/lib/rpm exists in case
+ the configures _dbpath is elsewhere. (bsc#1178910)
+- Url: Hide known password entires when writing the query part
+ (bsc#1050625 bsc#1177583)
+- adapt testcase to change introduced by libsolv#402.
+- RepoManager: Force refresh if repo url has changed (bsc#1174016)
+- RepoInfo: ignore legacy type= in a .repo file and let RepoManager
+ probe (bsc#1177427, Fixes openSUSE/zypper#357).
+- version 17.25.3 (22)
+
+-------------------------------------------------------------------
Wed Oct 7 12:05:33 CEST 2020 - ma@suse.de
- Bump version to force rebuild against a fixed libsolv.
"Project-Id-Version: zypp\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-18 16:45+0200\n"
-"PO-Revision-Date: 2020-02-19 23:54+0000\n"
-"Last-Translator: Juan Sarria <juansarriam@gmail.com>\n"
+"PO-Revision-Date: 2020-10-08 19:48+0000\n"
+"Last-Translator: Andrés Barrantes Silman <andresbs2000@protonmail.com>\n"
"Language-Team: Spanish <https://l10n.opensuse.org/projects/libzypp/master/es/"
">\n"
"Language: es\n"
"Download (curl) error for '%s':\n"
"Error code: %s\n"
msgstr ""
+"(curl) Error de descarga para '%s':\n"
+"Código de error: %s\n"
#: zypp/zyppng/media/network/networkrequesterror.cc:138
#, c-format, boost-format
"Download (curl) error for '%s':\n"
"Unable to retrieve HTTP response\n"
msgstr ""
+"(curl) Error de descarga para '%s':\n"
+"No se recibió una respuesta HTTP\n"
#~ msgid "Can't open lock file: %s"
#~ msgstr "No es posible abrir el archivo de bloqueo: %s"
"Project-Id-Version: zypp.fi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-18 16:45+0200\n"
-"PO-Revision-Date: 2020-06-28 06:55+0000\n"
-"Last-Translator: Kimmo Kujansuu <mrkujansuu@gmail.com>\n"
+"PO-Revision-Date: 2020-10-28 22:49+0000\n"
+"Last-Translator: Tommi Nieminen <software@legisign.org>\n"
"Language-Team: Finnish <https://l10n.opensuse.org/projects/libzypp/master/fi/"
">\n"
"Language: fi\n"
"Download (curl) error for '%s':\n"
"Error code: %s\n"
msgstr ""
+"Latausvirhe (curl) kohteelle ”%s”:\n"
+"Virhekoodi: %s\n"
#: zypp/zyppng/media/network/networkrequesterror.cc:138
#, c-format, boost-format
"Download (curl) error for '%s':\n"
"Unable to retrieve HTTP response\n"
msgstr ""
+"Latausvirhe (curl) kohteelle ”%s”:\n"
+"HTTP-vastausta ei saatu\n"
#~ msgid "Can't open lock file: %s"
#~ msgstr "Lukitustiedoston avaaminen ei onnistu: %s"
}
{
- base::SetTracker<LocaleSet> localesTracker = setup.localesTracker;
+ base::SetTracker<LocaleSet> localesTracker = setup.localesTracker();
localesTracker.removed().insert( localesTracker.current().begin(), localesTracker.current().end() );
satpool().initRequestedLocales( localesTracker.removed() );
BOOST_CHECK( q.strMatcher() );
BOOST_CHECK_EQUAL( q.size(), 9 );
- for_(it,q.begin(),q.end())
- { cout << it << endl;}
}
BOOST_AUTO_TEST_CASE(LookupAttr_iterate_solvables)
BOOST_CHECK_EQUAL( q.size(), 1212 );
// search any id in any parent-structure:
+ // - https://github.com/openSUSE/libsolv/pull/402 added an additional
+ // <update:collection> flexarray to each of the 2287 entries. This is
+ // why the total size varies depending on the libsolv version used.
q = sat::LookupAttr( sat::SolvAttr::allAttr, sat::SolvAttr::allAttr );
- BOOST_CHECK_EQUAL( q.size(), 10473 );
+ auto qs = q.size();
+ BOOST_CHECK( qs == 10473 || qs == 12760 );
+ // for_(it,q.begin(),q.end())
+ // { cout << it << endl;}
}
BOOST_AUTO_TEST_CASE(LookupAttr_repoattr)
BOOST_AUTO_TEST_CASE(repostatus_test)
{
- TmpFile tmpPath;
- TmpFile tmpPath2;
- RepoStatus status;
- RepoStatus fstatus( tmpPath );
- RepoStatus fstatus2( tmpPath2 );
- BOOST_CHECK_EQUAL( status.empty(), true );
- BOOST_CHECK_EQUAL( (status&&status).empty(), true );
-
- BOOST_CHECK_EQUAL( fstatus.empty(), false );
- BOOST_CHECK_EQUAL( (fstatus&&status).empty(), false );
-
- BOOST_CHECK_EQUAL( (fstatus&&status), (status&&fstatus) );
- BOOST_CHECK_EQUAL( (fstatus&&fstatus2), (fstatus2&&fstatus) );
-
+ RepoStatus e;
+ RepoStatus E { "", 42 }; // empty refers to the checksum only, not to the timestamp!
+ RepoStatus a { "aa", 0 };
+ RepoStatus b { "bb", 1 };
+ RepoStatus c { "cc", 2 };
+
+ BOOST_CHECK_EQUAL( e.empty(), true );
+ BOOST_CHECK_EQUAL( e.timestamp(), 0 );
+ BOOST_CHECK_EQUAL( (e && e).empty(), true );
+
+ BOOST_CHECK_EQUAL( E.empty(), true );
+ BOOST_CHECK_EQUAL( E.timestamp(), 42 );
+ RepoStatus r { E && e };
+ BOOST_CHECK_EQUAL( r.empty(), true );
+ BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+ r = e && E;
+ BOOST_CHECK_EQUAL( r.empty(), true );
+ BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+ r = E && E;
+ BOOST_CHECK_EQUAL( r.empty(), true );
+ BOOST_CHECK_EQUAL( r.timestamp(), 42 );
+
+
+ BOOST_CHECK_EQUAL( a.empty(), false );
+ BOOST_CHECK_EQUAL( a.timestamp(), 0 );
+
+ r = e && a;
+ BOOST_CHECK_EQUAL( r.empty(), false );
+ BOOST_CHECK_EQUAL( r.timestamp(), a.timestamp() ); // max timestamp
+
+ r = a && b;
+ BOOST_CHECK_EQUAL( r, (b && a) );
+ BOOST_CHECK_EQUAL( r.timestamp(), b.timestamp() ); // max timestamp
+
+ r = a && b && c;
+ BOOST_CHECK_EQUAL( r, (a && b) && c );
+ BOOST_CHECK_EQUAL( r, a && (b && c) );
+ BOOST_CHECK_EQUAL( r.timestamp(), c.timestamp() ); // max timestamp
}
// asString shouldn't print the password, asCompleteString should.
// further, the "//" at the begin of the path should be keept.
- str = "http://user:pass@localhost//srv/ftp";
- one = "http://user@localhost//srv/ftp";
+ str = "http://user:pass@localhost//srv/ftp?proxypass=@PROXYPASS@&proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS&proxypass=@PROXYPASS@&proxypass=@PROXYPASS@";
+ one = "http://user@localhost//srv/ftp?proxy=proxy.my&proxyuser=@PROXYUSER@&Xproxypass=NOTTHIS";
two = str;
url = str;
BOOST_CHECK_EQUAL( one, url.asString() );
BOOST_CHECK_EQUAL( two, url.asCompleteString() );
+ // hidden proxypass in the query is available when explicitely asked for
+ BOOST_CHECK_EQUAL( url.getQueryParam( "proxypass" ), "@PROXYPASS@" );
// absolute path defaults to 'file://'
str = "/some/local/path";
Misc.h
misc/DefaultLoadSystem.h
misc/CheckAccessDeleted.h
+ misc/TestcaseSetup.h
misc/LoadTestcase.h
)
SET( zypp_misc_SRCS
misc/DefaultLoadSystem.cc
misc/CheckAccessDeleted.cc
+ misc/TestcaseSetup.cc
misc/LoadTestcase.cc
)
if ( retval == -1 )
{
- ERR << "select error: " << strerror(errno) << endl;
- if ( errno != EINTR )
+ if ( errno != EINTR ) {
+ ERR << "select error: " << strerror(errno) << endl;
break;
+ }
}
else if ( retval )
{
#include <set>
#include <fstream>
#include <boost/function.hpp>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
#include <algorithm>
#include <zypp/base/Regex.h>
return logResult( ENOTDIR );
}
+ p.lstat(); // get dir symlinks
+ if ( !p.isDir() ) {
+ MIL << "unlink symlink ";
+ if ( ::unlink( path.asString().c_str() ) == -1 ) {
+ return logResult( errno );
+ }
+ return logResult( 0 );
+ }
+
return logResult( recursive_rmdir_1( path ) );
}
else if ( PathInfo(path_r/"/cookie").isFile() )
{ ret = repo::RepoType::RPMPLAINDIR; }
}
- MIL << "Probed cached type " << ret << " at " << path_r << endl;
+ DBG << "Probed cached type " << ret << " at " << path_r << endl;
return ret;
}
} // namespace
std::string indent;
for ( const auto & url : _pimpl->baseUrls().raw() )
{
- str << indent << url << endl;
+ str << indent << hotfix1050625::asString( url ) << endl;
if ( indent.empty() ) indent = " "; // "baseurl="
}
}
str << "path="<< path() << endl;
if ( ! (rawMirrorListUrl().asString().empty()) )
- str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
+ str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << hotfix1050625::asString( rawMirrorListUrl() ) << endl;
if ( type() != repo::RepoType::NONE )
str << "type=" << type().asString() << endl;
std::set<std::string> oldfiles;
set_difference( entries.begin(), entries.end(), repoEscAliases_r.begin(), repoEscAliases_r.end(),
std::inserter( oldfiles, oldfiles.end() ) );
+
+ // bsc#1178966: Files or symlinks here have been created by the user
+ // for whatever purpose. It's our cache, so we purge them now before
+ // they may later conflict with directories we need.
+ PathInfo pi;
for ( const std::string & old : oldfiles )
{
if ( old == Repository::systemRepoAlias() ) // don't remove the @System solv file
continue;
- filesystem::recursive_rmdir( cachePath_r / old );
+ pi( cachePath_r/old );
+ if ( pi.isDir() )
+ filesystem::recursive_rmdir( pi.path() );
+ else
+ filesystem::unlink( pi.path() );
}
}
}
if ( repokind == RepoType::NONE )
repokind = probeCache( productdatapath );
+ // NOTE: The calling code expects an empty RepoStatus being returned
+ // if the metadata cache is empty. So additioanl components like the
+ // RepoInfos status are joined after the switch IFF the status is not
+ // empty.
RepoStatus status;
switch ( repokind.toEnum() )
{
break;
case RepoType::RPMPLAINDIR_e :
- status = RepoStatus::fromCookieFile( productdatapath/"cookie" );
+ status = RepoStatus::fromCookieFile( productdatapath/"cookie" ); // dir status at last refresh
break;
case RepoType::NONE_e :
// ZYPP_THROW(RepoUnknownTypeException());
break;
}
+
+ if ( ! status.empty() )
+ status = status && RepoStatus( info );
+
return status;
}
assert_alias(info);
try
{
- MIL << "Going to try to check whether refresh is needed for " << url << " (" << info.type() << ")" << endl;
+ MIL << "Check if to refresh repo " << info.alias() << " at " << url << " (" << info.type() << ")" << endl;
// first check old (cached) metadata
Pathname mediarootpath = rawcache_path_for_repoinfo( _options, info );
filesystem::assert_dir( mediarootpath );
RepoStatus oldstatus = metadataStatus( info );
+
if ( oldstatus.empty() )
{
MIL << "No cached metadata, going to refresh" << endl;
policy = RefreshIfNeededIgnoreDelay;
}
- // now we've got the old (cached) status, we can decide repo.refresh.delay
+ // Check whether repo.refresh.delay applies...
if ( policy != RefreshIfNeededIgnoreDelay )
{
- // difference in seconds
- double diff = difftime(
- (Date::ValueType)Date::now(),
- (Date::ValueType)oldstatus.timestamp()) / 60;
+ // bsc#1174016: Prerequisite to skipping the refresh is that metadata
+ // and solv cache status match. They will not, if the repos URL was
+ // changed e.g. due to changed repovars.
+ RepoStatus cachestatus = cacheStatus( info );
- DBG << "oldstatus: " << (Date::ValueType)oldstatus.timestamp() << endl;
- DBG << "current time: " << (Date::ValueType)Date::now() << endl;
- DBG << "last refresh = " << diff << " minutes ago" << endl;
-
- if ( diff < ZConfig::instance().repo_refresh_delay() )
- {
- if ( diff < 0 )
- {
- WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
- }
- else
+ if ( oldstatus == cachestatus )
+ {
+ // difference in seconds
+ double diff = ::difftime( (Date::ValueType)Date::now(), (Date::ValueType)oldstatus.timestamp() ) / 60;
+ if ( diff < ZConfig::instance().repo_refresh_delay() )
{
- MIL << "Repository '" << info.alias()
- << "' has been refreshed less than repo.refresh.delay ("
- << ZConfig::instance().repo_refresh_delay()
- << ") minutes ago. Advising to skip refresh" << endl;
- return REPO_CHECK_DELAYED;
+ if ( diff < 0 )
+ {
+ WAR << "Repository '" << info.alias() << "' was refreshed in the future!" << endl;
+ }
+ else
+ {
+ MIL << "Repository '" << info.alias()
+ << "' has been refreshed less than repo.refresh.delay ("
+ << ZConfig::instance().repo_refresh_delay()
+ << ") minutes ago. Advising to skip refresh" << endl;
+ return REPO_CHECK_DELAYED;
+ }
}
- }
+ }
+ else {
+ MIL << "Metadata and solv cache don't match. Check data on server..." << endl;
+ }
}
repo::RepoType repokind = info.type();
case RepoType::RPMMD_e:
{
MediaSetAccess media( url );
- newstatus = yum::Downloader( info, mediarootpath ).status( media );
+ newstatus = RepoStatus( info ) && yum::Downloader( info, mediarootpath ).status( media );
}
break;
case RepoType::YAST2_e:
{
MediaSetAccess media( url );
- newstatus = susetags::Downloader( info, mediarootpath ).status( media );
+ newstatus = RepoStatus( info ) && susetags::Downloader( info, mediarootpath ).status( media );
}
break;
case RepoType::RPMPLAINDIR_e:
- newstatus = RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status
+ newstatus = RepoStatus( info ) && RepoStatus( MediaMounter(url).getPathName(info.path()) ); // dir status
break;
default:
}
else if ( repokind.toEnum() == RepoType::RPMPLAINDIR_e )
{
+ // as substitute for real metadata remember the checksum of the directory we refreshed
MediaMounter media( url );
RepoStatus newstatus = RepoStatus( media.getPathName( info.path() ) ); // dir status
#include <iostream>
#include <sstream>
#include <fstream>
+#include <set>
#include <zypp/base/Logger.h>
#include <zypp/base/String.h>
#include <zypp/RepoStatus.h>
+#include <zypp/RepoInfo.h>
#include <zypp/PathInfo.h>
using std::endl;
///////////////////////////////////////////////////////////////////
namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
+ ///////////////////////////////////////////////////////////////////
+ namespace
+ {
+ /** Recursive computation of max dir timestamp. */
+ void recursiveTimestamp( 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();
+ recursiveTimestamp( pi.path(), max_r );
+ }
+ }
+ }
+ } // namespace
+ ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
/** RepoStatus implementation. */
struct RepoStatus::Impl
{
- public:
- std::string _checksum;
- Date _timestamp;
+ using Checksums = std::set<std::string>;
- // 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.
+ public:
+ /** Assign data called from RepoStatus ctor (adds magic).
+ *
+ * \Note Changing magic will at once invalidate all solv file caches.
+ * Helpfull if solv file content must be refreshed (e.g. due to different
+ * repo2solv 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 )
{
- _checksum = std::move(checksum_r);
- _timestamp = std::move(timestamp_r);
- if ( !_checksum.empty() )
- {
+ if ( !checksum_r.empty() ) {
static const std::string magic( "43" );
- _checksum += magic;
+ checksum_r += magic;
+ _checksums.insert( std::move(checksum_r) );
}
+ _timestamp = std::move(timestamp_r);
}
- /** Recursive computation of max dir timestamp. */
- static void recursive_timestamp( const Pathname & dir_r, time_t & max_r )
+ /** Inject raw data (no magic added). */
+ void inject( std::string && checksum_r, Date && timestamp_r )
{
- std::list<std::string> dircontent;
- if ( filesystem::readdir( dircontent, dir_r, false/*no dots*/ ) != 0 )
- return; // readdir logged the error
+ if ( !checksum_r.empty() ) {
+ _checksums.insert( std::move(checksum_r) );
+ _cachedchecksum.reset();
+ }
- 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 );
+ if ( timestamp_r > _timestamp )
+ _timestamp = timestamp_r;
+ }
+
+ /** Inject the raw data from rhs */
+ void injectFrom( const Impl & rhs )
+ {
+ if ( &rhs == this ) // no self insert
+ return;
+
+ if ( !rhs._checksums.empty() ) {
+ _checksums.insert( rhs._checksums.begin(), rhs._checksums.end() );
+ _cachedchecksum.reset();
+ }
+
+ if ( rhs._timestamp > _timestamp )
+ _timestamp = rhs._timestamp;
+ }
+
+ bool empty() const
+ { return _checksums.empty(); }
+
+ std::string checksum() const
+ {
+ std::string ret;
+ if ( _checksums.empty() )
+ return ret;
+
+ if ( _checksums.size() == 1 )
+ ret = *_checksums.begin();
+ else {
+ if ( !_cachedchecksum ) {
+ std::stringstream ss;
+ for ( std::string_view c : _checksums )
+ ss << c;
+ _cachedchecksum = CheckSum::sha1(ss).checksum();
}
+ ret = *_cachedchecksum;
}
+ return ret;
}
+ Date timestamp() const
+ { return _timestamp; }
+
+ /** Dump to log file (not to/from CookieFile). */
+ std::ostream & dumpOn( std::ostream & str ) const
+ { return str << ( empty() ? "NO_REPOSTATUS" : checksum() ) << " " << time_t(_timestamp); }
+
+ private:
+ Checksums _checksums;
+ Date _timestamp;
+
+ mutable std::optional<std::string> _cachedchecksum;
+
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
/** clone for RWCOW_pointer */
};
///////////////////////////////////////////////////////////////////
- /** \relates RepoStatus::Impl Stream output */
- inline std::ostream & operator<<( std::ostream & str, const RepoStatus::Impl & obj )
- { return str << obj._checksum << " " << (time_t)obj._timestamp; }
-
///////////////////////////////////////////////////////////////////
//
// CLASS NAME : RepoStatus
else if ( info.isDir() )
{
time_t t = info.mtime();
- Impl::recursive_timestamp( path_r, t );
+ recursiveTimestamp( path_r, t );
_pimpl->assignFromCtor( CheckSum::sha1FromString( str::numstring( t ) ).checksum(), Date( t ) );
}
}
}
+ RepoStatus::RepoStatus( const RepoInfo & info_r )
+ : _pimpl( new Impl() )
+ {
+ _pimpl->assignFromCtor( CheckSum::sha1FromString( info_r.url().asString() ).checksum(), Date() );
+ }
+
RepoStatus::RepoStatus( std::string checksum_r, Date timestamp_r )
: _pimpl( new Impl() )
{
}
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;
+ // line := "[checksum] time_t" !!! strip time from line
+ std::string line { str::getline( file ) };
+ Date stmp { str::strtonum<time_t>( str::stripLastWord( line ) ) };
+ ret._pimpl->inject( std::move(line), std::move(stmp) ); // raw inject to avoid magic being added
}
return ret;
}
if (!file) {
ZYPP_THROW (Exception( "Can't open " + path_r.asString() ) );
}
- file << _pimpl->_checksum << " " << (time_t)_pimpl->_timestamp << endl;
+ file << _pimpl->checksum() << " " << time_t(_pimpl->timestamp()) << endl;
file.close();
}
bool RepoStatus::empty() const
- { return _pimpl->_checksum.empty(); }
+ { return _pimpl->empty(); }
Date RepoStatus::timestamp() const
- { return _pimpl->_timestamp; }
+ { return _pimpl->timestamp(); }
std::ostream & operator<<( std::ostream & str, const RepoStatus & obj )
- { return str << *obj._pimpl; }
+ { return obj._pimpl->dumpOn( str ); }
RepoStatus operator&&( const RepoStatus & lhs, const RepoStatus & rhs )
{
- RepoStatus result;
-
- 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 );
- std::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 );
- }
+ RepoStatus result { lhs };
+ result._pimpl->injectFrom( *rhs._pimpl );
return result;
}
bool operator==( const RepoStatus & lhs, const RepoStatus & rhs )
- { return lhs._pimpl->_checksum == rhs._pimpl->_checksum; }
+ { return lhs._pimpl->checksum() == rhs._pimpl->checksum(); }
/////////////////////////////////////////////////////////////////
} // namespace zypp
namespace zypp
{ /////////////////////////////////////////////////////////////////
+ class RepoInfo;
+
///////////////////////////////////////////////////////////////////
/// \class RepoStatus
/// \brief Track changing files or directories.
*/
explicit RepoStatus( const Pathname & path_r );
+ /** Compute status of a \a RepoInfo to track changes requiring a refresh. */
+ explicit RepoStatus( const RepoInfo & info_r );
+
/** Explicitly specify checksum string and timestamp to use. */
RepoStatus( std::string checksum_r, Date timestamp_r );
void saveToCookieFile( const Pathname & path_r ) const;
public:
- /** Whether the status is empty (default constucted) */
+ /** Whether the status is empty (empty checksum) */
bool empty() const;
/** The time the data were changed the last time */
Date timestamp() const;
public:
- struct Impl; ///< Implementation
+ struct Impl; ///< Implementation
private:
RWCOW_pointer<Impl> _pimpl; ///< Pointer to implementation
};
std::ostream & ServiceInfo::dumpAsIniOn( std::ostream & str ) const
{
RepoInfoBase::dumpAsIniOn(str)
- << "url = " << rawUrl() << endl
+ << "url = " << hotfix1050625::asString( rawUrl() ) << endl
<< "type = " << type() << endl;
if ( ttl() )
return (lhs.asCompleteString() != rhs.asCompleteString());
}
+ namespace hotfix1050625 {
+ std::string asString( const Url & url_r )
+ { return url_r.m_impl->asString1050625(); }
+ }
+
////////////////////////////////////////////////////////////////////
} // namespace zypp
//////////////////////////////////////////////////////////////////////
namespace zypp
{ ////////////////////////////////////////////////////////////////////
+ class Url;
+ namespace hotfix1050625 {
+ std::string asString( const Url & url_r );
+ }
namespace filesystem {
class Pathname;
}
setViewOptions(const ViewOptions &vopts);
private:
+ friend std::string hotfix1050625::asString( const Url & url_r );
url::UrlRef m_impl;
};
bool equivalent( IdString lVendor, IdString rVendor ) const
{ return lVendor == rVendor || vendorMatchId( lVendor ) == vendorMatchId( rVendor ); }
+ unsigned foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
+ {
+ std::map<unsigned,VendorList> lists;
+ for( const auto & el : _vendorGroupMap )
+ lists[el.second].push_back( el.first );
+
+ unsigned ret = 0;
+ for ( auto el : lists ) {
+ VendorList & vlist { el.second };
+ if ( vlist.empty() )
+ continue;
+ ++ret;
+ if ( fnc_r && !fnc_r( std::move(vlist) ) )
+ break;
+ }
+ return ret;
+ }
+
private:
using VendorGroupMap = std::map<std::string,unsigned>;
VendorGroupMap _vendorGroupMap; ///< Vendor group definition. Equivalent groups share the same ID.
void VendorAttr::_addVendorList( VendorList && vendorList_r )
{ _pimpl->addVendorList( std::move(vendorList_r) ); }
+ unsigned VendorAttr::foreachVendorList( std::function<bool(VendorList)> fnc_r ) const
+ { return _pimpl->foreachVendorList( std::move(fnc_r) ); }
+
#if LEGACY(1722)
bool VendorAttr::addVendorDirectory( const Pathname & dirname ) const
{ return const_cast<VendorAttr*>(this)->addVendorDirectory( dirname ); }
bool equivalent( const PoolItem & lVendor, const PoolItem & rVendor ) const;
public:
+ /** Call \a fnc_r for each equivalent vendor list (return \c false to break).
+ * \return The number of calls to \a fnc_r.
+ */
+ unsigned foreachVendorList( std::function<bool(VendorList)> fnc_r ) const;
+
+ public:
class Impl; ///< Implementation class.
RWCOW_pointer<Impl> _pimpl; ///< Pointer to implementation.
{
WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
_pimpl->cfg_textLocale = locale_r;
-#warning prefer signal
+ // Propagate changes
sat::Pool::instance().setTextLocale( locale_r );
}
}
#include <zypp/ZYppFactory.h>
#include <zypp/zypp_detail/ZYppImpl.h>
-#include <zypp/zypp_detail/ZYppReadOnlyHack.h>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
static bool active = getenv("ZYPP_READONLY_HACK");
- void IWantIt()
+ void IWantIt() // see zypp/zypp_detail/ZYppReadOnlyHack.h
{
active = true;
MIL << "ZYPP_READONLY promised." << endl;
#define ZYPP_BASE_FUNCTION_H
#include <boost/function.hpp>
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/bind.hpp>
#include <boost/ref.hpp>
int retval = g_poll( &fd, 1, timeout );
if ( retval == -1 )
{
- ERR << "select error: " << strerror(errno) << std::endl;
- if ( errno != EINTR )
+ if ( errno != EINTR ) {
+ ERR << "select error: " << strerror(errno) << std::endl;
return std::make_pair( ReceiveUpToResult::Error, std::string() );
+ }
}
else if ( retval )
{
#include <boost/functional.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
#include <zypp/base/Iterable.h>
class Measure::Impl
{
public:
- Impl( const std::string & ident_r )
+ Impl( const std::string & ident_r, std::ostream * log_r = nullptr )
: _ident ( ident_r )
, _level ( _glevel )
, _seq ( 0 )
+ , _log ( log_r )
{
_glevel += "..";
log() << _level << "START MEASURE(" << _ident << ")" << endl;
_elapsed = _stop;
}
- private:
/** Return the log stream. */
std::ostream & log() const
- { return INT; }
+ { return _log ? *_log : INT; }
+ std::ostream * logp() const
+ { return _log; }
+ private:
std::ostream & dumpMeasure( std::ostream & str_r, const std::string & tag_r = std::string() ) const
{
str_r << ( _stop - _start );
mutable unsigned _seq;
mutable Tm _elapsed;
mutable Tm _stop;
+
+ std::ostream * _log = nullptr;
};
std::string Measure::Impl::_glevel;
: _pimpl( new Impl( ident_r ) )
{}
+ Measure::Measure( const std::string & ident_r, std::ostream & out_r )
+ : _pimpl( new Impl( ident_r, &out_r ) )
+ {}
+
Measure::~Measure()
{}
void Measure::start( const std::string & ident_r )
- { stop(); _pimpl.reset( new Impl( ident_r ) ); }
+ { stop(); _pimpl.reset( _pimpl ? new Impl( ident_r, _pimpl->logp() ) : new Impl( ident_r ) ); }
void Measure::restart()
{ _pimpl->restart(); }
/** Ctor taking \a ident_r string and auto starts timer. */
explicit
Measure( const std::string & ident_r );
+ /** \overload log to custom ostream */
+ Measure( const std::string & ident_r, std::ostream & out_r );
/** Dtor. */
~Measure();
/** Assign */
ProvideNumericId & operator=( const ProvideNumericId & /*rhs*/ )
{ return *this; }
+ /** Move ctor */
+ ProvideNumericId( ProvideNumericId && rhs )
+ : _numericId( rhs._numericId )
+ { /*rhs._numericId = 0;*/ }
+ /** Move Assign */
+ ProvideNumericId & operator=( ProvideNumericId && rhs )
+ { if ( &rhs != this ) { _numericId = rhs._numericId; /*rhs._numericId = 0;*/ } return *this; }
/** Dtor */
~ProvideNumericId()
{}
{
#warning REIMPLEMENT
std::vector<std::string> words;
- str::split( std::string(line_r), std::back_inserter(words), ",", str::TRIM );
+ str::split( std::string(line_r), std::back_inserter(words), std::string(sep_r), str::TRIM );
+
if ( fnc_r ) {
for ( const auto & w : words )
fnc_r( std::string_view(w) );
#include <zypp/AutoDispose.h>
#include <zypp/base/LogControl.h>
#include <zypp/misc/LoadTestcase.h>
+#include <zypp/misc/TestcaseSetupImpl.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
return res;
}
- bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err )
+ bool parseSetup ( const XmlNode &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err )
{
+ auto &target = t.data();
auto architecture = setup.getProp( "arch" );
if ( !architecture.empty() )
{
target.resolverFocus = zypp::resolverFocusFromString( node->getProp("value") );
}
else if ( node->equals("system") ) {
- target.systemRepo = zypp::misc::testcase::RepoData {
+ target.systemRepo = zypp::misc::testcase::RepoDataImpl {
zypp::misc::testcase::TestcaseRepoType::Helix,
"@System",
99,
prio = zypp::str::strtonum<unsigned>( priority );
}
- target.repos.push_back( zypp::misc::testcase::RepoData{
+ target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
zypp::misc::testcase::TestcaseRepoType::Helix,
name,
prio,
{
std::string url = node->getProp("url");
std::string alias = node->getProp("name");
- target.repos.push_back( zypp::misc::testcase::RepoData{
+ target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
zypp::misc::testcase::TestcaseRepoType::Url,
alias,
99,
}
else if ( node->equals("force-install") )
{
- target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
+ target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
node->getProp("channel"),
node->getProp("package"),
node->getProp("kind")
bool parseTrialNode ( const XmlNode &node, zypp::misc::testcase::TestcaseTrial::Node &testcaseNode )
{
- testcaseNode.name = node.name();
+ testcaseNode.name() = node.name();
const auto & content = node.getContent();
if ( !content.empty() ) {
- testcaseNode.value = content;
+ testcaseNode.value() = content;
}
- testcaseNode.properties = node.getAllProps();
+ testcaseNode.properties() = node.getAllProps();
for ( auto childNode = node.children(); childNode; childNode = childNode->next() ) {
auto testNode = std::make_shared<zypp::misc::testcase::TestcaseTrial::Node>();
if ( !parseTrialNode( *childNode, *testNode ) )
return false;
- testcaseNode.children.push_back( testNode );
+ testcaseNode.children().push_back( testNode );
}
return true;
}
zypp::misc::testcase::TestcaseTrial::Node testcaseNode;
parseTrialNode( *node, testcaseNode );
- target.nodes.push_back( testcaseNode );
+ target.nodes().push_back( testcaseNode );
node = node->next();
}
return true;
#include "YamlTestcaseHelpers.h"
#include <zypp/PathInfo.h>
#include <zypp/base/LogControl.h>
-#include <zypp/Repository.h>
-#include <zypp/RepoManager.h>
-#include <zypp/sat/Pool.h>
-
-#define ZYPP_USE_RESOLVER_INTERNALS
-#include <zypp/solver/detail/SystemCheck.h>
namespace zypp::misc::testcase {
};
+ struct TestcaseTrial::Impl
+ {
+ std::vector<Node> nodes;
+ Impl *clone() const { return new Impl(*this); }
+ };
+
+ struct TestcaseTrial::Node::Impl
+ {
+ std::string name;
+ std::string value;
+ std::map<std::string, std::string> properties;
+ std::vector<std::shared_ptr<Node>> children;
+ Impl *clone() const { return new Impl(*this); }
+ };
+
+ TestcaseTrial::TestcaseTrial() : _pimpl ( new Impl() )
+ { }
+
+ TestcaseTrial::~TestcaseTrial()
+ { }
+
+ const std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes() const
+ { return _pimpl->nodes; }
+
+ std::vector<TestcaseTrial::Node> &TestcaseTrial::nodes()
+ { return _pimpl->nodes; }
+
+ TestcaseTrial::Node::Node() : _pimpl ( new Impl() )
+ { }
+
+ TestcaseTrial::Node::~Node()
+ { }
+
+ const std::string &TestcaseTrial::Node::name() const
+ { return _pimpl->name; }
+
+ std::string &TestcaseTrial::Node::name()
+ { return _pimpl->name; }
+
+ const std::string &TestcaseTrial::Node::value() const
+ { return _pimpl->value; }
+
+ std::string &TestcaseTrial::Node::value()
+ { return _pimpl->value; }
+
+ const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
+ {
+ if ( _pimpl->properties.find( name) == _pimpl->properties.end() )
+ return def;
+ return _pimpl->properties.at( name );
+ }
+
+ const std::map<std::string, std::string> &TestcaseTrial::Node::properties() const
+ { return _pimpl->properties; }
+
+ std::map<std::string, std::string> &TestcaseTrial::Node::properties()
+ { return _pimpl->properties; }
+
+ const std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children() const
+ { return _pimpl->children; }
+
+ std::vector<std::shared_ptr<TestcaseTrial::Node> > &TestcaseTrial::Node::children()
+ { return _pimpl->children; }
+
bool LoadTestcase::Impl::loadHelix(const zypp::filesystem::Pathname &filename, std::string *err)
{
xmlDocPtr xml_doc = xmlParseFile ( filename.c_str() );
// reset everything
_pimpl.reset( new Impl() );
- _pimpl->_setup.globalPath = path;
+ _pimpl->_setup.data().globalPath = path;
switch (t) {
case LoadTestcase::Helix:
return _pimpl->_trials;
}
- const std::string &TestcaseTrial::Node::getProp( const std::string &name, const std::string &def ) const
- {
- if ( properties.find( name) == properties.end() )
- return def;
- return properties.at( name );
- }
-
- bool TestcaseSetup::applySetup( RepoManager &manager) const
- {
- const auto &setup = *this;
- if ( !setup.architecture.empty() )
- {
- MIL << "Setting architecture to '" << setup.architecture << "'" << std::endl;
- ZConfig::instance().setSystemArchitecture( setup.architecture );
- setenv ("ZYPP_TESTSUITE_FAKE_ARCH", setup.architecture.c_str(), 1);
- }
-
- if ( setup.systemRepo ) {
- if (!loadRepo( manager, setup, *setup.systemRepo ) )
- {
- ERR << "Can't setup 'system'" << std::endl;
- return false;
- }
- }
-
- if ( !setup.hardwareInfoFile.empty() ) {
- setenv( "ZYPP_MODALIAS_SYSFS", setup.hardwareInfoFile.asString().c_str(), 1 );
- MIL << "setting HardwareInfo to: " << setup.hardwareInfoFile.asString() << std::endl;
- }
-
- for ( const auto &channel : setup.repos ) {
- if ( !loadRepo( manager, setup, channel ) )
- {
- ERR << "Can't setup 'channel'" << std::endl;
- return false;
- }
- }
-
- if ( !setup.systemCheck.empty() ) {
- MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
- SystemCheck::instance().setFile( setup.systemCheck );
- }
-
- return true;
- }
-
- bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
- {
- Pathname pathname = setup.globalPath + data.path;
- MIL << "'" << pathname << "'" << std::endl;
-
- Repository repo;
-
- using TrType = zypp::misc::testcase::TestcaseRepoType;
-
- if ( data.type == TrType::Url ) {
- try {
- MIL << "Load from Url '" << data.path << "'" << std::endl;
-
- RepoInfo nrepo;
- nrepo.setAlias ( data.alias );
- nrepo.setName ( data.alias );
- nrepo.setEnabled ( true );
- nrepo.setAutorefresh( false );
- nrepo.setPriority ( data.priority );
- nrepo.addBaseUrl ( Url(data.path) );
-
- manager.refreshMetadata( nrepo );
- manager.buildCache( nrepo );
- manager.loadFromCache( nrepo );
- }
- catch ( Exception & excpt_r ) {
- ZYPP_CAUGHT (excpt_r);
- ERR << "Couldn't load packages from Url '" << data.path << "'" << std::endl;
- return false;
- }
- }
- else {
- try {
- MIL << "Load from File '" << pathname << "'" << std::endl;
- zypp::Repository satRepo;
-
- if ( data.alias == "@System" ) {
- satRepo = zypp::sat::Pool::instance().systemRepo();
- } else {
- satRepo = zypp::sat::Pool::instance().reposInsert( data.alias );
- }
-
- RepoInfo nrepo;
-
- nrepo.setAlias ( data.alias );
- nrepo.setName ( data.alias );
- nrepo.setEnabled ( true );
- nrepo.setAutorefresh( false );
- nrepo.setPriority ( data.priority );
- nrepo.addBaseUrl ( pathname.asUrl() );
-
- satRepo.setInfo (nrepo);
- if ( data.type == TrType::Helix )
- satRepo.addHelix( pathname );
- else
- satRepo.addTesttags( pathname );
- MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( data.path.empty()?pathname.asString():data.path) << "." << std::endl;
- }
- catch ( Exception & excpt_r ) {
- ZYPP_CAUGHT (excpt_r);
- ERR << "Couldn't load packages from XML file '" << data.path << "'" << std::endl;
- return false;
- }
- }
- return true;
- }
-
-
-
}
#ifndef ZYPP_MISC_LOADTESTCASE_H
#define ZYPP_MISC_LOADTESTCASE_H
-#include <zypp/Arch.h>
-#include <zypp/Locale.h>
#include <zypp/Pathname.h>
-#include <zypp/ResolverFocus.h>
#include <zypp/Url.h>
#include <zypp/base/PtrTypes.h>
-#include <zypp/base/SetTracker.h>
#include <zypp/base/NonCopyable.h>
-#include <zypp/sat/Queue.h>
-#include <zypp/target/modalias/Modalias.h>
+#include <zypp/misc/TestcaseSetup.h>
#include <optional>
#include <memory>
-namespace zypp {
- class RepoManager;
-}
-
namespace zypp::misc::testcase {
- enum class TestcaseRepoType {
- Helix,
- Testtags,
- Url
- };
-
- struct RepoData {
- TestcaseRepoType type;
- std::string alias;
- uint priority = 99;
- std::string path;
- };
-
- struct ForceInstall {
- std::string channel;
- std::string package;
- std::string kind;
- };
-
- struct TestcaseSetup
- {
- Arch architecture = Arch_noarch;
-
- std::optional<RepoData> systemRepo;
- std::vector<RepoData> repos;
-
- // solver flags: default to false - set true if mentioned in <setup>
- ResolverFocus resolverFocus = ResolverFocus::Default;
-
- Pathname globalPath;
- Pathname hardwareInfoFile;
- Pathname systemCheck;
-
- target::Modalias::ModaliasList modaliasList;
- base::SetTracker<LocaleSet> localesTracker;
- sat::StringQueue autoinstalled;
- std::set<std::string> multiversionSpec;
- std::vector<ForceInstall> forceInstallTasks;
-
- bool set_licence = false;
- bool show_mediaid = false;
-
- bool ignorealreadyrecommended = false;
- bool onlyRequires = false;
- bool forceResolve = false;
- bool cleandepsOnRemove = false;
-
- bool allowDowngrade = false;
- bool allowNameChange = false;
- bool allowArchChange = false;
- bool allowVendorChange = false;
-
- bool dupAllowDowngrade = false;
- bool dupAllowNameChange = false;
- bool dupAllowArchChange = false;
- bool dupAllowVendorChange = false;
-
- bool applySetup ( zypp::RepoManager &manager ) const;
-
- static bool loadRepo (zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data );
- };
-
struct TestcaseTrial
{
struct Node {
- std::string name;
- std::string value;
+ struct Impl;
+
+ Node();
+ ~Node();
+ const std::string &name () const;
+ std::string &name ();
+ const std::string &value () const;
+ std::string &value ();
const std::string &getProp( const std::string &name, const std::string &def = std::string() ) const;
+ const std::map<std::string, std::string> &properties() const;
+ std::map<std::string, std::string> &properties();
+ const std::vector<std::shared_ptr<Node>> &children() const;
+ std::vector<std::shared_ptr<Node>> &children();
+
+ private:
+ RWCOW_pointer<Impl> _pimpl;
- std::map<std::string, std::string> properties;
- std::vector<std::shared_ptr<Node>> children;
};
- std::vector<Node> nodes;
+
+ TestcaseTrial();
+ ~TestcaseTrial();
+ const std::vector<Node> &nodes () const;
+ std::vector<Node> &nodes ();
+ private:
+ struct Impl;
+ RWCOW_pointer<Impl> _pimpl;
};
class LoadTestcase : private zypp::base::NonCopyable
--- /dev/null
+#include "TestcaseSetupImpl.h"
+
+namespace zypp::misc::testcase
+{
+ RepoData::RepoData() : _pimpl( new RepoDataImpl )
+ {}
+
+ RepoData::~RepoData()
+ { }
+
+ RepoData::RepoData(RepoDataImpl &&data) : _pimpl( new RepoDataImpl( std::move(data)) )
+ { }
+
+ TestcaseRepoType RepoData::type() const
+ { return _pimpl->type; }
+
+ const std::string &RepoData::alias() const
+ { return _pimpl->alias; }
+
+ uint RepoData::priority() const
+ { return _pimpl->priority; }
+
+ const std::string &RepoData::path() const
+ { return _pimpl->path; }
+
+ const RepoDataImpl &RepoData::data() const
+ { return *_pimpl; }
+
+ RepoDataImpl &RepoData::data()
+ { return *_pimpl; }
+
+ ForceInstall::ForceInstall() : _pimpl( new ForceInstallImpl )
+ { }
+
+ ForceInstall::~ForceInstall()
+ { }
+
+ ForceInstall::ForceInstall(ForceInstallImpl &&data) : _pimpl( new ForceInstallImpl( std::move(data) ))
+ { }
+
+ const ForceInstallImpl &ForceInstall::data() const
+ { return *_pimpl; }
+
+ ForceInstallImpl &ForceInstall::data()
+ { return *_pimpl; }
+
+ const std::string &ForceInstall::channel() const
+ { return _pimpl->channel; }
+
+ const std::string &ForceInstall::package() const
+ { return _pimpl->package; }
+
+ const std::string &ForceInstall::kind() const
+ { return _pimpl->kind; }
+
+ TestcaseSetup::TestcaseSetup() : _pimpl( new TestcaseSetupImpl )
+ { }
+
+ TestcaseSetup::~TestcaseSetup()
+ { }
+
+ Arch TestcaseSetup::architecture() const
+ { return _pimpl->architecture; }
+
+ const std::optional<RepoData> &TestcaseSetup::systemRepo() const
+ { return _pimpl->systemRepo; }
+
+ const std::vector<RepoData> &TestcaseSetup::repos() const
+ { return _pimpl->repos; }
+
+ ResolverFocus TestcaseSetup::resolverFocus() const
+ { return _pimpl->resolverFocus; }
+
+ const zypp::filesystem::Pathname &TestcaseSetup::globalPath() const
+ { return _pimpl->globalPath; }
+
+ const zypp::filesystem::Pathname &TestcaseSetup::hardwareInfoFile() const
+ { return _pimpl->hardwareInfoFile; }
+
+ const zypp::filesystem::Pathname &TestcaseSetup::systemCheck() const
+ { return _pimpl->systemCheck; }
+
+ const target::Modalias::ModaliasList &TestcaseSetup::modaliasList() const
+ { return _pimpl->modaliasList; }
+
+ const base::SetTracker<LocaleSet> &TestcaseSetup::localesTracker() const
+ { return _pimpl->localesTracker; }
+
+ const std::vector<std::vector<std::string> > &TestcaseSetup::vendorLists() const
+ { return _pimpl->vendorLists; }
+
+ const sat::StringQueue &TestcaseSetup::autoinstalled() const
+ { return _pimpl->autoinstalled; }
+
+ const std::set<std::string> &TestcaseSetup::multiversionSpec() const
+ { return _pimpl->multiversionSpec; }
+
+ const std::vector<ForceInstall> &TestcaseSetup::forceInstallTasks() const
+ { return _pimpl->forceInstallTasks; }
+
+ bool TestcaseSetup::set_licence() const
+ { return _pimpl->set_licence; }
+
+ bool TestcaseSetup::show_mediaid() const
+ { return _pimpl->show_mediaid; }
+
+ bool TestcaseSetup::ignorealreadyrecommended() const
+ { return _pimpl->ignorealreadyrecommended; }
+
+ bool TestcaseSetup::onlyRequires() const
+ { return _pimpl->onlyRequires; }
+
+ bool TestcaseSetup::forceResolve() const
+ { return _pimpl->forceResolve; }
+
+ bool TestcaseSetup::cleandepsOnRemove() const
+ { return _pimpl->cleandepsOnRemove; }
+
+ bool TestcaseSetup::allowDowngrade() const
+ { return _pimpl->allowDowngrade; }
+
+ bool TestcaseSetup::allowNameChange() const
+ { return _pimpl->allowNameChange; }
+
+ bool TestcaseSetup::allowArchChange() const
+ { return _pimpl->allowArchChange; }
+
+ bool TestcaseSetup::allowVendorChange() const
+ { return _pimpl->allowVendorChange; }
+
+ bool TestcaseSetup::dupAllowDowngrade() const
+ { return _pimpl->dupAllowDowngrade; }
+
+ bool TestcaseSetup::dupAllowNameChange() const
+ { return _pimpl->dupAllowNameChange; }
+
+ bool TestcaseSetup::dupAllowArchChange() const
+ { return _pimpl->dupAllowArchChange; }
+
+ bool TestcaseSetup::dupAllowVendorChange() const
+ { return _pimpl->dupAllowVendorChange; }
+
+ bool TestcaseSetup::applySetup( zypp::RepoManager &manager ) const
+ {
+ const auto &setup = data();
+ if ( !setup.architecture.empty() )
+ {
+ MIL << "Setting architecture to '" << setup.architecture << "'" << std::endl;
+ ZConfig::instance().setSystemArchitecture( setup.architecture );
+ setenv ("ZYPP_TESTSUITE_FAKE_ARCH", setup.architecture.c_str(), 1);
+ }
+
+ if ( setup.systemRepo ) {
+ if (!loadRepo( manager, *this, *setup.systemRepo ) )
+ {
+ ERR << "Can't setup 'system'" << std::endl;
+ return false;
+ }
+ }
+
+ if ( !setup.hardwareInfoFile.empty() ) {
+ setenv( "ZYPP_MODALIAS_SYSFS", setup.hardwareInfoFile.asString().c_str(), 1 );
+ MIL << "setting HardwareInfo to: " << setup.hardwareInfoFile.asString() << std::endl;
+ }
+
+ for ( const auto &channel : setup.repos ) {
+ if ( !loadRepo( manager, *this, channel ) )
+ {
+ ERR << "Can't setup 'channel'" << std::endl;
+ return false;
+ }
+ }
+
+ if ( !setup.systemCheck.empty() ) {
+ MIL << "setting systemCheck to: " << setup.systemCheck.asString() << std::endl;
+ SystemCheck::instance().setFile( setup.systemCheck );
+ }
+
+ return true;
+ }
+
+ bool TestcaseSetup::loadRepo( zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data )
+ {
+ const auto &repoData = data.data();
+ Pathname pathname = setup._pimpl->globalPath + repoData.path;
+ MIL << "'" << pathname << "'" << std::endl;
+
+ Repository repo;
+
+ using TrType = zypp::misc::testcase::TestcaseRepoType;
+
+ if ( repoData.type == TrType::Url ) {
+ try {
+ MIL << "Load from Url '" << repoData.path << "'" << std::endl;
+
+ RepoInfo nrepo;
+ nrepo.setAlias ( repoData.alias );
+ nrepo.setName ( repoData.alias );
+ nrepo.setEnabled ( true );
+ nrepo.setAutorefresh( false );
+ nrepo.setPriority ( repoData.priority );
+ nrepo.addBaseUrl ( Url(repoData.path) );
+
+ manager.refreshMetadata( nrepo );
+ manager.buildCache( nrepo );
+ manager.loadFromCache( nrepo );
+ }
+ catch ( Exception & excpt_r ) {
+ ZYPP_CAUGHT (excpt_r);
+ ERR << "Couldn't load packages from Url '" << repoData.path << "'" << std::endl;
+ return false;
+ }
+ }
+ else {
+ try {
+ MIL << "Load from File '" << pathname << "'" << std::endl;
+ zypp::Repository satRepo;
+
+ if ( repoData.alias == "@System" ) {
+ satRepo = zypp::sat::Pool::instance().systemRepo();
+ } else {
+ satRepo = zypp::sat::Pool::instance().reposInsert( repoData.alias );
+ }
+
+ RepoInfo nrepo;
+
+ nrepo.setAlias ( repoData.alias );
+ nrepo.setName ( repoData.alias );
+ nrepo.setEnabled ( true );
+ nrepo.setAutorefresh( false );
+ nrepo.setPriority ( repoData.priority );
+ nrepo.addBaseUrl ( pathname.asUrl() );
+
+ satRepo.setInfo (nrepo);
+ if ( repoData.type == TrType::Helix )
+ satRepo.addHelix( pathname );
+ else
+ satRepo.addTesttags( pathname );
+ MIL << "Loaded " << satRepo.solvablesSize() << " resolvables from " << ( repoData.path.empty()?pathname.asString():repoData.path) << "." << std::endl;
+ }
+ catch ( Exception & excpt_r ) {
+ ZYPP_CAUGHT (excpt_r);
+ ERR << "Couldn't load packages from XML file '" << repoData.path << "'" << std::endl;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ TestcaseSetupImpl &TestcaseSetup::data()
+ {
+ return *_pimpl;
+ }
+
+ const TestcaseSetupImpl &TestcaseSetup::data() const
+ {
+ return *_pimpl;
+ }
+
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/misc/TestcaseSetup.h
+ *
+*/
+
+#ifndef ZYPP_MISC_TESTCASESETUP_H
+#define ZYPP_MISC_TESTCASESETUP_H
+
+#include <zypp/Arch.h>
+#include <zypp/Locale.h>
+#include <zypp/Pathname.h>
+#include <zypp/ResolverFocus.h>
+#include <zypp/Url.h>
+#include <zypp/base/PtrTypes.h>
+#include <zypp/base/SetTracker.h>
+#include <zypp/sat/Queue.h>
+#include <zypp/target/modalias/Modalias.h>
+
+#include <optional>
+#include <vector>
+
+namespace zypp {
+ class RepoManager;
+}
+
+namespace zypp::misc::testcase
+{
+
+ enum class TestcaseRepoType {
+ Helix,
+ Testtags,
+ Url
+ };
+
+ struct RepoDataImpl;
+ struct ForceInstallImpl;
+ struct TestcaseSetupImpl;
+
+ class RepoData {
+ public:
+ RepoData ();
+ ~RepoData ();
+ RepoData ( RepoDataImpl &&data );
+ TestcaseRepoType type() const;
+ const std::string &alias() const;
+ uint priority() const;
+ const std::string &path() const;
+
+ const RepoDataImpl &data() const;
+ RepoDataImpl &data();
+ private:
+ RWCOW_pointer<RepoDataImpl> _pimpl;
+ };
+
+ class ForceInstall {
+ public:
+ ForceInstall ();
+ ~ForceInstall ();
+ ForceInstall ( ForceInstallImpl &&data );
+ const std::string &channel () const;
+ const std::string &package () const;
+ const std::string &kind () const;
+
+ const ForceInstallImpl &data() const;
+ ForceInstallImpl &data();
+ private:
+ RWCOW_pointer<ForceInstallImpl> _pimpl;
+ };
+
+ class TestcaseSetup
+ {
+ public:
+
+ TestcaseSetup();
+ ~TestcaseSetup();
+
+ Arch architecture () const;
+
+ const std::optional<RepoData> &systemRepo() const;
+ const std::vector<RepoData> &repos() const;
+
+ // solver flags: default to false - set true if mentioned in <setup>
+ ResolverFocus resolverFocus() const;
+
+ const Pathname &globalPath() const;
+ const Pathname &hardwareInfoFile() const;
+ const Pathname &systemCheck() const;
+
+ const target::Modalias::ModaliasList &modaliasList() const;
+ const base::SetTracker<LocaleSet> &localesTracker() const;
+ const std::vector<std::vector<std::string>> &vendorLists() const;
+ const sat::StringQueue &autoinstalled() const;
+ const std::set<std::string> &multiversionSpec() const;
+ const std::vector<ForceInstall> &forceInstallTasks() const;
+
+ bool set_licence() const;
+ bool show_mediaid() const;
+
+ bool ignorealreadyrecommended() const;
+ bool onlyRequires() const;
+ bool forceResolve() const;
+ bool cleandepsOnRemove() const;
+
+ bool allowDowngrade() const;
+ bool allowNameChange() const;
+ bool allowArchChange() const;
+ bool allowVendorChange() const;
+
+ bool dupAllowDowngrade() const;
+ bool dupAllowNameChange() const;
+ bool dupAllowArchChange() const;
+ bool dupAllowVendorChange() const;
+
+ bool applySetup ( zypp::RepoManager &manager ) const;
+
+ static bool loadRepo (zypp::RepoManager &manager, const TestcaseSetup &setup, const RepoData &data );
+
+ TestcaseSetupImpl &data();
+ const TestcaseSetupImpl &data() const;
+
+ private:
+ RWCOW_pointer<TestcaseSetupImpl> _pimpl;
+ };
+
+}
+
+
+#endif // ZYPP_MISC_TESTCASESETUPIMPL_H
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_MISC_TESTCASESETUPIMPL_H
+#define ZYPP_MISC_TESTCASESETUPIMPL_H
+
+#include <zypp/misc/TestcaseSetup.h>
+#include <zypp/ZConfig.h>
+#include <zypp/base/LogControl.h>
+#include <zypp/Repository.h>
+#include <zypp/RepoManager.h>
+#include <zypp/sat/Pool.h>
+
+#define ZYPP_USE_RESOLVER_INTERNALS
+#include <zypp/solver/detail/SystemCheck.h>
+
+namespace zypp::misc::testcase
+{
+ struct RepoDataImpl {
+ TestcaseRepoType type;
+ std::string alias;
+ uint priority = 99;
+ std::string path;
+
+ RepoDataImpl *clone () const { return new RepoDataImpl(*this); }
+ };
+
+ struct ForceInstallImpl {
+ std::string channel;
+ std::string package;
+ std::string kind;
+
+ ForceInstallImpl *clone () const { return new ForceInstallImpl(*this); }
+ };
+
+ struct TestcaseSetupImpl
+ {
+ Arch architecture = Arch_noarch;
+
+ std::optional<RepoData> systemRepo;
+ std::vector<RepoData> repos;
+
+ // solver flags: default to false - set true if mentioned in <setup>
+ ResolverFocus resolverFocus = ResolverFocus::Default;
+
+ Pathname globalPath;
+ Pathname hardwareInfoFile;
+ Pathname systemCheck;
+
+ target::Modalias::ModaliasList modaliasList;
+ base::SetTracker<LocaleSet> localesTracker;
+ std::vector<std::vector<std::string>> vendorLists;
+ sat::StringQueue autoinstalled;
+ std::set<std::string> multiversionSpec;
+ std::vector<ForceInstall> forceInstallTasks;
+
+ bool set_licence = false;
+ bool show_mediaid = false;
+
+ bool ignorealreadyrecommended = false;
+ bool onlyRequires = false;
+ bool forceResolve = false;
+ bool cleandepsOnRemove = false;
+
+ bool allowDowngrade = false;
+ bool allowNameChange = false;
+ bool allowArchChange = false;
+ bool allowVendorChange = false;
+
+ bool dupAllowDowngrade = false;
+ bool dupAllowNameChange = false;
+ bool dupAllowArchChange = false;
+ bool dupAllowVendorChange = false;
+
+ TestcaseSetupImpl *clone () const { return new TestcaseSetupImpl(*this); }
+ };
+}
+
+#endif
#include <zypp/base/LogControl.h>
#include "LoadTestcase.h"
+#include "TestcaseSetupImpl.h"
#include <yaml-cpp/yaml.h>
namespace yamltest::detail {
- bool parseSetup ( const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &target, std::string *err ) {
+ bool parseSetup ( const YAML::Node &setup, zypp::misc::testcase::TestcaseSetup &t, std::string *err ) {
+ auto &target = t.data();
MIL << "Parsing setup node " << std::endl;
for ( YAML::const_iterator it = setup.begin(); it != setup.end(); it++ ) {
target.resolverFocus = zypp::resolverFocusFromString( data["focus"].as<std::string>() );
}
} else if ( key == ("system") ) {
- target.systemRepo = zypp::misc::testcase::RepoData {
+ target.systemRepo = zypp::misc::testcase::RepoDataImpl {
zypp::misc::testcase::TestcaseRepoType::Testtags,
"@System",
99,
if ( dataNode["priority"] )
prio = dataNode["priority"].as<unsigned>();
- target.repos.push_back( zypp::misc::testcase::RepoData{
+ target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
zypp::misc::testcase::TestcaseRepoType::Testtags,
name,
prio,
bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
std::string url = dataNode["url"].as<std::string>();
std::string alias = dataNode["name"].as<std::string>();
- target.repos.push_back( zypp::misc::testcase::RepoData{
+ target.repos.push_back( zypp::misc::testcase::RepoDataImpl{
zypp::misc::testcase::TestcaseRepoType::Url,
alias,
99,
else if ( key == ("force-install") )
{
bool success = readListInlineOrFromFile( [&target]( const YAML::Node &dataNode, auto ){
- target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstall{
+ target.forceInstallTasks.push_back( zypp::misc::testcase::ForceInstallImpl{
dataNode["channel"].as<std::string>(),
dataNode["package"].as<std::string>(),
dataNode["kind"].as<std::string>()
}, err );
if ( !success ) return false;
}
+ else if ( key == ("vendors") )
+ {
+ bool success = readListInlineOrFromFile( [&target]( const YAML::Node & dataNode, std::string * err ) {
+ std::vector<std::string> vlist;
+ for ( const auto & node : dataNode )
+ vlist.push_back( node.as<std::string>() );
+ if ( ! vlist.empty() )
+ target.vendorLists.push_back( std::move(vlist) );
+ return true;
+ }, err );
+ if ( !success ) return false;
+ }
else if ( key == ("autoinst") ) {
bool success = readListInlineOrFromFile( [&]( const YAML::Node &dataNode, auto ){
target.autoinstalled.push( zypp::IdString( dataNode.as<std::string>() ).id() );
const std::string &key = elem.first.as<std::string>();
const auto &data = elem.second;
if ( key == "job" ) {
- n.name = data.as<std::string>();
+ n.name() = data.as<std::string>();
} else if ( key == "__content") {
- n.value = data.as<std::string>();
+ n.value() = data.as<std::string>();
} else {
if( data.IsScalar() ) {
- n.properties.insert( { key, data.as<std::string>() } );
+ n.properties().insert( { key, data.as<std::string>() } );
} if ( data.IsSequence() ) {
// if the type of a data field is a sequence, we treat all the elements in there
// as sub elements. Just like in XML you can have sub nodes its the same here
// the key name is ignored in those cases and can be chosen freely
- if ( !parseJobs( data, n.children, err ) )
+ if ( !parseJobs( data, n.children(), err ) )
return false;
} else if ( data.IsMap() ) {
// if the type of a data field is a map, we build a child node from it.
// Just like with sequence but a single field.
// The key name is ignored in those cases and can be chosen freely
- if ( !parseSingleJob( data, n.children, err) )
+ if ( !parseSingleJob( data, n.children(), err) )
return false;
} else {
ERR << "Ignoring field " << key << " with unsupported type." << std::endl;
bool parseTrial ( const YAML::Node &trial, zypp::misc::testcase::TestcaseTrial &target, std::string *err ) {
MIL << "Parsing trials." << std::endl;
- return parseJobs( trial, target.nodes, err );
+ return parseJobs( trial, target.nodes(), err );
}
}
else if ( it->first == "path" )
info.setPath( Pathname(it->second) );
else if ( it->first == "type" )
- info.setType(repo::RepoType(it->second));
+ ; // bsc#1177427 et.al.: type in a .repo file is legacy - ignore it and let RepoManager probe
else if ( it->first == "autorefresh" )
info.setAutorefresh( str::strToTrue( it->second ) );
else if ( it->first == "mirrorlist" && !it->second.empty())
Url RepoVariablesUrlReplacer::operator()( const Url & value ) const
{
Url::ViewOptions toReplace = value.getViewOptions() - url::ViewOption::WITH_USERNAME - url::ViewOption::WITH_PASSWORD;
- const std::string & replaced( RepoVarExpand()( value.asString( toReplace ), RepoVarsMap::lookup ) );
+ // Legacy: Not 100% correct because it substitutes inside the 'proxypass=' value,
+ // but this was done before as well. The final fix will have to keep the proxypasswd
+ // out side the url in a cedential file.
+ Url tmpurl { value };
+ tmpurl.setViewOptions( toReplace );
+ const std::string & replaced( RepoVarExpand()( hotfix1050625::asString( tmpurl ), RepoVarsMap::lookup ) );
+
Url newurl;
if ( !replaced.empty() )
{
+++ /dev/null
-/*---------------------------------------------------------------------\
-| ____ _ __ __ ___ |
-| |__ / \ / / . \ . \ |
-| / / \ V /| _/ _/ |
-| / /__ | | | | | | |
-| /_____||_| |_| |_| |
-| |
-\---------------------------------------------------------------------*/
-/** \file zypp/sat/AttrMatcher.h
- *
-*/
-#ifndef ZYPP_SAT_ATTRMATCHER_H
-#define ZYPP_SAT_ATTRMATCHER_H
-#warning sat::AttrMatcher was renamed to StrMatcher. Deprecated include of zypp/sat/AttrMatcher.h use zypp/base/StrMatcher.h
-
-#include <zypp/base/StrMatcher.h>
-
-///////////////////////////////////////////////////////////////////
-namespace zypp
-{
- ///////////////////////////////////////////////////////////////////
- namespace sat
- {
- typedef StrMatcher AttrMatcher;
-
- } // namespace sat
- ///////////////////////////////////////////////////////////////////
-} // namespace zypp
-///////////////////////////////////////////////////////////////////
-#endif // ZYPP_SAT_ATTRMATCHER_H
const SolvAttr SolvAttr::allAttr( detail::noId );
const SolvAttr SolvAttr::noAttr;
-#warning STILL ATTRIBUTES HERE WHICH ARE NOT PROVIDED BY SOLV FILES
+// There are some attributes here which are not provided by solv files.
// At least the ones that do nat have a solv/knownid.
const SolvAttr SolvAttr::name ( SOLVABLE_NAME );
#include <fstream>
#include <sstream>
#include <streambuf>
-#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
#define ZYPP_USE_RESOLVER_INTERNALS
#include <zypp/PathInfo.h>
#include <zypp/ResPool.h>
#include <zypp/Repository.h>
+#include <zypp/VendorAttr.h>
#include <zypp/target/modalias/Modalias.h>
#include <zypp/sat/detail/PoolImpl.h>
bool Testcase::createTestcase(Resolver & resolver, bool dumpPool, bool runSolver)
{
+ MIL << "createTestcase at " << dumpPath << (dumpPool?" dumpPool":"") << (runSolver?" runSolver":"") << endl;
PathInfo path (dumpPath);
if ( !path.isExist() ) {
}
yOut << YAML::EndSeq; // locales
+ // Vendor settings
+ yOut << YAML::Key << "vendors" << YAML::Value << YAML::BeginSeq ;
+ VendorAttr::instance().foreachVendorList( [&]( VendorAttr::VendorList vlist )->bool {
+ if ( ! vlist.empty() ) {
+ yOut << YAML::Value << YAML::BeginSeq;
+ for( const auto & v : vlist )
+ yOut << YAML::Value << v ;
+ yOut << YAML::EndSeq;
+ }
+ return true;
+ } );
+ yOut << YAML::EndSeq; // vendors
+
// helper lambda to write a list of elements into a external file instead of the main file
const auto &writeListOrFile = [&]( const std::string &name, const auto &list, const auto &callback ) {
if ( list.size() > 10 ) {
std::ofstream fout( dumpPath+"/zypp-control.yaml" );
fout << yOut.c_str();
+ MIL << "createTestcase done at " << dumpPath << endl;
return true;
}
///////////////////////////////////////////////////////////////////
continue;
}
-#warning Exception handling
// create a installation progress report proxy
RpmInstallPackageReceiver progress( citem.resolvable() );
progress.connect(); // disconnected on destruction.
if ( root_r.empty() )
root_r = "/";
- // NOTE: Former argument, but now locked to "/var/lib/rpm".
- // A custom dbPath is not actually needed and would only work
- // reliably if libsolv also supports it. By now no further
- // cleanup in the code.
- const Pathname & dbPath_r { librpmDb::defaultDbPath() };
+ const Pathname & dbPath_r { librpmDb::suggestedDbPath( root_r ) }; // also asserts root_r is absolute
- if ( ! root_r.absolute() )
+ // The rpmdb compat symlink.
+ // Required at least until rpmdb2solv takes a dppath argument.
+ // Otherwise it creates a db at "/var/lib/rpm".
+ if ( dbPath_r != "/var/lib/rpm" && ! PathInfo( root_r/"/var/lib/rpm" ).isExist() )
{
- ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
- ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
+ WAR << "Inject missing /var/lib/rpm compat symlink to " << dbPath_r << endl;
+ filesystem::assert_dir( root_r/"/var/lib" );
+ filesystem::symlink( "../../"/dbPath_r, root_r/"/var/lib/rpm" );
}
- if ( ! PathInfo( root_r/"/var/lib/rpm" ).isExist()
- && PathInfo( root_r/"/usr/lib/sysimage/rpm" ).isDir() )
- {
- WAR << "Rpm package was deleted? Injecting missing rpmdb compat symlink." << endl;
- filesystem::symlink( "../../usr/lib/sysimage/rpm", root_r/"/var/lib/rpm" );
- }
-
- MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
- << ( doRebuild_r ? " (rebuilddb)" : "" )
- << ( quickinit ? " (quickinit)" : "" ) << endl;
-
///////////////////////////////////////////////////////////////////
// Check whether already initialized
///////////////////////////////////////////////////////////////////
if ( initialized() )
{
- if ( root_r == _root && dbPath_r == _dbPath )
- {
+ // Just check for a changing root because the librpmDb::suggestedDbPath
+ // may indeed change: rpm %post moving the db from /var/lib/rpm
+ // to /usr/lib/sysimage/rpm. We continue to use the old dbpath
+ // (via the compat symlink) until a re-init.
+ if ( root_r == _root ) {
+ MIL << "Calling initDatabase: already initialized at " << stringPath( _root, _dbPath ) << endl;
return;
}
else
- {
ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
- }
}
+ MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
+ << ( doRebuild_r ? " (rebuilddb)" : "" )
+ << ( quickinit ? " (quickinit)" : "" ) << endl;
+
///////////////////////////////////////////////////////////////////
// init database
///////////////////////////////////////////////////////////////////
}
/**
- * Prepare access to the rpm database at \c/var/lib/rpm.
+ * Prepare access to the rpm database below \a root_r.
*
* An optional argument denotes the root directory for all operations. If
* an empty Pathname is given the default (\c/) is used.
{
return int_val( RPMTAG_BUILDTIME );
}
-#warning CHECK IF FILE REQUIRES HANDLING IS OBSOLETE
+
///////////////////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////////////////
-Pathname librpmDb::_defaultRoot ( "/" );
-// NOTE: Former variable, but now locked to "/var/lib/rpm".
-// A custom dbPath is not actually needed and would only work
-// reliably if libsolv also supports it.
-// The protected librpmDb ctor would allow to build a db_const_iterator
-// to access (ro) a database at a custom location.
-const Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
+Pathname librpmDb::_defaultRoot { "/" };
+Pathname librpmDb::_defaultDbPath; // set in dbAccess depending on suggestedDbPath below /root
+Pathname librpmDb::_rpmDefaultDbPath; // set by globalInit
librpmDb::constPtr librpmDb::_defaultDb;
-bool librpmDb::_dbBlocked ( true );
+bool librpmDb::_dbBlocked = true;
///////////////////////////////////////////////////////////////////
//
}
initialized = true; // Necessary to be able to use exand().
+ _rpmDefaultDbPath = expand( "%{_dbpath}" );
-#define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
- MIL << "librpm init done:"
- OUTVAL(_target)
- OUTVAL(_dbpath)
- << endl;
-#undef OUTVAL
+ MIL << "librpm init done: (_target:" << expand( "%{_target}" ) << ") (_dbpath:" << _rpmDefaultDbPath << ")" << endl;
return initialized;
}
return ret;
}
+
+Pathname librpmDb::suggestedDbPath( const Pathname & root_r )
+{
+ if ( ! root_r.absolute() )
+ ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
+
+ // initialize librpm (for _rpmDefaultDbPath)
+ if ( ! globalInit() )
+ ZYPP_THROW(GlobalRpmInitException());
+
+ if ( PathInfo( root_r ).isDir() ) {
+ // If a known dbpath exsists, we continue to use it
+ for ( auto p : { "/var/lib/rpm", "/usr/lib/sysimage/rpm" } ) {
+ if ( PathInfo( root_r/p, PathInfo::LSTAT/*!no symlink*/ ).isDir() ) {
+ MIL << "Suggest existing database at " << stringPath( root_r, p ) << endl;
+ return p;
+ }
+ }
+ }
+
+ MIL << "Suggest rpm _dbpath " << stringPath( root_r, _rpmDefaultDbPath ) << endl;
+ return _rpmDefaultDbPath;
+}
+
///////////////////////////////////////////////////////////////////
//
//
}
// got no database: we could switch to a new one (even if blocked!)
-
- if ( root_r.empty() || ! root_r.absolute() )
- ZYPP_THROW(RpmInvalidRootException(root_r, _defaultDbPath));
-
- PathInfo pi { root_r / _defaultDbPath };
- if ( pi.isExist() && ! pi.isDir() ) {
- RpmInvalidRootException excpt { root_r, _defaultDbPath };
- excpt.addHistory( str::Str() << pi );
- ZYPP_THROW(excpt);
- }
-
+ _defaultDbPath = suggestedDbPath( root_r ); // also asserts root_r is absolute
_defaultRoot = root_r;
- MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
+ MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
return dbAccess();
}
{
if ( ! create( RPMDBI_PACKAGES ) )
return false;
-#warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
#ifdef RPMFILEITERMAX // since rpm.4.12
::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
#else
if ( !_mi )
return 0;
int ret = ::rpmdbGetIteratorCount( _mi );
-#warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
return( ret ? ret : -1 ); // -1: sequential access
}
};
/**
* Current root directory for all operations.
- * (initialy /)
+ * (initially /)
**/
static Pathname _defaultRoot;
/**
* Current directory (below root) that contains the rpmdb.
- * (initialy /var/lib/rpm)
**/
- static const Pathname _defaultDbPath;
+ static Pathname _defaultDbPath;
+
+ /**
+ * %_dbpath configured in rpm config.
+ **/
+ static Pathname _rpmDefaultDbPath;
/**
* Current rpmdb handle.
}
/**
+ * \return The preferred location of the rpmdb below \a root_r.
+ * It's the location of an already exising db, otherwise the
+ * default location sugested by rpms config.
+ *
+ * \throws RpmInvalidRootException if root is not an absolute path or
+ * no directory for the rpmdb can determined.
+ **/
+ static Pathname suggestedDbPath( const Pathname & root_r );
+
+ /**
* Adjust access to the given database location, making it the new
* default location on success. No relative Pathnames are allowed.
*
static inline PoolProxyIterator pkgBegin() { return poolProxyBegin<Package>(); }
static inline PoolProxyIterator pkgEnd() { return poolProxyEnd<Package>(); }
-// static inline PoolProxyIterator langBegin() { return poolProxyBegin<Language>(); }
-// static inline PoolProxyIterator langEnd() { return poolProxyEnd<Language>(); }
-
static inline PoolProxyIterator patchesBegin() { return poolProxyBegin<Patch>(); }
static inline PoolProxyIterator patchesEnd() { return poolProxyEnd<Patch>(); }
static void addDirectlySelectedPackages ( set<string> & pkgNames );
template<class PkgSet_T> void addPkgSetPackages( set<string> & pkgNames );
- static void addPatternPackages ( set<string> & pkgNames );
static void addPatchPackages ( set<string> & pkgNames );
DBG << "Collecting packages the user explicitly asked for" << endl;
addDirectlySelectedPackages ( pkgNames );
- addPatternPackages ( pkgNames );
addPatchPackages ( pkgNames );
return pkgNames;
}
-
- static void addPatternPackages( set<string> & pkgNames )
- {
- addPkgSetPackages<Pattern>( pkgNames );
- }
-
-
- /**
- * Template to handle Patterns
- **/
- template<class PkgSet_T> void addPkgSetPackages( set<string> & pkgNames )
- {
- for ( PoolProxyIterator it = poolProxyBegin<PkgSet_T>();
- it != poolProxyEnd<PkgSet_T>();
- ++it )
- {
- // Take all pkg sets (patterns) into account that
- // will be transacted, no matter if the user explicitly asked
- // for that pkg set or if the patterns is required by another
- // pkg set of the same class
-
- typename PkgSet_T::constPtr pkgSet = dynamic_pointer_cast<const PkgSet_T>( (*it)->theObj() ? (*it)->theObj().resolvable() : 0L );
-
- if ( pkgSet && (*it)->toModify() )
- {
- DBG << (*it)->theObj()->kind().asString()
- << " will be transacted: \"" << pkgSet->name() << "\"" << endl;
-
-#warning NEEDS FIX
- set<string> setPkgs;// = pkgSet->install_packages();
- pkgNames.insert( setPkgs.begin(), setPkgs.end() );
- }
- }
- }
-
-
static void addPatchPackages( set<string> & pkgNames )
{
for ( PoolProxyIterator patch_it = patchesBegin();
#include <zypp/base/String.h>
#include <zypp/base/Gettext.h>
#include <zypp/base/Regex.h>
+#include <zypp/base/StringV.h>
#include <stdexcept>
#include <climits>
const ViewOption ViewOption::EMPTY_QUERY_STR = 0x1000;
const ViewOption ViewOption::EMPTY_FRAGMENT = 0x2000;
const ViewOption ViewOption::DEFAULTS = 0x07bb;
+
+ const ViewOption ViewOption::hotfix1050625 = 0x8000;
/*
const ViewOption ViewOption::DEFAULTS =
ViewOption::WITH_SCHEME +
// ---------------------------------------------------------------
+
+ /// \brief Hide passwords embedded in a querystr,
+ ///
+ /// Stores the full querystring and maintains a safe version with
+ /// password field stripped. Url::asString will print the passwords
+ /// on demand only.
+ ///
+ /// \see bsc#1050625: VUL-1: CVE-2017-9271: zypper: proxy credentials written to log files
+ class SafeQuerystr
+ {
+ public:
+ SafeQuerystr()
+ {}
+
+ SafeQuerystr( std::string rhs )
+ { _assign( std::move(rhs) ); }
+
+ SafeQuerystr & operator=( std::string rhs )
+ { _assign( std::move(rhs) ); return *this; }
+
+
+ operator const std::string &() const
+ { return str(); }
+
+ const std::string & str() const
+ { return fullStr(); }
+
+ const std::string & str( const ViewOptions & viewopts_r ) const
+ { return (viewopts_r.has( ViewOptions::WITH_PASSWORD ) || viewopts_r.has( ViewOptions::hotfix1050625 )) ? fullStr() : safeStr(); }
+
+ const std::string & fullStr() const
+ { return _fullQuerytsr; }
+
+ const std::string & safeStr() const
+ { return _safeQuerytsr ? _safeQuerytsr.value() : _fullQuerytsr; }
+
+ private:
+ void _assign( std::string && rhs )
+ {
+ _fullQuerytsr = std::move(rhs);
+
+ static constexpr std::string_view tag { "proxypass=" };
+ if ( _fullQuerytsr.find( tag ) != std::string::npos )
+ {
+ std::string safe;
+ strv::split( _fullQuerytsr, "&", [&safe]( std::string_view val ) {
+ if ( val.substr( 0, tag.size() ) != tag ) {
+ if ( ! safe.empty() )
+ safe += "&";
+ safe += val;
+ }
+ });
+ _safeQuerytsr = std::move(safe);
+ }
+ else
+ _safeQuerytsr = std::nullopt;
+ }
+ private:
+ std::string _fullQuerytsr; ///<
+ std::optional<std::string> _safeQuerytsr; ///<.
+ };
+
/**
* \brief Internal data used by UrlBase.
*/
std::string port;
std::string pathname;
std::string pathparams;
- std::string querystr;
+ SafeQuerystr querystr;
std::string fragment;
};
return asString(getViewOptions());
}
+ std::string UrlBase::asString1050625() const
+ {
+ // Temp. fix to keep the proxypass in the query when writing the .repo files,
+ // but otherwise hiding it, when WITH_PASSWORD is not set.
+ return asString(getViewOptions()+ViewOptions::hotfix1050625);
+ }
// ---------------------------------------------------------------
std::string
if( opts.has(ViewOptions::WITH_QUERY_STR))
{
- tmp.querystr = getQueryString();
- if( !tmp.querystr.empty())
+ const std::string & querystr { getQueryString( opts ) }; // full or safe depending on opts
+ if( !querystr.empty() )
{
- url += "?" + tmp.querystr;
+ url += "?" + querystr;
}
else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
{
return m_data->querystr;
}
+ std::string
+ UrlBase::getQueryString( const ViewOptions & viewopts_r ) const
+ {
+ return m_data->querystr.str( viewopts_r );
+ }
// ---------------------------------------------------------------
std::string
return o.opt & opt;
}
+ static const ViewOption hotfix1050625;
private:
ViewOption(int option);
int opt;
virtual std::string
getQueryString() const;
+ /** \overload Returns the safe query string (passwds stripped) unless WITH_PASSWORD is set. */
+ virtual std::string
+ getQueryString( const ViewOptions & viewopts_r ) const;
+
/**
* Returns a vector with query string parameter substrings.
*
void
setViewOptions(const ViewOptions &vopts);
-
+ std::string asString1050625() const;
protected:
/**
* Utility method to cleanup an encoded path name.