From ac81c0f9b79351258d3a29212f7fda312e5afeb5 Mon Sep 17 00:00:00 2001 From: josch Date: Tue, 19 Aug 2014 10:29:29 +0200 Subject: [PATCH] implement the updated build profile spec --- apt-pkg/deb/deblistparser.cc | 112 +++++++++++------- .../test-bug-661537-build-profiles-support | 86 +++++++------- test/libapt/parsedepends_test.cc | 29 +++-- 3 files changed, 130 insertions(+), 97 deletions(-) diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 7d4fd52c..8311b5d7 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -635,72 +635,94 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, if (ParseRestrictionsList == true) { - // Parse a restrictions list - if (I != Stop && *I == '<') + // Parse a restrictions formula which is in disjunctive normal form: + // (foo AND bar) OR (blub AND bla) + + std::vector const profiles = APT::Configuration::getBuildProfiles(); + + // if the next character is a restriction list, then by default the + // dependency does not apply and the conditions have to be checked + // if the next character is not a restriction list, then by default the + // dependency applies + bool applies1 = (*I != '<'); + while (I != Stop) { + if (*I != '<') + break; + ++I; // malformed if (unlikely(I == Stop)) return 0; - std::vector const profiles = APT::Configuration::getBuildProfiles(); - const char *End = I; - bool Found = false; - bool NegRestriction = false; - while (I != Stop) - { - // look for whitespace or ending '>' - for (;End != Stop && !isspace(*End) && *End != '>'; ++End); - if (unlikely(End == Stop)) - return 0; - - if (*I == '!') + // if of the prior restriction list is already fulfilled, then + // we can just skip to the end of the current list + if (applies1) { + for (;End != Stop && *End != '>'; ++End); + I = ++End; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } else { + bool applies2 = true; + // all the conditions inside a restriction list have to be + // met so once we find one that is not met, we can skip to + // the end of this list + while (I != Stop) { - NegRestriction = true; - ++I; - } + // look for whitespace or ending '>' + // End now points to the character after the current term + for (;End != Stop && !isspace(*End) && *End != '>'; ++End); - std::string restriction(I, End); + if (unlikely(End == Stop)) + return 0; - std::string prefix = "profile."; - // only support for "profile" prefix, ignore others - if (restriction.size() > prefix.size() && - restriction.substr(0, prefix.size()) == prefix) - { - // get the name of the profile - restriction = restriction.substr(prefix.size()); + bool NegRestriction = false; + if (*I == '!') + { + NegRestriction = true; + ++I; + } + + std::string restriction(I, End); if (restriction.empty() == false && profiles.empty() == false && - std::find(profiles.begin(), profiles.end(), restriction) != profiles.end()) + std::find(profiles.begin(), profiles.end(), restriction) != profiles.end()) { - Found = true; - if (I[-1] != '!') - NegRestriction = false; - // we found a match, so fast-forward to the end of the wildcards - for (; End != Stop && *End != '>'; ++End); + if (NegRestriction) { + applies2 = false; + // since one of the terms does not apply we don't have to check the others + for (; End != Stop && *End != '>'; ++End); + } + } else { + if (!NegRestriction) { + applies2 = false; + // since one of the terms does not apply we don't have to check the others + for (; End != Stop && *End != '>'; ++End); + } + } + + if (*End++ == '>') { + I = End; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + break; } - } - if (*End++ == '>') { I = End; - break; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } + if (applies2) { + applies1 = true; } - - I = End; - for (;I != Stop && isspace(*I) != 0; I++); } - - if (NegRestriction == true) - Found = !Found; - - if (Found == false) - Package = ""; /* not for this restriction */ } - // Skip whitespace - for (;I != Stop && isspace(*I) != 0; I++); + if (applies1 == false) { + Package = ""; //not for this restriction + } } if (I != Stop && *I == '|') diff --git a/test/integration/test-bug-661537-build-profiles-support b/test/integration/test-bug-661537-build-profiles-support index ae1403f7..6c850fdf 100755 --- a/test/integration/test-bug-661537-build-profiles-support +++ b/test/integration/test-bug-661537-build-profiles-support @@ -11,18 +11,16 @@ insertinstalledpackage 'build-essential' 'all' '0' 'Multi-Arch: foreign' insertpackage 'unstable' 'foo' 'all' '1.0' insertpackage 'unstable' 'bar' 'all' '1.0' -insertsource 'unstable' 'buildprofiles' 'any' '1' 'Build-Depends: foo (>= 1.0) [i386 arm] , bar' +insertsource 'unstable' 'buildprofiles' 'any' '1' 'Build-Depends: foo (>= 1.0) [i386 arm] , bar' # table from https://wiki.debian.org/BuildProfileSpec -insertsource 'unstable' 'spec-1' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-2' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-3' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-4' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-5' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-6' 'any' '1' 'Build-Depends: foo ' -# multiple stanzas not supported: error out -insertsource 'unstable' 'spec-7' 'any' '1' 'Build-Depends: foo ' -insertsource 'unstable' 'spec-8' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-1' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-2' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-3' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-4' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-5' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-6' 'any' '1' 'Build-Depends: foo ' +insertsource 'unstable' 'spec-7' 'any' '1' 'Build-Depends: foo ' setupaptarchive @@ -72,7 +70,7 @@ Building dependency tree... 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.' msgtest 'Check if version of installed dpkg is high enough for' 'build profiles support' -if dpkg --compare-versions "$(command dpkg-query --showformat='${Version}' --show dpkg)" 'ge' '1.17.2'; then +if dpkg --compare-versions "$(command dpkg-query --showformat='${Version}' --show dpkg)" 'ge' '1.17.14'; then msgpass testwithdpkg() { msgtest "Test with" "dpkg-checkbuilddeps -d '$1' -P '$2'" @@ -113,35 +111,37 @@ testprofile() { testwithdpkg "$2" "$3" "$4" } -testprofile 'spec-1' 'foo ' '' "$KEEP" -testprofile 'spec-1' 'foo ' 'stage1' "$DROP" -testprofile 'spec-1' 'foo ' 'notest' "$KEEP" -testprofile 'spec-1' 'foo ' 'stage1,notest' "$DROP" - -testprofile 'spec-2' 'foo ' '' "$DROP" -testprofile 'spec-2' 'foo ' 'stage1' "$KEEP" -testprofile 'spec-2' 'foo ' 'notest' "$DROP" -testprofile 'spec-2' 'foo ' 'stage1,notest' "$KEEP" - -testprofile 'spec-3' 'foo ' '' "$KEEP" -testprofile 'spec-3' 'foo ' 'stage1' "$DROP" -testprofile 'spec-3' 'foo ' 'notest' "$DROP" -testprofile 'spec-3' 'foo ' 'stage1,notest' "$DROP" - -testprofile 'spec-4' 'foo ' '' "$DROP" -testprofile 'spec-4' 'foo ' 'stage1' "$KEEP" -testprofile 'spec-4' 'foo ' 'notest' "$KEEP" -testprofile 'spec-4' 'foo ' 'stage1,notest' "$KEEP" - -testprofile 'spec-5' 'foo ' '' "$KEEP" -testprofile 'spec-5' 'foo ' 'stage1' "$DROP" -testprofile 'spec-5' 'foo ' 'notest' "$KEEP" -testprofile 'spec-5' 'foo ' 'stage1,notest' "$DROP" - -testprofile 'spec-6' 'foo ' '' "$KEEP" -testprofile 'spec-6' 'foo ' 'stage1' "$KEEP" -testprofile 'spec-6' 'foo ' 'notest' "$DROP" -testprofile 'spec-6' 'foo ' 'stage1,notest' "$KEEP" - -testfailure aptget build-dep spec-7 -s -testfailure aptget build-dep spec-8 -s +testprofile 'spec-1' 'foo ' '' "$KEEP" +testprofile 'spec-1' 'foo ' 'stage1' "$DROP" +testprofile 'spec-1' 'foo ' 'notest' "$KEEP" +testprofile 'spec-1' 'foo ' 'stage1,notest' "$DROP" + +testprofile 'spec-2' 'foo ' '' "$DROP" +testprofile 'spec-2' 'foo ' 'stage1' "$KEEP" +testprofile 'spec-2' 'foo ' 'notest' "$DROP" +testprofile 'spec-2' 'foo ' 'stage1,notest' "$KEEP" + +testprofile 'spec-3' 'foo ' '' "$KEEP" +testprofile 'spec-3' 'foo ' 'stage1' "$DROP" +testprofile 'spec-3' 'foo ' 'notest' "$DROP" +testprofile 'spec-3' 'foo ' 'stage1,notest' "$DROP" + +testprofile 'spec-4' 'foo ' '' "$DROP" +testprofile 'spec-4' 'foo ' 'stage1' "$DROP" +testprofile 'spec-4' 'foo ' 'notest' "$DROP" +testprofile 'spec-4' 'foo ' 'stage1,notest' "$KEEP" + +testprofile 'spec-5' 'foo ' '' "$DROP" +testprofile 'spec-5' 'foo ' 'stage1' "$DROP" +testprofile 'spec-5' 'foo ' 'notest' "$KEEP" +testprofile 'spec-5' 'foo ' 'stage1,notest' "$DROP" + +testprofile 'spec-6' 'foo ' '' "$DROP" +testprofile 'spec-6' 'foo ' 'stage1' "$KEEP" +testprofile 'spec-6' 'foo ' 'notest' "$DROP" +testprofile 'spec-6' 'foo ' 'stage1,notest' "$DROP" + +testprofile 'spec-7' 'foo ' '' "$KEEP" +testprofile 'spec-7' 'foo ' 'stage1' "$KEEP" +testprofile 'spec-7' 'foo ' 'notest' "$DROP" +testprofile 'spec-7' 'foo ' 'stage1,notest' "$KEEP" diff --git a/test/libapt/parsedepends_test.cc b/test/libapt/parsedepends_test.cc index 52eac823..f644599b 100644 --- a/test/libapt/parsedepends_test.cc +++ b/test/libapt/parsedepends_test.cc @@ -33,9 +33,10 @@ static void parseDependency(bool const StripMultiArch, bool const ParseArchFlag "os-for-me [ linux-any ], " "cpu-not-for-me [ any-armel ], " "os-not-for-me [ kfreebsd-any ], " - "not-in-stage1 , " - "not-in-stage1-or-nodoc , " - "only-in-stage1 , " + "not-in-stage1 , " + "not-stage1-and-not-nodoc , " + "not-stage1-or-not-nodoc , " + "unknown-profile , " "overlord-dev:any (= 7.15.3~) | overlord-dev:native (>> 7.15.5), " ; @@ -184,7 +185,7 @@ static void parseDependency(bool const StripMultiArch, bool const ParseArchFlag if (ParseRestrictionsList == true) { Start = debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList); - EXPECT_EQ("", Package); // not-in-stage1-or-in-nodoc + EXPECT_EQ("", Package); // not-stage1-and-not-nodoc } else { EXPECT_EQ(true, 0 == debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList)); Start = strstr(Start, ","); @@ -193,7 +194,16 @@ static void parseDependency(bool const StripMultiArch, bool const ParseArchFlag if (ParseRestrictionsList == true) { Start = debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList); - EXPECT_EQ("only-in-stage1", Package); + EXPECT_EQ("not-stage1-or-not-nodoc", Package); + } else { + EXPECT_EQ(true, 0 == debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList)); + Start = strstr(Start, ","); + Start++; + } + + if (ParseRestrictionsList == true) { + Start = debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList); + EXPECT_EQ("", Package); // unknown-profile } else { EXPECT_EQ(true, 0 == debListParser::ParseDepends(Start, End, Package, Version, Op, ParseArchFlags, StripMultiArch, ParseRestrictionsList)); Start = strstr(Start, ","); @@ -232,10 +242,11 @@ test: SCOPED_TRACE(std::string("ParseRestrictionsList: ") + (ParseRestrictionsList ? "true" : "false")); parseDependency(StripMultiArch, ParseArchFlags, ParseRestrictionsList); } - if (StripMultiArch == false) - if (ParseArchFlags == false) - ParseRestrictionsList = !ParseRestrictionsList; - ParseArchFlags = !ParseArchFlags; + if (StripMultiArch == false) { + if (ParseArchFlags == false) + ParseRestrictionsList = !ParseRestrictionsList; + ParseArchFlags = !ParseArchFlags; + } StripMultiArch = !StripMultiArch; runner++; -- 2.20.1