[devel] [PATCH for apt v2] Implemented generic callback system for package manager transactions

Oleg Solovyov mcpain на altlinux.org
Вт Дек 10 17:38:10 MSK 2019


We're introducing custom callback for higher layers (like packagekit),
letting them pass their own callbacks to APT instead of using rpmShowProgress
when it's necessary.
It's useful in particular case of offline updating when packagekit can
send messages to plymouth letting user know about transaction progress but
because APT does not send anything since it's using rpmShowProgress, packagekit
reports nothing because it's just nothing to report.
---
 apt/apt-pkg/packagemanager.cc |   4 +-
 apt/apt-pkg/packagemanager.h  |  30 +++++++-
 apt/apt-pkg/rpm/rpmpm.cc      | 137 ++++++++++++++++++++++++++++++++--
 apt/apt-pkg/rpm/rpmpm.h       |  16 ++--
 4 files changed, 170 insertions(+), 17 deletions(-)

diff --git a/apt/apt-pkg/packagemanager.cc b/apt/apt-pkg/packagemanager.cc
index 0bcd902..f5adbfd 100644
--- a/apt/apt-pkg/packagemanager.cc
+++ b/apt/apt-pkg/packagemanager.cc
@@ -665,11 +665,11 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
 // ---------------------------------------------------------------------
 /* This uses the filenames in FileNames and the information in the
    DepCache to perform the installation of packages.*/
-pkgPackageManager::OrderResult pkgPackageManager::DoInstall()
+pkgPackageManager::OrderResult pkgPackageManager::DoInstall(PackageManagerCallback_t callback, void *callbackData)
 {
    OrderResult Res = OrderInstall();
    if (Res != Failed)
-      if (Go() == false)
+      if (Go(callback, callbackData) == false)
 	 return Failed;
    return Res;
 }
diff --git a/apt/apt-pkg/packagemanager.h b/apt/apt-pkg/packagemanager.h
index 917dbc1..e60ba51 100644
--- a/apt/apt-pkg/packagemanager.h
+++ b/apt/apt-pkg/packagemanager.h
@@ -49,6 +49,32 @@ class pkgDepCache;
 class pkgSourceList;
 class pkgOrderList;
 class pkgRecords;
+
+typedef enum aptCallbackType_e {
+    APTCALLBACK_UNKNOWN = 0,
+    APTCALLBACK_INST_PROGRESS,
+    APTCALLBACK_INST_START,
+    APTCALLBACK_INST_STOP,
+    APTCALLBACK_TRANS_PROGRESS,
+    APTCALLBACK_TRANS_START,
+    APTCALLBACK_TRANS_STOP,
+    APTCALLBACK_UNINST_PROGRESS,
+    APTCALLBACK_UNINST_START,
+    APTCALLBACK_UNINST_STOP,
+    APTCALLBACK_UNPACK_ERROR,
+    APTCALLBACK_CPIO_ERROR,
+    APTCALLBACK_SCRIPT_ERROR,
+    APTCALLBACK_SCRIPT_START,
+    APTCALLBACK_SCRIPT_STOP,
+    APTCALLBACK_ELEM_PROGRESS,
+} aptCallbackType;
+
+typedef void (*PackageManagerCallback_t)(const char *nevra,
+                                         const aptCallbackType what,
+                                         const uint64_t amount,
+                                         const uint64_t total,
+                                         void *callbackData);
+
 class pkgPackageManager : protected pkgCache::Namespace
 {
    public:
@@ -80,7 +106,7 @@ class pkgPackageManager : protected pkgCache::Namespace
    virtual bool Install(PkgIterator /*Pkg*/,const string &/*File*/) {return false;};
    virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
    virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;};
-   virtual bool Go() {return true;};
+   virtual bool Go(PackageManagerCallback_t /*callback*/ = nullptr, void * /*callbackData*/ = nullptr) {return true;};
    virtual void Reset() {};
    
    public:
@@ -88,7 +114,7 @@ class pkgPackageManager : protected pkgCache::Namespace
    // Main action members
    bool GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
 		    pkgRecords *Recs);
-   OrderResult DoInstall();
+   OrderResult DoInstall(PackageManagerCallback_t callback = nullptr, void *callbackData = nullptr);
    bool FixMissing();
    
    // If marks updating not supported, skip this step
diff --git a/apt/apt-pkg/rpm/rpmpm.cc b/apt/apt-pkg/rpm/rpmpm.cc
index a6a3837..d5ff786 100644
--- a/apt/apt-pkg/rpm/rpmpm.cc
+++ b/apt/apt-pkg/rpm/rpmpm.cc
@@ -278,7 +278,7 @@ bool pkgRPMPM::RunScriptsWithPkgs(const char *Cnf)
 // RPMPM::Go - Run the sequence						/*{{{*/
 // ---------------------------------------------------------------------
 /* This globs the operations and calls rpm */
