From ca8da1bf83ecc90ba882520b79c1cda03ee7485d Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 28 May 2017 16:55:45 +0200 Subject: allow frontends to override releaseinfo change behaviour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having messages being printed on the error stack and confirm them by commandline flags is an okayish first step, but some frontends will probably want to have a more interactive feeling here with a proper question the user can just press yes/no for as for some frontends a commandline flag makes no sense… --- apt-pkg/acquire-item.cc | 61 ++++++++++++++++++++++++++----------------------- apt-pkg/acquire.cc | 31 ++++++++++++++++++++++++- apt-pkg/acquire.h | 43 +++++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 30 deletions(-) diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index ddcff5808..975116d1a 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1609,6 +1609,7 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/ // changed info potentially breaks user config like pinning if (TransactionManager->LastMetaIndexParser != nullptr) { + std::vector Changes; auto const AllowInfoChange = _config->FindB("Acquire::AllowReleaseInfoChange", false); auto const quietInfoChange = _config->FindB("quiet::ReleaseInfoChange", false); struct { @@ -1623,24 +1624,21 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/ { "Codename", AllowInfoChange, &metaIndex::GetCodename }, { nullptr, false, nullptr } }; - _error->PushToStack(); auto const CheckReleaseInfo = [&](char const * const Type, bool const AllowChange, decltype(checkers[0].Getter) const Getter) { std::string const Last = (TransactionManager->LastMetaIndexParser->*Getter)(); std::string const Now = (TransactionManager->MetaIndexParser->*Getter)(); if (Last == Now) - return true; - auto const Allow = _config->FindB(std::string("Acquire::AllowReleaseInfoChange::").append(Type), AllowChange); - auto const msg = _("Repository '%s' changed its '%s' value from '%s' to '%s'"); - if (Allow == false) - _error->Error(msg, Desc.Description.c_str(), Type, Last.c_str(), Now.c_str()); - else if (_config->FindB(std::string("quiet::ReleaseInfoChange::").append(Type), quietInfoChange) == false) - _error->Notice(msg, Desc.Description.c_str(), Type, Last.c_str(), Now.c_str()); - return Allow; + return; + auto const Allow = _config->FindB(std::string("Acquire::AllowReleaseInfoChange::").append(Type), AllowChange); + if (Allow == true && _config->FindB(std::string("quiet::ReleaseInfoChange::").append(Type), quietInfoChange) == true) + return; + std::string msg; + strprintf(msg, _("Repository '%s' changed its '%s' value from '%s' to '%s'"), + Desc.Description.c_str(), Type, Last.c_str(), Now.c_str()); + Changes.push_back({Type, std::move(Last), std::move(Now), std::move(msg), Allow}); }; - bool CRI = true; for (short i = 0; checkers[i].Type != nullptr; ++i) - if (CheckReleaseInfo(checkers[i].Type, checkers[i].Allowed, checkers[i].Getter) == false) - CRI = false; + CheckReleaseInfo(checkers[i].Type, checkers[i].Allowed, checkers[i].Getter); { auto const Last = TransactionManager->LastMetaIndexParser->GetDefaultPin(); @@ -1648,31 +1646,38 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/ if (Last != Now) { auto const Allow = _config->FindB("Acquire::AllowReleaseInfoChange::DefaultPin", AllowInfoChange); - auto const msg = _("Repository '%s' changed its default priority for %s from %hi to %hi."); - if (Allow == false) - _error->Error(msg, Desc.Description.c_str(), "apt_preferences(5)", Last, Now); - else if (_config->FindB("quiet::ReleaseInfoChange::DefaultPin", quietInfoChange) == false) - _error->Notice(msg, Desc.Description.c_str(), "apt_preferences(5)", Last, Now); - CRI &= Allow; + if (Allow == false || _config->FindB("quiet::ReleaseInfoChange::DefaultPin", quietInfoChange) == false) + { + std::string msg; + strprintf(msg, _("Repository '%s' changed its default priority for %s from %hi to %hi."), + Desc.Description.c_str(), "apt_preferences(5)", Last, Now); + Changes.push_back({"DefaultPin", std::to_string(Last), std::to_string(Now), std::move(msg), Allow}); + } } } - if (_error->empty(GlobalError::NOTICE) == false) + if (Changes.empty() == false) { auto const notes = TransactionManager->MetaIndexParser->GetReleaseNotes(); if (notes.empty() == false) { + std::string msg; // TRANSLATOR: the "this" refers to changes in the repository like a new release or owner change - _error->Notice(_("More information about this can be found online in the Release notes at: %s"), notes.c_str()); + strprintf(msg, _("More information about this can be found online in the Release notes at: %s"), notes.c_str()); + Changes.push_back({"Release-Notes", "", std::move(notes), std::move(msg), true}); } + if (std::any_of(Changes.begin(),Changes.end(),[](pkgAcquireStatus::ReleaseInfoChange const &c) { return c.DefaultAction == false; })) + { + std::string msg; + // TRANSLATOR: %s is the name of the manpage in question, e.g. apt-secure(8) + strprintf(msg, _("This must be accepted explicitly before updates for " + "this repository can be applied. See %s manpage for details."), "apt-secure(8)"); + Changes.push_back({"Confirmation", "", "", std::move(msg), true}); + } + } - _error->MergeWithStack(); - if (CRI == false) - { - // TRANSLATOR: %s is the name of the manpage in question, e.g. apt-secure(8) - _error->Notice(_("This must be accepted explicitly before updates for " - "this repository can be applied. See %s manpage for details."), "apt-secure(8)"); - return false; - } + if (Owner->Log == nullptr) + return pkgAcquireStatus::ReleaseInfoChangesAsGlobalErrors(std::move(Changes)); + return Owner->Log->ReleaseInfoChanges(TransactionManager->LastMetaIndexParser, TransactionManager->MetaIndexParser, std::move(Changes)); } return true; } diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 8a6928fb9..f1dbff9f1 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -1406,10 +1406,39 @@ void pkgAcquireStatus::Stop() // --------------------------------------------------------------------- /* This is used to get accurate final transfer rate reporting. */ void pkgAcquireStatus::Fetched(unsigned long long Size,unsigned long long Resume) -{ +{ FetchedBytes += Size - Resume; } /*}}}*/ +bool pkgAcquireStatus::ReleaseInfoChanges(metaIndex const * const LastRelease, metaIndex const * const CurrentRelease, std::vector &&Changes)/*{{{*/ +{ + auto const virt = dynamic_cast(this); + if (virt != nullptr) + return virt->ReleaseInfoChanges(LastRelease, CurrentRelease, std::move(Changes)); + return ReleaseInfoChangesAsGlobalErrors(std::move(Changes)); +} + /*}}}*/ +bool pkgAcquireStatus::ReleaseInfoChangesAsGlobalErrors(std::vector &&Changes)/*{{{*/ +{ + bool AllOkay = true; + for (auto const &c: Changes) + if (c.DefaultAction) + _error->Notice("%s", c.Message.c_str()); + else + { + _error->Error("%s", c.Message.c_str()); + AllOkay = false; + } + return AllOkay; +} + /*}}}*/ +bool pkgAcquireStatus2::ReleaseInfoChanges(metaIndex const * const, metaIndex const * const, std::vector &&Changes) +{ + return ReleaseInfoChangesAsGlobalErrors(std::move(Changes)); +} +pkgAcquireStatus2::pkgAcquireStatus2() : pkgAcquireStatus() {} +pkgAcquireStatus2::~pkgAcquireStatus2() {} + pkgAcquire::UriIterator::UriIterator(pkgAcquire::Queue *Q) : d(NULL), CurQ(Q), CurItem(0) { diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h index 5f1212338..8331c56e9 100644 --- a/apt-pkg/acquire.h +++ b/apt-pkg/acquire.h @@ -86,6 +86,7 @@ using std::string; #endif class pkgAcquireStatus; +class metaIndex; /** \brief The core download scheduler. {{{ * @@ -794,7 +795,39 @@ class pkgAcquireStatus * with prejudice. */ virtual bool MediaChange(std::string Media,std::string Drive) = 0; - + + struct ReleaseInfoChange + { + std::string Type; /*!< Type of the change like "Origin", "Codename", "Version", … */ + std::string From; /*!< old value */ + std::string To; /*!< new value */ + std::string Message; /*!< translated message describing the change */ + bool DefaultAction; /*!< true if the change is informational, false if it must be explicitly confirmed */ + }; + /** \brief ask the user for confirmation of changes to infos about a repository + * + * This method should present the user with a choice of accepting the change + * or not and indicate the user opinion via the return value. If DefaultAction is true + * it is acceptable to only notify the user about the change, but to accept the change + * automatically on behalf of the user. + * + * The default implementation will fail if any Change has DefaultAction == false. Regardless of + * success it will print for each change the message attached to it via GlobalError either as an + * error (if DefaultAction == false) or as a notice otherwise. + * + * \b Note: To keep ABI compatibility for now this method isn't marked as + * virtual, but you can derive your class from #pkgAcquireStatus2 which has it + * marked as virtual. TODO on next ABI break: merge both classes. + * + * @param LastRelease can be used to extract further information from the previous Release file + * @param CurrentRelease can be used to extract further information from the current Release file + * @param Changes is an array of changes alongside explanatory messages + * which should be presented in some way to the user. + * @return \b true if all changes are accepted by user, otherwise or if user can't be asked \b false + */ + bool ReleaseInfoChanges(metaIndex const * const LastRelease, metaIndex const * const CurrentRelease, std::vector &&Changes); + APT_HIDDEN static bool ReleaseInfoChangesAsGlobalErrors(std::vector &&Changes); + /** \brief Invoked when an item is confirmed to be up-to-date. * For instance, when an HTTP download is informed that the file on @@ -834,6 +867,14 @@ class pkgAcquireStatus /** \brief Initialize all counters to 0 and the time to the current time. */ pkgAcquireStatus(); virtual ~pkgAcquireStatus(); +}; +class pkgAcquireStatus2: public pkgAcquireStatus +{ +public: + virtual bool ReleaseInfoChanges(metaIndex const * const LastRelease, metaIndex const * const CurrentRelease, std::vector &&Changes); + + pkgAcquireStatus2(); + virtual ~pkgAcquireStatus2(); }; /*}}}*/ /** @} */ -- cgit v1.2.3