diff options
-rw-r--r-- | apt-pkg/cacheiterators.h | 12 | ||||
-rw-r--r-- | apt-pkg/deb/deblistparser.cc | 34 | ||||
-rw-r--r-- | apt-pkg/pkgcache.h | 12 | ||||
-rw-r--r-- | apt-pkg/policy.cc | 57 | ||||
-rw-r--r-- | doc/apt_preferences.5.xml | 21 |
5 files changed, 99 insertions, 37 deletions
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 5c3ad9bbb..ff2b65cdf 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -116,6 +116,7 @@ class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> { inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;} inline PkgIterator PackageList() const; + inline VerIterator VersionsInSource() const; PkgIterator FindPkg(APT::StringView Arch = APT::StringView("any", 3)) const; /** \brief find the package with the "best" architecture @@ -193,6 +194,13 @@ class pkgCache::VerIterator : public Iterator<Version, VerIterator> { inline VerIterator& operator++() {if (S != Owner->VerP) S = Owner->VerP + S->NextVer; return *this;} inline VerIterator operator++(int) { VerIterator const tmp(*this); operator++(); return tmp; } + inline VerIterator NextInSource() + { + if (S != Owner->VerP) + S = Owner->VerP + S->NextInSource; + return *this; + } + // Comparison int CompareVer(const VerIterator &B) const; /** \brief compares two version and returns if they are similar @@ -494,6 +502,10 @@ class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> { // Inlined Begin functions can't be in the class because of order problems /*{{{*/ inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);} + inline pkgCache::VerIterator pkgCache::GrpIterator::VersionsInSource() const + { + return VerIterator(*Owner, Owner->VerP + S->VersionsInSource); + } inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const {return VerIterator(*Owner,Owner->VerP + S->VersionList);} inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 21d1736e4..7614423df 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -166,8 +166,12 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) } // Parse the source package name pkgCache::GrpIterator G = Ver.ParentPkg().Group(); + + // Setup the defaults Ver->SourcePkgName = G->Name; Ver->SourceVerStr = Ver->VerStr; + + // Parse the name and version str if (Section.Find(pkgTagSection::Key::Source,Start,Stop) == true) { const char * const Space = static_cast<const char *>(memchr(Start, ' ', Stop - Start)); @@ -194,33 +198,19 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) } APT::StringView const pkgname(Start, Stop - Start); + // Oh, our group is the wrong one for the source package. Make a new one. if (pkgname != G.Name()) { - for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P)) - { - for (V = P.VersionList(); V.end() == false; ++V) - { - if (pkgname == V.SourcePkgName()) - { - Ver->SourcePkgName = V->SourcePkgName; - break; - } - } - if (V.end() == false) - break; - } - if (V.end() == true) - { - pkgCache::GrpIterator SG; - if (not NewGroup(SG, pkgname)) - return false; - - G = Ver.ParentPkg().Group(); - Ver->SourcePkgName = SG->Name; - } + if (not NewGroup(G, pkgname)) + return false; } } + // Link into by source package group. + Ver->SourcePkgName = G->Name; + Ver->NextInSource = G->VersionsInSource; + G->VersionsInSource = Ver.Index(); + Ver->MultiArch = ParseMultiArch(true); // Archive Size Ver->Size = Section.FindULL(pkgTagSection::Key::Size); diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index fcfef012f..8d31e4de9 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -381,7 +381,11 @@ struct pkgCache::Header On or more packages with the same name form a group, so we have a simple way to access a package built for different architectures Group exists in a singly linked list of group records starting at - the hash index of the name in the pkgCache::Header::GrpHashTable */ + the hash index of the name in the pkgCache::Header::GrpHashTable + + They also act as a representation of source packages, allowing you to + iterate over all binaries produced by a source package. + */ struct pkgCache::Group { /** \brief Name of the group */ @@ -392,11 +396,15 @@ struct pkgCache::Group map_pointer_t FirstPackage; // Package /** \brief Link to the last package which belongs to the group */ map_pointer_t LastPackage; // Package + /** \brief Link to the next Group */ map_pointer_t Next; // Group /** \brief unique sequel ID */ map_id_t ID; + /** \brief List of binary produces by source package with this name. */ + map_pointer_t VersionsInSource; // Version + }; /*}}}*/ // Package structure /*{{{*/ @@ -640,6 +648,8 @@ struct pkgCache::Version map_id_t ID; /** \brief parsed priority value */ map_number_t Priority; + /** \brief next version in the source package (might be different binary) */ + map_pointer_t NextInSource; // Version }; /*}}}*/ // Description structure /*{{{*/ diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc index 70d63fedb..034fce79c 100644 --- a/apt-pkg/policy.cc +++ b/apt-pkg/policy.cc @@ -171,6 +171,11 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, return; } + bool IsSourcePin = APT::String::Startswith(Name, "src:"); + if (IsSourcePin) { + Name = Name.substr(sizeof("src:") - 1); + } + size_t found = Name.rfind(':'); string Arch; if (found != string::npos) { @@ -186,10 +191,11 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G) if (Name != G.Name() && match.ExpressionMatches(Name, G.Name())) { + auto NameToPinFor = IsSourcePin ? string("src:").append(G.Name()) : string(G.Name()); if (Arch.empty() == false) - CreatePin(Type, string(G.Name()).append(":").append(Arch), Data, Priority); + CreatePin(Type, NameToPinFor.append(":").append(Arch), Data, Priority); else - CreatePin(Type, G.Name(), Data, Priority); + CreatePin(Type, NameToPinFor, Data, Priority); } return; } @@ -205,20 +211,19 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, else MatchingArch = Arch; APT::CacheFilter::PackageArchitectureMatchesSpecification pams(MatchingArch); - for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) - { - if (pams(Pkg.Arch()) == false) - continue; - - PkgPin P(Pkg.FullName()); - P.Type = Type; - P.Priority = Priority; - P.Data = Data; - // Find matching version(s) and copy the pin into it - pkgVersionMatch Match(P.Data,P.Type); - for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() != true; ++Ver) + if (IsSourcePin) { + for (pkgCache::VerIterator Ver = Grp.VersionsInSource(); not Ver.end(); Ver = Ver.NextInSource()) { + if (pams(Ver.ParentPkg().Arch()) == false) + continue; + + PkgPin P(Ver.ParentPkg().FullName()); + P.Type = Type; + P.Priority = Priority; + P.Data = Data; + // Find matching version(s) and copy the pin into it + pkgVersionMatch Match(P.Data,P.Type); if (Match.VersionMatches(Ver)) { Pin *VP = VerPins + Ver->ID; if (VP->Type == pkgVersionMatch::None) { @@ -227,6 +232,30 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, } } } + } else { + for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) + { + if (pams(Pkg.Arch()) == false) + continue; + + PkgPin P(Pkg.FullName()); + P.Type = Type; + P.Priority = Priority; + P.Data = Data; + + // Find matching version(s) and copy the pin into it + pkgVersionMatch Match(P.Data,P.Type); + for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() != true; ++Ver) + { + if (Match.VersionMatches(Ver)) { + Pin *VP = VerPins + Ver->ID; + if (VP->Type == pkgVersionMatch::None) { + *VP = P; + matched = true; + } + } + } + } } } diff --git a/doc/apt_preferences.5.xml b/doc/apt_preferences.5.xml index cac9a96e1..dacf3dc21 100644 --- a/doc/apt_preferences.5.xml +++ b/doc/apt_preferences.5.xml @@ -303,7 +303,28 @@ a &glob; expression in itself. </para> </refsect2> +<refsect2><title>Pinning by source package</title> +<para>APT supports pinning by source packages. To pin by a source package, +prepend "src:" to the package name.</para> +<para>For example, to pin all binaries produced by the apt source package +of this APT's version to 990, you can do:</para> +<programlisting> +Package: src:apt +Pin: version &apt-product-version; +Pin-Priority: 990 +</programlisting> + +<para>Source package pinning can be combined with regular expressions and +glob patterns, and can also take a binary architecture.</para> +<para>For example, let's pin all binaries for all architectures produced by +any source package containing apt in its name to 990:</para> +<programlisting> +Package: src:*apt*:any +Pin: version * +Pin-Priority: 990 +</programlisting> +</refsect2> |