summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2020-02-18 12:38:46 +0000
committerJulian Andres Klode <jak@debian.org>2020-02-18 12:38:46 +0000
commit62683ed6459e874119f3346d8be66b85e8a90533 (patch)
tree438581b4c0d1ee233244d7a20636eba96950adfc
parent9a0a2daa268bd718a4b7fd9617b46ed74c76e94a (diff)
parent450af26202424bef33e0c58f3f99dfd0c21e7297 (diff)
Merge branch 'pu/source-version' into 'master'
ABI BREAK: Implement pinning by source package See merge request apt-team/apt!96
-rw-r--r--apt-pkg/cacheiterators.h12
-rw-r--r--apt-pkg/deb/deblistparser.cc34
-rw-r--r--apt-pkg/pkgcache.h12
-rw-r--r--apt-pkg/policy.cc57
-rw-r--r--doc/apt_preferences.5.xml21
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>