Преглед изворни кода

support lang= and target= sources.list options

We support arch= for a while, now we finally add lang= as well and as a
first simple way of controlling which targets to acquire also target=.

This asked for a redesign of the internal API of parsing and storing
information about 'deb' and 'deb-src' lines. As this API isn't visible
to the outside no damage done through.

Beside being a nice cleanup (= it actually does more in less lines) it
also provides us with a predictable order of architectures as provides
in the configuration rather than based on string sorting-order, so that
now the native architecture is parsed/displayed first. Observeable e.g.
in apt-get output.
David Kalnischkies пре 11 година
родитељ
комит
463c8d8015

+ 3 - 3
apt-pkg/deb/debindexfile.cc

@@ -510,7 +510,7 @@ class APT_HIDDEN debIFTypeDebPkgFile : public pkgIndexFile::Type
    {
       return new debDebFileRecordParser(File.FileName());
    };
-   debIFTypeDebPkgFile() {Label = "deb Package file";};
+   debIFTypeDebPkgFile() {Label = "Debian deb file";};
 };
 class APT_HIDDEN debIFTypeDscFile : public pkgIndexFile::Type
 {
@@ -519,7 +519,7 @@ class APT_HIDDEN debIFTypeDscFile : public pkgIndexFile::Type
    {
       return new debDscRecordParser(DscFile, NULL);
    };
-   debIFTypeDscFile() {Label = "dsc File Source Index";};
+   debIFTypeDscFile() {Label = "Debian dsc file";};
 };
 class APT_HIDDEN debIFTypeDebianSourceDir : public pkgIndexFile::Type
 {
@@ -528,7 +528,7 @@ class APT_HIDDEN debIFTypeDebianSourceDir : public pkgIndexFile::Type
    {
       return new debDscRecordParser(SourceDir + string("/debian/control"), NULL);
    };
-   debIFTypeDebianSourceDir() {Label = "debian/control File Source Index";};
+   debIFTypeDebianSourceDir() {Label = "Debian control file";};
 };
 
 APT_HIDDEN debIFTypeSrc _apt_Src;

+ 186 - 244
apt-pkg/deb/debmetaindex.cc

@@ -29,11 +29,25 @@
 #include <unistd.h>
 #include <string.h>
 
-using namespace std;
-
-string debReleaseIndex::MetaIndexInfo(const char *Type) const
+class APT_HIDDEN debReleaseIndexPrivate					/*{{{*/
+{
+   public:
+   struct APT_HIDDEN debSectionEntry
+   {
+      std::string Name;
+      std::vector<std::string> Targets;
+      std::vector<std::string> Architectures;
+      std::vector<std::string> Languages;
+   };
+
+   std::vector<debSectionEntry> DebEntries;
+   std::vector<debSectionEntry> DebSrcEntries;
+};
+									/*}}}*/
+// ReleaseIndex::MetaIndex* - display helpers				/*{{{*/
+std::string debReleaseIndex::MetaIndexInfo(const char *Type) const
 {
-   string Info = ::URI::ArchiveOnly(URI) + ' ';
+   std::string Info = ::URI::ArchiveOnly(URI) + ' ';
    if (Dist[Dist.size() - 1] == '/')
    {
       if (Dist != "/")
@@ -50,15 +64,15 @@ std::string debReleaseIndex::Describe() const
    return MetaIndexInfo("Release");
 }
 
-string debReleaseIndex::MetaIndexFile(const char *Type) const
+std::string debReleaseIndex::MetaIndexFile(const char *Type) const
 {
    return _config->FindDir("Dir::State::lists") +
       URItoFileName(MetaIndexURI(Type));
 }
 
-string debReleaseIndex::MetaIndexURI(const char *Type) const
+std::string debReleaseIndex::MetaIndexURI(const char *Type) const
 {
-   string Res;
+   std::string Res;
 
    if (Dist == "/")
       Res = URI;
@@ -70,8 +84,8 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const
    Res += Type;
    return Res;
 }
-
-std::string debReleaseIndex::LocalFileName() const
+									/*}}}*/
+std::string debReleaseIndex::LocalFileName() const			/*{{{*/
 {
    // see if we have a InRelease file
    std::string PathInRelease =  MetaIndexFile("InRelease");
@@ -84,28 +98,24 @@ std::string debReleaseIndex::LocalFileName() const
 
    return "";
 }
-
-debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) :
-					metaIndex(URI, Dist, "deb"), d(NULL), Trusted(CHECK_TRUST)
+									/*}}}*/
+// ReleaseIndex Con- and Destructors					/*{{{*/
+debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist) :
+					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate()), Trusted(CHECK_TRUST)
 {}
-
-debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist, bool const Trusted) :
-					metaIndex(URI, Dist, "deb"), d(NULL) {
+debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, bool const Trusted) :
+					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate()) {
 	SetTrusted(Trusted);
 }
-
 debReleaseIndex::~debReleaseIndex() {
-	for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin();
-	     A != ArchEntries.end(); ++A)
-		for (vector<const debSectionEntry *>::const_iterator S = A->second.begin();
-		     S != A->second.end(); ++S)
-			delete *S;
+   if (d != NULL)
+      delete d;
 }
