From adf379e7ad1900db6d3942ac7dca5cec4737d9a1 Mon Sep 17 00:00:00 2001
From: Michael Vogt <mvo@debian.org>
Date: Wed, 11 Dec 2013 08:21:04 +0100
Subject: [PATCH] add support for "apt-get source pkg:arch"

---
 cmdline/apt-get.cc                        | 60 +++++++++++++++++++++++++------
 test/integration/test-apt-get-source-arch | 60 +++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 10 deletions(-)
 create mode 100755 test/integration/test-apt-get-source-arch

diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc
index 5814663..9cc5b40 100644
--- a/cmdline/apt-get.cc
+++ b/cmdline/apt-get.cc
@@ -198,18 +198,31 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 			       pkgSrcRecords &SrcRecs,string &Src,
 			       CacheFile &CacheFile)
 {
-  string VerTag, UserRequestedVerTag;
+   string VerTag, UserRequestedVerTag;
+   string ArchTag = "";
    string RelTag = _config->Find("APT::Default-Release");
    string TmpSrc = Name;
    pkgDepCache *Cache = CacheFile.GetDepCache();
 
-   // extract the version/release from the pkgname
-   const size_t found = TmpSrc.find_last_of("/=");
-   if (found != string::npos) {
-      if (TmpSrc[found] == '/')
-	 RelTag = TmpSrc.substr(found+1);
-      else
-	 VerTag = UserRequestedVerTag = TmpSrc.substr(found+1);
+   // extract release
+   size_t found = TmpSrc.find_last_of("/");
+   if (found != string::npos) 
+   {
+      RelTag = TmpSrc.substr(found+1);
+      TmpSrc = TmpSrc.substr(0,found);
+   }
+   // extract the version
+   found = TmpSrc.find_last_of("=");
+   if (found != string::npos) 
+   {
+      VerTag = UserRequestedVerTag = TmpSrc.substr(found+1);
+      TmpSrc = TmpSrc.substr(0,found);
+   }
+   // extract arch 
+   found = TmpSrc.find_last_of(":");
+   if (found != string::npos) 
+   {
+      ArchTag = TmpSrc.substr(found+1);
       TmpSrc = TmpSrc.substr(0,found);
    }
 
@@ -217,10 +230,25 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
       install a version and determine the source package name, then look
       in the archive for a source package of the same name. */
    bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source");
-   const pkgCache::PkgIterator Pkg = Cache->FindPkg(TmpSrc);
+   pkgCache::PkgIterator Pkg;
+   if (ArchTag != "")
+      Pkg = Cache->FindPkg(TmpSrc, ArchTag);
+   else
+      Pkg = Cache->FindPkg(TmpSrc);
+
+   // if we can't find a package but the user qualified with a arch,
+   // error out here
+   if (Pkg.end() && ArchTag != "")
+   {
+      Src = Name;
+      _error->Error(_("Can not find a package for architecture '%s'"),
+                    ArchTag.c_str());
+      return 0;
+   }
+
    if (MatchSrcOnly == false && Pkg.end() == false) 
    {
-      if(VerTag.empty() == false || RelTag.empty() == false) 
+      if(VerTag != "" || RelTag != "" || ArchTag != "")
       {
 	 bool fuzzy = false;
 	 // we have a default release, try to locate the pkg. we do it like
@@ -240,6 +268,17 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 	       if (Ver.end() == true)
 		  break;
 	    }
+
+            // pick highest version for the arch unless the user wants
+            // something else
+            if (ArchTag != "" && VerTag == "" && RelTag == "")
+            {
+               if(Ver.Arch() != ArchTag)
+                  continue;
+               if(Cache->VS().CmpVersion(VerTag, Ver.VerStr()) < 0)
+                  VerTag = Ver.VerStr();
+            }
+
 	    // We match against a concrete version (or a part of this version)
 	    if (VerTag.empty() == false &&
 		(fuzzy == true || Cache->VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match
@@ -280,6 +319,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
 	       break;
 	 }
       }
+
       if (Src.empty() == true)
       {
 	 // if we don't have found a fitting package yet so we will
diff --git a/test/integration/test-apt-get-source-arch b/test/integration/test-apt-get-source-arch
new file mode 100755
index 0000000..3ac6907
--- /dev/null
+++ b/test/integration/test-apt-get-source-arch
@@ -0,0 +1,60 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture "i386" "amd64"
+
+
+# different version for the individual arches
+insertpackage 'stable' 'foo' 'amd64' '1.0'
+insertsource 'stable' 'foo' 'amd64' '1.0'
+
+insertpackage 'stable' 'foo' 'i386' '1.0'
+insertsource  'stable' 'foo' 'i386' '1.0'
+insertpackage 'stable' 'foo' 'i386' '2.0'
+insertsource  'stable' 'foo' 'i386' '2.0'
+
+insertpackage 'oldstable' 'foo' 'i386' '0.1'
+insertsource  'oldstable' 'foo' 'i386' '0.1'
+# just needed so that there is a release file entry for the test
+insertpackage 'oldstable' 'unreleated' 'amd64' '0.1'
+
+setupaptarchive
+
+APTARCHIVE=$(readlink -f ./aptarchive)
+
+HEADER="Reading package lists...
+Building dependency tree..."
+
+# pick :amd64
+testequal "$HEADER
+Need to get 0 B of source archives.
+'file://${APTARCHIVE}/foo_1.0.dsc' foo_1.0.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
+'file://${APTARCHIVE}/foo_1.0.tar.gz' foo_1.0.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris foo:amd64
+
+# pick :i386
+testequal "$HEADER
+Need to get 0 B of source archives.
+'file://${APTARCHIVE}/foo_2.0.dsc' foo_2.0.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
+'file://${APTARCHIVE}/foo_2.0.tar.gz' foo_2.0.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris foo:i386
+
+# pick :i386 by release
+testequal "$HEADER
+Selected version '0.1' (oldstable) for foo
+Need to get 0 B of source archives.
+'file://${APTARCHIVE}/foo_0.1.dsc' foo_0.1.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
+'file://${APTARCHIVE}/foo_0.1.tar.gz' foo_0.1.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris foo:i386/oldstable
+
+# pick :i386 by version
+testequal "$HEADER
+Need to get 0 B of source archives.
+'file://${APTARCHIVE}/foo_1.0.dsc' foo_1.0.dsc 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e
+'file://${APTARCHIVE}/foo_1.0.tar.gz' foo_1.0.tar.gz 0 MD5Sum:d41d8cd98f00b204e9800998ecf8427e" aptget source -q --print-uris foo:i386=1.0
+
+# error on unknown arch
+testequal "$HEADER
+E: Can not find a package for architecture 'not-a-available-arch'
+E: Unable to find a source package for foo:not-a-available-arch" aptget source -q --print-uris foo:not-a-available-arch
-- 
1.8.3.2

