[devel] PATCH for apt: custom callbacks

Ivan Zakharyaschev imz на altlinux.org
Ср Июн 30 16:09:40 MSK 2021


Hello!

Предлагается патч на apt (API), добавляющий custom callbacks.

После чтения в общих чертах у меня не появилось замечаний по архитектуре 
(а также оформлению, стилю: git show --check; отдельные места, где 
возможны разные стилистические решения вполне соответствуют окружающему 
коду, а enforced style guide у нас отсутствует).

apt имеет свой тип для callback-ов, особенности rpm скрыты, что 
соответствует общему подходу в apt. "Переводом" для rpm занимается функция 
pkgRPMLibPM::customCallback из apt-pkg/rpm/rpmpm.{h,cc}:

   static void * customCallback(const void * h, const rpmCallbackType what,
				const uint64_t amount, const uint64_t total,
				const void * pkgKey, void * data);


Потом через неё rpm работает с apt-овыми callback-ами в 
apt-pkg/rpm/rpmpm.cc:

   struct CallbackData data;

   if (callback != nullptr ) {
      data.callback = callback;
      data.callbackData = callbackData;

      rc = rpmtsSetNotifyCallback(TS, customCallback, &data);
   } else {
      rc = rpmtsSetNotifyCallback(TS, rpmShowProgress,
                                  (void *) (unsigned long) notifyFlags);
   }

Я ещё сейчас почитаю внимательнее, в первую очередь, чтобы изменения не 
приводили к изменению старого поведения.

Вот патч -- вдруг у кого-то будут ценные замечания:

$ git --no-pager show --reverse gears/sisyphus..276207.200/master
commit 07dfdf44e9df71646815dcdf83f8e405bf6c988b
Author: Oleg Solovyov <mcpain на altlinux.org>
Date:   Wed Dec 11 12:15:00 2019 +0300

    Implemented generic callback system for package manager transactions
    
    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.

diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index c2e2f08be..50bb304ea 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -661,11 +661,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-pkg/packagemanager.h b/apt-pkg/packagemanager.h
index 9c5f04825..dce84811f 100644
--- a/apt-pkg/packagemanager.h
+++ b/apt-pkg/packagemanager.h
@@ -45,6 +45,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:
@@ -76,7 +102,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:
@@ -84,7 +110,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-pkg/rpm/rpmpm.cc b/apt-pkg/rpm/rpmpm.cc
index 287de77e2..700031e1b 100644
--- a/apt-pkg/rpm/rpmpm.cc
+++ b/apt-pkg/rpm/rpmpm.cc
@@ -270,7 +270,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;
@@ -356,7 +356,7 @@ bool pkgRPMPM::Go()
    }
 #endif
 
-   if (Process(install, upgrade, uninstall) == false)
+   if (Process(install, upgrade, uninstall, callback, callbackData) == false)
       Ret = false;
 
 #ifdef WITH_LUA
@@ -685,7 +685,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);
@@ -786,9 +787,82 @@ 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);
+   }
+
+#define DEF_CASE(name) case RPMCALLBACK_##name: callbackType = APTCALLBACK_##name; break
+
+   aptCallbackType callbackType = APTCALLBACK_UNKNOWN;
+   switch (what) {
+      DEF_CASE(INST_PROGRESS);
+      DEF_CASE(INST_START);
+      DEF_CASE(INST_STOP);
+      DEF_CASE(TRANS_PROGRESS);
+      DEF_CASE(TRANS_START);
+      DEF_CASE(TRANS_STOP);
+      DEF_CASE(UNINST_PROGRESS);
+      DEF_CASE(UNINST_START);
+      DEF_CASE(UNINST_STOP);
+      DEF_CASE(UNPACK_ERROR);
+      DEF_CASE(CPIO_ERROR);
+      DEF_CASE(SCRIPT_ERROR);
+      DEF_CASE(SCRIPT_START);
+      DEF_CASE(SCRIPT_STOP);
+      DEF_CASE(ELEM_PROGRESS);
+
+#undef DEF_CASE
+      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;
@@ -906,8 +980,17 @@ 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 *) (unsigned long) notifyFlags);
+   struct CallbackData data;
+
+   if (callback != nullptr ) {
+      data.callback = callback;
+      data.callbackData = callbackData;
+
+      rc = rpmtsSetNotifyCallback(TS, customCallback, &data);
+   } else {
+      rc = rpmtsSetNotifyCallback(TS, rpmShowProgress,
+                                  (void *) (unsigned long) notifyFlags);
+   }
    rc = rpmtsRun(TS, NULL, (rpmprobFilterFlags)probFilter);
    probs = rpmtsProblems(TS);
 
diff --git a/apt-pkg/rpm/rpmpm.h b/apt-pkg/rpm/rpmpm.h
index 8a01b80cc..157e113ee 100644
--- a/apt-pkg/rpm/rpmpm.h
+++ b/apt-pkg/rpm/rpmpm.h
@@ -49,9 +49,10 @@ class pkgRPMPM : public pkgPackageManager
 
    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:
@@ -66,7 +67,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);
@@ -80,9 +82,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:
 

commit 1403c34da1bc0e22762146010a002114c2ac88da (HEAD -> callbacks, tag: 
276207.200/0.5.15lorg2-alt73, 276207.200/master)
Author: Oleg Solovyov <mcpain на altlinux.org>
Date:   Mon Jun 28 14:47:56 2021 +0300

    0.5.15lorg2-alt73
    
    - implement generic callback system

diff --git a/apt.spec b/apt.spec
index deee52a23..ddda19609 100644
--- a/apt.spec
+++ b/apt.spec
@@ -7,7 +7,7 @@
 
 Name: apt
 Version: 0.5.15lorg2
-Release: alt72
+Release: alt73
 
 Summary: Debian's Advanced Packaging Tool with RPM support
 Summary(ru_RU.UTF-8): Debian APT - Усовершенствованное средство управления пакетами с поддержкой RPM
@@ -406,6 +406,9 @@ popd
 %_datadir/%name/tests/
 
 %changelog
+* Mon Jun 28 2021 Oleg Solovyov <mcpain на altlinux.org> 0.5.15lorg2-alt73
+- implement generic callback system
+
 * Thu Mar 18 2021 Ivan Zakharyaschev <imz на altlinux.org> 0.5.15lorg2-alt72
 - Cleaned up the code (thx Dmitry V. Levin ldv@; including
   quite a few commits cherry-picked from http://apt-rpm.org/scm/apt.git):


-- 
Best regards,
Ivan


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