-
-template<typename CallC>
-void foreachTarget(std::string const &URI, std::string const &Dist,
-      std::map<std::string, std::vector<debReleaseIndex::debSectionEntry const *> > const &ArchEntries,
-      CallC &Call)
+									/*}}}*/
+// ReleaseIndex::GetIndexTargets					/*{{{*/
+static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
+      std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
+      std::vector<IndexTarget> &IndexTargets)
 {
    bool const flatArchive = (Dist[Dist.length() - 1] == '/');
    std::string baseURI = URI;
@@ -118,148 +128,101 @@ void foreachTarget(std::string const &URI, std::string const &Dist,
       baseURI += "dists/" + Dist + "/";
    std::string const Release = (Dist == "/") ? "" : Dist;
    std::string const Site = ::URI::ArchiveOnly(URI);
-   std::vector<std::string> lang = APT::Configuration::getLanguages(true);
-   if (lang.empty())
-      lang.push_back("none");
-   map<string, vector<debReleaseIndex::debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source");
-   if (src != ArchEntries.end())
+
+   for (std::vector<debReleaseIndexPrivate::debSectionEntry>::const_iterator E = entries.begin(); E != entries.end(); ++E)
    {
-      std::vector<std::string> const targets = _config->FindVector("APT::Acquire::Targets::deb-src", "", true);
-      for (std::vector<std::string>::const_iterator T = targets.begin(); T != targets.end(); ++T)
+      for (std::vector<std::string>::const_iterator T = E->Targets.begin(); T != E->Targets.end(); ++T)
       {
-#define APT_T_CONFIG(X) _config->Find(std::string("APT::Acquire::Targets::deb-src::") + *T + "::" + (X))
-	 std::string const MetaKey = APT_T_CONFIG(flatArchive ? "flatMetaKey" : "MetaKey");
-	 std::string const ShortDesc = APT_T_CONFIG("ShortDescription");
-	 std::string const LongDesc = APT_T_CONFIG(flatArchive ? "flatDescription" : "Description");
+#define APT_T_CONFIG(X) _config->Find(std::string("APT::Acquire::Targets::") + Type  + "::" + *T + "::" + (X))
+	 std::string const tplMetaKey = APT_T_CONFIG(flatArchive ? "flatMetaKey" : "MetaKey");
+	 std::string const tplShortDesc = APT_T_CONFIG("ShortDescription");
+	 std::string const tplLongDesc = APT_T_CONFIG(flatArchive ? "flatDescription" : "Description");
 	 bool const IsOptional = _config->FindB(std::string("APT::Acquire::Targets::deb-src::") + *T + "::Optional", true);
 #undef APT_T_CONFIG
-	 if (MetaKey.empty())
+	 if (tplMetaKey.empty())
 	    continue;
 
-	 vector<debReleaseIndex::debSectionEntry const*> const SectionEntries = src->second;
-	 for (vector<debReleaseIndex::debSectionEntry const*>::const_iterator I = SectionEntries.begin();
-	       I != SectionEntries.end(); ++I)
+	 for (std::vector<std::string>::const_iterator L = E->Languages.begin(); L != E->Languages.end(); ++L)
 	 {
-	    for (vector<std::string>::const_iterator l = lang.begin(); l != lang.end(); ++l)
+	    if (*L == "none" && tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
+	       continue;
+
+	    for (std::vector<std::string>::const_iterator A = E->Architectures.begin(); A != E->Architectures.end(); ++A)
 	    {
-	       if (*l == "none" && MetaKey.find("$(LANGUAGE)") != std::string::npos)
-		  continue;
 
 	       std::map<std::string, std::string> Options;
 	       Options.insert(std::make_pair("SITE", Site));
 	       Options.insert(std::make_pair("RELEASE", Release));
-	       if (MetaKey.find("$(COMPONENT)") != std::string::npos)
-		  Options.insert(std::make_pair("COMPONENT", (*I)->Section));
-	       if (MetaKey.find("$(LANGUAGE)") != std::string::npos)
-		  Options.insert(std::make_pair("LANGUAGE", *l));
-	       Options.insert(std::make_pair("ARCHITECTURE", "source"));
+	       if (tplMetaKey.find("$(COMPONENT)") != std::string::npos)
+		  Options.insert(std::make_pair("COMPONENT", E->Name));
+	       if (tplMetaKey.find("$(LANGUAGE)") != std::string::npos)
+		  Options.insert(std::make_pair("LANGUAGE", *L));
+	       if (tplMetaKey.find("$(ARCHITECTURE)") != std::string::npos)
+		  Options.insert(std::make_pair("ARCHITECTURE", *A));
 	       Options.insert(std::make_pair("BASE_URI", baseURI));
 	       Options.insert(std::make_pair("REPO_URI", URI));
 	       Options.insert(std::make_pair("TARGET_OF", "deb-src"));
 	       Options.insert(std::make_pair("CREATED_BY", *T));
-	       Call(MetaKey, ShortDesc, LongDesc, IsOptional, Options);
 
-	       if (MetaKey.find("$(LANGUAGE)") == std::string::npos)
+	       std::string MetaKey = tplMetaKey;
+	       std::string ShortDesc = tplShortDesc;
+	       std::string LongDesc = tplLongDesc;
+	       for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
+	       {
+		  MetaKey = SubstVar(MetaKey, std::string("$(") + O->first + ")", O->second);
+		  ShortDesc = SubstVar(ShortDesc, std::string("$(") + O->first + ")", O->second);
+		  LongDesc = SubstVar(LongDesc, std::string("$(") + O->first + ")", O->second);
+	       }
+	       IndexTarget Target(
+		     MetaKey,
+		     ShortDesc,
+		     LongDesc,
+		     Options.find("BASE_URI")->second + MetaKey,
+		     IsOptional,
+		     Options
+		     );
+	       IndexTargets.push_back(Target);
+
+	       if (tplMetaKey.find("$(ARCHITECTURE)") == std::string::npos)
 		  break;
-	    }
-
-	    if (MetaKey.find("$(COMPONENT)") == std::string::npos)
-	       break;
-	 }
-      }
-   }
-
-   std::vector<std::string> const targets = _config->FindVector("APT::Acquire::Targets::deb", "", true);
-   for (std::vector<std::string>::const_iterator T = targets.begin(); T != targets.end(); ++T)
-   {
-#define APT_T_CONFIG(X) _config->Find(std::string("APT::Acquire::Targets::deb::") + *T + "::" + (X))
-      std::string const MetaKey = APT_T_CONFIG(flatArchive ? "flatMetaKey" : "MetaKey");
-      std::string const ShortDesc = APT_T_CONFIG("ShortDescription");
-      std::string const LongDesc = APT_T_CONFIG(flatArchive ? "flatDescription" : "Description");
-      bool const IsOptional = _config->FindB(std::string("APT::Acquire::Targets::deb::") + *T + "::Optional", true);
-#undef APT_T_CONFIG
-      if (MetaKey.empty())
-	 continue;
-
-      for (map<string, vector<debReleaseIndex::debSectionEntry const*> >::const_iterator a = ArchEntries.begin();
-	    a != ArchEntries.end(); ++a)
-      {
-	 if (a->first == "source")
-	    continue;
-
-	 for (vector <const debReleaseIndex::debSectionEntry *>::const_iterator I = a->second.begin();
-	       I != a->second.end(); ++I) {
-
-	    for (vector<std::string>::const_iterator l = lang.begin(); l != lang.end(); ++l)
-	    {
-	       if (*l == "none" && MetaKey.find("$(LANGUAGE)") != std::string::npos)
-		  continue;
-
-	       std::map<std::string, std::string> Options;
-	       Options.insert(std::make_pair("SITE", Site));
-	       Options.insert(std::make_pair("RELEASE", Release));
-	       if (MetaKey.find("$(COMPONENT)") != std::string::npos)
-		  Options.insert(std::make_pair("COMPONENT", (*I)->Section));
-	       if (MetaKey.find("$(LANGUAGE)") != std::string::npos)
-		  Options.insert(std::make_pair("LANGUAGE", *l));
-	       if (MetaKey.find("$(ARCHITECTURE)") != std::string::npos)
-		  Options.insert(std::make_pair("ARCHITECTURE", a->first));
-	       Options.insert(std::make_pair("BASE_URI", baseURI));
-	       Options.insert(std::make_pair("REPO_URI", URI));
-	       Options.insert(std::make_pair("TARGET_OF", "deb"));
-	       Options.insert(std::make_pair("CREATED_BY", *T));
-	       Call(MetaKey, ShortDesc, LongDesc, IsOptional, Options);
 
-	       if (MetaKey.find("$(LANGUAGE)") == std::string::npos)
-		  break;
 	    }
 
-	    if (MetaKey.find("$(COMPONENT)") == std::string::npos)
+	    if (tplMetaKey.find("$(LANGUAGE)") == std::string::npos)
 	       break;
+
 	 }
 
-	 if (MetaKey.find("$(ARCHITECTURE)") == std::string::npos)
-	    break;
       }
    }
 }
-
-
-struct ComputeIndexTargetsClass
-{
-   vector <IndexTarget> IndexTargets;
-
-   void operator()(std::string MetaKey, std::string ShortDesc, std::string LongDesc,
-	 bool const IsOptional, std::map<std::string, std::string> Options)
-   {
-      for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
-      {
-	 MetaKey = SubstVar(MetaKey, std::string("$(") + O->first + ")", O->second);
-	 ShortDesc = SubstVar(ShortDesc, std::string("$(") + O->first + ")", O->second);
-	 LongDesc = SubstVar(LongDesc, std::string("$(") + O->first + ")", O->second);
-      }
-      IndexTarget Target(
-	    MetaKey,
-	    ShortDesc,
-	    LongDesc,
-	    Options.find("BASE_URI")->second + MetaKey,
-	    IsOptional,
-	    Options
-	    );
-      IndexTargets.push_back(Target);
-   }
-};
-
 std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
 {
-   ComputeIndexTargetsClass comp;
-   foreachTarget(URI, Dist, ArchEntries, comp);
-   return comp.IndexTargets;
+   std::vector<IndexTarget> IndexTargets;
+   GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets);
+   GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets);
+   return IndexTargets;
 }
