ALT Linux Team development discussions
 help / color / mirror / Atom feed
From: Oleg Solovyov <mcpain@altlinux.org>
To: devel@lists.altlinux.org
Cc: Oleg Solovyov <mcpain@altlinux.org>
Subject: [devel] [PATCH for apt v3] Implemented generic callback system for package manager transactions
Date: Wed, 11 Dec 2019 12:15:51 +0300
Message-ID: <20191211091551.304536-1-mcpain@altlinux.org> (raw)
In-Reply-To: <20191210003042.GF15867@altlinux.org>

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      | 111 +++++++++++++++++++++++++++++++---
 apt/apt-pkg/rpm/rpmpm.h       |  16 +++--
 4 files changed, 144 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..a2c9068 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,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;
@@ -990,13 +1064,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.1



      parent reply	other threads:[~2019-12-11  9:15 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-06 13:12 [devel] [PATCH for apt] " Oleg Solovyov
2019-12-10  0:30 ` Dmitry V. Levin
2019-12-10  7:27   ` Oleg Solovyov
2019-12-10 22:39     ` Dmitry V. Levin
2019-12-10  7:37   ` Aleksei Nikiforov
2019-12-10 14:38   ` [devel] [PATCH for apt v2] " Oleg Solovyov
2019-12-11  9:15   ` Oleg Solovyov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191211091551.304536-1-mcpain@altlinux.org \
    --to=mcpain@altlinux.org \
    --cc=devel@lists.altlinux.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

ALT Linux Team development discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/devel/0 devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 devel devel/ http://lore.altlinux.org/devel \
		devel@altlinux.org devel@altlinux.ru devel@lists.altlinux.org devel@lists.altlinux.ru devel@linux.iplabs.ru mandrake-russian@linuxteam.iplabs.ru sisyphus@linuxteam.iplabs.ru
	public-inbox-index devel

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git