From 081fbea14d12f79c8d91ce4fe1f1004c7bc08656 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 12 Apr 2017 17:39:06 +0200 Subject: error in update on Release information changes The value of Origin, Label, Codename and co can be used in user configuration from apts own pinning to unattended upgrades. A repository changing this values can therefore have serious effects on the behaviour of apt and other tools using these values. In a first step we will generate error messages for these changes now explaining the need for explicit confirmation and provide config options and commandline flags to accept them. --- apt-pkg/acquire-item.cc | 60 +++++++++++++++++++++++++++++++++++++++++---- apt-pkg/deb/debmetaindex.cc | 19 +++++++++++++- apt-pkg/metaindex.cc | 32 ++++++++++++++++++++++-- apt-pkg/metaindex.h | 13 +++++++++- 4 files changed, 115 insertions(+), 9 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 574ef4939..f5ff8288b 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1605,13 +1605,63 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/ if (TransactionManager->MetaIndexParser->CheckDist(ExpectedDist) == false) _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"), Desc.Description.c_str(), ExpectedDist.c_str(), NowCodename.c_str()); - // might be okay, might be not + + // changed info potentially breaks user config like pinning if (TransactionManager->LastMetaIndexParser != nullptr) { - auto const LastCodename = TransactionManager->LastMetaIndexParser->GetCodename(); - if (LastCodename.empty() == false && NowCodename.empty() == false && LastCodename != NowCodename) - _error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"), - Desc.Description.c_str(), LastCodename.c_str(), NowCodename.c_str()); + auto const AllowInfoChange = _config->FindB("Acquire::AllowReleaseInfoChange", false); + auto const quietInfoChange = _config->FindB("quiet::ReleaseInfoChange", false); + struct { + char const * const Type; + bool const Allowed; + decltype(&metaIndex::GetOrigin) const Getter; + } checkers[] = { + { "Origin", AllowInfoChange, &metaIndex::GetOrigin }, + { "Label", AllowInfoChange, &metaIndex::GetLabel }, + { "Version", true, &metaIndex::GetVersion }, // numbers change all the time, that is okay + { "Suite", AllowInfoChange, &metaIndex::GetSuite }, + { "Codename", AllowInfoChange, &metaIndex::GetCodename }, + { nullptr, false, nullptr } + }; + 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; + }; + 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; + + { + auto const Last = TransactionManager->LastMetaIndexParser->GetDefaultPin(); + auto const Now = TransactionManager->MetaIndexParser->GetDefaultPin(); + 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 (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; + } } return true; } diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index 8c82414cb..424ef08f6 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -393,6 +393,9 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro // FIXME: find better tag name SupportsAcquireByHash = Section.FindB("Acquire-By-Hash", false); + SetOrigin(Section.FindS("Origin")); + SetLabel(Section.FindS("Label")); + SetVersion(Section.FindS("Version")); Suite = Section.FindS("Suite"); Codename = Section.FindS("Codename"); { @@ -415,6 +418,20 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro else // e.g. security.debian.org uses this style d->SupportedComponents.push_back(comp.substr(pos + 1)); } + { + decltype(pkgCache::ReleaseFile::Flags) flags = 0; + Section.FindFlag("NotAutomatic", flags, pkgCache::Flag::NotAutomatic); + signed short defaultpin = 500; + if ((flags & pkgCache::Flag::NotAutomatic) == pkgCache::Flag::NotAutomatic) + { + Section.FindFlag("ButAutomaticUpgrades", flags, pkgCache::Flag::ButAutomaticUpgrades); + if ((flags & pkgCache::Flag::ButAutomaticUpgrades) == pkgCache::Flag::ButAutomaticUpgrades) + defaultpin = 100; + else + defaultpin = 1; + } + SetDefaultPin(defaultpin); + } bool FoundHashSum = false; bool FoundStrongHashSum = false; @@ -472,7 +489,6 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro if (CheckValidUntil == true) { - std::string const Label = Section.FindS("Label"); std::string const StrValidUntil = Section.FindS("Valid-Until"); // if we have a Valid-Until header in the Release file, use it as default @@ -485,6 +501,7 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro return false; } } + auto const Label = GetLabel(); // get the user settings for this archive and use what expires earlier time_t MaxAge = d->ValidUntilMax; if (MaxAge == 0) diff --git a/apt-pkg/metaindex.cc b/apt-pkg/metaindex.cc index 624c7c9c7..8765851d6 100644 --- a/apt-pkg/metaindex.cc +++ b/apt-pkg/metaindex.cc @@ -9,6 +9,16 @@ #include /*}}}*/ +class metaIndexPrivate /*{{{*/ +{ + public: + std::string Origin; + std::string Label; + std::string Version; + signed short DefaultPin; +}; + /*}}}*/ + std::string metaIndex::Describe() const { return "Release"; @@ -26,7 +36,7 @@ bool metaIndex::Merge(pkgCacheGenerator &Gen,OpProgress *) const metaIndex::metaIndex(std::string const &URI, std::string const &Dist, char const * const Type) -: d(NULL), Indexes(NULL), Type(Type), URI(URI), Dist(Dist), Trusted(TRI_UNSET), +: d(new metaIndexPrivate()), Indexes(NULL), Type(Type), URI(URI), Dist(Dist), Trusted(TRI_UNSET), Date(0), ValidUntil(0), SupportsAcquireByHash(false), LoadedSuccessfully(TRI_UNSET) { /* nothing */ @@ -43,6 +53,7 @@ metaIndex::~metaIndex() } for (auto const &E: Entries) delete E.second; + delete d; } // one line Getters for public fields /*{{{*/ @@ -51,8 +62,12 @@ APT_PURE std::string metaIndex::GetDist() const { return Dist; } APT_PURE const char* metaIndex::GetType() const { return Type; } APT_PURE metaIndex::TriState metaIndex::GetTrusted() const { return Trusted; } APT_PURE std::string metaIndex::GetSignedBy() const { return SignedBy; } +APT_PURE std::string metaIndex::GetOrigin() const { return d->Origin; } +APT_PURE std::string metaIndex::GetLabel() const { return d->Label; } +APT_PURE std::string metaIndex::GetVersion() const { return d->Version; } APT_PURE std::string metaIndex::GetCodename() const { return Codename; } APT_PURE std::string metaIndex::GetSuite() const { return Suite; } +APT_PURE signed short metaIndex::GetDefaultPin() const { return d->DefaultPin; } APT_PURE bool metaIndex::GetSupportsAcquireByHash() const { return SupportsAcquireByHash; } APT_PURE time_t metaIndex::GetValidUntil() const { return ValidUntil; } APT_PURE time_t metaIndex::GetDate() const { return this->Date; } @@ -104,11 +119,19 @@ std::vector metaIndex::MetaKeys() const /*{{{*/ /*}}}*/ void metaIndex::swapLoad(metaIndex * const OldMetaIndex) /*{{{*/ { - std::swap(Entries, OldMetaIndex->Entries); + std::swap(SignedBy, OldMetaIndex->SignedBy); + std::swap(Suite, OldMetaIndex->Suite); + std::swap(Codename, OldMetaIndex->Codename); std::swap(Date, OldMetaIndex->Date); std::swap(ValidUntil, OldMetaIndex->ValidUntil); std::swap(SupportsAcquireByHash, OldMetaIndex->SupportsAcquireByHash); + std::swap(Entries, OldMetaIndex->Entries); std::swap(LoadedSuccessfully, OldMetaIndex->LoadedSuccessfully); + + OldMetaIndex->SetOrigin(d->Origin); + OldMetaIndex->SetLabel(d->Label); + OldMetaIndex->SetVersion(d->Version); + OldMetaIndex->SetDefaultPin(d->DefaultPin); } /*}}}*/ @@ -136,3 +159,8 @@ bool metaIndex::HasSupportForComponent(std::string const &component) const/*{{{* return true; } /*}}}*/ + +void metaIndex::SetOrigin(std::string const &origin) { d->Origin = origin; } +void metaIndex::SetLabel(std::string const &label) { d->Label = label; } +void metaIndex::SetVersion(std::string const &version) { d->Version = version; } +void metaIndex::SetDefaultPin(signed short const defaultpin) { d->DefaultPin = defaultpin; } diff --git a/apt-pkg/metaindex.h b/apt-pkg/metaindex.h index 531143bcb..eeeb9d807 100644 --- a/apt-pkg/metaindex.h +++ b/apt-pkg/metaindex.h @@ -25,6 +25,8 @@ class IndexTarget; class pkgCacheGenerator; class OpProgress; +class metaIndexPrivate; + class metaIndex { public: @@ -43,7 +45,7 @@ public: TRI_YES, TRI_DONTCARE, TRI_NO, TRI_UNSET }; private: - void * const d; + metaIndexPrivate * const d; protected: std::vector *Indexes; // parsed from the sources.list @@ -70,8 +72,12 @@ public: TriState GetTrusted() const; std::string GetSignedBy() const; + std::string GetOrigin() const; + std::string GetLabel() const; + std::string GetVersion() const; std::string GetCodename() const; std::string GetSuite() const; + signed short GetDefaultPin() const; bool GetSupportsAcquireByHash() const; time_t GetValidUntil() const; time_t GetDate() const; @@ -112,6 +118,11 @@ public: bool IsArchitectureSupported(std::string const &arch) const; bool IsArchitectureAllSupportedFor(IndexTarget const &target) const; bool HasSupportForComponent(std::string const &component) const; + // FIXME: should be members of the class on abi break + APT_HIDDEN void SetOrigin(std::string const &origin); + APT_HIDDEN void SetLabel(std::string const &label); + APT_HIDDEN void SetVersion(std::string const &version); + APT_HIDDEN void SetDefaultPin(signed short const defaultpin); }; #endif -- cgit v1.2.3 From 96ebab48c25fcd1ee83729cdba4be8a6343a8766 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 28 May 2017 13:24:33 +0200 Subject: show a Release-Notes URI if infos were changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives the repository owner a chance to explain why this change was needed – e.g. explaining the organisational changes or simply detailing the changes in the new release made. Note that this URI is also shown if the change is accepted, so it also draws attention to release notes of minor updates (if users watch apt output closely). --- apt-pkg/acquire-item.cc | 11 +++++++++++ apt-pkg/deb/debmetaindex.cc | 1 + apt-pkg/metaindex.cc | 3 +++ apt-pkg/metaindex.h | 2 ++ 4 files changed, 17 insertions(+) (limited to 'apt-pkg') diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index f5ff8288b..ddcff5808 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1623,6 +1623,7 @@ 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)(); @@ -1655,6 +1656,16 @@ bool pkgAcqMetaBase::VerifyVendor(string const &) /*{{{*/ CRI &= Allow; } } + if (_error->empty(GlobalError::NOTICE) == false) + { + auto const notes = TransactionManager->MetaIndexParser->GetReleaseNotes(); + if (notes.empty() == false) + { + // 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()); + } + } + _error->MergeWithStack(); if (CRI == false) { // TRANSLATOR: %s is the name of the manpage in question, e.g. apt-secure(8) diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index 424ef08f6..df7419ddd 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -398,6 +398,7 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro SetVersion(Section.FindS("Version")); Suite = Section.FindS("Suite"); Codename = Section.FindS("Codename"); + SetReleaseNotes(Section.FindS("Release-Notes")); { std::string const archs = Section.FindS("Architectures"); if (archs.empty() == false) diff --git a/apt-pkg/metaindex.cc b/apt-pkg/metaindex.cc index 8765851d6..695cf8804 100644 --- a/apt-pkg/metaindex.cc +++ b/apt-pkg/metaindex.cc @@ -16,6 +16,7 @@ class metaIndexPrivate /*{{{*/ std::string Label; std::string Version; signed short DefaultPin; + std::string ReleaseNotes; }; /*}}}*/ @@ -67,6 +68,7 @@ APT_PURE std::string metaIndex::GetLabel() const { return d->Label; } APT_PURE std::string metaIndex::GetVersion() const { return d->Version; } APT_PURE std::string metaIndex::GetCodename() const { return Codename; } APT_PURE std::string metaIndex::GetSuite() const { return Suite; } +APT_PURE std::string metaIndex::GetReleaseNotes() const { return d->ReleaseNotes; } APT_PURE signed short metaIndex::GetDefaultPin() const { return d->DefaultPin; } APT_PURE bool metaIndex::GetSupportsAcquireByHash() const { return SupportsAcquireByHash; } APT_PURE time_t metaIndex::GetValidUntil() const { return ValidUntil; } @@ -164,3 +166,4 @@ void metaIndex::SetOrigin(std::string const &origin) { d->Origin = origin; } void metaIndex::SetLabel(std::string const &label) { d->Label = label; } void metaIndex::SetVersion(std::string const &version) { d->Version = version; } void metaIndex::SetDefaultPin(signed short const defaultpin) { d->DefaultPin = defaultpin; } +void metaIndex::SetReleaseNotes(std::string const ¬es) { d->ReleaseNotes = notes; } diff --git a/apt-pkg/metaindex.h b/apt-pkg/metaindex.h index eeeb9d807..1951f118f 100644 --- a/apt-pkg/metaindex.h +++ b/apt-pkg/metaindex.h @@ -77,6 +77,7 @@ public: std::string GetVersion() const; std::string GetCodename() const; std::string GetSuite() const; + std::string GetReleaseNotes() const; signed short GetDefaultPin() const; bool GetSupportsAcquireByHash() const; time_t GetValidUntil() const; @@ -123,6 +124,7 @@ public: APT_HIDDEN void SetLabel(std::string const &label); APT_HIDDEN void SetVersion(std::string const &version); APT_HIDDEN void SetDefaultPin(signed short const defaultpin); + APT_HIDDEN void SetReleaseNotes(std::string const ¬es); }; #endif -- cgit v1.2.3 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(-) (limited to 'apt-pkg') 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