releasing/cbrtools/perl/Symbian/CBR/ApplyDelta.pm
changeset 607 378360dbbdba
parent 602 3145852acc89
equal deleted inserted replaced
591:22486c9c7b15 607:378360dbbdba
       
     1 # Copyright (c) 2007-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 # Symbian::CBR::ApplyDelta.pm
       
    18 #
       
    19 
       
    20 package Symbian::CBR::ApplyDelta;
       
    21 
       
    22 use strict;
       
    23 use File::Basename;
       
    24 use FindBin qw($Bin);
       
    25 use File::Spec;
       
    26 use Symbian::CBR::Component::Manifest;
       
    27 use Symbian::CBR::DeltaRelease::Manifest qw(META_FILES DELTA_MANIFEST_FILE);
       
    28 use ExportData;
       
    29 use EnvDb;
       
    30 use Utils;
       
    31 use File::Path;
       
    32 use File::Temp;
       
    33 use XML::Simple;
       
    34 use File::Copy;
       
    35 use Carp;
       
    36 use Cwd;
       
    37 
       
    38 
       
    39 sub new {
       
    40   my $pkg = shift;
       
    41   my $iniData = shift;
       
    42   my $verbose = shift;
       
    43   my $self;
       
    44   $self->{iniData} = $iniData;
       
    45   $self->{verbose} = $verbose;
       
    46   bless $self, $pkg;
       
    47   return $self;
       
    48 }
       
    49 
       
    50 
       
    51 sub ReconstructEnv {
       
    52   my $self = shift;
       
    53   my $zipFile = shift;
       
    54   my $overwrite = shift;
       
    55 
       
    56   $self->{deltaManifest} = Symbian::CBR::DeltaRelease::Manifest->new($self->{verbose});
       
    57   Utils::InitialiseTempDir($self->{iniData});
       
    58   $self->{deltaDir} = Utils::TempDir();
       
    59 
       
    60   my $deltaManifestFile = File::Spec->catfile($self->{deltaDir}, DELTA_MANIFEST_FILE );
       
    61   print "Extracting delta release package.\n";
       
    62   eval {Utils::Unzip($zipFile,$self->{deltaDir},0,1);};
       
    63   croak "Error: Couldn't Extract File $zipFile $@\n" if($@);
       
    64   #Read delta manifest file.
       
    65 
       
    66   $self->{deltaManifest}->LoadManifest($deltaManifestFile);
       
    67   my $referenceBaseline = $self->{deltaManifest}->GetReferenceBaselineComp();
       
    68   my $referenceVersion = $self->{deltaManifest}->GetReferenceBaselineVer();
       
    69   my $destination =  $self->{iniData}->PathData->LocalArchivePathForExistingComponent($referenceBaseline, $referenceVersion);
       
    70   croak "Error: Reference baseline $referenceBaseline $referenceVersion does not exist.\n" unless (defined $destination);
       
    71   my $index = index($destination, $referenceBaseline);
       
    72   $destination = substr($destination, 0, ($index));
       
    73   foreach  my $comp (sort keys %{$self->{deltaManifest}->ListAllComponents()}) {
       
    74     my $compStatus = $self->{deltaManifest}->GetCompStatus($comp);
       
    75     my $hasError;
       
    76     if ($compStatus eq "modified") {
       
    77       $hasError = $self->ReconstructComp($comp, $destination, $overwrite); #Reconstruct modified component.
       
    78     }
       
    79     elsif ($compStatus eq "added") {
       
    80       $hasError = $self->CopyCompToBaseline($comp, $destination, $overwrite); #Directly copy component to baseline.
       
    81     }
       
    82     
       
    83     if ($hasError) {
       
    84       my $version = $self->{deltaManifest}->GetCompNominatedVer($comp);
       
    85       print "Error: Can't reconstruct component $comp, version $version\n";
       
    86       next;
       
    87     }
       
    88   }
       
    89   rmtree($self->{deltaDir}) or print "Warning: Couldn't delete temp directory ".$self->{deltaDir}.".\n";
       
    90 }
       
    91 
       
    92 sub CopyCompToBaseline {
       
    93   my $self = shift;
       
    94   my $comp = shift;
       
    95   my $destination = shift;
       
    96   my $overwrite = shift;
       
    97 
       
    98   print "$comp is newly added to the baseline.\n";
       
    99   my $tempNewCompPath = File::Spec->catfile($self->{deltaDir},"new", $comp);
       
   100   my $nomVersion = $self->{deltaManifest}->GetCompNominatedVer($comp);
       
   101   my $archiveCompPath = File::Spec->catdir($destination, $comp, $nomVersion);
       
   102   if (-d $archiveCompPath and !$overwrite) {
       
   103     print "Error: $comp already exists. Please use -o option to overwrite.\n";
       
   104     return 1;
       
   105   }
       
   106   mkpath($archiveCompPath) unless (-d $archiveCompPath);
       
   107   foreach my $thisFile (@{Utils::ReadDir($tempNewCompPath)}) {
       
   108     my $thisTempFile = File::Spec->catfile($tempNewCompPath, $thisFile);
       
   109     my $thisArchivepFile = File::Spec->catfile($archiveCompPath, $thisFile);
       
   110     if (-e $thisArchivepFile) {
       
   111       print "Overwriting $thisFile.\n " if ($self->{verbose});	
       
   112       unless (unlink($thisArchivepFile)) {
       
   113         print "Error: Couldn't delete $thisArchivepFile : $!\n";
       
   114 	return 1;
       
   115       }
       
   116     }	  
       
   117     unless (copy($thisTempFile, $thisArchivepFile)) {
       
   118       print "Error: Couldn't copy file from $thisTempFile to $thisArchivepFile.\n";
       
   119       return 1;
       
   120     }
       
   121   }
       
   122   return 0;
       
   123 }
       
   124 
       
   125 sub ReconstructComp {
       
   126   my $self = shift;
       
   127   my $comp = shift;
       
   128   my $destination = shift;
       
   129   my $overwrite = shift;
       
   130 
       
   131   my $refVersion =  $self->{deltaManifest}->GetCompReferenceVer($comp);
       
   132   my $nomVersion = $self->{deltaManifest}->GetCompNominatedVer($comp);
       
   133   print "Reconstructing $comp component.\n";
       
   134   my $refCompVer = File::Spec->catdir($destination, $comp, $refVersion);
       
   135   my $nomCompVer = File::Spec->catdir($destination, $comp, $nomVersion);
       
   136   if (-d $nomCompVer and !$overwrite) {
       
   137     print "Error: $comp of $nomVersion version already exists. Please use -o option to overwrite.\n";
       
   138     return 1;
       
   139   }
       
   140   if (-d $nomCompVer) {
       
   141     print "Overwriting $comp\n" if($self->{verbose});
       
   142     my $origDir = cwd();
       
   143 
       
   144     chdir(dirname($nomCompVer)); #If you try to rmtree a UNC path the cwd must also be a UNC path
       
   145     unless (rmtree($nomCompVer)) {
       
   146       print "Error: Couldn't delete $nomCompVer directory\n";
       
   147       return 1;
       
   148     }
       
   149     chdir($origDir);
       
   150   }
       
   151   mkpath($nomCompVer);
       
   152   #Make copy of reference version.
       
   153   foreach my $thisFile (@{Utils::ReadDir($refCompVer)}) {
       
   154     my $thisRefFile = File::Spec->catfile($refCompVer, $thisFile);
       
   155     my $thisNomFile = File::Spec->catfile($nomCompVer, $thisFile);
       
   156     unless (copy($thisRefFile, $thisNomFile)) {
       
   157       print "Error: Couldn't copy file from $thisRefFile to $thisNomFile. $!\n";
       
   158       return 1;
       
   159     }
       
   160   }
       
   161 
       
   162   #Reconstruct modified zip files, copy newly added zip files and delete deleted zip files.
       
   163   foreach  my $zipfile (keys  %{$self->{deltaManifest}->GetZipFilesForComp($comp)}) {
       
   164     my $zipStatus = $self->{deltaManifest}->GetZipStatus($comp, $zipfile);
       
   165     my $nomZipFile = File::Spec->catfile($nomCompVer, $zipfile);
       
   166     if ($zipStatus eq "modified") {
       
   167       my $hasError = $self->ReconstructZipFile($comp, $zipfile, $nomCompVer); #If zip file is modified, then reconstruct it.
       
   168       return $hasError if($hasError);
       
   169     }
       
   170     
       
   171     elsif ($zipStatus eq "added") {
       
   172       my $tempZipFile = File::Spec->catfile(Utils::TempDir(),"modified","addedZips",$comp,$zipfile);
       
   173       if (-e $nomZipFile) {
       
   174         print "Overwriting $nomZipFile.\n " if ($self->{verbose});
       
   175         unless (unlink($nomZipFile)) {
       
   176           print "Error: Couldn't delete $nomZipFile : $!\n";
       
   177 	  return 1;
       
   178 	}
       
   179       }
       
   180       unless (copy($tempZipFile, $nomZipFile)) {
       
   181         print "Error: Couldn't copy $tempZipFile to $nomZipFile. $!\n";
       
   182 	return 1;
       
   183       }
       
   184     }
       
   185     elsif ($zipStatus eq "deleted") {
       
   186       if (-e $nomZipFile) {
       
   187         unless (unlink($nomZipFile)) {
       
   188           print "Error: Couldn't delete $nomZipFile : $!\n";
       
   189 	  return 1;
       
   190         }
       
   191       }
       
   192     }
       
   193     elsif ($zipStatus eq "identical") {
       
   194       print "$zipfile is not modified.\n" if($self->{verbose} > 1);
       
   195     }
       
   196     else {
       
   197       print "Error: Unknown zip file status \"$zipStatus\" for $zipfile of $comp component in delta manifest file.\n";
       
   198       return 1;
       
   199     }
       
   200   }
       
   201   #Reconstruct reldata, manifest.xml and exports.txt files.
       
   202   my $deltaFilePath = File::Spec->catdir($self->{deltaDir}, META_FILES);
       
   203   foreach my $metafile (keys %{$self->{deltaManifest}->GetMetaFiles($comp)}) {
       
   204     my $nomFile = File::Spec->catfile($nomCompVer, $metafile);
       
   205     my $deltaFile = $comp."_".$metafile;
       
   206     $deltaFile = File::Spec->catfile($deltaFilePath, $deltaFile);
       
   207     #retry 10 times
       
   208     my $retries = 10;
       
   209     while ($retries > 0) {
       
   210       if (-e $nomFile) {
       
   211         unlink($nomFile) or print "Warning: delete file $nomFile failed. $?, $!\n";
       
   212       }
       
   213       print "Copying $metafile.\n" if( -e $metafile and $self->{verbose});
       
   214       if (copy($deltaFile, $nomFile) == 0) {
       
   215         #copy failed, warning and try again
       
   216         print "Warning: Couldn't copy file from $deltaFile to $nomFile. $!\n";
       
   217         $retries--;
       
   218       }
       
   219       else {
       
   220         #copy successfully, jump out of the loop
       
   221         last;
       
   222       }
       
   223     }
       
   224     if ($retries<=0) {
       
   225       print "Error: Couldn't copy file $deltaFile to $nomFile. $!\n";
       
   226       return 1;
       
   227     }
       
   228   }
       
   229   
       
   230   return 0;
       
   231 }
       
   232 
       
   233 
       
   234 sub ReconstructZipFile {
       
   235   my $self = shift;
       
   236   my $comp = shift;
       
   237   my $zipfile = shift;
       
   238   my $releaseFolder = shift;
       
   239   
       
   240   my $nomZipFile = File::Spec->catfile($releaseFolder, $zipfile);
       
   241   my $tempCompPath = mkdtemp($self->{iniData}->TempDir().'\_XXXX');
       
   242   mkpath ($tempCompPath) unless(-d $tempCompPath);
       
   243   my $tempCompZips = File::Spec->catdir($self->{deltaDir}, "TempZips");
       
   244   mkpath($tempCompZips) unless(-d $tempCompZips);
       
   245   my $tempCompZipFile = File::Spec->catdir($tempCompZips, $zipfile);
       
   246   #Move zip file to temporary location.
       
   247   unless (move($nomZipFile, $tempCompZipFile)) {
       
   248     print "Error: Couldn't move $zipfile to temp directory. $!\n";
       
   249     return 1;
       
   250   }
       
   251   print "Extracting $zipfile file.\n" if($self->{verbose} > 1);
       
   252   Utils::Unzip($tempCompZipFile,$tempCompPath,0,1);
       
   253   unless (unlink($tempCompZipFile)) {
       
   254     print "Error: Couldn't delete $tempCompZipFile : $!\n";
       
   255     return 1;
       
   256   }
       
   257 
       
   258   foreach my $file (keys %{$self->{deltaManifest}->GetFilesForZip($comp, $zipfile)}) {
       
   259     my $deltaFilePath = File::Spec->catfile($self->{deltaDir},"modified",$file);
       
   260     my $tempCompFilePath = File::Spec->catfile($tempCompPath,$file);
       
   261     my $fileStatus = $self->{deltaManifest}->GetFileStatus($comp, $zipfile, $file);
       
   262     my $type = $self->{deltaManifest}->GetFileType($comp, $zipfile, $file );
       
   263 
       
   264     if ($fileStatus eq "added") {
       
   265       print "Copying $file\n" if($self->{verbose});
       
   266       my $tempFilePath = dirname ($tempCompFilePath);
       
   267       unless (-e $tempFilePath) {
       
   268         unless (mkpath ($tempFilePath)) {
       
   269           print "Error: Unable to create $tempFilePath path.\n";
       
   270 	  return 1;
       
   271 	}
       
   272       }
       
   273       unless (-e $deltaFilePath) {
       
   274         print "Error: $deltaFilePath file doesn't exists.\n";
       
   275 	return 1;
       
   276       }
       
   277       unless (copy($deltaFilePath, $tempCompFilePath)) {
       
   278         print "Error: Couldn't copy file from $deltaFilePath to $tempCompFilePath\n";
       
   279 	return 1;
       
   280       }
       
   281     }
       
   282     elsif ($fileStatus eq "modified") {
       
   283       if ($type eq "file") {
       
   284         if (-e $tempCompFilePath) {
       
   285           unless (unlink($tempCompFilePath)) {
       
   286             print "Error: Couldn't delete $tempCompFilePath : $!\n";
       
   287 	    return 1;
       
   288 	  }
       
   289         }
       
   290         my $tempFilePath = dirname ($tempCompFilePath);
       
   291         unless (-e $tempFilePath) {
       
   292           mkpath ($tempFilePath) or croak "Error: Unable to create $tempFilePath path.\n";
       
   293         }		  
       
   294         unless (-e $deltaFilePath) {
       
   295           print "Error: $deltaFilePath file doesn't exist.\n";
       
   296 	  return 1;
       
   297 	}
       
   298         unless (copy ($deltaFilePath, $tempCompFilePath)) {
       
   299           print "Error: Couldn't copy file from $deltaFilePath to $tempCompFilePath\n";
       
   300 	  return 1;
       
   301 	}
       
   302       }
       
   303       elsif ($type eq "delta") {
       
   304         my $deltaFile = $deltaFilePath.".delta";
       
   305         $self->ReconstructFile($tempCompFilePath, $deltaFile, $tempCompFilePath);
       
   306       }
       
   307       else {
       
   308         print "Error: Unknown file type \"$type\" in delta manifest file.\n";
       
   309 	return 1;
       
   310       }
       
   311     }
       
   312     elsif ($fileStatus eq "deleted") {
       
   313       if (unlink($tempCompFilePath) == 0) {
       
   314         if (-e $tempCompFilePath) {
       
   315           print "Error: Couldn't delete $tempCompFilePath : $!\n";
       
   316 	  return 1;
       
   317         }
       
   318         else {
       
   319           print "Warning: Expecting to delete $tempCompFilePath, but it does not exist.\n";
       
   320         }
       
   321       }
       
   322     }
       
   323     else {
       
   324       print "Error: Unknown file status \"$fileStatus\" for \"$file\" file.\n";
       
   325       return 1;
       
   326     }
       
   327   }
       
   328   #Pack all files of a zipfile to form a category.zip file.
       
   329   my @allFiles;
       
   330   my @filesToBeZipped;
       
   331   Utils::ListAllFiles($tempCompPath, \@allFiles);
       
   332   foreach  my $thisFile (@allFiles) {
       
   333     my $file = substr($thisFile, (length($tempCompPath)+1));
       
   334     push @filesToBeZipped, $file;
       
   335   }
       
   336   Utils::ZipList( $nomZipFile, \@filesToBeZipped, $self->{verbose}, undef,$tempCompPath);
       
   337   unless (rmtree ($tempCompPath)) {
       
   338     print "Error: Couldn't delete $tempCompPath directory.\n"; 
       
   339     return 1;
       
   340   }
       
   341   
       
   342   return 0;
       
   343 }
       
   344 
       
   345 sub ReconstructFile {
       
   346   my $self = shift;
       
   347   my $referenceFile = shift;
       
   348   my $deltaFilePath = shift;
       
   349   my $destination = shift;
       
   350 
       
   351   my $destinationDir = dirname($destination);
       
   352   mkpath($destinationDir) unless(-d $destinationDir);
       
   353   print "Reconstructing ".basename($referenceFile)." file.\n" if($self->{verbose} > 1);
       
   354   my $status = system "zdu \"$referenceFile\" \"$deltaFilePath\"  \"$destination\"" ;
       
   355   if( $status != 0 ) {
       
   356     $status = system "zdu" ;
       
   357     $! = $? >> 8;
       
   358     if( $status != 0 ) {
       
   359       print "Error: The zdelta tool is not installed. Please install zdelta.\n";
       
   360       croak;
       
   361     }
       
   362     else {
       
   363       print "Error: The zdelta tool is not installed properly. Please install zdelta once again.\n";
       
   364       croak;
       
   365     }
       
   366   }
       
   367 }
       
   368 
       
   369 1;
       
   370 
       
   371 __END__
       
   372 
       
   373 
       
   374 =head1 NAME
       
   375 
       
   376 Symbian::CBR::ApplyDelta.pm - Reconstructs the nominated baseline using deltas and reference version of baseline.
       
   377 
       
   378 =head2 new
       
   379 
       
   380 Expects to be passed an C<IniData> reference and verbosity level. Creates an ApplyDelta object. 
       
   381 
       
   382 =head2 ReconstructEnv
       
   383 
       
   384 Expects to be passed a delta zip file path, a destination archive where the environment is to be created, and an overwrite flag specifying whether existing components should be overwritten or not. It makes use of the delta zip file and a reference baseline (specified by the delta manifest file) and reconstructs the originally nominated baseline.
       
   385 
       
   386 =head2 ReconstructComp
       
   387 
       
   388 Expects to be passed a component name, a destination and an overwrite flag specifying whether existing component should be overwritten or not. It makes use of the delta for a component and a reference version of a component (specified by the delta manifest file) and reconstructs the originally nominated version of a component.
       
   389 
       
   390 =head2 ReconstructFile
       
   391 
       
   392 Expects to be passed a reference file, path to a delta file and a destination path. Makes use of the zdelta third party tool to reconstruct the originally nominated version of the file from the inputs.
       
   393 
       
   394 =head1 KNOWN BUGS
       
   395 
       
   396 None.
       
   397 
       
   398 =head1 COPYRIGHT
       
   399 
       
   400  Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
   401  All rights reserved.
       
   402  This component and the accompanying materials are made available
       
   403  under the terms of the License "Eclipse Public License v1.0"
       
   404  which accompanies this distribution, and is available
       
   405  at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
   406  
       
   407  Initial Contributors:
       
   408  Nokia Corporation - initial contribution.
       
   409  
       
   410  Contributors:
       
   411  
       
   412  Description:
       
   413  
       
   414 
       
   415 =cut