summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2021-11-09 20:37:18 +0100
committerDavid Kalnischkies <david@kalnischkies.de>2021-11-23 14:18:25 +0100
commitdd81b736095f244454c7f179e67f21c08f3fbce9 (patch)
tree72dab24369cf26bc9d7a4e30986b25a18a2f002a
parentd08b87a711e4aad3e0c9b8777262cba6bd755099 (diff)
Support more than exact release matches in 'source'
The Debian 11 release notes elevate matching with regex to a documented and much used feature, which it previously wasn't. For binary packages this is not a problem, but source packages are special and it turns out that matching by release is here an exact string match only. A bit of refactoring later we can reuse the code we use for Packages files also for Release files, which is what we have for Sources files as those files itself have no representation in the cache. This means that we do not support matching based on components (c=main) in source, but we didn't before and we can cross that bridge if anyone notices… Closes: #998444
-rw-r--r--apt-pkg/versionmatch.cc100
-rw-r--r--apt-pkg/versionmatch.h1
-rw-r--r--apt-private/private-source.cc9
-rwxr-xr-xtest/integration/test-bug-998444-regex-as-target-release65
4 files changed, 127 insertions, 48 deletions
diff --git a/apt-pkg/versionmatch.cc b/apt-pkg/versionmatch.cc
index 82590edfe..83a969c4a 100644
--- a/apt-pkg/versionmatch.cc
+++ b/apt-pkg/versionmatch.cc
@@ -228,64 +228,80 @@ bool pkgVersionMatch::ExpressionMatches(const std::string& pattern, const char *
/*}}}*/
// VersionMatch::FileMatch - Match against an index file /*{{{*/
// ---------------------------------------------------------------------
-/* This matcher checks against the release file and the origin location
+/* This matcher checks against the release file and the origin location
to see if the constraints are met. */
-bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
+bool pkgVersionMatch::FileMatch(pkgCache::RlsFileIterator const &File)
{
if (Type == Release)
{
- if (MatchAll == true)
+ if (MatchAll)
return true;
-/* cout << RelVerStr << ',' << RelOrigin << ',' << RelArchive << ',' << RelLabel << endl;
- cout << File.Version() << ',' << File.Origin() << ',' << File.Archive() << ',' << File.Label() << endl;*/
-
- if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
- RelArchive.empty() == true && RelLabel.empty() == true &&
- RelRelease.empty() == true && RelCodename.empty() == true &&
- RelComponent.empty() == true && RelArchitecture.empty() == true)
+ if (RelVerStr.empty() && RelOrigin.empty() &&
+ RelArchive.empty() && RelLabel.empty() &&
+ RelRelease.empty() && RelCodename.empty() &&
+ RelComponent.empty() && RelArchitecture.empty())
return false;
- if (RelVerStr.empty() == false)
- if (MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false &&
- ExpressionMatches(RelVerStr, File.Version()) == false)
- return false;
- if (RelOrigin.empty() == false)
- if (!ExpressionMatches(RelOrigin,File.Origin()))
- return false;
- if (RelArchive.empty() == false)
- if (!ExpressionMatches(RelArchive,File.Archive()))
- return false;
- if (RelCodename.empty() == false)
- if (!ExpressionMatches(RelCodename,File.Codename()))
- return false;
- if (RelRelease.empty() == false)
- if (!ExpressionMatches(RelRelease,File.Archive()) &&
- !ExpressionMatches(RelRelease,File.Codename()))
- return false;
- if (RelLabel.empty() == false)
- if (!ExpressionMatches(RelLabel,File.Label()))
- return false;
- if (RelComponent.empty() == false)
- if (!ExpressionMatches(RelComponent,File.Component()))
- return false;
- if (RelArchitecture.empty() == false)
- if (!ExpressionMatches(RelArchitecture,File.Architecture()))
- return false;
+ if (not RelVerStr.empty() && not MatchVer(File.Version(), RelVerStr, RelVerPrefixMatch) &&
+ not ExpressionMatches(RelVerStr, File.Version()))
+ return false;
+ if (not RelOrigin.empty() && not ExpressionMatches(RelOrigin, File.Origin()))
+ return false;
+ if (not RelArchive.empty() && not ExpressionMatches(RelArchive, File.Archive()))
+ return false;
+ if (not RelCodename.empty() && not ExpressionMatches(RelCodename, File.Codename()))
+ return false;
+ if (not RelRelease.empty() && not ExpressionMatches(RelRelease, File.Archive()) &&
+ not ExpressionMatches(RelRelease, File.Codename()))
+ return false;
+ if (not RelLabel.empty() && not ExpressionMatches(RelLabel, File.Label()))
+ return false;
return true;
}
if (Type == Origin)
{
- if (OrSite.empty() == false) {
- if (File.Site() == NULL)
- return false;
- }
- else if (File->Release == 0)// only 'bad' files like dpkg.status file has no release file
+ if (not OrSite.empty() && File.Site() == nullptr)
return false;
- return (ExpressionMatches(OrSite, File.Site())); /* both strings match */
+ return ExpressionMatches(OrSite, File.Site()); /* both strings match */
}
return false;
}
+bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
+{
+ if (auto const RlsFile = File.ReleaseFile(); not RlsFile.end())
+ {
+ if (not FileMatch(RlsFile))
+ return false;
+ }
+ else if (Type == Release)
+ {
+ // only 'bad' files like dpkg.status file have no release file
+ // those reuse the Component of te PkgFile to store the Archive "now".
+ if (not RelArchive.empty() && not ExpressionMatches(RelArchive, File.Component()))
+ return false;
+ if (not RelRelease.empty() && not ExpressionMatches(RelRelease, File.Component()))
+ return false;
+ if (not RelOrigin.empty() || not RelLabel.empty() ||
+ not RelVerStr.empty() || not RelCodename.empty())
+ return false;
+ }
+ else
+ return false;
+
+ if (Type == Release)
+ {
+ if (MatchAll)
+ return true;
+
+ if (not RelComponent.empty() && not ExpressionMatches(RelComponent, File.Component()))
+ return false;
+ if (not RelArchitecture.empty() && not ExpressionMatches(RelArchitecture, File.Architecture()))
+ return false;
+ }
+
+ return true;
+}
/*}}}*/
diff --git a/apt-pkg/versionmatch.h b/apt-pkg/versionmatch.h
index 0f84f8dfa..faf1fd436 100644
--- a/apt-pkg/versionmatch.h
+++ b/apt-pkg/versionmatch.h
@@ -68,6 +68,7 @@ class APT_PUBLIC pkgVersionMatch
static bool ExpressionMatches(const char *pattern, const char *string);
static bool ExpressionMatches(const std::string& pattern, const char *string);
bool FileMatch(pkgCache::PkgFileIterator File);
+ bool FileMatch(pkgCache::RlsFileIterator const &File);
pkgCache::VerIterator Find(pkgCache::PkgIterator Pkg);
bool VersionMatches(pkgCache::VerIterator Ver);
diff --git a/apt-private/private-source.cc b/apt-private/private-source.cc
index db96cb17f..f3ee0e594 100644
--- a/apt-private/private-source.cc
+++ b/apt-private/private-source.cc
@@ -243,6 +243,7 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
unsigned long Offset = 0;
std::string Version;
pkgSourceList const * const SrcList = Cache.GetSourceList();
+ pkgVersionMatch RelTagMatch{RelTag, pkgVersionMatch::Release};
/* Iterate over all of the hits, which includes the resulting
binary packages in the search */
@@ -258,12 +259,8 @@ static pkgSrcRecords::Parser *FindSrc(const char *Name,
if (RelTag.empty() == false && UserRequestedVerTag.empty() == true)
{
pkgCache::RlsFileIterator const Rls = GetReleaseFileForSourceRecord(Cache, SrcList, Parse);
- if (Rls.end() == false)
- {
- if ((Rls->Archive != 0 && RelTag != Rls.Archive()) &&
- (Rls->Codename != 0 && RelTag != Rls.Codename()))
- continue;
- }
+ if (not Rls.end() && not RelTagMatch.FileMatch(Rls))
+ continue;
}
// Ignore all versions which doesn't fit
diff --git a/test/integration/test-bug-998444-regex-as-target-release b/test/integration/test-bug-998444-regex-as-target-release
new file mode 100755
index 000000000..97970bccd
--- /dev/null
+++ b/test/integration/test-bug-998444-regex-as-target-release
@@ -0,0 +1,65 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+setupenvironment
+configarchitecture 'amd64'
+
+addpackage() {
+ insertpackage "$@"
+ insertsource "$@"
+}
+
+addpackage 'stable' 'foo' 'all' '1'
+addpackage 'stable-security' 'foo' 'all' '1.1~security.1'
+addpackage 'stable-updates' 'foo' 'all' '2~stable.1'
+addpackage 'unstable' 'foo' 'all' '2'
+addpackage 'experimental' 'foo' 'all' '3'
+addpackage 'external' 'foo' 'all' '4'
+
+cat > rootdir/etc/apt/preferences <<EOF
+Package: *
+Pin: release a=external
+Pin-Priority: -10
+EOF
+
+setupaptarchive
+
+APTARCHIVE="file:${TMPWORKINGDIRECTORY}/aptarchive"
+
+testfoo() {
+ testsuccessequal "foo:
+ Installed: (none)
+ Candidate: $1
+ Version table:
+ 4 $2
+ $(printf '%3s' "$2") ${APTARCHIVE} external/main all Packages
+ 3 $3
+ $(printf '%3s' "$3") ${APTARCHIVE} experimental/main all Packages
+ 2 $4
+ $(printf '%3s' "$4") ${APTARCHIVE} unstable/main all Packages
+ 2~stable.1 $5
+ $(printf '%3s' "$5") ${APTARCHIVE} stable-updates/main all Packages
+ 1.1~security.1 $6
+ $(printf '%3s' "$6") ${APTARCHIVE} stable-security/main all Packages
+ 1 $7
+ $(printf '%3s' "$7") ${APTARCHIVE} stable/main all Packages" apt policy foo -t "$8"
+ testsuccessequal "'${APTARCHIVE}/pool/main/foo/foo_$(apthelper quote-string "${1}" '+~ ')_all.deb' foo_${1}_all.deb 42 SHA256:0000000000000000000000000000000000000000000000000000000000000000" apt download foo --print-uris -t "$8"
+ testsuccess apt source -t "$8" --print-uris foo
+ tail -n 2 rootdir/tmp/testsuccess.output | cut -d' ' -f 2 > aptsource.output
+ testfileequal 'aptsource.output' "foo_${9:-$1}.dsc
+foo_${9:-$1}.tar.gz"
+}
+testfoo '2' '-10' '1' '500' '500' '500' '500' '' '4'
+testfoo '2' '-10' '1' '990' '500' '500' '500' 'unstable' '2'
+testfoo '1' '-10' '1' '500' '500' '500' '990' 'stable'
+testfoo '2~stable.1' '-10' '1' '500' '990' '500' '500' 'stable-updates'
+testfoo '1.1~security.1' '-10' '1' '500' '500' '990' '500' 'stable-security'
+testfoo '4' '990' '1' '500' '500' '500' '500' 'a=external'
+testfoo '2' '-10' '1' '990' '990' '990' '990' '/stable/'
+testfoo '2~stable.1' '-10' '1' '500' '990' '990' '990' '/^stable/'
+testfoo '1.1~security.1' '-10' '1' '500' '500' '990' '990' '/^stable(|-security)$/'
+testfoo '2~stable.1' '-10' '1' '500' '990' '990' '500' '/^stable(-security|-updates)$/'
+testfoo '2~stable.1' '-10' '1' '500' '990' '990' '990' '/^stable(|-security|-updates)$/'
+testfoo '4' '990' '990' '990' '990' '990' '990' '/./'