+									/*}}}*/
+void debReleaseIndex::AddComponent(bool const isSrc, std::string const &Name,/*{{{*/
+	 std::vector<std::string> const &Targets,
+	 std::vector<std::string> const &Architectures,
+	 std::vector<std::string> Languages)
+{
+   if (Languages.empty() == true)
+      Languages.push_back("none");
+   debReleaseIndexPrivate::debSectionEntry const entry = {
+      Name, Targets, Architectures, Languages
+   };
+   if (isSrc)
+      d->DebSrcEntries.push_back(entry);
+   else
+      d->DebEntries.push_back(entry);
+}
+									/*}}}*/
 
 
-									/*}}}*/
-bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
+bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const/*{{{*/
 {
    indexRecords * const iR = new indexRecords(Dist);
    if (Trusted == ALWAYS_TRUSTED)
@@ -282,7 +245,8 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 
    return true;
 }
-
+									/*}}}*/
+// ReleaseIndex::*Trusted setters and checkers				/*{{{*/
 void debReleaseIndex::SetTrusted(bool const Trusted)
 {
 	if (Trusted == true)
@@ -290,7 +254,6 @@ void debReleaseIndex::SetTrusted(bool const Trusted)
 	else
 		this->Trusted = NEVER_TRUSTED;
 }
-
 bool debReleaseIndex::IsTrusted() const
 {
    if (Trusted == ALWAYS_TRUSTED)
@@ -303,19 +266,13 @@ bool debReleaseIndex::IsTrusted() const
       if(URI.substr(0,strlen("cdrom:")) == "cdrom:")
 	 return true;
 
-   string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
-      URItoFileName(MetaIndexURI("Release")) + ".gpg";
-
-   if (FileExists(VerifiedSigFile))
+   if (FileExists(MetaIndexFile("Release.gpg")))
       return true;
 
-   VerifiedSigFile = _config->FindDir("Dir::State::lists") +
-      URItoFileName(MetaIndexURI("InRelease"));
-
-   return FileExists(VerifiedSigFile);
+   return FileExists(MetaIndexFile("InRelease"));
 }
-
-std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
+									/*}}}*/
+std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()		/*{{{*/
 {
    if (Indexes != NULL)
       return Indexes;
@@ -335,23 +292,9 @@ std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
    }
    return Indexes;
 }
+									/*}}}*/
 
-void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) {
-	for (vector<string>::const_iterator a = Archs.begin();
-	     a != Archs.end(); ++a)
-		ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc));
-	delete Entry;
-}
-
-void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) {
-	ArchEntries[Arch].push_back(Entry);
-}
-
-debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section,
-		bool const &IsSrc): Section(Section), IsSrc(IsSrc)
-{}
-
-static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)
+static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
 {
    ReleaseFile = That->MetaIndexFile("InRelease");
    bool releaseExists = false;
@@ -365,7 +308,7 @@ static bool ReleaseFileName(debReleaseIndex const * const That, std::string &Rel
    }
    return releaseExists;
 }