-bool pkgRPMPM::Go()
+bool pkgRPMPM::Go(PackageManagerCallback_t callback, void *callbackData)
 {
    if (List.empty() == true)
       return true;
@@ -364,7 +364,7 @@ bool pkgRPMPM::Go()
    }
 #endif
 
-   if (Process(install, upgrade, uninstall) == false)
+   if (Process(install, upgrade, uninstall, callback, callbackData) == false)
       Ret = false;
 
 #ifdef WITH_LUA
@@ -687,7 +687,8 @@ bool pkgRPMExtPM::ExecRPM(Item::RPMOps op, const std::vector<apt_item> &files)
 
 bool pkgRPMExtPM::Process(const std::vector<apt_item> &install,
 		       const std::vector<apt_item> &upgrade,
-		       const std::vector<apt_item> &uninstall)
+		       const std::vector<apt_item> &uninstall,
+		       PackageManagerCallback_t callback, void *callbackData)
 {
    if (uninstall.empty() == false)
        ExecRPM(Item::RPMErase, uninstall);
@@ -827,9 +828,108 @@ bool pkgRPMLibPM::AddToTransaction(Item::RPMOps op, const std::vector<apt_item>
    return true;
 }
 
+struct CallbackData
+{
+   PackageManagerCallback_t callback;
+   void *callbackData;
+};
+
+void * pkgRPMLibPM::customCallback(const void * h,
+                                   const rpmCallbackType what,
+                                   const uint64_t amount,
+                                   const uint64_t total,
+                                   const void * pkgKey,
+                                   void * data)
+{
+   /* When invoking rpmShowProgress, the last parameter is notifyFlags,
+      which ain't used when callback type is OPEN_FILE or CLOSE_FILE
+      so it's safe to just pass zero. */
+   if (what == RPMCALLBACK_INST_OPEN_FILE || what == RPMCALLBACK_INST_CLOSE_FILE)
+      return rpmShowProgress(h, what, amount, total, pkgKey, 0);
+
+   CallbackData *s = (CallbackData *) data;
+   PackageManagerCallback_t func = s->callback;
+   rpmtd td = nullptr;
+
+   const char* nevra = nullptr;
+   if (h != nullptr) {
+      td = rpmtdNew();
+
+      // Get NEVRA for package
+      int rc = headerGet((rpmHeader) h, RPMTAG_NEVRA, td, HEADERGET_DEFAULT);
+      if (rc == 1)
+         nevra = rpmtdGetString(td);
+   }
+
+   aptCallbackType callbackType = APTCALLBACK_UNKNOWN;
+   switch (what) {
+      case RPMCALLBACK_INST_PROGRESS:
+         callbackType = APTCALLBACK_INST_PROGRESS;
+         break;
+      case RPMCALLBACK_INST_START:
+         callbackType = APTCALLBACK_INST_START;
+         break;
+      case RPMCALLBACK_TRANS_PROGRESS:
+         callbackType = APTCALLBACK_TRANS_PROGRESS;
+         break;
+      case RPMCALLBACK_TRANS_START:
+         callbackType = APTCALLBACK_TRANS_START;
+         break;
+      case RPMCALLBACK_TRANS_STOP:
+         callbackType = APTCALLBACK_TRANS_STOP;
+         break;
+      case RPMCALLBACK_UNINST_PROGRESS:
+         callbackType = APTCALLBACK_UNINST_PROGRESS;
+         break;
+      case RPMCALLBACK_UNINST_START:
+         callbackType = APTCALLBACK_UNINST_START;
+         break;
+      case RPMCALLBACK_UNINST_STOP:
+         callbackType = APTCALLBACK_UNINST_STOP;
+         break;
+      case RPMCALLBACK_UNPACK_ERROR:
+         callbackType = APTCALLBACK_UNPACK_ERROR;
+         break;
+      case RPMCALLBACK_CPIO_ERROR:
+         callbackType = APTCALLBACK_CPIO_ERROR;
+         break;
+      case RPMCALLBACK_SCRIPT_ERROR:
+         callbackType = APTCALLBACK_SCRIPT_ERROR;
+         break;
+      case RPMCALLBACK_SCRIPT_START:
+         callbackType = APTCALLBACK_SCRIPT_START;
+         break;
+      case RPMCALLBACK_SCRIPT_STOP:
+         callbackType = APTCALLBACK_SCRIPT_STOP;
+         break;
+      case RPMCALLBACK_INST_STOP:
+         callbackType = APTCALLBACK_INST_STOP;
+         break;
+      case RPMCALLBACK_ELEM_PROGRESS:
+         callbackType = APTCALLBACK_ELEM_PROGRESS;
+         break;
+      default:
+         break;
+   }
+
+   try {
+      func(nevra, callbackType, amount, total, s->callbackData);
+   }
+   catch (...)
+   {
+   }
+
+   if (h != nullptr) {
+      rpmtdFreeData(td);
+      rpmtdFree(td);
+   }
+   return nullptr;
+}
+
 bool pkgRPMLibPM::Process(const std::vector<apt_item> &install,
 			  const std::vector<apt_item> &upgrade,
-			  const std::vector<apt_item> &uninstall)
+			  const std::vector<apt_item> &uninstall,
+			  PackageManagerCallback_t callback, void *callbackData)
 {
    int rc = 0;
    bool Success = false;
@@ -990,13 +1090,34 @@ bool pkgRPMLibPM::Process(const std::vector<apt_item> &install,
    probFilter |= rpmtsFilterFlags(TS);
    rpmtsSetFlags(TS, (rpmtransFlags)(rpmtsFlags(TS) | tsFlags));
    rpmtsClean(TS);
-   rc = rpmtsSetNotifyCallback(TS, rpmShowProgress, (void *)notifyFlags);
+
+   struct CallbackData data;
+
+   if (callback != nullptr ) {
+      data.callback = callback;
+      data.callbackData = callbackData;
+
+      rc = rpmtsSetNotifyCallback(TS, customCallback, &data);
+   } else {
+      rc = rpmtsSetNotifyCallback(TS, rpmShowProgress, (void *)notifyFlags);
+   }
+
    rc = rpmtsRun(TS, NULL, (rpmprobFilterFlags)probFilter);
    probs = rpmtsProblems(TS);
 #else
-   rc = rpmRunTransactions(TS, rpmShowProgress, (void *)notifyFlags, NULL,
-                           &probs, (rpmtransFlags)tsFlags,
-			   (rpmprobFilterFlags)probFilter);
+   if (callback != nullptr ) {
+      struct CallbackData data;
+      data.callback = callback;
+      data.callbackData = callbackData;
+
+      rc = rpmRunTransactions(TS, customCallback, &data, NULL,
+                              &probs, (rpmtransFlags)tsFlags,
+			      (rpmprobFilterFlags)probFilter);
+   } else {
+      rc = rpmRunTransactions(TS, rpmShowProgress, (void *)notifyFlags, NULL,
+                              &probs, (rpmtransFlags)tsFlags,
+			      (rpmprobFilterFlags)probFilter);
+   }
 #endif
 
    if (rc > 0) {
diff --git a/apt/apt-pkg/rpm/rpmpm.h b/apt/apt-pkg/rpm/rpmpm.h
index e6968b8..692b9a9 100644
--- a/apt/apt-pkg/rpm/rpmpm.h
+++ b/apt/apt-pkg/rpm/rpmpm.h
@@ -54,12 +54,13 @@ class pkgRPMPM : public pkgPackageManager
    virtual bool Install(PkgIterator Pkg,const string &File) override;
    virtual bool Configure(PkgIterator Pkg) override;
    virtual bool Remove(PkgIterator Pkg,bool Purge = false) override;
-    
+
    virtual bool Process(const std::vector<apt_item> &install,
 		const std::vector<apt_item> &upgrade,
-		const std::vector<apt_item> &uninstall) {return false;};
+		const std::vector<apt_item> &uninstall,
+		PackageManagerCallback_t callback, void *callbackData) {return false;};
    
-   virtual bool Go() override;
+   virtual bool Go(PackageManagerCallback_t callback, void *callbackData) override;
    virtual void Reset() override;
    
    public:
@@ -74,7 +75,8 @@ class pkgRPMExtPM : public pkgRPMPM
    bool ExecRPM(Item::RPMOps op, const std::vector<apt_item> &files);
    virtual bool Process(const std::vector<apt_item> &install,
 		const std::vector<apt_item> &upgrade,
-		const std::vector<apt_item> &uninstall) override;
+		const std::vector<apt_item> &uninstall,
+		PackageManagerCallback_t callback, void *callbackData) override;
 
    public:
    pkgRPMExtPM(pkgDepCache *Cache);
@@ -93,9 +95,13 @@ class pkgRPMLibPM : public pkgRPMPM
 
    bool ParseRpmOpts(const char *Cnf, int *tsFlags, int *probFilter);
    bool AddToTransaction(Item::RPMOps op, const std::vector<apt_item> &files);
+   static void * customCallback(const void * h, const rpmCallbackType what,
+				const uint64_t amount, const uint64_t total,
+				const void * pkgKey, void * data);
    virtual bool Process(const std::vector<apt_item> &install,
 		const std::vector<apt_item> &upgrade,
-		const std::vector<apt_item> &uninstall) override;
+		const std::vector<apt_item> &uninstall,
+		PackageManagerCallback_t callback, void *callbackData) override;
 
    public:
 
-- 
2.24.0



Подробная информация о списке рассылки Devel