releasing/cbrtools/perl/RelTransfer/Export.pm
changeset 602 3145852acc89
equal deleted inserted replaced
600:6d08f4a05d93 602:3145852acc89
       
     1 # Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of the License "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 # 
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 # 
       
    11 # Contributors:
       
    12 # 
       
    13 # Description:
       
    14 # 
       
    15 #
       
    16 # Description:
       
    17 # RelTransfer::Export.pm
       
    18 #
       
    19 
       
    20 package RelTransfer::Export;
       
    21 
       
    22 use strict;
       
    23 use ExportData;
       
    24 use Utils;
       
    25 use Cwd;
       
    26 
       
    27 use RelTransfer;
       
    28 use vars qw(@ISA);
       
    29 @ISA=("RelTransfer");
       
    30 
       
    31 #
       
    32 # Constructor
       
    33 #
       
    34 
       
    35 sub Initialize {
       
    36   my $self = shift;
       
    37 
       
    38   $self->SUPER::Initialize();
       
    39   $self->{exportData} = ExportData->New(exports_file => $self->{iniData}->ExportDataFile(),
       
    40 					verbose => $self->{verbose});
       
    41 
       
    42   #check to see if all the pgp keys used for exporting exist on the public keyring
       
    43   my @pgpKeys = @{$self->{iniData}->PgpEncryptionKeys};
       
    44   unless (@pgpKeys) {
       
    45     die "Error: No PGP encrypting keys defined in reltools.ini\n";
       
    46   }
       
    47   push @pgpKeys, @{$self->{exportData}->AllPgpKeys};
       
    48   foreach my $pgpKey (@pgpKeys) {
       
    49     unless ($self->{crypt}->PublicKeyExists($pgpKey)) {
       
    50       die "Error: PGP key $pgpKey is required for exporting but does not exist on public keyring\n";
       
    51     }
       
    52   }	
       
    53 }
       
    54 
       
    55 #
       
    56 # Public methods
       
    57 #
       
    58 
       
    59 sub CheckExportable {
       
    60   my $self = shift;
       
    61   my $comp = shift;
       
    62   my $ver = shift;
       
    63 
       
    64   unless ($self->ReleaseExistsInLocalArchive($comp, $ver)) {
       
    65     die "Error: $comp $ver does not exist in local archive\n";
       
    66   }
       
    67   unless ($self->{exportData}->ComponentIsExportable($comp)) {
       
    68     print "Warning: component \"$comp\" is not defined in export table.\n";
       
    69   }
       
    70 }
       
    71 
       
    72 sub TransferRelease {
       
    73   my $self = shift;
       
    74   my $comp = shift;
       
    75   my $ver = shift;
       
    76 
       
    77   if ($self->{verbose}) {
       
    78     print "\nExporting $comp $ver...\n";
       
    79   }
       
    80 
       
    81   #check to see if ok to export
       
    82   unless ($self->ReleaseExistsInLocalArchive($comp, $ver)) {
       
    83     die "Error: $comp $ver does not exist in local archive\n";
       
    84   }
       
    85 
       
    86   my $releaseExists = $self->ReleaseExistsOnRemoteSite($comp, $ver);
       
    87   unless ($self->{exportData}->ComponentIsExportable($comp)) {
       
    88     if (not $releaseExists or $self->{force}) {
       
    89       die "Error: cannot export $comp: not defined in export table\n";
       
    90     }
       
    91     else {
       
    92       if ($self->{verbose}) {
       
    93 	print "$comp $ver already exported to remote site\n";
       
    94       }	
       
    95       return 0;
       
    96     }
       
    97   }
       
    98   else {
       
    99     if ($releaseExists and not $self->{force}) {
       
   100       if ($self->{verbose}) {
       
   101 	print "$comp $ver already exported to remote site\n";
       
   102       }	
       
   103       return 0;
       
   104     }
       
   105   }
       
   106 
       
   107   #encrypt, zip and then send release to remote site
       
   108   eval {
       
   109     my $localdir = $self->PathData->LocalArchivePathForExistingComponent($comp, $ver);
       
   110     print "Local directory for \"$comp\" \"$ver\" is \"$localdir\"\n" if ($self->{verbose});
       
   111     $self->EncryptReleaseFiles($comp, $ver, $localdir);
       
   112     $self->ZipEncryptedReleaseFiles($comp, $ver);
       
   113     $self->SendZippedReleaseFile($comp, $ver, $localdir);
       
   114     return 1 if ($self->{dummy});
       
   115     my $localsize = $self->SizeOfNewlyZippedFile($comp, $ver);
       
   116     my $remotesize = $self->SizeOfRemoteFile($comp, $ver);
       
   117     $self->CompareSizes($localsize, $remotesize, $comp, $ver);
       
   118   };
       
   119   if ($@) {
       
   120     my $error = $@;
       
   121     $self->CleanupTempDir();
       
   122     die $error;
       
   123   }
       
   124 
       
   125   #optionally send a log file to the remote site
       
   126   if (defined $self->{iniData}->RemoteLogsDir) {
       
   127     eval {
       
   128       $self->SendLogFile($comp, $ver);
       
   129     };
       
   130     if ($@) {
       
   131       print "Warning: Export of log file failed. $@\n";
       
   132     }
       
   133   }
       
   134 
       
   135   #delete all the files in the temporary directory
       
   136   $self->CleanupTempDir();
       
   137 
       
   138   if ($self->{verbose}) {
       
   139     print "$comp $ver successfully exported to remote site.\n";
       
   140   }
       
   141   return 1;
       
   142 }
       
   143 
       
   144 sub ExamineExportedRelease {
       
   145   my $self = shift;
       
   146   my $comp = shift;
       
   147   my $ver = shift;
       
   148 
       
   149   unless ($self->ReleaseExistsInLocalArchive($comp, $ver)) {
       
   150     die "Error: $comp $ver does not exist in local archive\n";
       
   151   }
       
   152 
       
   153   eval {
       
   154     my $localdir = $self->PathData->LocalArchivePathForExistingComponent($comp, $ver);
       
   155     my $remotesize = $self->SizeOfRemoteFile($comp, $ver);
       
   156     $self->EncryptReleaseFiles($comp, $ver, $localdir);
       
   157     $self->ZipEncryptedReleaseFiles($comp, $ver);
       
   158     my $localsize = $self->SizeOfNewlyZippedFile($comp, $ver);
       
   159     $self->CompareSizes($localsize, $remotesize, $comp, $ver);
       
   160   };
       
   161   if ($@) {
       
   162     my $error = $@;
       
   163     $self->CleanupTempDir();
       
   164     die $error;
       
   165   }
       
   166 
       
   167   $self->CleanupTempDir();
       
   168 }
       
   169 
       
   170 #
       
   171 # Private methods
       
   172 #
       
   173 
       
   174 sub CompareSizes {
       
   175   my $self = shift;
       
   176   my $localsize = shift;
       
   177   my $remotesize = shift;
       
   178   my $comp = shift; # comp and ver are just used for error messages
       
   179   my $ver = shift;
       
   180 
       
   181   my $diff = abs ($remotesize - $localsize);
       
   182   if ($diff == 0) {
       
   183     return; # disappointingly rare
       
   184   } elsif ($diff <=8) {
       
   185     print "Warning: the size of the exported $comp $ver is slightly different ($remotesize) to the local copy ($localsize): difference $diff. This may be due to the way the remote site reports sizes, or the randomness of PGP encryption.\n" if ($self->{verbose});
       
   186   } else {
       
   187     die "Error: $comp $ver exported file size ($remotesize) differs from local copy ($localsize)\n";
       
   188   }
       
   189 }
       
   190 
       
   191 sub SizeOfNewlyZippedFile {
       
   192   my $self = shift;
       
   193   my $comp = shift;
       
   194   my $ver = shift;
       
   195 
       
   196   my $tempDir = Utils::TempDir();
       
   197   my $zipName = "$tempDir/$comp$ver.zip";
       
   198   die "Error: newly zipped file \"$zipName\" for $comp $ver didn't exist\n" unless -e $zipName;
       
   199   return -s $zipName;
       
   200 }
       
   201 
       
   202 sub SizeOfRemoteFile {
       
   203   my $self = shift;
       
   204   my $comp = shift;
       
   205   my $ver = shift;
       
   206 
       
   207   die "No component name provided to SizeOfRemoteFile" unless $comp;
       
   208   die "No version for $comp provided to SizeOfRemoteFile" unless $ver;
       
   209 
       
   210   my $remoteFile = $self->PathData->RemoteArchivePathForExistingComponent($comp, $ver, $self->{remoteSite})."/$comp$ver.zip";
       
   211   die "Error: $comp $ver didn't exist on the remote site\n" unless $remoteFile;
       
   212   return $self->{remoteSite}->FileSize($remoteFile);
       
   213 }
       
   214 
       
   215 sub EncryptReleaseFiles {
       
   216   my $self = shift;
       
   217   my $comp = shift;
       
   218   my $ver = shift;
       
   219   my $relDir = shift;
       
   220   my $tempDir = Utils::TempDir();
       
   221   
       
   222   my %excludedKeys;
       
   223   @excludedKeys{@{$self->{exportData}->AllPgpKeys()}} = ();
       
   224 
       
   225   #encrypt release files using pgp keys from export table and reltools.ini
       
   226   opendir(RELDIR, $relDir) or die "Error: Cannot open $relDir\n";
       
   227   while (defined(my $file = readdir RELDIR)) {
       
   228     my @pgpKeys;
       
   229     next if ($file =~ /^\.\.?$/);
       
   230     
       
   231     if ($file =~ /^(exports)([a-z])\.zip$/i or $file =~ /^(exports)([a-z])\.txt$/i) {
       
   232       @pgpKeys = @{$self->{exportData}->PgpKeysForExports($comp, $2)};
       
   233     }
       
   234     elsif ($file =~ /^(source)([a-z])\.zip$/i or $file =~ /^(source)([a-z])\.txt$/i) {
       
   235       if($self->{excludeSource}) {
       
   236         print "Skipping the encryption of source file $file (in directory \"$relDir\")\n" if ($self->{verbose});	
       
   237         next;
       
   238       }
       
   239       @pgpKeys = @{$self->{exportData}->PgpKeysForSource($comp, $2)};
       
   240     }
       
   241     elsif ( $file =~ /^reldata$/i ){
       
   242       @pgpKeys = @{$self->{exportData}->PgpKeysForRelData($comp)};
       
   243     }
       
   244     elsif ($file =~ /^binaries.zip$/i or $self->IsBinaryZipRequired($comp, $ver, $file)) {
       
   245       @pgpKeys = @{$self->{exportData}->PgpKeysForBinaries($comp)};
       
   246     } 
       
   247     else { 
       
   248       die "Error: Unexpected release file \"$file\" in $comp $ver\n";
       
   249     }
       
   250 
       
   251     #do the encryption
       
   252     if (@pgpKeys) {
       
   253       push @pgpKeys, @{$self->{iniData}->PgpEncryptionKeys}; #encrypt with users keys aswell
       
   254       print "Encrypting \"$file\" (in directory \"$relDir\") to keys @pgpKeys\n" if ($self->{verbose});
       
   255         # Warning: productisation scripts may depend on the format of the above line.
       
   256       $self->{crypt}->Encrypt("$relDir/$file", "$tempDir/$file.pgp", \@pgpKeys) unless ($self->{dummy});
       
   257     
       
   258       #Remove the keys that have been used from the list of keys which have been excluded for this release
       
   259       delete @excludedKeys{@pgpKeys};
       
   260     }
       
   261   }
       
   262   closedir(RELDIR);
       
   263   
       
   264   # DEF104279 The exclude keyword in the CBR export table breaks the exported archive.
       
   265   # All keys which are not used for this release will be used to encrypt a file called exclude.txt
       
   266   # When the release is imported it will not give the unable to decrypt any part error
       
   267   # as it can decrypt the exclude.txt file.
       
   268 
       
   269   if (keys %excludedKeys) {
       
   270     # Create an exclude.txt in the reldir  
       
   271     open (EXCLUDE, ">$tempDir/exclude.txt");
       
   272     print EXCLUDE "If you can decrypt this file then this release has been excluded for you based on your PGP key\n";
       
   273     close EXCLUDE;    
       
   274     
       
   275     $self->{crypt}->Encrypt("$tempDir/exclude.txt", "$tempDir/exclude.txt.pgp", \@{[keys %excludedKeys]}) unless ($self->{dummy});
       
   276   }
       
   277 }
       
   278 
       
   279 sub IsBinaryZipRequired {
       
   280   my $self = shift;
       
   281   my $comp = shift;
       
   282   my $ver = shift;
       
   283   my $zip = shift;
       
   284 
       
   285   # If the required_binaries keyword isn't used, we need all builds
       
   286   return 1 unless defined $self->{iniData}->RequiredBinaries($comp);
       
   287 
       
   288   unless ($zip =~ /^binaries_(.*)\.zip$/) {
       
   289     die "Error: Unexpected file \"$zip\" in $comp $ver\n";
       
   290   }
       
   291   my $category = $1;
       
   292   foreach my $requiredBinary (@{$self->{iniData}->RequiredBinaries($comp)}) {
       
   293     if ($category =~ /^$requiredBinary/) {
       
   294       return 1;
       
   295     }
       
   296   }
       
   297   return 0;
       
   298 }
       
   299 
       
   300 sub ZipEncryptedReleaseFiles {
       
   301   my $self = shift;
       
   302   my $comp = shift;
       
   303   my $ver = shift;
       
   304 
       
   305   if ($self->{verbose}) {
       
   306     print "Zipping encrypted files to $comp$ver.zip ...\n";
       
   307   }
       
   308 	
       
   309   #build up list of pgp encrypted files in TEMP_DIR 
       
   310   my $tempDir = Utils::TempDir();  
       
   311   opendir(TEMPDIR, $tempDir);
       
   312   my @encryptedFiles = grep {/\.pgp$/} readdir TEMPDIR;
       
   313   closedir(TEMPDIR);
       
   314 
       
   315   unless (@encryptedFiles || $self->{dummy}) {
       
   316     die "Error: No encrypted files exist in $tempDir\n";
       
   317   }	
       
   318 
       
   319   #zip list of pgp encrypted files (archive only, no compression)
       
   320   my $origDir = getcwd();
       
   321   chdir($tempDir);
       
   322   my $zipName = "$tempDir/$comp$ver.zip";
       
   323   print "Zipping @encryptedFiles to \"$zipName\"\n";
       
   324   eval {
       
   325     Utils::ZipList($zipName, \@encryptedFiles, $self->{verbose} > 1, 1) unless ($self->{dummy});
       
   326   };
       
   327   chdir ($origDir);
       
   328   if ($@) {
       
   329     die $@;
       
   330   }	 
       
   331 }
       
   332 
       
   333 sub SendZippedReleaseFile {
       
   334   my $self = shift;
       
   335   my $comp = shift;
       
   336   my $ver = shift;
       
   337   my $localdir = shift;
       
   338   
       
   339   my $localFile = Utils::TempDir()."/$comp$ver.zip";
       
   340   my $remoteFile = $self->PathData->RemoteArchivePathForExportingComponent($comp, $ver, $localdir, $self->{remoteSite})."/$comp$ver.zip";
       
   341 
       
   342   print "Sending \"$localFile\" to \"$remoteFile\"\n" if ($self->{verbose});
       
   343   $self->{remoteSite}->SendFile($localFile, $remoteFile) unless ($self->{dummy});
       
   344 }
       
   345 
       
   346 sub SendLogFile {
       
   347   my $self = shift;
       
   348   my $comp = shift;
       
   349   my $ver = shift;
       
   350 
       
   351   
       
   352   my $localLogFile = Utils::TempDir()."/$comp$ver.log";
       
   353   my $remoteLogFile = $self->{iniData}->RemoteLogsDir($comp)."/$comp$ver.log";
       
   354 
       
   355   if ($self->{verbose}) {
       
   356     print "Sending $comp $ver log file to remote site \"$remoteLogFile\"\n";
       
   357   }
       
   358 
       
   359   return if ($self->{dummy});
       
   360 
       
   361   #create empty log file
       
   362   open LOG, ">$localLogFile"  or die "Error: Cannot open $localLogFile for writing\n";
       
   363   close LOG;
       
   364 
       
   365   #send log file to the remote site
       
   366   $self->{remoteSite}->SendFile($localLogFile, $remoteLogFile);
       
   367 
       
   368   unlink $localLogFile;
       
   369 }
       
   370 
       
   371 1;
       
   372 
       
   373 __END__
       
   374 
       
   375 =head1 NAME
       
   376 
       
   377 RelTransfer::Export.pm - Export releases to the remote site
       
   378 
       
   379 =head1 SYNOPSIS
       
   380 
       
   381  use RelTransfer::Export;
       
   382 
       
   383  $exporter = RelTransfer::Export->New(ini_data => $iniData,
       
   384 				      force => 1;
       
   385 				      verbose => 1);
       
   386 
       
   387  $exporter->TransferRelease('componentname', 'componentversion');
       
   388 
       
   389 =head1 DESCRIPTION
       
   390 
       
   391 Implements the abstract TransferRelease method from the C<RelTransfer> base class module which transfers a release from the local archive to the remote site.
       
   392 
       
   393 =head1 INTERFACE
       
   394 
       
   395 =head2 New
       
   396 
       
   397 Passed an argument list in the form of hash key value pairs. The supported arguments are...
       
   398 
       
   399  ini_data    =>  $iniData_object
       
   400  force       =>  $force_integer
       
   401  verbose     =>  $verbosity_integer
       
   402 
       
   403 Returns a reference to a C<RelTransfer::Export> object.
       
   404 
       
   405 =head2 TransferRelease
       
   406 
       
   407 Passed a component name and version number. Performs the following steps:
       
   408 
       
   409 =over 4
       
   410 
       
   411 =item *
       
   412 
       
   413 Check to see if the release can or needs to be exported. If the component does not exist in the users export table no attempt will be made to export it. If the component is listed in the export table but the release already exists on the remote site then, again, no attempt will be made to export it (unless the C<force> member variable is set to a nonzero value)
       
   414 
       
   415 =item *
       
   416 
       
   417 Encrypt the release files (ie source zips, binaries zip and reldata file). The keys used to encrypt the files depend on the data stored in the users export table 
       
   418 
       
   419 =item *
       
   420 
       
   421 Create a zip archive (without compression) of the encrypted files 
       
   422 
       
   423 =item *
       
   424 
       
   425 Send the release zip file to the remote site
       
   426 
       
   427 =item *
       
   428 
       
   429 If a remote logs dir is defined in the F<reltools.ini> file send an empty log file to the remote site 
       
   430 
       
   431 =back
       
   432 
       
   433 =head2 ExamineExportedRelease
       
   434 
       
   435 This goes through most of the same stages above, but instead of actually transferring the zip file, it will ensure that the size of the existing file on the remote site matches that which is expected.
       
   436 
       
   437 =head1 KNOWN BUGS
       
   438 
       
   439 None
       
   440 
       
   441 =head1 COPYRIGHT
       
   442 
       
   443  Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
   444  All rights reserved.
       
   445  This component and the accompanying materials are made available
       
   446  under the terms of the License "Eclipse Public License v1.0"
       
   447  which accompanies this distribution, and is available
       
   448  at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
   449  
       
   450  Initial Contributors:
       
   451  Nokia Corporation - initial contribution.
       
   452  
       
   453  Contributors:
       
   454  
       
   455  Description:
       
   456  
       
   457 
       
   458 =cut