-
+									/*}}}*/
 bool debReleaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress * /*Prog*/) const/*{{{*/
 {
    std::string ReleaseFile;
@@ -459,46 +402,46 @@ pkgCache::RlsFileIterator debReleaseIndex::FindInCache(pkgCache &Cache, bool con
 }
 									/*}}}*/
 
-debDebFileMetaIndex::~debDebFileMetaIndex() {}
-
-class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type
+static std::vector<std::string> parsePlusMinusOptions(std::string const &Name, /*{{{*/
+      std::map<std::string, std::string> const &Options, std::vector<std::string> const &defaultValues)
 {
-   protected:
+   std::map<std::string, std::string>::const_iterator val = Options.find(Name);
+   std::vector<std::string> Values;
+   if (val != Options.end())
+      Values = VectorizeString(val->second, ',');
+   else
+      Values = defaultValues;
 
-   bool CreateItemInternal(vector<metaIndex *> &List, string const &URI,
-			   string const &Dist, string const &Section,
-			   bool const &IsSrc, map<string, string> const &Options) const
+   if ((val = Options.find(Name + "+")) != Options.end())
    {
-      // parse arch=, arch+= and arch-= settings
-      map<string, string>::const_iterator arch = Options.find("arch");
-      vector<string> Archs;
-      if (arch != Options.end())
-	 Archs = VectorizeString(arch->second, ',');
-      else
-	 Archs = APT::Configuration::getArchitectures();
-
-      if ((arch = Options.find("arch+")) != Options.end())
-      {
-	 std::vector<std::string> const plusArch = VectorizeString(arch->second, ',');
-	 for (std::vector<std::string>::const_iterator plus = plusArch.begin(); plus != plusArch.end(); ++plus)
-	    if (std::find(Archs.begin(), Archs.end(), *plus) == Archs.end())
-	       Archs.push_back(*plus);
-      }
-      if ((arch = Options.find("arch-")) != Options.end())
+      std::vector<std::string> const plusArch = VectorizeString(val->second, ',');
+      for (std::vector<std::string>::const_iterator plus = plusArch.begin(); plus != plusArch.end(); ++plus)
+	 if (std::find(Values.begin(), Values.end(), *plus) == Values.end())
+	    Values.push_back(*plus);
+   }
+   if ((val = Options.find(Name + "-")) != Options.end())
+   {
+      std::vector<std::string> const minusArch = VectorizeString(val->second, ',');
+      for (std::vector<std::string>::const_iterator minus = minusArch.begin(); minus != minusArch.end(); ++minus)
       {
-	 std::vector<std::string> const minusArch = VectorizeString(arch->second, ',');
-	 for (std::vector<std::string>::const_iterator minus = minusArch.begin(); minus != minusArch.end(); ++minus)
-	 {
-	    std::vector<std::string>::iterator kill = std::find(Archs.begin(), Archs.end(), *minus);
-	    if (kill != Archs.end())
-	       Archs.erase(kill);
-	 }
+	 std::vector<std::string>::iterator kill = std::find(Values.begin(), Values.end(), *minus);
+	 if (kill != Values.end())
+	    Values.erase(kill);
       }
+   }
+   return Values;
+}
+									/*}}}*/
+class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
+{
+   protected:
 
-      map<string, string>::const_iterator const trusted = Options.find("trusted");
-
+   bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
+			   std::string const &Dist, std::string const &Section,
+			   bool const &IsSrc, std::map<std::string, std::string> const &Options) const
+   {
       debReleaseIndex *Deb = NULL;
-      for (vector<metaIndex *>::const_iterator I = List.begin();
+      for (std::vector<metaIndex *>::const_iterator I = List.begin();
 	   I != List.end(); ++I)
       {
 	 // We only worry about debian entries here
@@ -523,87 +466,86 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type
 	 List.push_back(Deb);
       }
 
-      if (IsSrc == true)
-	 Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc));
-      else
-      {
-	 if (Dist[Dist.size() - 1] == '/')
-	    Deb->PushSectionEntry ("any", new debReleaseIndex::debSectionEntry(Section, IsSrc));
-	 else
-	    Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc));
-      }
+      Deb->AddComponent(
+	    IsSrc,
+	    Section,
+	    parsePlusMinusOptions("target", Options, _config->FindVector(std::string("APT::Acquire::Targets::") + Name, "", true)),
+	    parsePlusMinusOptions("arch", Options, APT::Configuration::getArchitectures()),
+	    parsePlusMinusOptions("lang", Options, APT::Configuration::getLanguages(true))
+	    );
 
+      std::map<std::string, std::string>::const_iterator const trusted = Options.find("trusted");
       if (trusted != Options.end())
 	 Deb->SetTrusted(StringToBool(trusted->second, false));
 
       return true;
    }
-};
-
-debDebFileMetaIndex::debDebFileMetaIndex(std::string const &DebFile)
-   : metaIndex(DebFile, "local-uri", "deb-dist"), d(NULL), DebFile(DebFile)
-{
-   DebIndex = new debDebPkgFileIndex(DebFile);
-   Indexes = new vector<pkgIndexFile *>();
-   Indexes->push_back(DebIndex);
-}
 
-
-class APT_HIDDEN debSLTypeDeb : public debSLTypeDebian
+   debSLTypeDebian(char const * const Name, char const * const Label) : Type(Name, Label)
+   {
+   }
+};
+									/*}}}*/
+class APT_HIDDEN debSLTypeDeb : public debSLTypeDebian			/*{{{*/
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List, string const &URI,
-		   string const &Dist, string const &Section,
-		   std::map<string, string> const &Options) const
+   bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
+		   std::string const &Dist, std::string const &Section,
+		   std::map<std::string, std::string> const &Options) const
    {
       return CreateItemInternal(List, URI, Dist, Section, false, Options);
    }
 
-   debSLTypeDeb()
+   debSLTypeDeb() : debSLTypeDebian("deb", "Debian binary tree")
    {
-      Name = "deb";
-      Label = "Standard Debian binary tree";
-   }   
+   }
 };
