*
* Pass a filename to the application and provide the appropriate
* code to be exectued when the file is no longer needed:
- * <code>
+ * \code
* struct FileCache
* {
* Pathname getFile();
* return AutoDispose<const Pathname>();
* }
* }
- * <\code>
+ * \endcode
*
* Exception safe handling of temporary files:
- * <code>
+ * \code
* void provideFileAt( const Pathname & destination )
* {
* AutoDispose<const Pathname> guard( destination, unlink );
* // On success: reset the dispose function to NOOP.
* guard.resetDispose();
* }
- * <\code>
+ * \endcode
*/
template<class _Tp>
class AutoDispose
*
*/
#include <iostream>
+#include <sstream>
#include "zypp/base/Logger.h"
#include "zypp/source/PackageProvider.h"
namespace source
{ /////////////////////////////////////////////////////////////////
- PackageProvider::PackageProvider( const Package::constPtr & package )
- : _package( package )
+ ///////////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME : PackageProviderPolicy
+ //
+ ///////////////////////////////////////////////////////////////////
+
+ bool PackageProviderPolicy::queryInstalled( const std::string & name_r, const Edition & ed_r ) const
+ {
+ if ( _queryInstalledCB )
+ return _queryInstalledCB( name_r, ed_r );
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME : PackageProvider
+ //
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ namespace
+ { /////////////////////////////////////////////////////////////////
+
+ inline std::string defRpmFileName( const Package::constPtr & package )
+ {
+ std::ostringstream ret;
+ ret << package->name() << '-' << package->edition() << '.' << package->arch() << ".rpm";
+ return ret.str();
+ }
+
+ /////////////////////////////////////////////////////////////////
+ } // namespace source
+ ///////////////////////////////////////////////////////////////////
+ PackageProvider::PackageProvider( const Package::constPtr & package,
+ const PackageProviderPolicy & policy_r )
+ : _policy( policy_r )
+ , _package( package )
, _implPtr( detail::ImplConnect::resimpl( _package ) )
{}
ZYPP_RETHROW( excpt );
}
} while ( _retry );
+
report()->finish( _package, source::DownloadResolvableReport::NO_ERROR, std::string() );
MIL << "provided Package " << _package << " at " << ret << endl;
return ret;
}
- bool PackageProvider::considerDeltas() const
- {
-#warning ADD DOWNLOADING MEDIA CONDITION
- return applydeltarpm::haveApplydeltarpm();
- }
-
- bool PackageProvider::considerPatches() const
- {
-#warning ADD DOWNLOADING MEDIA CONDITION
- return _installedEdition != Edition::noedition;
- }
-
ManagedFile PackageProvider::doProvidePackage() const
{
- if ( considerDeltas() )
+ // check whether to process patch/delta rpms
+ if ( _package->source().remote() )
{
std::list<DeltaRpm> deltaRpms( _implPtr->deltaRpms() );
- if ( ! deltaRpms.empty() )
+ std::list<PatchRpm> patchRpms( _implPtr->patchRpms() );
+
+ if ( ! ( deltaRpms.empty() && patchRpms.empty() )
+ && queryInstalled() )
{
- for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
- it != deltaRpms.end(); ++it )
+ if ( ! deltaRpms.empty() && applydeltarpm::haveApplydeltarpm() )
{
- DBG << "tryDelta " << *it << endl;
- ManagedFile ret( tryDelta( *it ) );
- if ( ! ret->empty() )
- return ret;
+ for( std::list<DeltaRpm>::const_iterator it = deltaRpms.begin();
+ it != deltaRpms.end(); ++it )
+ {
+ DBG << "tryDelta " << *it << endl;
+ ManagedFile ret( tryDelta( *it ) );
+ if ( ! ret->empty() )
+ return ret;
+ }
}
- }
- }
- if ( considerPatches() )
- {
- std::list<PatchRpm> patchRpms( _implPtr->patchRpms() );
- if ( ! patchRpms.empty() )
- {
- for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
- it != patchRpms.end(); ++it )
+ if ( ! patchRpms.empty() )
{
- DBG << "tryPatch " << *it << endl;
- ManagedFile ret( tryPatch( *it ) );
- if ( ! ret->empty() )
- return ret;
+ for( std::list<PatchRpm>::const_iterator it = patchRpms.begin();
+ it != patchRpms.end(); ++it )
+ {
+ DBG << "tryPatch " << *it << endl;
+ ManagedFile ret( tryPatch( *it ) );
+ if ( ! ret->empty() )
+ return ret;
+ }
}
}
}
+ // no patch/delta -> provide full package
ManagedFile ret;
source::OnMediaLocation loc;
loc.medianr( _package->sourceMediaNr() )
ManagedFile PackageProvider::tryDelta( const DeltaRpm & delta_r ) const
{
+ if ( delta_r.baseversion().edition() != Edition::noedition
+ && ! queryInstalled( delta_r.baseversion().edition() ) )
+ return ManagedFile();
+
if ( ! applydeltarpm::quickcheck( delta_r.baseversion().sequenceinfo() ) )
return ManagedFile();
return ManagedFile();
}
-#warning FIX FIX PATHNAME
- Pathname destination( "/tmp/delta.rpm" );
+
+ Pathname destination( Pathname::dirname( delta ) / defRpmFileName( _package ) );
+ /* just to ease testing with non remote sources */
+ if ( ! _package->source().remote() )
+ destination = Pathname("/tmp") / defRpmFileName( _package );
+ /**/
+
if ( ! applydeltarpm::provide( delta, destination,
bind( &PackageProvider::progressDeltaApply, this, _1 ) ) )
{
{
// installed edition is in baseversions?
const PatchRpm::BaseVersions & baseversions( patch_r.baseversions() );
- if ( std::find( baseversions.begin(), baseversions.end(),
- _installedEdition ) == baseversions.end() )
+
+ if ( std::find_if( baseversions.begin(), baseversions.end(),
+ bind( &PackageProvider::queryInstalled, this, _1 ) )
+ == baseversions.end() )
return ManagedFile();
report()->startPatchDownload( patch_r.location().filename(),
return true; // anyway a failure
}
+ bool PackageProvider::queryInstalled( const Edition & ed_r ) const
+ { return _policy.queryInstalled( _package->name(), ed_r ); }
+
+
/////////////////////////////////////////////////////////////////
} // namespace source
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
+ // CLASS NAME : PackageProviderPolicy
+ //
+ /** */
+ class PackageProviderPolicy
+ {
+ public:
+ /** Get installed Editions callback signature. */
+ typedef function<bool ( const std::string &, const Edition & )> QueryInstalledCB;
+
+ /** Set callback. */
+ PackageProviderPolicy & queryInstalledCB( QueryInstalledCB queryInstalledCB_r )
+ { _queryInstalledCB = queryInstalledCB_r; return *this; }
+
+ /** Evaluate callback. */
+ bool queryInstalled( const std::string & name_r, const Edition & ed_r = Edition() ) const;
+
+ private:
+ QueryInstalledCB _queryInstalledCB;
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //
// CLASS NAME : PackageProvider
//
/** Provide a package from a Source.
public:
/** Ctor taking the Package to provide. */
- PackageProvider( const Package::constPtr & package );
+ PackageProvider( const Package::constPtr & package,
+ const PackageProviderPolicy & policy_r = PackageProviderPolicy() );
~PackageProvider();
public:
ManagedFile providePackage() const;
private:
- bool considerDeltas() const;
- bool considerPatches() const;
ManagedFile doProvidePackage() const;
ManagedFile tryDelta( const DeltaRpm & delta_r ) const;
ManagedFile tryPatch( const PatchRpm & patch_r ) const;
bool progressPatchDownload( int value ) const;
bool progressPackageDownload( int value ) const;
bool failOnChecksumError() const;
+ bool queryInstalled( const Edition & ed_r = Edition() ) const;
private:
+ PackageProviderPolicy _policy;
Package::constPtr _package;
PackageImpl_constPtr _implPtr;
- Edition _installedEdition;
mutable bool _retry;
mutable shared_ptr<Report> _report;
+
};
///////////////////////////////////////////////////////////////////
#include "zypp/pool/GetResolvablesToInsDel.h"
#include "zypp/solver/detail/Helper.h"
+#include "zypp/source/PackageProvider.h"
using namespace std;
using zypp::solver::detail::Helper;
namespace target
{ /////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////
- namespace
- { /////////////////////////////////////////////////////////////////
+ /** Helper for PackageProvider queries during commit. */
+ struct QueryInstalledEditionHelper
+ {
+ QueryInstalledEditionHelper( rpm::RpmDb & rpmdb_r )
+ : _rpmdb( rpmdb_r )
+ {}
- struct PubKeyHelper
+ bool operator()( const std::string & name_r, const Edition & ed_r ) const
{
- };
+ if ( ed_r == Edition::noedition )
+ return _rpmdb.hasPackage( name_r );
+ return _rpmdb.hasPackage( name_r, ed_r );
+ }
+ private:
+ rpm::RpmDb & _rpmdb;
+ };
- /////////////////////////////////////////////////////////////////
- } // namespace
- ///////////////////////////////////////////////////////////////////
IMPL_PTR_TYPE(TargetImpl);
// remember the last used source (if any)
Source_Ref lastUsedSource;
+ // Redirect PackageProvider queries for installed editions
+ // (in case of patch/delta rpm processing) to rpmDb.
+ source::PackageProviderPolicy packageProviderPolicy;
+ packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper(_rpm) );
+
+
for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
{
if (isKind<Package>(it->resolvable()))
Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
if (it->status().isToBeInstalled())
{
- Pathname localfile;
+ source::ManagedFile localfile;
try {
- localfile = p->source().providePackage(p);
+ source::PackageProvider pkgProvider( p, packageProviderPolicy );
+ localfile = pkgProvider.providePackage();
}
catch( const source::SkipRequestedException & e )
{
///////////////////////////////////////////////////////////////////
//
//
+// METHOD NAME : RpmDb::hasPackage
+// METHOD TYPE : bool
+//
+// DESCRIPTION :
+//
+bool RpmDb::hasPackage( const string & name_r, const Edition & ed_r ) const
+{
+ librpmDb::db_const_iterator it;
+ return it.findPackage( name_r, ed_r );
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
// METHOD NAME : RpmDb::getData
// METHOD TYPE : PMError
//
namespace zypp {
namespace target {
namespace rpm {
-
+
///////////////////////////////////////////////////////////////////
//
// CLASS NAME : RpmDb
class RpmDb : public base::ReferenceCounted, private base::NonCopyable
{
public:
-
+
/**
* Default error class
**/
typedef class InstTargetError Error;
-
+
///////////////////////////////////////////////////////////////////
//
// INITALISATION
//
///////////////////////////////////////////////////////////////////
private:
-
+
enum DbStateInfoBits {
DbSI_NO_INIT = 0x0000,
DbSI_HAVE_V4 = 0x0001,
DbSI_HAVE_V3TOV4 = 0x0010,
DbSI_MADE_V3TOV4 = 0x0020
};
-
+
friend std::ostream & operator<<( std::ostream & str, const DbStateInfoBits & obj );
-
+
void dbsi_set( DbStateInfoBits & val_r, const unsigned & bits_r ) const {
val_r = (DbStateInfoBits)(val_r | bits_r);
}
bool dbsi_has( const DbStateInfoBits & val_r, const unsigned & bits_r ) const {
return( (val_r & bits_r) == bits_r );
}
-
+
/**
* Internal state info
**/
DbStateInfoBits _dbStateInfo;
-
+
/**
* Root directory for all operations.
**/
Pathname _root;
-
+
/**
* Directory that contains the rpmdb.
**/
Pathname _dbPath;
-
+
/**
* Internal helper for @ref initDatabase.
*
**/
void internal_initDatabase( const Pathname & root_r, const Pathname & dbPath_r,
DbStateInfoBits & info_r );
-
+
/**
* Remove the rpm4 database in dbdir_r and optionally any backup created
* on conversion.
**/
static void removeV4( const Pathname & dbdir_r, bool v3backup_r );
-
+
/**
* Remove the rpm3 database in dbdir_r. Create a backup copy named
* packages.rpm3 if it does not already exist.
**/
static void removeV3( const Pathname & dbdir_r, bool v3backup_r );
-
+
/**
* Called before the database is modified by installPackage/removePackage.
* Invalidates Packages list and moves away any old database.
**/
void modifyDatabase();
-
+
public:
-
+
/**
* Constructor. There's no rpmdb access until @ref initDatabase
* was called.
**/
RpmDb();
-
+
/**
* Destructor.
**/
~RpmDb();
-
+
/**
* @return Root directory for all operations (empty if not initialized).
**/
const Pathname & root() const { return _root; }
-
+
/**
* @return Directory that contains the rpmdb (empty if not initialized).
**/
const Pathname & dbPath() const { return _dbPath; }
-
+
/**
* @return Whether we are initialized.
**/
bool initialized() const { return( ! _root.empty() ); }
-
+
/**
* Prepare access to the rpm database. Optional arguments may denote the
* root directory for all operations and the directory (below root) that
**/
void initDatabase( Pathname root_r = Pathname(),
Pathname dbPath_r = Pathname() );
-
+
/**
* Block further access to the rpm database and go back to uninitialized
* state. On update: Decides what to do with any converted database
*
**/
void closeDatabase();
-
+
/**
* Rebuild the rpm database (rpm --rebuilddb).
*
*
**/
void rebuildDatabase();
-
+
/**
* Import ascii armored public key in file pubkey_r.
*
*
**/
void importPubkey( const Pathname & pubkey_r );
-
+
/**
* Return the long ids of all installed public keys.
**/
std::list<PublicKey> pubkeys() const;
-
+
/**
* Return the edition of all installed public keys.
**/
std::set<Edition> pubkeyEditions() const;
-
+
///////////////////////////////////////////////////////////////////
//
// Cached RPM database retrieval via librpm.
//
///////////////////////////////////////////////////////////////////
private:
-
+
class Packages;
-
+
Packages & _packages;
-
+
std::set<std::string> _filerequires;
-
+
public:
-
+
/**
* @return Whether the list of installed packages is valid, or
* you'd better reread it. (<B>NOTE:</B> returns valid, if not
* initialized).
**/
bool packagesValid() const;
-
+
/**
* If necessary build, and return the list of all installed packages.
**/
const std::list<Package::Ptr> & getPackages();
-
+
#warning uncomment
-#if 0
+#if 0
/**
* Hack to lookup required and conflicting file relations.
**/
void traceFileRel( const PkgRelation & rel_r );
#endif
-
+
///////////////////////////////////////////////////////////////////
//
// Direct RPM database retrieval via librpm.
* Return true if package name_r owns file file_r (name_r nonempty).
**/
bool hasFile( const std::string & file_r, const std::string & name_r = "" ) const;
-
+
/**
* Return name of package owning file
* or empty string if no installed package owns file
**/
std::string whoOwnsFile( const std::string & file_r ) const;
-
+
/**
* Return true if at least one package provides a certain tag.
**/
bool hasProvides( const std::string & tag_r ) const;
-
+
/**
* Return true if at least one package requires a certain tag.
**/
bool hasRequiredBy( const std::string & tag_r ) const;
-
+
/**
* Return true if at least one package conflicts with a certain tag.
**/
bool hasConflicts( const std::string & tag_r ) const;
-
+
/**
* Return true if package is installed.
**/
bool hasPackage( const std::string & name_r ) const;
-
+
+ /**
+ * Return true if package is installed in a certain edition.
+ **/
+ bool hasPackage( const std::string & name_r, const Edition & ed_r ) const;
+
/**
* Get an installed packages data from rpmdb. Package is
* identified by name. Data returned via result are NULL,
**/
void getData( const std::string & name_r,
RpmHeader::constPtr & result_r ) const;
-
+
/**
* Get an installed packages data from rpmdb. Package is
* identified by name and edition. Data returned via result are NULL,
**/
void getData( const std::string & name_r, const Edition & ed_r,
RpmHeader::constPtr & result_r ) const;
-
+
/**
* Create a package from RpmHeader
* insert all rpm trusted keys into zypp trusted keyring
*/
void exportTrustedKeysInZyppKeyRing();
- private:
+ private:
/**
* The connection to the rpm process.
*/
ExternalProgram *process;
-
+
typedef std::vector<const char*> RpmArgVec;
-
+
/**
* Run rpm with the specified arguments and handle stderr.
* @param n_opts The number of arguments
void run_rpm( const RpmArgVec& options,
ExternalProgram::Stderr_Disposition stderr_disp =
ExternalProgram::Stderr_To_Stdout);
-
-
+
+
/**
* Read a line from the general rpm query
*/
bool systemReadLine(std::string &line);
-
+
/**
* Return the exit status of the general rpm process,
* closing the connection if not already done.
*/
int systemStatus();
-
+
/**
* Forcably kill the system process
*/
void systemKill();
-
+
/**
* The exit code of the rpm process, or -1 if not yet known.
*/
int exit_code;
-
+
/** /var/adm/backup */
Pathname _backuppath;
-
+
/** create package backups? */
bool _packagebackups;
-
+
/** whether <_root>/<WARNINGMAILPATH> was already created */
bool _warndirexists;
-
+
/**
* handle rpm messages like "/etc/testrc saved as /etc/testrc.rpmorig"
*
const char* typemsg,
const char* difffailmsg,
const char* diffgenmsg);
-
-
+
+
public:
-
+
typedef std::set<std::string> FileList;
-
+
/**
* Bits representing rpm installation options, useable as or
* combination
RPMINST_NOUPGRADE = 0x0100,
RPMINST_TEST = 0x0200
};
-
+
/**
* Bits of possible package corruptions
* @see checkPackage
CHK_INCORRECT_PKGMD5 = 0x20, // md5sum incorrect (inside)
CHK_OTHER_FAILURE = 0x40 // rpm failed for some reason
};
-
-
+
+
/**
* Check rpm with rpm --checksig
*
* @return checkPackageResult
*/
unsigned checkPackage (const Pathname& filename, std::string version = "", std::string md5 = "" );
-
+
/** install rpm package
*
* @param filename file to install
*
* */
void installPackage (const Pathname& filename, unsigned flags = 0 );
-
+
/** remove rpm package
*
* @param name_r Name of the rpm package to remove.
* */
void removePackage(const std::string & name_r, unsigned flags = 0);
void removePackage(Package::constPtr package, unsigned flags = 0);
-
+
/**
* get backup dir for rpm config files
*
* */
Pathname getBackupPath (void) { return _backuppath; }
-
+
/**
* create tar.gz of all changed files in a Package
*
* @see setBackupPath
* */
bool backupPackage(const std::string& packageName);
-
+
/**
* queries file for name and then calls above backupPackage
* function. For convenience.
* @param filename rpm file that is about to be installed
* */
bool backupPackage(const Pathname& filename);
-
+
/**
* set path where package backups are stored
*
* @see backupPackage
* */
void setBackupPath(const Pathname& path);
-
+
/**
* whether to create package backups during install or
* removal
* @param yes true or false
* */
void createPackageBackups(bool yes) { _packagebackups = yes; }
-
+
/**
* determine which files of an installed package have been
* modified.
* reason
* */
bool queryChangedFiles(FileList & fileList, const std::string& packageName);
-
+
public: // static members
-
+
/** create error description of bits set according to
* checkPackageResult
* */
static std::string checkPackageResult2string(unsigned code);
-
+
public:
-
+
/**
* Dump debug info.
**/
virtual std::ostream & dumpOn( std::ostream & str ) const;
-
+
///////////////////////////////////////////////////////////////////
//
// Installation log
//
///////////////////////////////////////////////////////////////////
private:
-
+
/**
* Progress of installation may be logged to file
**/
class Logfile;
-
+
public:
-
+
/**
* Set logfile for progress log. Empty filename to disable logging.
**/
void doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report );
const std::list<Package::Ptr> & doGetPackages(callback::SendReport<ScanDBReport> & report);
void doRebuildDatabase(callback::SendReport<RebuildDBReport> & report);
-
-
+
+
};
} // namespace rpm