|
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 |