build_release.pl (f219747d) build_release.pl (9dd622cd)
1#!/usr/bin/perl
2#**************************************************************
3#
4# Licensed to the Apache Software Foundation (ASF) under one
5# or more contributor license agreements. See the NOTICE file
6# distributed with this work for additional information
7# regarding copyright ownership. The ASF licenses this file
8# to you under the Apache License, Version 2.0 (the

--- 13 unchanged lines hidden (view full) ---

22
23use strict;
24use XML::LibXML;
25use open OUT => ":utf8";
26use LWP::Simple;
27use Digest;
28use Digest::MD5;
29use Digest::SHA;
1#!/usr/bin/perl
2#**************************************************************
3#
4# Licensed to the Apache Software Foundation (ASF) under one
5# or more contributor license agreements. See the NOTICE file
6# distributed with this work for additional information
7# regarding copyright ownership. The ASF licenses this file
8# to you under the Apache License, Version 2.0 (the

--- 13 unchanged lines hidden (view full) ---

22
23use strict;
24use XML::LibXML;
25use open OUT => ":utf8";
26use LWP::Simple;
27use Digest;
28use Digest::MD5;
29use Digest::SHA;
30use File::Temp;
31use File::Path;
30
31use Carp::always;
32
33=head1 NAME
34
35 build_release.pl - Tool for batch release builds and uploads and the creation of wiki pages that list install sets.
36
37=head1 SYNOPSIS
38
39 build_release.pl <command> {option} <release-description.xml>
40
41 comands:
42 build builds all install sets as requested by the XML file and supported by the platform.
32
33use Carp::always;
34
35=head1 NAME
36
37 build_release.pl - Tool for batch release builds and uploads and the creation of wiki pages that list install sets.
38
39=head1 SYNOPSIS
40
41 build_release.pl <command> {option} <release-description.xml>
42
43 comands:
44 build builds all install sets as requested by the XML file and supported by the platform.
45 build-missing
46 build only those install sets that have not been built earlier.
43 upload upload install sets to a local or remote (via ssh with public/private key)
44 directory structure. Uploads install sets that where build on other platforms.
45 wiki create a wiki (MediaWiki syntax) snippet that references all install sets at the upload
46 location. Includes install sets that where built and/or uploaded from other
47 platforms and machines.
48 options:
49 -j <count> maximum number of build processes
50 -k keep going if there are recoverable errors
51 -u <path> upload destination
52 -l check links on wiki page, write broken links as plain text
53 -ld check links on wiki page, mark broken links
54 -o <filename> filename of the output (wiki: wiki page, build: makefile)
47 upload upload install sets to a local or remote (via ssh with public/private key)
48 directory structure. Uploads install sets that where build on other platforms.
49 wiki create a wiki (MediaWiki syntax) snippet that references all install sets at the upload
50 location. Includes install sets that where built and/or uploaded from other
51 platforms and machines.
52 options:
53 -j <count> maximum number of build processes
54 -k keep going if there are recoverable errors
55 -u <path> upload destination
56 -l check links on wiki page, write broken links as plain text
57 -ld check links on wiki page, mark broken links
58 -o <filename> filename of the output (wiki: wiki page, build: makefile)
59 -n <number> maximal number of upload tries, defaults to 5.
60 -d dry-run
55
61
62 Typical calls are:
63 build_release.pl build -j4 instsetoo_native/util/aoo-410-release.xml
64 for building the installation sets, language packs and patches for the 4.1 release.
65
66 build_release.pl upload -u me@server:path -n 3 instsetoo_native/util/aoo-410-release.xml
67 to upload the previously built installation sets etc.
68
69 build_release.pl wiki -o /tmp/wiki.txt instsetoo_native/util/aoo-410-release.xml
70 to create an updated wiki page with installation sets etc built at several
71 places and uploaded to several locations.
72
73
56=head1 XML file format
57
74=head1 XML file format
75
76The release description could look like this:
77
58<release
59 name="snapshot"
60 version="4.1.0">
61
62 <language
63 id="ast" # As specified by 'configure --with-lang'
64 english-name="Asturian"
65 local-name="Asturianu"
66 />
67 ... more languages
68
69 <platform
70 id="wntmsci12.pro"
71 display-name="Windows"
78<release
79 name="snapshot"
80 version="4.1.0">
81
82 <language
83 id="ast" # As specified by 'configure --with-lang'
84 english-name="Asturian"
85 local-name="Asturianu"
86 />
87 ... more languages
88
89 <platform
90 id="wntmsci12.pro"
91 display-name="Windows"
72 base-url="http://people.apache.org/~hdu/developer-snapshots/snapshot/win32"
73 archive-platform="Win_x86"
74 word-size="32"
92 archive-platform="Win_x86"
93 word-size="32"
75 package-types="exe"
94 package-types="msi"
95 extension="exe"
76 />
77 ... more platforms
96 />
97 ... more platforms
78
79 <build
80 target="openoffice"
81 platform-list="all"
82 language-list="all">
83 </build>
84 ... more build entries
85
98
86 <wiki>
99 <download
100 platform-id="wntmsci12.pro"
101 base-url="http://people.apache.org/~somebody/developer-snapshots/snapshot/win32"
102 />
87
103
88 # Each wiki package will generate one row per language.
89 # For each language there will be one package block.
90 <package
104 <package
105 id="openoffice"
106 target="openoffice"
91 display-name="Full Install"
107 display-name="Full Install"
92 archive-name1=""
93 archive-name2="install"
108 archive-name="Apache_OpenOffice_%V_%P_install%T_%L.%E"
109 />
110
111 <build
112 package-id="openoffice"
113 platform-list="all"
94 language-list="all"
114 language-list="all"
115 />
116 ... more build entries
117
118 <wiki>
119 <package-ref
120 package-id="openoffice"
121 language-list="all"
95 platform-list="all"
96 table="main"
97 />
98 ... more packages
99 </wiki>
100
101</release>
122 platform-list="all"
123 table="main"
124 />
125 ... more packages
126 </wiki>
127
128</release>
129
130A single <release> tag contains any number of
131
132<language> id
133 The language id used internally by the build process, eg de, en-US
134 english-name
135 The english name of the language, eg german
136 local-name
137 The language name in that language, eg Deutsch
138
139 Each listed language is expected to have been passed to configure via --with-lang
140 The set of languages defines for which languages to
141 build installation sets, language packs etc. (build command)
142 upload installation sets, etc (upload command)
143 add rows in the wiki page (wiki command)
144
145<platform> id
146 The platform id that is used internally by the build process, eg wntmsci12.pro
147 Note that <p>.pro and <p> are treated as two different platforms.
148 display-name
149 Name which is printed in the wiki table.
150 archive-platform
151 Platform name as used in the name of the installation set, eg Win_x86
152 word-size
153 Bit size of the installation sets, etc, typically either 32 or 64
154 package-types
155 Semicolon separated list of package types, eg "msi" or "deb;rpm"
156 add-package-type-to-archive-name
157 For deb and rpm archives it is necessary to add the package type to the archive name.
158 extension
159 Extension of the archive name, eg "exe" or "tar.gz"
160
161 For the build command only those <platform> elements are used that match the platform on which this
162 script is run.
163
164<download>
165 platform-id
166 Reference to one of the <platform> elements and has to match the id attribute of that platform.
167 base-url
168 URL head to which the name of the downloadable installation set etc. is appended.
169 Eg. http://people.apache.org/~somebody/developer-snapshots/snapshot/win32
170
171 Defines one download source that is referenced in the wiki page. Multiple <download> elements
172 per platform are possible. Earlier entires are preferred over later ones.
173
174<package>
175 id
176 Internal name that is used to reference the package.
177 target
178 Target name recognized by instsetoo_native/util/makefile.mk, eg openoffice or oolanguagepack.
179 display-name
180 Name of the package that is shown in the wiki page, eg "Full Install" or "Langpack".
181 archive-name
182 Template of the archive name.
183 %V version
184 %P archive package name
185 %T package type
186 %L language
187 %E extension.
188
189 Defines a downloadable and distributable package, eg openoffice for the binary OpenOffice installation set.
102
190
191<build> target
192 platform-list
193 Semicolon separated list of platforms for which to build the target.
194 Ignores all platforms that don't match the platform on which this script is executed.
195 The special value 'all' is a shortcut for all platforms listed by <platform> elements.
196 language-list
197 Semicolon separated list of languages for which the build the target.
198 The special value 'all' is a shortcut for all languages listed by <language> elements.
199
200 Defines the sets of targets, plaforms and languages which are to be built.
201
202<wiki>
203 <package-ref>
204 package-id
205 The id of the referenced package.
206 platform-list
207 See <build> tag for explanation.
208 language-list
209 See <build> tag for explanation.
210 table
211 Specifies the wiki table into which to add the package lines. Can be "main" or "secondary".
212
103=cut
104
105
106
213=cut
214
215
216
107my %PlatformDescriptors = (
108 "wntmsci12" => {
109 'name' => "windows",
110 'extension' => "exe",
111 'pack-platform' => "Win_x86",
112 'package-formats' => ["msi"]
113 },
114 "unxmaccxi" => {
115 'name' => "unxmaccx_x86-64",
116 'extension' => "dmg",
117 'pack-platform' => "MacOS_x86",
118 'package-formats' => ["dmg"]
119 },
120 "unxlngi6" => {
121 'name' => "Linux_x86",
122 'extension' => "tar.gz",
123 'pack-platform' => "Linux_x86",
124 'package-formats' => ["deb", "rpm"]
125 },
126 "unxlngx6" => {
127 'name' => "Linux_x86-64",
128 'extension' => "tar.gz",
129 'pack-platform' => "Linux_x86-64",
130 'package-formats' => ["deb", "rpm"]
131 }
132);
133my %ProductDescriptors = (
134 "openoffice" => {
135 'pack-name' => "install",
136 'product-name-tail' => ""
137 },
138 "oolanguagepack" => {
139 'pack-name' => "langpack",
140 'product-name-tail' => "_languagepack"
141 }
142);
143my %EnUSBasedLanguages = (
144 'ast' => 1
145 );
146
147
217my %EnUSBasedLanguages = (
218 'ast' => 1
219 );
220
221
222sub GetInstallationPackageName ($$$$$);
148
149sub ProcessCommandline (@)
150{
151 my @arguments = @_;
152
153 my $command = undef;
154 my $description_filename = undef;
155 my $max_process_count = 1;
156 my $keep_going = 0;
157 my $upload_destination = undef;
158 my $check_links = 0;
159 my $mark_broken_links = 0;
160 my $output_filename = undef;
223
224sub ProcessCommandline (@)
225{
226 my @arguments = @_;
227
228 my $command = undef;
229 my $description_filename = undef;
230 my $max_process_count = 1;
231 my $keep_going = 0;
232 my $upload_destination = undef;
233 my $check_links = 0;
234 my $mark_broken_links = 0;
235 my $output_filename = undef;
236 my $max_upload_count = 5;
237 my $build_only_missing = 0;
238 my $dry_run = 0;
161
162 my $error = 0;
163 while (scalar @arguments > 0)
164 {
165 my $argument = shift @arguments;
166 if ($argument =~ /^-/)
167 {
168 if ($argument eq "-j")

--- 17 unchanged lines hidden (view full) ---

186 {
187 $check_links = 1;
188 $mark_broken_links = 1;
189 }
190 elsif ($argument eq "-o")
191 {
192 $output_filename = shift @arguments;
193 }
239
240 my $error = 0;
241 while (scalar @arguments > 0)
242 {
243 my $argument = shift @arguments;
244 if ($argument =~ /^-/)
245 {
246 if ($argument eq "-j")

--- 17 unchanged lines hidden (view full) ---

264 {
265 $check_links = 1;
266 $mark_broken_links = 1;
267 }
268 elsif ($argument eq "-o")
269 {
270 $output_filename = shift @arguments;
271 }
272 elsif ($argument eq "-n")
273 {
274 $max_upload_count = shift @arguments;
275 }
276 elsif ($argument eq "-d")
277 {
278 $dry_run = 1;
279 }
194 else
195 {
196 printf STDERR "unknown option $argument %s\n", $argument;
197 $error = 1;
198 }
199 }
200 elsif ( ! defined $command)
201 {
202 $command = $argument;
280 else
281 {
282 printf STDERR "unknown option $argument %s\n", $argument;
283 $error = 1;
284 }
285 }
286 elsif ( ! defined $command)
287 {
288 $command = $argument;
203 if ($command !~ /^(build|upload|wiki)$/)
289 if ($command eq "build-missing")
290 {
291 $command = "build";
292 $build_only_missing = 1;
293 }
294 elsif ($command !~ /^(build|build-missing|upload|wiki)$/)
204 {
205 printf STDERR "unknown command '%s'\n", $command;
206 $error = 1;
207 }
208 }
209 else
210 {
211 $description_filename = $argument;

--- 4 unchanged lines hidden (view full) ---

216 }
217 }
218 }
219
220 if ( ! defined $description_filename)
221 {
222 $error = 1;
223 }
295 {
296 printf STDERR "unknown command '%s'\n", $command;
297 $error = 1;
298 }
299 }
300 else
301 {
302 $description_filename = $argument;

--- 4 unchanged lines hidden (view full) ---

307 }
308 }
309 }
310
311 if ( ! defined $description_filename)
312 {
313 $error = 1;
314 }
224 if ($command =~ /^(build|wiki)$/)
315 if ($command =~ /^(wiki)$/)
225 {
226 if ( ! defined $output_filename)
227 {
228 printf STDERR "ERROR: no output filename\n",
229 $error = 1;
230 }
231 }
232

