From 4a3125544637260e4beabadb5e316e315f304523 Mon Sep 17 00:00:00 2001
From: Niels Thykier <niels@thykier.net>
Date: Mon, 11 Jul 2011 12:31:53 +0200
Subject: [PATCH] Added support for multi-version/arch in temporary labs

This patch makes temporary labs able to extract and maintain more
than one instance of the same package as long as the version
or/and the architecture combinations are unique.  This allows for
things like:

  $ lintian -v pkg_1.0-{1,2}_amd64.deb pkg_1.0-{1,2}_i386.deb

without causing an internal error (see #632115).

The LAB_FORMAT has not been bumped since temporary labs are not to
be reused anyway and static labs do not have this feature enabled.

The emitted tag output remain unchanged, since some may depend on
the output format.  Thus this feature is rather hard to use witout
--verbose.
---
 debian/changelog      |   15 +++++++++++++++
 frontend/lintian      |   14 ++++++++------
 lib/Lab.pm            |   21 ++++++++++++++++++++-
 lib/Lab/Package.pm    |    8 ++++++--
 lib/Lintian/Output.pm |    2 +-
 5 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 0ddd930..156c199 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -158,7 +158,18 @@ lintian (2.5.2) UNRELEASED; urgency=low
     + [NT] Ensure that all dependency collections of a check are
       loaded.  Previously Lintian would only load direct
       dependencies of a collection and assume that was enough.
-
+    + [NT] Output the package architecture as a part of some
+      debug messages.
+
+  * lib/Lab{,/Package}.pm:
+    + [NT] Added support for unpacking multiple packages of same
+      name if their version or/and architecture are different.
+      This is currently only enabled for temporary labs and the
+      LAB_FORMAT has not been bumped (since temporary labs are
+      not reused anyway).  This feature may give surprising
+      results due to assumptions in cross package and it may be
+      hard to tell one package from another without --verbose.
+      (Closes: #632115)
   * lib/Lab/Package.pm:
     + [NT] Symlink in all components of the source package when
       creating the source entry in the lab.  Also removed legacy
@@ -175,6 +186,10 @@ lintian (2.5.2) UNRELEASED; urgency=low
       err_append options.
   * lib/Lintian/{Internal/FrontendUtil,Profile}.pm:
     + [NT] New files.
+  * lib/Lintian/Output.pm:
+    + [NT] Add architecture to the verbose messages, but not for
+      emitted tags as others may rely on the currnet output
+      format.
   * lib/Lintian/{Tag/Info,Tags}.pm:
     + [NT] Updated for profile support.
 
diff --git a/frontend/lintian b/frontend/lintian
index 30cdb82..f21ed10 100755
--- a/frontend/lintian
+++ b/frontend/lintian
@@ -989,8 +989,9 @@ if($action eq 'remove'){
 	    my $pkg_ver  = $proc->pkg_version();
 	    my $pkg_type = $proc->pkg_type();
 	    my $pkg_path = $proc->pkg_path();
+	    my $pkg_arch = $proc->pkg_arch();
 	    eval{
-		$lpkg = $LAB->get_lab_package($pkg_name, $pkg_ver,
+		$lpkg = $LAB->get_lab_package($pkg_name, $pkg_ver, $pkg_arch,
 					      $pkg_type, $pkg_path);
 	    };
 	    if(!defined($lpkg)){
@@ -1001,7 +1002,7 @@ if($action eq 'remove'){
 		next;
 	    }
 	    $TAGS->file_start($pkg_path, $pkg_name, $pkg_ver,
-			      $proc->pkg_arch(), $pkg_type);
+			      $pkg_arch, $pkg_type);
 	    unless($lpkg->delete_lab_entry()){
 		$exit_code = 2;
 	    }
@@ -1440,12 +1441,13 @@ sub unpack_group {
 	my $pkg_type = $proc->pkg_type();
 	my $pkg_path = $proc->pkg_path();
 	my $pkg_ver  = $proc->pkg_version();
+	my $pkg_arch = $proc->pkg_arch();
 	my $lpkg;
 	my $base;
 	my $info;
 	my $cid;
 	eval{
-	    $lpkg = $LAB->get_lab_package($pkg_name, $pkg_ver,
+	    $lpkg = $LAB->get_lab_package($pkg_name, $pkg_ver, $pkg_arch,
 					  $pkg_type, $pkg_path);
 	};
 	if(!defined($lpkg)){
@@ -1458,7 +1460,7 @@ sub unpack_group {
 	}
 	# determine base directory
 	$base = $lpkg->base_dir();
-	debug_msg(1, "Unpacking $pkg_name $pkg_ver ($pkg_type)  in $base");
+	debug_msg(1, "Unpacking $pkg_name $pkg_ver $pkg_arch ($pkg_type) in $base");
 
 	# Ensure it has been unpacked
 	unless ($lpkg->create_entry()){
@@ -1517,7 +1519,7 @@ sub unpack_group {
 	    }
 	    # wait until a job finishes to run its branches, if any, or skip
 	    # this package if any of the jobs failed.
-	    debug_msg(1, "Reaping done jobs ... unpack $pkg_name $pkg_ver ($pkg_type)");
+	    debug_msg(1, "Reaping done jobs ... unpack $pkg_name $pkg_ver $pkg_arch ($pkg_type)");
 
 	    while (my ($coll, $cmd) = Lintian::Command::Simple::wait(\%running_jobs)) {
 		delete $running_jobs{$coll};
@@ -1539,7 +1541,7 @@ sub unpack_group {
 
 		$collmap->satisfy('coll-' . $coll);
 	    }
-	    debug_msg(1, "Reap done jobs ... unpack $pkg_name $pkg_ver ($pkg_type)");
+	    debug_msg(1, "Reap done jobs ... unpack $pkg_name $pkg_ver $pkg_arch ($pkg_type)");
 	}
 	%running_jobs = ();
 
diff --git a/lib/Lab.pm b/lib/Lab.pm
index 4725b1d..f7c9163 100644
--- a/lib/Lab.pm
+++ b/lib/Lab.pm
@@ -277,19 +277,38 @@ sub delete_force {
     );
 
     sub get_lab_package {
-        my ($self, $pkg_name, $pkg_version, $pkg_type, $pkg_path) = @_;
+        my ($self, $pkg_name, $pkg_version, $pkg_arch, $pkg_type, $pkg_path) = @_;
         my $vpkg_type = $pkg_types{$pkg_type};
         my $realpath = Cwd::realpath($pkg_path);
         my $dir;
         fail("Unknown package type $pkg_type") unless($vpkg_type);
         fail("Could not resolve the path of $pkg_path") unless($realpath);
         $dir = $self->{dir} . '/' . $vpkg_type . '/' . $pkg_name;
+        $dir .= '/' . $pkg_version if $self->_supports_multiple_versions();
+        $dir .= '/' . $pkg_arch if $self->_supports_multiple_architectures();
         return new Lab::Package($self, $pkg_name, $pkg_version, $vpkg_type,
                                 $realpath, $dir);
 
     }
 }
 
+# Returns a truth value if this is a "multi-version" Lab
+# This means that a new version of the same package can be extracted to the lab
+# without overwriting the old one.
+sub _supports_multiple_versions{
+    my ($self) = @_;
+    return $self->{mode} eq 'temporary';
+}
+
+# Returns a truth value if this is a "multi-arch" Lab
+# This means that (e.g.) an i386 and amd64 package with the same name will be stored
+# separatedly.  Otherwise unpacking a new package with different architecture will
+# override the old one.
+sub _supports_multiple_architectures{
+    my ($self) = @_;
+    return $self->{mode} eq 'temporary';
+}
+
 1;
 
 # vim: ts=4 sw=4 noet
diff --git a/lib/Lab/Package.pm b/lib/Lab/Package.pm
index b7c881a..8a48564 100644
--- a/lib/Lab/Package.pm
+++ b/lib/Lab/Package.pm
@@ -30,7 +30,7 @@ Lab::Package - A package inside the Lab
  use Lab;
  
  my $lab = new Lab("dir", "dist");
- my $lpkg = $lab->get_lab_package("name", "version", "type", "path");
+ my $lpkg = $lab->get_lab_package("name", "version", "arch", "type", "path");
 
  # Unpack the package
  $lpkg->unpack() or die("Could not unpack: $!");
@@ -192,7 +192,11 @@ sub create_entry(){
     return 1 if ($self->entry_exists());
 
     unless (-d $base_dir) {
-	mkdir($base_dir, 0777) or return 0;
+	# if we are in a multi-arch or/and multi-version lab we may
+	# need to make more than one dir.  On error we will only kill
+	# the "top dir" and that is enough.
+	system ('mkdir', '-p', $base_dir) == 0
+	    or return 0;
 	$madedir = 1;
     }
     if ($pkg_type eq 'changes'){
diff --git a/lib/Lintian/Output.pm b/lib/Lintian/Output.pm
index 158efdc..103ee8a 100644
--- a/lib/Lintian/Output.pm
+++ b/lib/Lintian/Output.pm
@@ -340,7 +340,7 @@ sub print_start_pkg {
     }
 
     $self->v_msg($self->delimiter,
-		 "Processing $pkg_info->{type} $object $pkg_info->{package} (version $pkg_info->{version}) ...");
+		 "Processing $pkg_info->{type} $object $pkg_info->{package} (version $pkg_info->{version}, arch $pkg_info->{arch}) ...");
 }
 
 =item C<print_start_pkg($pkg_info)>
-- 
1.7.5.4

