#
SET(LIBZYPP_MAJOR "15")
SET(LIBZYPP_COMPATMINOR "14")
-SET(LIBZYPP_MINOR "14")
+SET(LIBZYPP_MINOR "15")
SET(LIBZYPP_PATCH "0")
#
-# LAST RELEASED: 15.14.0 (14)
+# LAST RELEASED: 15.15.0 (14)
# (The number in parenthesis is LIBZYPP_COMPATMINOR)
#=======
-------------------------------------------------------------------
+Fri Sep 4 13:49:33 CEST 2015 - ma@suse.de
+
+- Don't cache repo releasever (bnc#943563)
+- Selectable: allow setPickStatus for non-multiversion packages
+ (bnc#943870)
+- ResPoolProxy: add ScopedSaveState
+- version 15.15.0 (14)
+
+-------------------------------------------------------------------
Tue Sep 1 18:19:27 CEST 2015 - ma@suse.de
- zypp.conf: add solver.dupAllow{Downgrade,NameChange,ArchChange,
} while ( comb.next() );
}
-BOOST_AUTO_TEST_CASE(status_change)
+BOOST_AUTO_TEST_CASE(status_verify)
{
// this verifies the Selectables computes ui::Status
ResPoolProxy poolProxy( test.poolProxy() );
- poolProxy.saveState();
+ ResPoolProxy::ScopedSaveState saveState( poolProxy );
{
ui::Selectable::Ptr sel( poolProxy.lookup( ResKind::package, "installed_only" ) );
BOOST_REQUIRE( !sel->installedEmpty() );
/////////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(pickstatus_cycle)
+{
+ return;
+ // TODO: automate it
+ ResPoolProxy poolProxy( test.poolProxy() );
+ ResPoolProxy::ScopedSaveState saveState( poolProxy );
+ ui::Selectable::Ptr sel( poolProxy.lookup( ResKind::package, "installed_and_available" ) );
+
+ USR << dump(sel) << endl;
+ for ( const PoolItem & pi : sel->picklist() )
+ {
+ (sel->pickInstall( pi, ResStatus::USER ) ? WAR : ERR) << (pi.multiversionInstall() ? "M " : " " ) << pi << endl;
+ USR << dump(sel) << endl;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
{
/////////////////////////////////////////////////////////////////////////
/// \class ProblemSolution
- /// \brief Class representing one possible solution to one problem found during resolving
+ /// \brief Class representing one possible solution to a problem found during resolving
///
/// All problems should have at least 2-3 (mutually exclusive) solutions:
///
const SolutionActionList & actions() const;
/**
- * Set description of the problem.
+ * Set description of the solution.
**/
void setDescription( std::string description );
/**
- * Set detail description of the problem.
+ * Set detail description of the solution.
**/
void setDetails( std::string details );
public:
/** \name Save and restore state per kind of resolvable.
- * Simple version, no savety net. So don't restore or diff,
+ * Simple version, no safety net. So don't restore or diff,
* if you didn't save before.
*
* Diff returns true, if current stat differs from the saved
* state.
- */
+ *
+ * Use \ref scopedSaveState for exception safe scoped save/restore
+ */
//@{
void saveState() const;
template<class _Res>
bool diffState() const
{ return diffState( ResTraits<_Res>::kind ); }
+
+ /**
+ * \class ScopedSaveState
+ * \brief Exception safe scoped save/restore state.
+ * Call \ref acceptState to prevent the class from restoring
+ * the remembered state.
+ * \ingroup g_RAII
+ */
+ struct ScopedSaveState;
+
+ ScopedSaveState scopedSaveState() const;
+
+ ScopedSaveState scopedSaveState( const ResKind & kind_r ) const;
+
+ template<class _Res>
+ ScopedSaveState && scopedSaveState() const
+ { return scopedSaveState( ResTraits<_Res>::kind ); }
+
//@}
private:
/** \relates ResPoolProxy Verbose stream output */
std::ostream & dumpOn( std::ostream & str, const ResPoolProxy & obj );
+ ///////////////////////////////////////////////////////////////////
+
+ struct ResPoolProxy::ScopedSaveState
+ {
+ NON_COPYABLE_BUT_MOVE( ScopedSaveState );
+
+ ScopedSaveState( const ResPoolProxy & pool_r )
+ : _pimpl( new Impl( pool_r ) )
+ { _pimpl->saveState(); }
+
+ ScopedSaveState( const ResPoolProxy & pool_r, const ResKind & kind_r )
+ : _pimpl( new Impl( pool_r, kind_r ) )
+ { _pimpl->saveState(); }
+
+ ~ScopedSaveState()
+ { if ( _pimpl ) _pimpl->restoreState(); }
+
+ void acceptState()
+ { _pimpl.reset(); }
+
+ private:
+ struct Impl
+ {
+ Impl( const ResPoolProxy & pool_r )
+ : _pool( pool_r )
+ {}
+ Impl( const ResPoolProxy & pool_r, const ResKind & kind_r )
+ : _pool( pool_r ), _kind( new ResKind( kind_r ) )
+ {}
+ void saveState()
+ { if ( _kind ) _pool.saveState( *_kind ); else _pool.saveState(); }
+ void restoreState()
+ { if ( _kind ) _pool.restoreState( *_kind ); else _pool.restoreState(); }
+ ResPoolProxy _pool;
+ scoped_ptr<ResKind> _kind;
+
+ };
+ std::unique_ptr<Impl> _pimpl;
+ };
+
+ inline ResPoolProxy::ScopedSaveState ResPoolProxy::scopedSaveState() const
+ { return ScopedSaveState( *this ); }
+
+ inline ResPoolProxy::ScopedSaveState ResPoolProxy::scopedSaveState( const ResKind & kind_r ) const
+ { return ScopedSaveState( *this, kind_r ); }
+
/////////////////////////////////////////////////////////////////
} // namespace zypp
///////////////////////////////////////////////////////////////////
#include "zypp/base/String.h"
#include "zypp/base/Regex.h"
+#include "zypp/ZYppFactory.h"
#include "zypp/ZConfig.h"
#include "zypp/Target.h"
#include "zypp/Arch.h"
///////////////////////////////////////////////////////////////////
namespace
{
+ inline std::string getReleaseverString()
+ {
+ std::string ret( env::ZYPP_REPO_RELEASEVER() );
+ if( ret.empty() )
+ {
+ Target_Ptr trg( getZYpp()->getTarget() );
+ if ( trg )
+ ret = trg->distributionVersion();
+ else
+ ret = Target::distributionVersion( Pathname()/*guess*/ );
+ }
+ else
+ WAR << "ENV overwrites $releasever=" << ret << endl;
+
+ return ret;
+ }
+
/** \brief Provide lazy initialized repo variables
*/
struct RepoVars : private zypp::base::NonCopyable
void assertReleaseverStr() const
{
- if ( _releasever.empty() )
+ // check for changing releasever (bnc#943563)
+ std::string check( getReleaseverString() );
+ if ( check != _releasever )
{
- _releasever = env::ZYPP_REPO_RELEASEVER();
- if( _releasever.empty() )
- _releasever = Target::distributionVersion( Pathname()/*guess*/ );
- else
- WAR << "ENV overwrites $releasever=" << _releasever << endl;
-
+ _releasever = std::move(check);
// split major/minor for SLE
std::string::size_type pos = _releasever.find( "." );
if ( pos == std::string::npos )
/** \overload */
static std::string targetDistributionFlavor( const Pathname & root_r );
- /** \copydoc Target::distributionVersion()*/
+ /** \copydoc Target::distributionLabel()*/
Target::DistributionLabel distributionLabel() const;
/** \overload */
static Target::DistributionLabel distributionLabel( const Pathname & root_r );
return true;
}
+ /** highlevel remove transact from non-multiversion packages. */
+ bool unsetNonMultiTransact( const PoolItem & pi_r, Causer causer_r )
+ {
+ ResStatus & status( backup( pi_r ) );
+ if ( status.transacts() && ! pi_r.multiversionInstall() )
+ {
+ if ( ! status.setTransact( false, causer_r ) ) return false;
+ }
+ return true;
+ }
+
+ /** highlevel remove transact from multiversion packages. */
+ bool unsetMultiTransact( const PoolItem & pi_r, Causer causer_r )
+ {
+ ResStatus & status( backup( pi_r ) );
+ if ( status.transacts() && pi_r.multiversionInstall() )
+ {
+ if ( ! status.setTransact( false, causer_r ) ) return false;
+ }
+ return true;
+ }
+
/** Highlevel action. */
typedef bool (StatusBackup::*Action)( const PoolItem &, Causer );
if ( pi_r.ident() != ident() )
return false; // not my PoolItem
- if ( ! pi_r.multiversionInstall() )
- return false; // We're not yet ready for this.
- // TODO: Without multiversionInstall take care at most ONE available is set
- // to install. Upon install ALL installed get deleted. Only upon deletetion
- // one might pick individual versions (but more than one would be an error here).
-
StatusBackup backup;
std::vector<PoolItem> i;
std::vector<PoolItem> a;
}
break;
- case S_Install:
- if ( i.empty() && ! a.empty() )
- {
- // maybe unlock candidate only?
- if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
- const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
- if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
- return true;
- }
- break;
-
- case S_Update:
- if ( ! i.empty() && ! a.empty() )
- {
- if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
- if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
- // maybe unlock candidate only?
- if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
- const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r ); // status already backed up above
- if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
- return true;
- }
- break;
+ case S_Install:
+ if ( i.empty() && ! a.empty() )
+ {
+ const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
+ if ( cand.multiversionInstall() )
+ {
+ if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
+ // maybe unlock candidate only?
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+ return true;
+ }
+ else
+ {
+ // For non-multiversion use ordinary setStatus
+ // NOTE that S_Update/S_Install here depends on !installedEmpty()
+ // and not on picklists identicalInstalled.
+ if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
+ if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
+ if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
+ return true;
+ }
+ }
+ break;
+
+ case S_Update:
+ if ( ! i.empty() && ! a.empty() )
+ {
+ const PoolItem & cand( pi_r.status().isInstalled() ? *a.begin() : pi_r );
+ if ( cand.multiversionInstall() )
+ {
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ if ( ! backup.forEach( i.begin(), i.end(), &StatusBackup::setTransactTrue, ResStatus::SOLVER ) ) return backup.restore();
+ if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetNonMultiTransact, causer_r ) ) return backup.restore();
+ // maybe unlock candidate only?
+ if ( ! backup.forEach( a.begin(), a.end(), &StatusBackup::unlock, causer_r ) ) return backup.restore();
+ if ( ! cand.status().setTransact( true, causer_r ) ) return backup.restore();
+ return true;
+ }
+ else
+ {
+ // For non-multiversion use ordinary setStatus
+ // NOTE that S_Update/S_Install here depends on !installedEmpty()
+ // and not on picklists identicalInstalled.
+ if ( ! backup.forEach( availableBegin(), availableEnd(), &StatusBackup::unsetMultiTransact, causer_r ) ) return backup.restore();
+ if ( ! setCandidate( cand, causer_r ) ) return backup.restore();
+ if ( ! setStatus( installedEmpty() ? S_Install : S_Update, causer_r ) ) return backup.restore();
+ return true;
+ }
+ }
+ break;
case S_KeepInstalled:
if ( ! i.empty() )