--- 5 unchanged lines hidden (view full) ---

238 return {
239 'command' => $command,
240 'filename' => $description_filename,
241 'max-process-count' => $max_process_count,
242 'keep-going' => $keep_going,
243 'upload-destination' => $upload_destination,
244 'check-links' => $check_links,
245 'mark-broken-links' => $mark_broken_links,
316 {
317 if ( ! defined $output_filename)
318 {
319 printf STDERR "ERROR: no output filename\n",
320 $error = 1;
321 }
322 }
323

--- 5 unchanged lines hidden (view full) ---

329 return {
330 'command' => $command,
331 'filename' => $description_filename,
332 'max-process-count' => $max_process_count,
333 'keep-going' => $keep_going,
334 'upload-destination' => $upload_destination,
335 'check-links' => $check_links,
336 'mark-broken-links' => $mark_broken_links,
246 'output-filename' => $output_filename
337 'output-filename' => $output_filename,
338 'max-upload-count' => $max_upload_count,
339 'build-only-missing' => $build_only_missing,
340 'dry-run' => $dry_run
247 };
248}
249
250
251
252
253sub PrintUsageAndExit ()
254{
255 print STDERR "usage: $0 <command> {option} <release-description.xml>\n";
256 print STDERR " comands:\n";
257 print STDERR " build\n";
341 };
342}
343
344
345
346
347sub PrintUsageAndExit ()
348{
349 print STDERR "usage: $0 <command> {option} <release-description.xml>\n";
350 print STDERR " comands:\n";
351 print STDERR " build\n";
352 print STDERR " build-missing\n";
258 print STDERR " upload\n";
259 print STDERR " wiki create a download page in MediaWiki syntax\n";
260 print STDERR " options:\n";
261 print STDERR " -j <count> maximum number of build processes\n";
262 print STDERR " -k keep going if there are recoverable errors\n";
263 print STDERR " -u <path> upload destination\n";
264 print STDERR " -l check links on wiki page, write broken links as plain text\n";
265 print STDERR " -ld check links on wiki page, mark broken links\n";
266 print STDERR " -o <filename> filename of the output (wiki: wiki page, build: makefile)\n";
353 print STDERR " upload\n";
354 print STDERR " wiki create a download page in MediaWiki syntax\n";
355 print STDERR " options:\n";
356 print STDERR " -j <count> maximum number of build processes\n";
357 print STDERR " -k keep going if there are recoverable errors\n";
358 print STDERR " -u <path> upload destination\n";
359 print STDERR " -l check links on wiki page, write broken links as plain text\n";
360 print STDERR " -ld check links on wiki page, mark broken links\n";
361 print STDERR " -o <filename> filename of the output (wiki: wiki page, build: makefile)\n";
362 print STDERR " -n <number> maximal number of upload tries, defaults to 5.\n";
363 print STDERR " -d dry run\n";
267 exit(1);
268}
269
270
271
272
364 exit(1);
365}
366
367
368
369
370=head2 Trim ($text)
371
372 Remove leading and trailing space from the given string.
373
374=cut
273sub Trim ($)
274{
275 my ($text) = @_;
276 $text =~ s/^\s+|\s+$//g;
277 return $text;
278}
279
280
281
282
375sub Trim ($)
376{
377 my ($text) = @_;
378 $text =~ s/^\s+|\s+$//g;
379 return $text;
380}
381
382
383
384
385=head2 ReadReleaseDescription ($$)
386
387 Read the release description from $filename.
388
389=cut
283sub ReadReleaseDescription ($$)
284{
285 my ($filename, $context) = @_;
286
287 my $document = XML::LibXML->load_xml('location' => $filename);
288 my $root = $document->documentElement();
289
290 # Initialize the release description.
291 my $release = {
292 'name' => $root->getAttribute("name"),
293 'version' => $root->getAttribute("version"),
294 'builds' => [],
295 'languages' => {},
296 'language-ids' => [],
297 'platforms' => {},
390sub ReadReleaseDescription ($$)
391{
392 my ($filename, $context) = @_;
393
394 my $document = XML::LibXML->load_xml('location' => $filename);
395 my $root = $document->documentElement();
396
397 # Initialize the release description.
398 my $release = {
399 'name' => $root->getAttribute("name"),
400 'version' => $root->getAttribute("version"),
401 'builds' => [],
402 'languages' => {},
403 'language-ids' => [],
404 'platforms' => {},
405 'downloads' => [],
406 'packages' => {},
298 'platform-ids' => [],
407 'platform-ids' => [],
299 'wiki-packages' => [],
408 'wiki-packages' => []
300 };
301
302 # Process the language descriptions.
303 for my $language_element ($root->getChildrenByTagName("language"))
304 {
305 my $language_descriptor = ProcessLanguageDescription($language_element, $context);
306 $release->{'languages'}->{$language_descriptor->{'id'}} = $language_descriptor;
307 push @{$release->{'language-ids'}}, $language_descriptor->{'id'};
308 }
309 printf "%d languages\n", scalar keys %{$release->{'languages'}};
310
311 # Process the platform descriptions.
312 for my $platform_element ($root->getChildrenByTagName("platform"))
313 {
409 };
410
411 # Process the language descriptions.
412 for my $language_element ($root->getChildrenByTagName("language"))
413 {
414 my $language_descriptor = ProcessLanguageDescription($language_element, $context);
415 $release->{'languages'}->{$language_descriptor->{'id'}} = $language_descriptor;
416 push @{$release->{'language-ids'}}, $language_descriptor->{'id'};
417 }
418 printf "%d languages\n", scalar keys %{$release->{'languages'}};
419
420 # Process the platform descriptions.
421 for my $platform_element ($root->getChildrenByTagName("platform"))
422 {
314 foreach my $platform_descriptor (ProcessPlatformDescription($platform_element, $context))
315 {
316 $release->{'platforms'}->{$platform_descriptor->{'id'}} = $platform_descriptor;
317 push @{$release->{'platform-ids'}}, $platform_descriptor->{'id'};
318 }
423 my $platform_descriptor = ProcessPlatformDescription($platform_element, $context);
424 $release->{'platforms'}->{$platform_descriptor->{'id'}} = $platform_descriptor;
425 push @{$release->{'platform-ids'}}, $platform_descriptor->{'id'};
319 }
320 printf "%d platforms\n", scalar keys %{$release->{'platforms'}};
321
426 }
427 printf "%d platforms\n", scalar keys %{$release->{'platforms'}};
428
429 # Process the package descriptions.
430 for my $package_element ($root->getChildrenByTagName("package"))
431 {
432 my $package_descriptor = ProcessPackageDescription($package_element, $context);
433 $release->{'packages'}->{$package_descriptor->{'id'}} = $package_descriptor;
434 }
435 printf "%d packages\n", scalar keys %{$release->{'packages'}};
436
437 # Process the download descriptions.
438 for my $download_element ($root->getChildrenByTagName("download"))
439 {
440 my $download_descriptor = ProcessDownloadDescription($download_element, $context);
441 push @{$release->{'downloads'}}, $download_descriptor;
442 }
443 printf "%d downloads\n", scalar @{$release->{'downloads'}};
444
322 if ($context->{'command'} =~ /^(build|upload)$/)
323 {
324 # Process the build descriptions.
325 for my $build_element ($root->getChildrenByTagName("build"))
326 {
327 push @{$release->{'builds'}}, ProcessBuildDescription($build_element, $context, $release);
328 }
329 printf "%d build targets\n", scalar @{$release->{'builds'}};
330 }
331
332 if ($context->{'command'} eq "wiki")
333 {
334 for my $wiki_element ($root->getChildrenByTagName("wiki"))
335 {
445 if ($context->{'command'} =~ /^(build|upload)$/)
446 {
447 # Process the build descriptions.
448 for my $build_element ($root->getChildrenByTagName("build"))
449 {
450 push @{$release->{'builds'}}, ProcessBuildDescription($build_element, $context, $release);
451 }
452 printf "%d build targets\n", scalar @{$release->{'builds'}};
453 }
454
455 if ($context->{'command'} eq "wiki")
456 {
457 for my $wiki_element ($root->getChildrenByTagName("wiki"))
458 {
336 for my $wiki_package_element ($wiki_element->getChildrenByTagName("package"))
459 for my $wiki_package_element ($wiki_element->getChildrenByTagName("package-ref"))
337 {
338 my $wiki_package = ProcessWikiPackageDescription(
339 $wiki_package_element,
340 $context,
341 $release);
342 push @{$release->{'wiki-packages'}}, $wiki_package;
343 }
344 }
345 printf "%d wiki packages\n", scalar @{$release->{'wiki-packages'}};
346 }
347
348 return $release;
349}
350
351
352
353
460 {
461 my $wiki_package = ProcessWikiPackageDescription(
462 $wiki_package_element,
463 $context,
464 $release);
465 push @{$release->{'wiki-packages'}}, $wiki_package;
466 }
467 }
468 printf "%d wiki packages\n", scalar @{$release->{'wiki-packages'}};
469 }
470
471 return $release;
472}
473
474
475
476
477=head ProcessBuildDescription ($build_element, $context, $release_descriptor)
478
479 Process one <build> element.
480
481 If its platform-list does not match the current platform then the <build> element is ignored.
482
483=cut
354sub ProcessBuildDescription ($$$)
355{
356 my ($build_element, $context, $release_descriptor) = @_;
357
484sub ProcessBuildDescription ($$$)
485{
486 my ($build_element, $context, $release_descriptor) = @_;
487
358 my $target_name = $build_element->getAttribute("target");
488 my $package_id = $build_element->getAttribute("package-id");
359 my $languages = PostprocessLanguageList($build_element->getAttribute("language-list"), $release_descriptor);
360 my $platforms = PostprocessPlatformList($build_element->getAttribute("platform-list"), $release_descriptor);
361
362 # Check if the platform matches any for which the product shall be built.
363 my $current_platform = $ENV{'INPATH'};
364 my $is_platform_match = 0;
365 foreach my $platform_id (@$platforms)
366 {
367 if ($platform_id eq $current_platform)
368 {
369 $is_platform_match=1;
370 last;
371 }
372 }
373 if ($is_platform_match)
374 {
489 my $languages = PostprocessLanguageList($build_element->getAttribute("language-list"), $release_descriptor);
490 my $platforms = PostprocessPlatformList($build_element->getAttribute("platform-list"), $release_descriptor);
491
492 # Check if the platform matches any for which the product shall be built.
493 my $current_platform = $ENV{'INPATH'};
494 my $is_platform_match = 0;
495 foreach my $platform_id (@$platforms)
496 {
497 if ($platform_id eq $current_platform)
498 {
499 $is_platform_match=1;
500 last;
501 }
502 }
503 if ($is_platform_match)
504 {
375 printf "including build %s\n", $target_name;
505 printf "including build %s\n", $package_id;
376 }
377 else
378 {
506 }
507 else
508 {
379 printf "skipping build %s: no platform match\n", $target_name;
509 printf "skipping build %s: no platform match\n", $package_id;
380 printf "none of the platforms %s matches %s\n",
510 printf "none of the platforms %s matches %s\n",
381 join(", ", keys %{$release_descriptor->{'platforms'}}),
382 $current_platform;
511 join(", ", keys %{$release_descriptor->{'platforms'}}),
512 $current_platform;
383 return;
384 }
385
386 my @languages = CheckLanguageSet($context, @$languages);
387
388 return {
513 return;
514 }
515
516 my @languages = CheckLanguageSet($context, @$languages);
517
518 return {
389 'target' => $target_name,
519 'package-id' => $package_id,
520 'platform-list' => $platforms,
390 'language-list' => \@languages
391 };
392}
393
394
395
396
521 'language-list' => \@languages
522 };
523}
524
525
526
527
528
529=head2 ProcessPlatformDescription ($element, $context)
530
531 Process one <platform> element.
532
533 The corresponding platform descriptor is returned as a hash.
534
535=cut
397sub ProcessPlatformDescription ($$)
398{
399 my ($element, $context) = @_;
400
401 my $descriptor = {};
402 # Mandatory tags.
536sub ProcessPlatformDescription ($$)
537{
538 my ($element, $context) = @_;
539
540 my $descriptor = {};
541 # Mandatory tags.
403 foreach my $id ("id", "display-name", "base-url", "archive-platform", "word-size", "package-types")
542 foreach my $id ("id", "display-name", "archive-platform", "word-size", "package-types")
404 {
405 $descriptor->{$id} = $element->getAttribute($id);
543 {
544 $descriptor->{$id} = $element->getAttribute($id);
406 die "wiki/platform has no attribute $id" unless defined $descriptor->{$id};
545 die "release/platform has no attribute $id" unless defined $descriptor->{$id};
407 }
546 }
408 $descriptor->{"extension"} = $element->getAttribute("extension");
547 # Optional tags.
548 foreach my $id ("extension", "add-package-type-to-archive-name")
549 {
550 $descriptor->{$id} = $element->getAttribute($id);
551 }
409
552
410 # Split package-types at ';' into single package-type entries.
411 my @descriptors = ();
412 foreach my $package_type (split(/;/, $descriptor->{'package-types'}))
553 $descriptor->{'package-types'} = [split(/;/, $descriptor->{'package-types'})];
554
555 return $descriptor;
556}
557
558
559
560
561=head2 ProcessDownloadDescription ($element, $context)
562
563 Process one <download> element.
564
565 The corresponding download descriptor is returned as a hash.
566
567=cut
568sub ProcessDownloadDescription ($$)
569{
570 my ($element, $context) = @_;
571
572 my $descriptor = {};
573
574 # Mandatory tags.
575 foreach my $id ("platform-id", "base-url")
413 {
576 {
414 push @descriptors, {
415 %$descriptor,
416 'package-type' => $package_type
417 };
577 $descriptor->{$id} = $element->getAttribute($id);
578 die "release/download has no attribute $id" unless defined $descriptor->{$id};
418 }
419
579 }
580
420 return @descriptors;
581 return $descriptor;
421}
422
423
424
425
582}
583
584
585
586
426sub ProcessWikiPackageDescription ($$$)
587=head2 ProcessPackageDescription ($element, $context)
588
589 Process one <package> element.
590
591 The corresponding package descriptor is returned as a hash.
592
593=cut
594sub ProcessPackageDescription ($$$)
427{
428 my ($element, $context, $release_descriptor) = @_;
429
430 my $descriptor = {};
595{
596 my ($element, $context, $release_descriptor) = @_;
597
598 my $descriptor = {};
599
431 # Mandatory tags.
600 # Mandatory tags.
432 foreach my $id ("archive-name2", "display-name", "table")
601 foreach my $id ("id", "target", "archive-name", "display-name")
433 {
434 $descriptor->{$id} = $element->getAttribute($id);
602 {
603 $descriptor->{$id} = $element->getAttribute($id);
435 die "wiki/package has no attribute $id" unless defined $descriptor->{$id};
436 die "wiki/package attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
604 die "release/package has no attribute $id" unless defined $descriptor->{$id};
605 die "release/package attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
437 }
438 # Optional tags.
606 }
607 # Optional tags.
439 foreach my $id ("archive-name1", "link-tooltip", "link-URL", "download-extension")
608 foreach my $id ("link-tooltip", "link-URL", "download-extension")
440 {
441 $descriptor->{$id} = $element->getAttribute($id);
442 }
443
609 {
610 $descriptor->{$id} = $element->getAttribute($id);
611 }
612
613 return $descriptor;
614}
615
616
617
618
619=head2 ProcessWikiPackageDescription ($element, $context)
620
621 Process one <wiki><package-ref> element.
622
623 The corresponding descriptor is returned as a hash.
624
625=cut
626sub ProcessWikiPackageDescription ($$$)
627{
628 my ($element, $context, $release_descriptor) = @_;
629
630 my $descriptor = {};
631 # Mandatory tags.
632 foreach my $id ("package-id", "table")
633 {
634 $descriptor->{$id} = $element->getAttribute($id);
635 die "wiki/package-ref has no attribute $id" unless defined $descriptor->{$id};
636 die "wiki/package-ref attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
637 }
638
444 $descriptor->{'language-list'} = PostprocessLanguageList(
445 $element->getAttribute("language-list"),
446 $release_descriptor);
447 $descriptor->{'platform-list'} = PostprocessPlatformList(
448 $element->getAttribute("platform-list"),
449 $release_descriptor);
450
451 $descriptor->{'languages'} = {map{$_=>1} @{$descriptor->{'language-list'}}};
452 $descriptor->{'platforms'} = {map{$_=>1} @{$descriptor->{'platform-list'}}};
453
454 return $descriptor;
455}
456
457
458
459
639 $descriptor->{'language-list'} = PostprocessLanguageList(
640 $element->getAttribute("language-list"),
641 $release_descriptor);
642 $descriptor->{'platform-list'} = PostprocessPlatformList(
643 $element->getAttribute("platform-list"),
644 $release_descriptor);
645
646 $descriptor->{'languages'} = {map{$_=>1} @{$descriptor->{'language-list'}}};
647 $descriptor->{'platforms'} = {map{$_=>1} @{$descriptor->{'platform-list'}}};
648
649 return $descriptor;
650}
651
652
653
654
655=head2 ProcessLanguageDescription ($element, $context)
656
657 Process one <language> element.
658
659 The corresponding language descriptor is returned as a hash.
660
661=cut
460sub ProcessLanguageDescription ($$)
461{
462 my ($element, $context) = @_;
463
464 my $descriptor = {};
465 foreach my $id ("id", "english-name", "local-name")
466 {
467 $descriptor->{$id} = $element->getAttribute($id);
468 die "wiki/language has no attribute $id" unless defined $descriptor->{$id};
469 }
470
471 return $descriptor;
472}
473
474
475
476
662sub ProcessLanguageDescription ($$)
663{
664 my ($element, $context) = @_;
665
666 my $descriptor = {};
667 foreach my $id ("id", "english-name", "local-name")
668 {
669 $descriptor->{$id} = $element->getAttribute($id);
670 die "wiki/language has no attribute $id" unless defined $descriptor->{$id};
671 }
672
673 return $descriptor;
674}
675
676
677
678
679=head2 PostprocessLanguageList ($language_list, $release_descriptor)
680
681 Process a language list that is given as 'language-list' attribute to some tags.
682
683 If the attribute is missing, ie $language_list is undef, or its value is "all",
684 then the returned list of languages is set to all languages defined via <language> elements.
685
686=cut
477sub PostprocessLanguageList ($$)
478{
479 my ($language_list, $release_descriptor) = @_;
480
481 my @matching_languages = ();
482 if ( ! defined $language_list
483 || $language_list eq "all")
484 {

--- 5 unchanged lines hidden (view full) ---

490 }
491
492 return \@matching_languages;
493}
494
495
496
497
687sub PostprocessLanguageList ($$)
688{
689 my ($language_list, $release_descriptor) = @_;
690
691 my @matching_languages = ();
692 if ( ! defined $language_list
693 || $language_list eq "all")
694 {

--- 5 unchanged lines hidden (view full) ---

700 }
701
702 return \@matching_languages;
703}
704
705
706
707
708=head2 PostprocessPlatformList ($platform_list, $release_descriptor)
709
710 Process a platform list that is given as 'platform-list' attribute to some tags.
711
712 If the attribute is missing, ie $platform_list is undef, or its value is "all",
713 then the returned list of platforms is set to all platforms defined via <platform> elements.
714
715=cut
498sub PostprocessPlatformList ($$)
499{
500 my ($platform_list, $release_descriptor) = @_;
501
502 my @matching_platforms = ();
503 if ( ! defined $platform_list
504 || $platform_list eq "all")
505 {

--- 5 unchanged lines hidden (view full) ---

511 }
512
513 return \@matching_platforms;
514}
515
516
517
518
716sub PostprocessPlatformList ($$)
717{
718 my ($platform_list, $release_descriptor) = @_;
719
720 my @matching_platforms = ();
721 if ( ! defined $platform_list
722 || $platform_list eq "all")
723 {

--- 5 unchanged lines hidden (view full) ---

729 }
730
731 return \@matching_platforms;
732}
733
734
735
736
737=head2 CheckLanguageSet ($context, @languages)
738
739 Compare the given list of languages with the one defined by the 'WITH_LANG' environment variable.
740
741 This is to ensure that configure --with-lang was called with the same set of languages that are
742 listed by the <language> elements.
743
744=cut
519sub CheckLanguageSet ($@)
520{
521 my ($context, @languages) = @_;
522 my %configured_languages = map{$_=>1} split(/\s+/, $ENV{'WITH_LANG'});
523
524 my @missing_languages = ();
525 my @present_languages = ();
526 for my $language (@languages)

--- 5 unchanged lines hidden (view full) ---

532 else
533 {
534 push @missing_languages, $language;
535 }
536 }
537
538 if (scalar @missing_languages > 0)
539 {
745sub CheckLanguageSet ($@)
746{
747 my ($context, @languages) = @_;
748 my %configured_languages = map{$_=>1} split(/\s+/, $ENV{'WITH_LANG'});
749
750 my @missing_languages = ();
751 my @present_languages = ();
752 for my $language (@languages)

--- 5 unchanged lines hidden (view full) ---

758 else
759 {
760 push @missing_languages, $language;
761 }
762 }
763
764 if (scalar @missing_languages > 0)
765 {
540 printf STDERR " there are languages that where not configured via --with-lang:\n";
541 printf STDERR " %s\n", join(", ", @missing_languages);
766 my $message_head = $context->{'keep-going'} ? "WARNING" : "ERROR";
767 printf STDERR "%s: there are languages that where not configured via --with-lang:\n", $message_head;
768 printf STDERR "%s: %s\n", $message_head, join(", ", @missing_languages);
542 if ($context->{'keep-going'})
543 {
544 printf " available languages:\n";
545 printf " %s\n", join(", ", @present_languages);
546 }
547 else
548 {
769 if ($context->{'keep-going'})
770 {
771 printf " available languages:\n";
772 printf " %s\n", join(", ", @present_languages);
773 }
774 else
775 {
549 die;
776 printf STDERR "ERROR: please rerun configure with --with-lang=\"%s\"\n", join(" ", @languages);
777 exit(1);
550 }
551 }
552
553 return @present_languages;
554}
555
556
557
558
778 }
779 }
780
781 return @present_languages;
782}
783
784
785
786
787=head2 WriteMakefile ($release_description, $context)
788
789 Write a makefile with all targets that match the <build> elements.
790
791 The use of a makefile allows us to use make to handle concurrent building.
792
793 When an output file was specified on the command line (option -o) then the
794 makefile is written to that file but make is not run.
795
796 When no output file was specified then the makefile is written to a temporary
797 file. Then make is run for this makefile.
798
799=cut
559sub WriteMakefile ($$)
560{
800sub WriteMakefile ($$)
801{
561 my ($release_description, $output_filename) = @_;
802 my ($release_description, $context) = @_;
562
803
563 my $path = $ENV{'SRC_ROOT'} . "/instsetoo_native/util";
564 open my $make, ">", $output_filename;
804 my $filename = $context->{'output-filename'};
805 if ( ! defined $filename)
806 {
807 $filename = File::Temp->new();
808 }
565
809
566 # Write dependencies of 'all' on the products in all languages.
567 print $make "all .PHONY : \\\n";
568 for my $build (@{$release_description->{'builds'}})
810 # Collect the targets to make.
811 my @targets = ();
812 foreach my $build (@{$release_description->{'builds'}})
569 {
813 {
570 for my $language_id (@{$build->{'language-list'}})
814 my $platform_descriptor = GetCurrentPlatformDescriptor($release_description);
815 my $package_descriptor = $release_description->{'packages'}->{$build->{'package-id'}};
816 foreach my $language_id (@{$build->{'language-list'}})
571 {
817 {
572 printf $make " %s_%s \\\n", $build->{'target'}, $language_id;
818 foreach my $package_format (@{$platform_descriptor->{'package-types'}})
819 {
820 my $full_target = sprintf("%s_%s.%s",
821 $package_descriptor->{'target'},
822 $language_id,
823 $package_format);
824 if ($context->{'build-only-missing'})
825 {
826 my $source_path = GetInstallationPackagePath(
827 $platform_descriptor,
828 $package_format,
829 $language_id);
830 my $archive_name = GetInstallationPackageName(
831 $release_description,
832 $package_descriptor,
833 $package_format,
834 $platform_descriptor,
835 $language_id);
836 my $candidate = $source_path . "/" . $archive_name;
837 if (-f $candidate)
838 {
839 printf "download set for %s already exists, skipping\n", $full_target;
840 next;
841 }
842 }
843 push @targets, $full_target;
844 }
573 }
574 }
845 }
846 }
847
848 # Write the makefile.
849 open my $make, ">", $filename;
850
851 # Write dependencies of 'all' on the products in all languages.
852 print $make "all .PHONY : \\\n ";
853 printf $make "%s\n", join(" \\\n ", @targets);
575 printf $make "\n\n";
576
854 printf $make "\n\n";
855
856 if ($context->{'dry-run'})
857 {
858 printf ("adding make fules for\n %s\n", join("\n ", @targets));
859 }
860
577 # Write rules that chain dmake in instsetoo_native/util.
861 # Write rules that chain dmake in instsetoo_native/util.
578 for my $build (@{$release_description->{'builds'}})
862 foreach my $target (@targets)
579 {
863 {
580 for my $language_id (@{$build->{'language-list'}})
864 printf $make "%s :\n", $target;
865 printf $make "\tdmake \$@ release=t\n";
866 }
867 close $make;
868
869
870 if ( ! defined $context->{'output-filename'})
871 {
872 # Caller wants us to run make.
873 my $path = $ENV{'SRC_ROOT'} . "/instsetoo_native/util";
874 my $command = sprintf("make -f \"%s\" -C \"%s\" -j%d",
875 $filename,
876 $path,
877 $context->{'max-process-count'});
878 if ($context->{'dry-run'})
581 {
879 {
582 printf $make "%s_%s :\n", $build->{'target'}, $language_id;
583 printf $make "\tdmake \$@ release=t\n";
880 printf "would run %s\n", $command;
584 }
881 }
882 else
883 {
884 printf "running %s\n", $command;
885 system($command);
886 }
585 }
887 }
586
587 close $make;
588}
589
590
591
592
593sub Upload ($$)
594{
595 my ($release_description, $context) = @_;
596
597 if ( ! defined $context->{'upload-destination'})
598 {
599 printf STDERR "ERROR: upload destination is missing\n";
600 PrintUsageAndExit();
601 }
602
603 my @download_sets = CollectDownloadSets($release_description);
888}
889
890
891
892
893sub Upload ($$)
894{
895 my ($release_description, $context) = @_;
896
897 if ( ! defined $context->{'upload-destination'})
898 {
899 printf STDERR "ERROR: upload destination is missing\n";
900 PrintUsageAndExit();
901 }
902
903 my @download_sets = CollectDownloadSets($release_description);
604 my @actions = GetCopyActions($release_description, @download_sets);
605 foreach my $action (@actions)
904
905 ProvideChecksums($context, @download_sets);
906 my $source_path = PrepareUploadArea($context, @download_sets);
907 if ( ! defined $source_path)
606 {
908 {
607 printf "uploading %s to %s/%s\n",
608 $action->{'basename'},
609 $context->{'upload-destination'},
610 $action->{'to'};
909 exit(1);
910 }
911 if ( ! UploadFilesViaRsync($context, $source_path, @download_sets))
912 {
913 exit(1);
914 }
915}
611
916
612
613 ProvideChecksums($action);
614 if ($context->{'upload-destination'} =~ /@/)
917
918
919
920=head2 PrepareUploadArea ($context, @download_sets)
921
922 Create a temporary directory with the same sub directory strcuture that is requested in the upload location.
923 The files that are to be uploaded are not copied but linked into this temporary directory tree.
924
925 Returns the name of the temporary directory.
926
927=cut
928sub PrepareUploadArea ($@)
929{
930 my ($context, @download_sets) = @_;
931
932 my $tmpdir = File::Temp->newdir();
933 foreach my $download_set (@download_sets)
934 {
935 foreach my $extension ("", ".md5", ".sha256", ".asc")
615 {
936 {
616 my $destination = $action->{'to'};
617 my $server = $context->{'upload-destination'};
618 if ($server =~ /^(.*):(.*)$/)
937 my $basename = sprintf("%s%s", $download_set->{'archive-name'}, $extension);
938 my $source = sprintf("%s/%s", $download_set->{'source-path'}, $basename);
939 my $target_path = sprintf("%s/%s/%s", $tmpdir, $download_set->{'destination-path'});
940 my $target = sprintf("%s/%s", $target_path, $basename);
941 if ($context->{'dry-run'})
619 {
942 {
620 $server = $1;
621 $destination = $2 . "/" . $destination;
943 printf "would create link for %s\n", $basename;
622 }
944 }
623
624 my @path_parts = split(/\//, $destination);
625 my @paths = ();
626 my $path = undef;
627 foreach my $part (@path_parts)
945 else
628 {
946 {
629 if (defined $path)
947 mkpath($target_path);
948 unlink $target if ( -f $target);
949 my $result = symlink($source, $target);
950 if ($result != 1)
630 {
951 {
631 $path .= "/" . $part;
952 printf "ERROR: can not created symbolic link to %s\n", $basename;
953 printf " %s\n", $source;
954 printf " -> %s\n", $target;
955 return undef;
632 }
956 }
633 else
634 {
635 $path = $part;
636 }
637 push @paths, $path;
638 }
957 }
639 my $command = sprintf("ssh %s mkdir \"%s\"",
640 $server,
641 join("\" \"", @paths));
642 printf "running command '%s'\n", $command;
643 system($command);
958 }
959 }
644
960
645 my $command = sprintf("scp %s %s/%s/",
646 qx(cygpath -u \"$action->{'from'}\"),
647 $context->{'upload-destination'},
648 $action->{'to'});
649 printf "running command '%s'\n", $command;
650 system($command);
961 return $tmpdir;
962}
651
963
652 my $command = sprintf("ssh %s md5 \"%s/%s\"",
653 $server,
654 $destination,
655 $action->{'basename'});
656 printf "running command '%s'\n", $command;
657 system($command);
964
965
966
967sub UploadFilesViaRsync ($$@)
968{
969 my ($context, $source_path, @download_sets) = @_;
970
971
972 # Collect the rsync flags.
973 my @rsync_options = (
974 "-L", # Copy linked files
975 "-a", # Transfer the local attributes and modification times.
976 "-c", # Use checksums to compare source and destination files.
977 "--progress", # Show a progress indicator
978 "--partial", # Try to resume a previously failed upload
979 );
980
981 # (Optional) Add flags for upload to ssh server
982 my $upload_destination = $context->{'upload-destination'};
983 if ($upload_destination =~ /@/)
984 {
985 push @rsync_options, ("-e", "ssh");
986 }
987
988 # Set up the rsync command.
989 my $command = sprintf("rsync %s \"%s/\" \"%s\"",
990 join(" ", @rsync_options),
991 $source_path,
992 $upload_destination);
993 printf "%s\n", $command;
994
995 if ($context->{'dry-run'})
996 {
997 printf "would run %s up to %d times\n", $command, $context->{'max-upload-count'};
998 }
999 else
1000 {
1001 # Run the command. If it fails, repeat a number of times.
1002 my $max_run_count = $context->{'max-upload-count'};
1003 for (my $run_index=1; $run_index<=$max_run_count && scalar @download_sets>0; ++$run_index)
1004 {
1005 my $result = system($command);
1006 printf "%d %d\n", $result, $?;
1007 return 1 if $result == 0;
658 }
1008 }
1009 printf "ERROR: could not upload all files without error in %d runs\n", $max_run_count;
1010 return 0;
659 }
660}
661
662
663
664
665sub CollectDownloadSets ($)
666{
667 my ($release_description) = @_;
668
669 my @download_sets = ();
1011 }
1012}
1013
1014
1015
1016
1017sub CollectDownloadSets ($)
1018{
1019 my ($release_description) = @_;
1020
1021 my @download_sets = ();
670 my $platform_descriptor = GetPlatformDescriptor();
671
1022
672 for my $build (@{$release_description->{'builds'}})
1023 foreach my $platform_descriptor (values %{$release_description->{'platforms'}})
673 {
1024 {
674 my $product_descriptor = GetProductDescriptor($build->{'target'});
675 print $build->{'target'}."\n";
676 my @package_formats = @{$platform_descriptor->{'package-formats'}};
677 for my $package_format (@package_formats)
1025 my $platform_path = sprintf("%s/instsetoo_native/%s",
1026 $ENV{'SOLARSRC'},
1027 $platform_descriptor->{'id'});
1028 if ( ! -d $platform_path)
678 {
1029 {
679 for my $language (@{$build->{'language-list'}})
1030 printf "ignoring missing %s\n", $platform_path;
1031 next;
1032 }
1033 for my $package_descriptor (values %{$release_description->{'packages'}})
1034 {
1035
1036 my @package_formats = @{$platform_descriptor->{'package-types'}};
1037 for my $package_format (@package_formats)
680 {
1038 {
681 my $full_language = $language;
682 if ($EnUSBasedLanguages{$language})
1039 for my $language_id (@{$release_description->{'language-ids'}})
683 {
1040 {
684 $full_language = "en-US_".$language;
1041 my $source_path = GetInstallationPackagePath(
1042 $platform_descriptor,
1043 $package_format,
1044 $language_id);
1045 my $archive_name = GetInstallationPackageName(
1046 $release_description,
1047 $package_descriptor,
1048 $package_format,
1049 $platform_descriptor,
1050 $language_id);
1051 my $candidate = $source_path."/".$archive_name;
1052 if ( ! -f $candidate)
1053 {
1054# printf STDERR "ERROR: can not find download set '%s'\n", $candidate;
1055 next;
1056 }
1057 printf "adding %s\n", $archive_name;
1058 push @download_sets, {
1059 'source-path' => $source_path,
1060 'archive-name' => $archive_name,
1061 'platform' => $platform_descriptor->{'pack-platform'},
1062 'destination-path' => sprintf("developer-snapshots/%s/%s",
1063 $release_description->{'name'},
1064 $platform_descriptor->{'pack-platform'})
1065 };
685 }
1066 }
686 my $archive_name = GetInstallationPackageName($build, $language);
687
688 my $source_path = sprintf("%s/instsetoo_native/%s/Apache_OpenOffice%s/%s/install/%s_download",
689 $ENV{'SOLARSRC'},
690 $ENV{'INPATH'},
691 $product_descriptor->{'product-name-tail'},
692 $package_format,
693 $full_language);
694 if ( ! -f $source_path."/".$archive_name)
695 {
696 printf STDERR "ERROR: can not find download set '%s'\n", $source_path;
697 next;
698 }
699 push @download_sets, {
700 'source-path' => $source_path,
701 'archive-name' => $archive_name,
702 'platform' => $platform_descriptor->{'pack-platform'}
703 };
704 }
705 }
706 }
707
708 return @download_sets;
709}
710
711
712
713
1067 }
1068 }
1069 }
1070
1071 return @download_sets;
1072}
1073
1074
1075
1076
714sub ProvideChecksums ($)
1077=head2 ProvideChecksums ($context, @download_sets)
1078
1079 Create checksums in MD5 and SHA256 format and a gpg signature for the given download set.
1080 The checksums are not created when they already exists and are not older than the download set.
1081
1082=cut
1083sub ProvideChecksums ($@)
715{
1084{
716 my ($action) = @_;
1085 my ($context, @download_sets) = @_;
717
1086
718 printf "creating checksums for %s\n", $action->{'basename'};
719 my $full_archive_name = $action->{'from'} . "/" . $action->{'basename'};
1087 my @asc_requests = ();
1088 foreach my $download_set (@download_sets)
1089 {
1090 printf "%s\n", $download_set->{'archive-name'};
1091 my $full_archive_name = $download_set->{'source-path'} . "/" . $download_set->{'archive-name'};
1092 $full_archive_name = Trim(qx(cygpath -u "$full_archive_name"));
720
1093
721 my $digest = Digest::MD5->new();
722 open my $in, $full_archive_name;
723 $digest->addfile($in);
724 $action->{"MD5"} = $digest->hexdigest();
725 close $in;
1094 my $md5_filename = $full_archive_name . ".md5";
1095 if ( ! -f $md5_filename || IsOlderThan($md5_filename, $full_archive_name))
1096 {
1097 if ($context->{'dry-run'})
1098 {
1099 printf " would create MD5\n";
1100 }
1101 else
1102 {
1103 my $digest = Digest::MD5->new();
1104 open my $in, $full_archive_name;
1105 $digest->addfile($in);
1106 my $checksum = $digest->hexdigest();
1107 close $in;
726
1108
727 my $digest = Digest::SHA->new("sha256");
728 open my $in, $full_archive_name;
729 $digest->addfile($in);
730 $action->{"SHA256"} = $digest->hexdigest();
731 close $in;
1109 open my $out, ">", $md5_filename;
1110 printf $out "%s *%s", $checksum, $download_set->{'archive-name'};
1111 close $out;
1112
1113 printf " created MD5\n";
1114 }
1115 }
1116 else
1117 {
1118 printf " MD5 already exists\n";
1119 }
1120
1121 my $sha256_filename = $full_archive_name . ".sha256";
1122 if ( ! -f $sha256_filename || IsOlderThan($sha256_filename, $full_archive_name))
1123 {
1124 if ($context->{'dry-run'})
1125 {
1126 printf " would create SHA256\n";
1127 }
1128 else
1129 {
1130 my $digest = Digest::SHA->new("sha256");
1131 open my $in, $full_archive_name;
1132 $digest->addfile($in);
1133 my $checksum = $digest->hexdigest();
1134 close $in;
1135
1136 open my $out, ">", $sha256_filename;
1137 printf $out "%s *%s", $checksum, $download_set->{'archive-name'};
1138 close $out;
1139
1140 printf " created SHA256\n";
1141 }
1142 }
1143 else
1144 {
1145 printf " SHA256 already exists\n";
1146 }
1147
1148 my $asc_filename = $full_archive_name . ".asc";
1149 if ( ! -f $asc_filename || IsOlderThan($asc_filename, $full_archive_name))
1150 {
1151 if ($context->{'dry-run'})
1152 {
1153 printf " would create ASC\n";
1154 }
1155 else
1156 {
1157 # gpg seems not to be able to sign more than one file at a time.
1158 # Password has to be provided every time.
1159 my $command = sprintf("gpg --armor --detach-sig \"%s\"", $full_archive_name);
1160 print $command;
1161 my $result = system($command);
1162 printf " created ASC\n";
1163 }
1164 }
1165 else
1166 {
1167 printf " ASC already exists\n";
1168 }
1169 }
732}
733
734
735
736
1170}
1171
1172
1173
1174
737sub GetCopyActions ($@)
738{
739 my ($release_description, @download_sets) = @_;
1175=head2 IsOlderThan ($filename1, $filename2)
740
1176
741 my $platform_descriptor = GetPlatformDescriptor();
1177 Return true (1) if the last modification date of $filename1 is older than (<) that of $filename2.
742
1178
743 my @actions = ();
1179=cut
1180sub IsOlderThan ($$)
1181{
1182 my ($filename1, $filename2) = @_;
744
1183
745 for my $download_set (@download_sets)
746 {
747 my $destination_path = sprintf("developer-snapshots/%s/%s",
748 $release_description->{'name'},
749 $platform_descriptor->{'pack-platform'});
750
751 push @actions, {
752 'action'=>'copy',
753 'from' => $download_set->{'source-path'},
754 'to' => $destination_path,
755 'basename' => $download_set->{'archive-name'}
756 };
757 }
1184 my @stat1 = stat $filename1;
1185 my @stat2 = stat $filename2;
758
1186
759 return @actions;
1187 return $stat1[9] < $stat2[9];
760}
761
762
763
764
1188}
1189
1190
1191
1192
765sub GetInstallationPackageName ($$)
1193sub GetInstallationPackageName ($$$$$)
766{
1194{
767 my ($build, $language) = @_;
1195 my ($release_description, $package_descriptor, $package_format, $platform_descriptor, $language) = @_;
768
1196
769 my $platform_descriptor = GetPlatformDescriptor();
770 my $build_descriptor = GetProductDescriptor($build->{'target'});
771 my $name = sprintf ("Apache_OpenOffice_%s_%s_%s_%s.%s",
772 "4.1.0",
773 $platform_descriptor->{'pack-platform'},
774 $build_descriptor->{'pack-name'},
775 $language,
776 $platform_descriptor->{'extension'});
1197 my $name = $package_descriptor->{'archive-name'};
1198
1199 my $archive_package_type = "";
1200 if ($platform_descriptor->{'add-package-type-to-archive-name'} =~ /^(1|true|yes)$/i)
1201 {
1202 $archive_package_type = "-".$package_format;
1203 }
1204
1205 $name =~ s/%V/$release_description->{'version'}/g;
1206 $name =~ s/%P/$platform_descriptor->{'archive-platform'}/g;
1207 $name =~ s/%T/$archive_package_type/g;
1208 $name =~ s/%L/$language/g;
1209 $name =~ s/%E/$platform_descriptor->{'extension'}/g;
777 return $name;
778}
779
780
781
782
1210 return $name;
1211}
1212
1213
1214
1215
783sub GetPlatformDescriptor ()
1216sub GetInstallationPackagePath ($$$)
784{
1217{
785 if ( ! defined $ENV{'OUTPATH'})
1218 my ($product_descriptor, $package_format, $language) = @_;
1219
1220 my $full_language = $language;
1221 if ($EnUSBasedLanguages{$language})
786 {
1222 {
787 printf STDERR "ERROR: solar environment not loaded or broken (OUTPATH not defined)\n";
788 die;
1223 $full_language = "en-US_".$language;
789 }
1224 }
790 my $descriptor = $PlatformDescriptors{$ENV{'OUTPATH'}};
791 if ( ! defined $descriptor)
792 {
793 printf STDERR "ERROR: platform '%s' is not yet supported\n", $ENV{'OUTPATH'};
794 die;
795 }
796 return $descriptor;
1225
1226 return sprintf("%s/instsetoo_native/%s/Apache_OpenOffice%s/%s/install/%s_download",
1227 $ENV{'SOLARSRC'},
1228 $ENV{'INPATH'},
1229 $product_descriptor->{'product-name-tail'},
1230 $package_format,
1231 $full_language);
797}
798
799
800
801
1232}
1233
1234
1235
1236
802sub GetProductDescriptor ($)
1237sub GetCurrentPlatformDescriptor ($)
803{
1238{
804 my ($product_name) = @_;
805 my $descriptor = $ProductDescriptors{$product_name};
806 if ( ! defined $descriptor)
1239 my ($release_description) = @_;
1240
1241 my $platform_descriptor = $release_description->{'platforms'}->{$ENV{'INPATH'}};
1242 if ( ! defined $platform_descriptor)
807 {
1243 {
808 printf STDERR "ERROR: product '%s' is not supported\n", $product_name;
1244 printf STDERR "ERROR: platform '%s' is not supported\n", $ENV{'INPATH'};
809 }
1245 }
810 return $descriptor;
1246 return $platform_descriptor;
811}
812
813
814
815
816sub Wiki ($$)
817{
818 my ($release_descriptor, $context) = @_;
819
820 open my $out, ">", $context->{'output-filename'};
821
822 my @table_list = GetTableList($release_descriptor);
823 foreach my $table_name (@table_list)
824 {
825 my @table_packages = GetPackagesForTable($release_descriptor, $table_name);
826 my @table_languages = GetLanguagesForTable($release_descriptor, @table_packages);
827 my @table_platforms = GetPlatformsForTable($release_descriptor, @table_packages);
828
1247}
1248
1249
1250
1251
1252sub Wiki ($$)
1253{
1254 my ($release_descriptor, $context) = @_;
1255
1256 open my $out, ">", $context->{'output-filename'};
1257
1258 my @table_list = GetTableList($release_descriptor);
1259 foreach my $table_name (@table_list)
1260 {
1261 my @table_packages = GetPackagesForTable($release_descriptor, $table_name);
1262 my @table_languages = GetLanguagesForTable($release_descriptor, @table_packages);
1263 my @table_platforms = GetPlatformsForTable($release_descriptor, @table_packages);
1264
829 printf "packages: %s\n", join(", ", map {$_->{'display-name'}} @table_packages);
1265 printf "packages: %s\n", join(", ", map {$_->{'package'}->{'display-name'}} @table_packages);
830 printf "languages: %s\n", join(", ", map {$_->{'english-name'}} @table_languages);
831 printf "platforms: %s\n", join(", ", map {$_->{'id'}} @table_platforms);
832
833 print $out "{| class=\"wikitable\"\n";
1266 printf "languages: %s\n", join(", ", map {$_->{'english-name'}} @table_languages);
1267 printf "platforms: %s\n", join(", ", map {$_->{'id'}} @table_platforms);
1268
1269 print $out "{| class=\"wikitable\"\n";
1270
1271 # Write the table head.
834 print $out "|-\n";
835 print $out "! colspan=\"2\" | Language<br>The names do not refer to countries\n";
836 print $out "! Type\n";
837 foreach my $platform_descriptor (@table_platforms)
838 {
1272 print $out "|-\n";
1273 print $out "! colspan=\"2\" | Language<br>The names do not refer to countries\n";
1274 print $out "! Type\n";
1275 foreach my $platform_descriptor (@table_platforms)
1276 {
839 printf $out "! %s<br>%s bit<br>%s\n",
1277 foreach my $package_type (@{$platform_descriptor->{'package-types'}})
1278 {
1279 printf $out "! %s<br>%s bit<br>%s\n",
840 $platform_descriptor->{'display-name'},
841 $platform_descriptor->{'word-size'},
1280 $platform_descriptor->{'display-name'},
1281 $platform_descriptor->{'word-size'},
842 uc($platform_descriptor->{'package-type'});
1282 uc($package_type);
1283 }
843 }
844
845 foreach my $language_descriptor (@table_languages)
846 {
847 if ($context->{'check-links'})
848 {
849 $| = 1;
1284 }
1285
1286 foreach my $language_descriptor (@table_languages)
1287 {
1288 if ($context->{'check-links'})
1289 {
1290 $| = 1;
850 printf "%s: ", $language_descriptor->{'id'};
1291 printf "%-5%s: ", $language_descriptor->{'id'};
851 }
852
853 print $out "|-\n";
854 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'english-name'};
855 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'local-name'};
856
857 my $is_first = 1;
1292 }
1293
1294 print $out "|-\n";
1295 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'english-name'};
1296 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'local-name'};
1297
1298 my $is_first = 1;
858 foreach my $package_descriptor (@table_packages)
1299 foreach my $wiki_package_descriptor (@table_packages)
859 {
1300 {
1301 my $package_descriptor = $wiki_package_descriptor->{'package'};
1302
860 if ($is_first)
861 {
862 $is_first = 0;
863 }
864 else
865 {
866 printf $out "|-\n";
867 }

--- 7 unchanged lines hidden (view full) ---

875 }
876 else
877 {
878 printf $out "| %s\n", $package_descriptor->{'display-name'};
879 }
880
881 foreach my $platform_descriptor (@table_platforms)
882 {
1303 if ($is_first)
1304 {
1305 $is_first = 0;
1306 }
1307 else
1308 {
1309 printf $out "|-\n";
1310 }

--- 7 unchanged lines hidden (view full) ---

1318 }
1319 else
1320 {
1321 printf $out "| %s\n", $package_descriptor->{'display-name'};
1322 }
1323
1324 foreach my $platform_descriptor (@table_platforms)
1325 {
883 WriteDownloadLinks(
884 $out,
885 $context,
886 $release_descriptor,
887 $language_descriptor,
888 $package_descriptor,
889 $platform_descriptor);
1326 foreach my $package_type (@{$platform_descriptor->{'package-types'}})
1327 {
1328 WriteDownloadLinks(
1329 $out,
1330 $release_descriptor,
1331 $context,
1332 $release_descriptor,
1333 $language_descriptor,
1334 $wiki_package_descriptor,
1335 $platform_descriptor,
1336 $package_type);
1337 }
890 }
891 }
892
893 if ($context->{'check-links'})
894 {
895 printf "\n";
896 }
897 }

--- 7 unchanged lines hidden (view full) ---

905
906
907sub GetTableList ($)
908{
909 my ($release_descriptor) = @_;
910
911 my %seen_table_names = ();
912 my @table_names = ();
1338 }
1339 }
1340
1341 if ($context->{'check-links'})
1342 {
1343 printf "\n";
1344 }
1345 }

--- 7 unchanged lines hidden (view full) ---

1353
1354
1355sub GetTableList ($)
1356{
1357 my ($release_descriptor) = @_;
1358
1359 my %seen_table_names = ();
1360 my @table_names = ();
913 foreach my $package_descriptor (@{$release_descriptor->{'wiki-packages'}})
1361 foreach my $wiki_package_descriptor (@{$release_descriptor->{'wiki-packages'}})
914 {
1362 {
915 my $table_name = $package_descriptor->{'table'};
1363 my $table_name = $wiki_package_descriptor->{'table'};
916 if ( ! $seen_table_names{$table_name})
917 {
918 push @table_names, $table_name;
919 $seen_table_names{$table_name} = 1;
920 }
921 }
922 return @table_names;
923}
924
925
926
927
928sub GetPackagesForTable ($$)
929{
930 my ($release_descriptor, $table_name) = @_;
931
932 my @packages = ();
1364 if ( ! $seen_table_names{$table_name})
1365 {
1366 push @table_names, $table_name;
1367 $seen_table_names{$table_name} = 1;
1368 }
1369 }
1370 return @table_names;
1371}
1372
1373
1374
1375
1376sub GetPackagesForTable ($$)
1377{
1378 my ($release_descriptor, $table_name) = @_;
1379
1380 my @packages = ();
933 foreach my $package_descriptor (@{$release_descriptor->{'wiki-packages'}})
1381 foreach my $wiki_package_descriptor (@{$release_descriptor->{'wiki-packages'}})
934 {
1382 {
935 if ($package_descriptor->{'table'} eq $table_name)
1383 if ($wiki_package_descriptor->{'table'} eq $table_name)
936 {
1384 {
937 push @packages, $package_descriptor;
1385 my $package_descriptor = $release_descriptor->{'packages'}->{
1386 $wiki_package_descriptor->{'package-id'}};
1387 $wiki_package_descriptor->{'package'} = $package_descriptor;
1388 push @packages, $wiki_package_descriptor;
938 }
939 }
940 return @packages;
941}
942
943
944
945

--- 46 unchanged lines hidden (view full) ---

992 }
993
994 # Retrieve the platform descriptors for the plaform ids.
995 my @matching_platform_descriptors = ();
996 foreach my $platform_id (@{$release_descriptor->{'platform-ids'}})
997 {
998 if ($matching_platform_ids{$platform_id})
999 {
1389 }
1390 }
1391 return @packages;
1392}
1393
1394
1395
1396

--- 46 unchanged lines hidden (view full) ---

1443 }
1444
1445 # Retrieve the platform descriptors for the plaform ids.
1446 my @matching_platform_descriptors = ();
1447 foreach my $platform_id (@{$release_descriptor->{'platform-ids'}})
1448 {
1449 if ($matching_platform_ids{$platform_id})
1450 {
1451 print $platform_id."\n";
1000 push @matching_platform_descriptors, $release_descriptor->{'platforms'}->{$platform_id};
1001 }
1002 }
1003
1004 return @matching_platform_descriptors;
1005}
1006
1007
1008
1009
1010my $bold_text_start = "<b>";
1011my $bold_text_end = "</b>";
1012my $small_text_start = "<span style=\"font-size:80%\">";
1013my $small_text_end = "</span>";
1014my $broken_link_start = "<span style=\"color:#FF0000\">";
1015my $broken_link_end = "</span>";
1016
1017
1452 push @matching_platform_descriptors, $release_descriptor->{'platforms'}->{$platform_id};
1453 }
1454 }
1455
1456 return @matching_platform_descriptors;
1457}
1458
1459
1460
1461
1462my $bold_text_start = "<b>";
1463my $bold_text_end = "</b>";
1464my $small_text_start = "<span style=\"font-size:80%\">";
1465my $small_text_end = "</span>";
1466my $broken_link_start = "<span style=\"color:#FF0000\">";
1467my $broken_link_end = "</span>";
1468
1469
1018sub WriteDownloadLinks ($$$$$)
1470sub WriteDownloadLinks ($$$$$$$)
1019{
1020 my ($out,
1471{
1472 my ($out,
1473 $release_descriptor,
1021 $context,
1022 $release_descriptor,
1023 $language_descriptor,
1474 $context,
1475 $release_descriptor,
1476 $language_descriptor,
1024 $package_descriptor,
1025 $platform_descriptor) = @_;
1477 $wiki_package_descriptor,
1478 $platform_descriptor,
1479 $package_type) = @_;
1026
1480
1481 my $package_descriptor = $wiki_package_descriptor->{'package'};
1482
1027 # Check if the current language and platform match the package.
1483 # Check if the current language and platform match the package.
1028 if (defined $package_descriptor->{'platforms'}->{$platform_descriptor->{'id'}}
1029 && defined $package_descriptor->{'languages'}->{$language_descriptor->{'id'}})
1484 if (defined $wiki_package_descriptor->{'platforms'}->{$platform_descriptor->{'id'}}
1485 && defined $wiki_package_descriptor->{'languages'}->{$language_descriptor->{'id'}})
1030 {
1031 my $archive_package_name = "";
1486 {
1487 my $archive_package_name = "";
1032 my $package_type = $platform_descriptor->{'package-type'};
1033 my $extension = $package_type;
1034 if (defined $platform_descriptor->{'extension'})
1035 {
1036 $extension = $platform_descriptor->{'extension'};
1037 }
1038 if (defined $package_descriptor->{'download-extension'})
1039 {
1040 $extension = $package_descriptor->{'download-extension'};
1041 }
1042 $archive_package_name = "-".$package_type if ($package_type =~ /deb|rpm/);
1488 my $extension = $package_type;
1489 if (defined $platform_descriptor->{'extension'})
1490 {
1491 $extension = $platform_descriptor->{'extension'};
1492 }
1493 if (defined $package_descriptor->{'download-extension'})
1494 {
1495 $extension = $package_descriptor->{'download-extension'};
1496 }
1497 $archive_package_name = "-".$package_type if ($package_type =~ /deb|rpm/);
1043 my $archive_name = sprintf("Apache_OpenOffice%s_%s_%s_%s%s_%s.%s",
1044 $package_descriptor->{'archive-name1'},
1045 $release_descriptor->{'version'},
1046 $platform_descriptor->{'archive-platform'},
1047 $package_descriptor->{'archive-name2'},
1048 $archive_package_name,
1049 $language_descriptor->{'id'},
1050 $extension);
1051
1498
1052 my $url = $platform_descriptor->{'base-url'} . "/". $archive_name;
1053 printf $out
1054 "| align=\"center\" | %s%s%s<br><br>%s%s %s<br>%s%s\n",
1499 my $archive_name = GetInstallationPackageName(
1500 $release_descriptor,
1501 $package_descriptor,
1502 $package_type,
1503 $platform_descriptor,
1504 $language_descriptor->{'id'});
1505
1506 printf $out "| align=\"center\" | ";
1507 my $download = FindDownload(
1508 $context,
1509 $release_descriptor,
1510 $platform_descriptor,
1511 $package_type,
1512 $archive_name);
1513 if (defined $download)
1514 {
1515 my $url = $download->{'base-url'} . "/". $archive_name;
1516 printf $out "%s%s%s<br><br>%s%s %s<br>%s%s",
1055 $bold_text_start,
1056 CreateLink($url, $extension, $context),
1057 $bold_text_end,
1058 $small_text_start,
1059 CreateLink($url.".asc", "ASC", $context),
1060 CreateLink($url.".md5", "MD5", $context),
1061 CreateLink($url.".sha256", "SHA256", $context),
1062 $small_text_end;
1517 $bold_text_start,
1518 CreateLink($url, $extension, $context),
1519 $bold_text_end,
1520 $small_text_start,
1521 CreateLink($url.".asc", "ASC", $context),
1522 CreateLink($url.".md5", "MD5", $context),
1523 CreateLink($url.".sha256", "SHA256", $context),
1524 $small_text_end;
1525 }
1526 printf $out "\n";
1063 }
1064 else
1065 {
1066 printf $out "|\n";
1067 }
1068}
1069
1070
1071
1072
1527 }
1528 else
1529 {
1530 printf $out "|\n";
1531 }
1532}
1533
1534
1535
1536
1537sub FindDownload ($$$$$)
1538{
1539 my ($context,
1540 $release_descriptor,
1541 $platform_descriptor,
1542 $package_type,
1543 $archive_name) = @_;
1544
1545 foreach my $download (@{$release_descriptor->{'downloads'}})
1546 {
1547 if ($download->{'platform-id'} eq $platform_descriptor->{'id'})
1548 {
1549 my $url = $download->{'base-url'} . "/". $archive_name;
1550 if ($context->{'check-links'})
1551 {
1552 if (CheckLink($url))
1553 {
1554 # URL points to an existing file.
1555 printf "+";
1556 return $download;
1557 }
1558 else
1559 {
1560 # URL is broken.
1561 # Try the next download area for the platform.
1562 next;
1563 }
1564 }
1565 else
1566 {
1567 # Use the URL unchecked. If there is more than one download area for the platform then only
1568 # the first is ever used.
1569 printf ".";
1570 return $download;
1571 }
1572 }
1573 }
1574
1575 if ($context->{'check-links'})
1576 {
1577 printf "-";
1578 }
1579
1580 return undef;
1581}
1582
1583
1584
1585
1073sub CreateLink ($$$)
1074{
1075 my ($url, $text, $context) = @_;
1076
1077 my $is_link_broken = 0;
1078 if ($context->{'check-links'})
1079 {
1586sub CreateLink ($$$)
1587{
1588 my ($url, $text, $context) = @_;
1589
1590 my $is_link_broken = 0;
1591 if ($context->{'check-links'})
1592 {
1080 my $head = LWP::Simple::head($url);
1081 $is_link_broken = ! $head;
1593 if (CheckLink($url))
1594 {
1595 $is_link_broken = 0;
1596 printf "+";
1597 }
1598 else
1599 {
1600 $is_link_broken = 1;
1601 printf "-";
1602 }
1603 }
1604 else
1605 {
1082 printf ".";
1083 }
1084
1085 if ( ! $is_link_broken)
1086 {
1087 return sprintf ("[%s %s]", $url, $text);
1088 }
1089 elsif ($context->{'mark-broken-links'})

--- 4 unchanged lines hidden (view full) ---

1094 {
1095 return sprintf ("%s", $text);
1096 }
1097}
1098
1099
1100
1101
1606 printf ".";
1607 }
1608
1609 if ( ! $is_link_broken)
1610 {
1611 return sprintf ("[%s %s]", $url, $text);
1612 }
1613 elsif ($context->{'mark-broken-links'})

--- 4 unchanged lines hidden (view full) ---

1618 {
1619 return sprintf ("%s", $text);
1620 }
1621}
1622
1623
1624
1625
1626=head2 CheckLink ($url)
1627
1628 Check if the file referenced by $url can be downloaded.
1629 This is determined by downloading only the header.
1630
1631=cut
1632my $LastCheckedURL = undef;
1633my $LastCheckedResult = undef;
1634sub CheckLink ($)
1635{
1636 my ($url) = @_;
1637
1638 if ($url ne $LastCheckedURL)
1639 {
1640 my $head = LWP::Simple::head($url);
1641 $LastCheckedURL = $url;
1642 $LastCheckedResult = !!$head;
1643 }
1644
1645 return $LastCheckedResult;
1646}
1647
1648
1649
1650
1651sub SignFile ($$)
1652{
1653 my ($signature, $filename) = @_;
1654
1655 my $command = sprintf(
1656 "gpg --armor --output %s.asc --detach-sig %s",
1657 $filename,
1658 $filename);
1659}
1660
1661
1662
1663
1102my $context = ProcessCommandline(@ARGV);
1103my $release_description = ReadReleaseDescription($context->{'filename'}, $context);
1104if ($context->{'command'} eq "build")
1105{
1664my $context = ProcessCommandline(@ARGV);
1665my $release_description = ReadReleaseDescription($context->{'filename'}, $context);
1666if ($context->{'command'} eq "build")
1667{
1106 WriteMakefile($release_description, $context->{'output-filename'});
1107# open my $make, "|-", sprintf("make -C \"%s\" -j%d -f -", $path, $max_process_count);
1668 WriteMakefile($release_description, $context);
1108}
1109elsif ($context->{'command'} eq "upload")
1110{
1111 Upload($release_description, $context);
1112}
1113elsif ($context->{'command'} eq "wiki")
1114{
1115 Wiki($release_description, $context);
1116}
1669}
1670elsif ($context->{'command'} eq "upload")
1671{
1672 Upload($release_description, $context);
1673}
1674elsif ($context->{'command'} eq "wiki")
1675{
1676 Wiki($release_description, $context);
1677}