-
-class APT_HIDDEN debSLTypeDebSrc : public debSLTypeDebian
+									/*}}}*/
+class APT_HIDDEN debSLTypeDebSrc : public debSLTypeDebian		/*{{{*/
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List, string const &URI,
-		   string const &Dist, string const &Section,
-		   std::map<string, string> const &Options) const
+   bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
+		   std::string const &Dist, std::string const &Section,
+		   std::map<std::string, std::string> const &Options) const
    {
       return CreateItemInternal(List, URI, Dist, Section, true, Options);
    }
-   
-   debSLTypeDebSrc()
+
+   debSLTypeDebSrc() : debSLTypeDebian("deb-src", "Debian source tree")
    {
-      Name = "deb-src";
-      Label = "Standard Debian source tree";
-   }   
+   }
 };
+									/*}}}*/
 
-class APT_HIDDEN debSLTypeDebFile : public pkgSourceList::Type
+debDebFileMetaIndex::debDebFileMetaIndex(std::string const &DebFile)	/*{{{*/
+   : metaIndex(DebFile, "local-uri", "deb-dist"), d(NULL), DebFile(DebFile)
+{
+   DebIndex = new debDebPkgFileIndex(DebFile);
+   Indexes = new std::vector<pkgIndexFile *>();
+   Indexes->push_back(DebIndex);
+}
+debDebFileMetaIndex::~debDebFileMetaIndex() {}
+									/*}}}*/
+class APT_HIDDEN debSLTypeDebFile : public pkgSourceList::Type		/*{{{*/
 {
    public:
 
-   bool CreateItem(vector<metaIndex *> &List, string const &URI,
-		   string const &/*Dist*/, string const &/*Section*/,
-		   std::map<string, string> const &/*Options*/) const
+   bool CreateItem(std::vector<metaIndex *> &List, std::string const &URI,
+		   std::string const &/*Dist*/, std::string const &/*Section*/,
+		   std::map<std::string, std::string> const &/*Options*/) const
    {
       metaIndex *mi = new debDebFileMetaIndex(URI);
       List.push_back(mi);
       return true;
    }
-   
-   debSLTypeDebFile()
+
+   debSLTypeDebFile() : Type("deb-file", "Debian local deb file")
    {
-      Name = "deb-file";
-      Label = "Debian Deb File";
-   }   
+   }
 };
+									/*}}}*/
 
 APT_HIDDEN debSLTypeDeb _apt_DebType;
 APT_HIDDEN debSLTypeDebSrc _apt_DebSrcType;

+ 13 - 25
apt-pkg/deb/debmetaindex.h

@@ -1,4 +1,3 @@
-// ijones, walters
 #ifndef PKGLIB_DEBMETAINDEX_H
 #define PKGLIB_DEBMETAINDEX_H
 
@@ -22,26 +21,20 @@ class debDebPkgFileIndex;
 class IndexTarget;
 class pkgCacheGenerator;
 class OpProgress;
+class debReleaseIndexPrivate;
 
-class APT_HIDDEN debReleaseIndex : public metaIndex {
-   public:
+class APT_HIDDEN debReleaseIndex : public metaIndex
+{
+   debReleaseIndexPrivate * const d;
 
-   class debSectionEntry
-   {
-      public:
-      debSectionEntry (std::string const &Section, bool const &IsSrc);
-      std::string const Section;
-      bool const IsSrc;
-   };
-
-   private:
-   /** \brief dpointer placeholder (for later in case we need it) */
-   void * const d;
-   std::map<std::string, std::vector<debSectionEntry const*> > ArchEntries;
    enum APT_HIDDEN { ALWAYS_TRUSTED, NEVER_TRUSTED, CHECK_TRUST } Trusted;
 
    public:
 
+   APT_HIDDEN std::string MetaIndexInfo(const char *Type) const;
+   APT_HIDDEN std::string MetaIndexFile(const char *Types) const;
+   APT_HIDDEN std::string MetaIndexURI(const char *Type) const;
+
    debReleaseIndex(std::string const &URI, std::string const &Dist);
    debReleaseIndex(std::string const &URI, std::string const &Dist, bool const Trusted);
    virtual ~debReleaseIndex();
@@ -54,22 +47,17 @@ class APT_HIDDEN debReleaseIndex : public metaIndex {
    virtual pkgCache::RlsFileIterator FindInCache(pkgCache &Cache, bool const ModifyCheck) const;
    virtual bool Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const;
 
-   std::string MetaIndexInfo(const char *Type) const;
-   std::string MetaIndexFile(const char *Types) const;
-   std::string MetaIndexURI(const char *Type) const;
-
-#if APT_PKG_ABI >= 413
-   virtual
-#endif
-   std::string LocalFileName() const;
+   virtual std::string LocalFileName() const;
 
    virtual std::vector <pkgIndexFile *> *GetIndexFiles();
 
    void SetTrusted(bool const Trusted);
    virtual bool IsTrusted() const;
 
-   void PushSectionEntry(std::vector<std::string> const &Archs, const debSectionEntry *Entry);
-   void PushSectionEntry(std::string const &Arch, const debSectionEntry *Entry);
+   void AddComponent(bool const isSrc, std::string const &Name,
+	 std::vector<std::string> const &Targets,
+	 std::vector<std::string> const &Architectures,
+	 std::vector<std::string> Languages);
 };
 
 class APT_HIDDEN debDebFileMetaIndex : public metaIndex

+ 22 - 18
apt-pkg/sourcelist.cc

@@ -37,25 +37,26 @@
 using namespace std;
 
 // Global list of Items supported
-static  pkgSourceList::Type *ItmList[10];
+static pkgSourceList::Type *ItmList[10];
 pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList;
 unsigned long pkgSourceList::Type::GlobalListLen = 0;
 
 // Type::Type - Constructor						/*{{{*/
 // ---------------------------------------------------------------------
 /* Link this to the global list of items*/
-pkgSourceList::Type::Type() : Name(NULL), Label(NULL)
+pkgSourceList::Type::Type(char const * const pName, char const * const pLabel) : Name(pName), Label(pLabel)
 {
    ItmList[GlobalListLen] = this;
-   GlobalListLen++;
+   ++GlobalListLen;
 }
+pkgSourceList::Type::~Type() {}
 									/*}}}*/
 // Type::GetType - Get a specific meta for a given type			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type)
 {
-   for (unsigned I = 0; I != GlobalListLen; I++)
+   for (unsigned I = 0; I != GlobalListLen; ++I)
       if (strcmp(GlobalList[I]->Name,Type) == 0)
 	 return GlobalList[I];
    return 0;
@@ -91,23 +92,26 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List,
    string Enabled = Tags.FindS("Enabled");
    if (Enabled.size() > 0 && StringToBool(Enabled) == false)
       return true;
-   
-   // Define external/internal options
-   const char* option_deb822[] = { 
-      "Architectures", "Architectures-Add", "Architectures-Remove", "Trusted",
-   };
-   const char* option_internal[] = { 
-      "arch", "arch+", "arch-", "trusted",
-   };
-   for (unsigned int j=0; j < sizeof(option_deb822)/sizeof(char*); j++)
-      if (Tags.Exists(option_deb822[j]))
+
+   std::map<char const * const, char const * const> mapping;
+#define APT_PLUSMINUS(X, Y) \
+   mapping.insert(std::make_pair(X, Y)); \
+   mapping.insert(std::make_pair(X "Add", Y "+")); \
+   mapping.insert(std::make_pair(X "Remove", Y "-"))
+   APT_PLUSMINUS("Architectures", "arch");
+   APT_PLUSMINUS("Languages", "lang");
+   APT_PLUSMINUS("Targets", "target");
+#undef APT_PLUSMINUS
+   mapping.insert(std::make_pair("Trusted", "trusted"));
+   for (std::map<char const * const, char const * const>::const_iterator m = mapping.begin(); m != mapping.end(); ++m)
+      if (Tags.Exists(m->first))
       {
          // for deb822 the " " is the delimiter, but the backend expects ","
-         std::string option = Tags.FindS(option_deb822[j]);
+         std::string option = Tags.FindS(m->first);
          std::replace(option.begin(), option.end(), ' ', ',');
-         Options[option_internal[j]] = option;
+         Options[m->second] = option;
       }
-   
+
    // now create one item per suite/section
    string Suite = Tags.FindS("Suites");
    Suite = SubstVar(Suite,"$(ARCH)",_config->Find("APT::Architecture"));
@@ -209,7 +213,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List,
       
    if (FixupURI(URI) == false)
       return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
-   
+
    // Check for an absolute dists specification.
    if (Dist.empty() == false && Dist[Dist.size() - 1] == '/')
    {

+ 4 - 4
apt-pkg/sourcelist.h

@@ -66,8 +66,8 @@ class pkgSourceList
       static unsigned long GlobalListLen;
       static Type *GetType(const char *Type) APT_PURE;
 
-      const char *Name;
-      const char *Label;
+      char const * const Name;
+      char const * const Label;
 
       bool FixupURI(std::string &URI) const;
       virtual bool ParseStanza(std::vector<metaIndex *> &List,
@@ -80,8 +80,8 @@ class pkgSourceList
       virtual bool CreateItem(std::vector<metaIndex *> &List,std::string const &URI,
 			      std::string const &Dist,std::string const &Section,
 			      std::map<std::string, std::string> const &Options) const = 0;
-      Type();
-      virtual ~Type() {};
+      Type(char const * const Name, char const * const Label);
+      virtual ~Type();
    };
 
    typedef std::vector<metaIndex *>::const_iterator const_iterator;

+ 2 - 2
cmdline/apt-get.cc

@@ -1045,7 +1045,7 @@ static bool DoBuildDep(CommandLine &CmdL)
       {
          ioprintf(c1out, _("Note, using directory '%s' to get the build dependencies\n"), *I);
          // FIXME: how can we make this more elegant?
-         std::string TypeName = "debian/control File Source Index";
+         std::string TypeName = "Debian control file";
          pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str());
          if(Type != NULL)
             LastOwner = Last = Type->CreateSrcPkgParser(*I);
@@ -1056,7 +1056,7 @@ static bool DoBuildDep(CommandLine &CmdL)
          ioprintf(c1out, _("Note, using file '%s' to get the build dependencies\n"), *I);
 
          // see if we can get a parser for this pkgIndexFile type
-         string TypeName = flExtension(*I) + " File Source Index";
+         string TypeName = "Debian " + flExtension(*I) + " file";
          pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(TypeName.c_str());
          if(Type != NULL)
             LastOwner = Last = Type->CreateSrcPkgParser(*I);

+ 16 - 0
doc/sources.list.5.xml

@@ -137,9 +137,25 @@
    can be used to specify for which architectures information should
    be downloaded. If this option is not set all architectures defined by the
    <literal>APT::Architectures</literal> option will be downloaded.</para></listitem>
+
    <listitem><para><literal>arch+=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
    and <literal>arch-=<replaceable>arch1</replaceable>,<replaceable>arch2</replaceable>,…</literal>
    which can be used to add/remove architectures from the set which will be downloaded.</para></listitem>
+
+   <listitem><para><literal>lang=<replaceable>lang1</replaceable>,<replaceable>lang2</replaceable>,…</literal>,
+   <literal>lang+=<replaceable>lang1</replaceable>,<replaceable>lang2</replaceable>,…</literal> and
+   <literal>lang-=<replaceable>lang1</replaceable>,<replaceable>lang2</replaceable>,…</literal> functioning in
+   the same way as the <literal>arch</literal>-options described before. They can be used to specify for
+   which languages apt will acquire metadata, like translated package descriptions, for. If not specified, the
+   default set is defined by the <literal>Acquire::Languages</literal> config option.</para></listitem>
+
+   <listitem><para><literal>target=<replaceable>target1</replaceable>,<replaceable>target2</replaceable>,…</literal>,
+   <literal>target+=<replaceable>target1</replaceable>,<replaceable>target2</replaceable>,…</literal> and
+   <literal>target-=<replaceable>target1</replaceable>,<replaceable>target2</replaceable>,…</literal> again functioning in
+   the same way as the <literal>arch</literal>-options described before. They can be used to specify which
+   targets apt will try to acquire from this source. If not specified, the default set is defined by
+   the <literal>APT::Acquire::Targets</literal> configuration scope.</para></listitem>
+
    <listitem><para><literal>trusted=yes</literal> can be set to indicate that packages
    from this source are always authenticated even if the <filename>Release</filename> file
    is not signed or the signature can't be checked. This disables parts of &apt-secure;

+ 11 - 11
test/integration/test-bug-632221-cross-dependency-satisfaction

@@ -167,17 +167,17 @@ Conf libfwibble-dev (1.0 unstable [armel])' aptget build-dep apt -s
 testsuccessequal 'Reading package lists...
 Building dependency tree...
 The following NEW packages will be installed:
-  amdboot:amd64 cool doxygen foreigner libc6:amd64 libc6 libc6-dev:amd64
-  libc6-dev libfwibble-dev:amd64 libfwibble1:amd64 linux-stuff:amd64
+  amdboot:amd64 cool doxygen foreigner libc6 libc6:amd64 libc6-dev
+  libc6-dev:amd64 libfwibble-dev:amd64 libfwibble1:amd64 linux-stuff:amd64
 0 upgraded, 11 newly installed, 0 to remove and 0 not upgraded.
 Inst amdboot:amd64 (1.0 unstable [amd64])
 Inst cool (1.0 unstable [armel])
 Inst doxygen (1.0 unstable [armel])
 Inst foreigner (1.0 unstable [armel])
-Inst libc6:amd64 (1.0 unstable [amd64])
 Inst libc6 (1.0 unstable [armel])
-Inst libc6-dev:amd64 (1.0 unstable [amd64])
+Inst libc6:amd64 (1.0 unstable [amd64])
 Inst libc6-dev (1.0 unstable [armel])
+Inst libc6-dev:amd64 (1.0 unstable [amd64])
 Inst libfwibble1:amd64 (1.0 unstable [amd64])
 Inst libfwibble-dev:amd64 (1.0 unstable [amd64])
 Inst linux-stuff:amd64 (1.0 unstable [amd64])
@@ -185,10 +185,10 @@ Conf amdboot:amd64 (1.0 unstable [amd64])
 Conf cool (1.0 unstable [armel])
 Conf doxygen (1.0 unstable [armel])
 Conf foreigner (1.0 unstable [armel])
-Conf libc6:amd64 (1.0 unstable [amd64])
 Conf libc6 (1.0 unstable [armel])
-Conf libc6-dev:amd64 (1.0 unstable [amd64])
+Conf libc6:amd64 (1.0 unstable [amd64])
 Conf libc6-dev (1.0 unstable [armel])
+Conf libc6-dev:amd64 (1.0 unstable [amd64])
 Conf libfwibble1:amd64 (1.0 unstable [amd64])
 Conf libfwibble-dev:amd64 (1.0 unstable [amd64])
 Conf linux-stuff:amd64 (1.0 unstable [amd64])' aptget build-dep apt -s -a amd64
@@ -275,24 +275,24 @@ Conf libfwibble-dev (1.0 unstable [armel])' aptget build-dep apt -s
 testsuccessequal 'Reading package lists...
 Building dependency tree...
 The following NEW packages will be installed:
-  amdboot:amd64 doxygen libc6:amd64 libc6 libc6-dev:amd64 libc6-dev
+  amdboot:amd64 doxygen libc6 libc6:amd64 libc6-dev libc6-dev:amd64
   libfwibble-dev:amd64 libfwibble1:amd64 linux-stuff:amd64
 0 upgraded, 9 newly installed, 0 to remove and 2 not upgraded.
 Inst amdboot:amd64 (1.0 unstable [amd64])
 Inst doxygen (1.0 unstable [armel])
-Inst libc6:amd64 (1.0 unstable [amd64])
 Inst libc6 (1.0 unstable [armel])
-Inst libc6-dev:amd64 (1.0 unstable [amd64])
+Inst libc6:amd64 (1.0 unstable [amd64])
 Inst libc6-dev (1.0 unstable [armel])
+Inst libc6-dev:amd64 (1.0 unstable [amd64])
 Inst libfwibble1:amd64 (1.0 unstable [amd64])
 Inst libfwibble-dev:amd64 (1.0 unstable [amd64])
 Inst linux-stuff:amd64 (1.0 unstable [amd64])
 Conf amdboot:amd64 (1.0 unstable [amd64])
 Conf doxygen (1.0 unstable [armel])
-Conf libc6:amd64 (1.0 unstable [amd64])
 Conf libc6 (1.0 unstable [armel])
-Conf libc6-dev:amd64 (1.0 unstable [amd64])
+Conf libc6:amd64 (1.0 unstable [amd64])
 Conf libc6-dev (1.0 unstable [armel])
+Conf libc6-dev:amd64 (1.0 unstable [amd64])
 Conf libfwibble1:amd64 (1.0 unstable [amd64])
 Conf libfwibble-dev:amd64 (1.0 unstable [amd64])
 Conf linux-stuff:amd64 (1.0 unstable [amd64])' aptget build-dep apt -s -a amd64

+ 5 - 5
test/integration/test-ignore-provides-if-versioned-breaks

@@ -134,17 +134,17 @@ Conf foo-same-provider (1.0 unstable [i386])' aptget install foo-same-provider f
 testsuccessequal 'Reading package lists...
 Building dependency tree...
 The following extra packages will be installed:
-  foo-same:amd64 foo-same
+  foo-same foo-same:amd64
 The following NEW packages will be installed:
   foo-same-breaker-3 foo-same-provider
 The following packages will be upgraded:
-  foo-same:amd64 foo-same
+  foo-same foo-same:amd64
 2 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
-Inst foo-same:amd64 [2.0] (4.0 unstable [amd64]) [foo-same:amd64 on foo-same:i386] [foo-same:i386 on foo-same:amd64] [foo-same:i386 ]
-Inst foo-same [2.0] (4.0 unstable [i386])
+Inst foo-same [2.0] (4.0 unstable [i386]) [foo-same:i386 on foo-same:amd64] [foo-same:amd64 on foo-same:i386] [foo-same:amd64 ]
+Inst foo-same:amd64 [2.0] (4.0 unstable [amd64])
 Inst foo-same-breaker-3 (1.0 unstable [i386])
 Inst foo-same-provider (1.0 unstable [i386])
-Conf foo-same (4.0 unstable [i386])
 Conf foo-same:amd64 (4.0 unstable [amd64])
+Conf foo-same (4.0 unstable [i386])
 Conf foo-same-breaker-3 (1.0 unstable [i386])
 Conf foo-same-provider (1.0 unstable [i386])' aptget install foo-same-provider foo-same-breaker-3 -s

+ 5 - 5
test/integration/test-ignore-provides-if-versioned-conflicts

@@ -134,17 +134,17 @@ Conf foo-same-provider (1.0 unstable [i386])' aptget install foo-same-provider f
 testsuccessequal 'Reading package lists...
 Building dependency tree...
 The following extra packages will be installed:
-  foo-same:amd64 foo-same
+  foo-same foo-same:amd64
 The following NEW packages will be installed:
   foo-same-breaker-3 foo-same-provider
 The following packages will be upgraded:
-  foo-same:amd64 foo-same
+  foo-same foo-same:amd64
 2 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
-Inst foo-same:amd64 [2.0] (4.0 unstable [amd64]) [foo-same:amd64 on foo-same:i386] [foo-same:i386 on foo-same:amd64] [foo-same:i386 ]
-Inst foo-same [2.0] (4.0 unstable [i386])
+Inst foo-same [2.0] (4.0 unstable [i386]) [foo-same:i386 on foo-same:amd64] [foo-same:amd64 on foo-same:i386] [foo-same:amd64 ]
+Inst foo-same:amd64 [2.0] (4.0 unstable [amd64])
 Inst foo-same-breaker-3 (1.0 unstable [i386])
 Inst foo-same-provider (1.0 unstable [i386])
-Conf foo-same (4.0 unstable [i386])
 Conf foo-same:amd64 (4.0 unstable [amd64])
+Conf foo-same (4.0 unstable [i386])
 Conf foo-same-breaker-3 (1.0 unstable [i386])
 Conf foo-same-provider (1.0 unstable [i386])' aptget install foo-same-provider foo-same-breaker-3 -s

+ 87 - 0
test/integration/test-sourceslist-lang-plusminus-options

@@ -0,0 +1,87 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'native'
+
+testlangs() {
+	msgtest 'Test acquired languages for' "$1"
+	local LANGS="$2"
+	shift 2
+	rm -f gotlangs.list
+	aptget files --no-release-info 'Created-By: Translations' "$@" --format '$(LANGUAGE)' | sort -u > gotlangs.list
+	if [ -z "$LANGS" ]; then
+		echo -n | tr ',' '\n' | sort | checkdiff - gotlangs.list && msgpass || msgfail
+	else
+		echo -n "$LANGS" | tr ',' '\n' | sort | checkdiff - gotlangs.list && msgpass || msgfail
+	fi
+}
+echo 'deb http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'default' 'en'
+
+echo 'Acquire::Languages "environment,en";' > rootdir/etc/apt/apt.conf.d/langs.conf
+testlangs 'default config' 'en'
+
+echo 'Acquire::Languages "en,en,en";' > rootdir/etc/apt/apt.conf.d/langs.conf
+testlangs 'duplicated config' 'en'
+
+echo 'Acquire::Languages "none";' > rootdir/etc/apt/apt.conf.d/langs.conf
+testlangs 'none config' ''
+
+echo 'Acquire::Languages "en,none,de,de_DE";' > rootdir/etc/apt/apt.conf.d/langs.conf
+testlangs 'english + german config' 'en,de,de_DE'
+
+echo 'deb [lang=pt] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang=pt' 'pt'
+
+echo 'deb [lang=en] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang=en' 'en'
+
+echo 'deb [lang=de_DE] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang=de_DE' 'de_DE'
+
+echo 'deb [lang=none] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang=none' ''
+testequal 'amd64' aptget files --no-release-info 'Created-By: Packages' --format '$(ARCHITECTURE)'
+
+echo 'deb [lang+=pt] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang+=pt' 'en,de,de_DE,pt'
+
+echo 'deb [lang+=en] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang+=en' 'en,de,de_DE'
+
+echo 'deb [lang+=de_DE] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang+=de_DE' 'en,de,de_DE'
+
+echo 'deb [lang-=pt] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang-=pt' 'en,de,de_DE'
+
+echo 'deb [lang-=en] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang-=en' 'de,de_DE'
+
+echo 'deb [lang-=de_DE] http://example.org/debian stable rocks' > rootdir/etc/apt/sources.list
+testlangs 'lang-=de_DE' 'en,de'
+
+echo 'deb http://example.org/debian stable rocks
+deb http://example.org/debian stable solid' > rootdir/etc/apt/sources.list
+testlangs 'english + german config multicomponent' 'en,de,de_DE'
+
+echo 'deb http://example.org/debian stable rocks
+deb [lang=pt] http://example.org/debian stable solid' > rootdir/etc/apt/sources.list
+testlangs 'multicomponent one lang= combined' 'en,de,de_DE,pt'
+testlangs 'multicomponent one lang= rocks' 'en,de,de_DE' 'Component: rocks'
+testlangs 'multicomponent one lang= solid' 'pt' 'Component: solid'
+
+echo 'deb [lang=pt] http://example.org/debian stable rocks
+deb [lang=de] http://example.org/debian stable solid' > rootdir/etc/apt/sources.list
+testlangs 'multicomponent different lang= combined' 'de,pt'
+testlangs 'multicomponent different lang= rocks' 'pt' 'Component: rocks'
+testlangs 'multicomponent different lang= solid' 'de' 'Component: solid'
+
+echo 'deb [lang+=pt] http://example.org/debian stable rocks
+deb [lang-=de] http://example.org/debian stable solid' > rootdir/etc/apt/sources.list
+testlangs 'multicomponent different lang+-= combined' 'en,de,de_DE,pt'
+testlangs 'multicomponent different lang+-= rocks' 'en,de,de_DE,pt' 'Component: rocks'
+testlangs 'multicomponent different lang+-= solid' 'en,de_DE' 'Component: solid'