diff options
Diffstat (limited to 'bin/createpackage.pl')
-rwxr-xr-x | bin/createpackage.pl | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/bin/createpackage.pl b/bin/createpackage.pl new file mode 100755 index 0000000000..b7457e1c0b --- /dev/null +++ b/bin/createpackage.pl @@ -0,0 +1,433 @@ +#!/usr/bin/perl +############################################################################# +## +## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the S60 port of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################# + +############################################################################################ +# +# Convenience script for creating signed packages you can install on your phone. +# +############################################################################################ + +use strict; + +# use a command-line parsing module +use Getopt::Long; +# Use file name parsing module +use File::Basename; +# Use File::Spec services mainly rel2abs +use File::Spec; +# Use File::Path - to make stub sis target directory +use File::Path; +# use CWD abs_bath, which is exported only on request +use Cwd 'abs_path'; +use File::Copy; + +sub Usage() { + print <<ENDUSAGESTRING; + +============================================================================================== +Convenience script for creating signed packages you can install on your phone. + +Usage: createpackage.pl [options] templatepkg [target]-[platform] [certificate key [passphrase]] + +Where supported options are as follows: + [-i|install] = Install the package right away using PC suite. + [-p|preprocess] = Only preprocess the template .pkg file. + [-c|certfile <file>] = The file containing certificate information for signing. + The file can have several certificates, each specified in + separate line. The certificate, key and passphrase in line + must be ';' separated. Lines starting with '#' are treated + as a comments. Also empty lines are ignored. The paths in + <file> can be absolute or relative to <file>. + [-u|unsigned] = Preserves the unsigned package. + [-o|only-unsigned] = Creates only unsigned package. + [-s|stub] = Generates stub sis for ROM. + [-n|sisname <name>] = Specifies the final sis name. + [-g|gcce-is-armv5] = Convert gcce platform to armv5. + [-d|dont-patch] = Skip automatic patching of capabilities and pkg file if default certificate + is used. Instead non-self-signable capabilities just cause warnings. + [-t|tmp-dir <path>] = Specifies temporary directory to be used for package creation. + Defaults to 'createpackage_tmp' under same directory as templatepkg. +Where parameters are as follows: + templatepkg = Name of .pkg file template + target = Either debug or release + platform = One of the supported platform + winscw | gcce | armv5 | armv6 | armv7 + Note that when packaging binaries built using gcce and symbian-sbsv2 + mkspec, armv5 must be used for platform instead of gcce. + certificate = The certificate file used for signing + key = The certificate's private key file + passphrase = The passphrase of the certificate's private key file + +Example: + createpackage.pl fluidlauncher_template.pkg release-armv5 + +Example with certfile: + createpackage.pl -c=mycerts.txt fluidlauncher_template.pkg release-armv5 + + Content of 'mycerts.txt' must be something like this: + # This is comment line, also the empty lines are ignored + rd.cer;rd-key.pem + .\\cert\\mycert.cer;.\\cert\\mykey.key;yourpassword + X:\\QtS60\\s60installs\\selfsigned.cer;X:\\QtS60\\s60installs\\selfsigned.key + +If no certificate and key files are provided, either a RnD certificate or +a self-signed certificate from QtDir\\src\\s60installs directory is used. +In the latter case the resulting package will also be automatically patched +using patch_capabilities.pl script, which makes it unsuitable for distribution. +Always specify certificates explicitly if you wish to distribute your package. + +============================================================================================== + +ENDUSAGESTRING + + exit(); +} + +# Read given options +my $install = ""; +my $preprocessonly = ""; +my $certfile = ""; +my $preserveUnsigned = ""; +my $stub = ""; +my $signed_sis_name = ""; +my $onlyUnsigned = ""; +my $convertGcce = ""; +my $dontPatchCaps = ""; +my $tempPackageDir = ""; + +unless (GetOptions('i|install' => \$install, + 'p|preprocess' => \$preprocessonly, + 'c|certfile=s' => \$certfile, + 'u|unsigned' => \$preserveUnsigned, + 'o|only-unsigned' => \$onlyUnsigned, + 's|stub' => \$stub, + 'n|sisname=s' => \$signed_sis_name, + 'g|gcce-is-armv5' => \$convertGcce, + 'd|dont-patch' => \$dontPatchCaps, + 't|tmp-dir=s' => \$tempPackageDir,)) { + Usage(); +} + +my $epocroot = $ENV{EPOCROOT}; +my $epocToolsDir = ""; +if ($epocroot ne "") { + $epocroot =~ s,\\,/,g; + if ($epocroot =~ m,[^/]$,) { + $epocroot = $epocroot."/"; + } + $epocToolsDir = "${epocroot}epoc32/tools/"; +} + +my $certfilepath = abs_path(dirname($certfile)); + +# Read params to variables +my $templatepkg = $ARGV[0]; +my $targetplatform = lc $ARGV[1]; + +if ($targetplatform eq "") { + $targetplatform = "-"; +} + +my @tmpvalues = split('-', $targetplatform); +my $target; +$target = $tmpvalues[0] or $target = ""; +my $platform; +$platform = $tmpvalues[1] or $platform = ""; + +if ($platform =~ m/^gcce$/i) { + if (($convertGcce ne "")) { + $platform = "armv5"; + } elsif ($ENV{SBS_HOME}) { + # Print a informative note in case suspected misuse is detected. + print "\nNote: You should use armv5 as platform or specify -g parameter to convert platform\n"; + print " when packaging gcce binaries built using symbian-sbsv2 mkspec.\n\n"; + } +} + +# Convert visual target to real target (debug->udeb and release->urel) +$target =~ s/debug/udeb/i; +$target =~ s/release/urel/i; + +my $certificate; +$certificate = $ARGV[2] or $certificate = ""; +my $key; +$key = $ARGV[3] or $key = ""; +my $passphrase; +$passphrase = $ARGV[4] or $passphrase = ""; + +if ($tempPackageDir eq "") { + my ($templateVolume, $templatePath, $templateFileName) = File::Spec->splitpath($templatepkg); + $tempPackageDir = File::Spec->catpath($templateVolume, $templatePath."createpackage_tmp", ""); +} + +mkpath($tempPackageDir); + +# Generate output pkg basename (i.e. file name without extension) +my $pkgoutputbasename = $templatepkg; +$pkgoutputbasename =~ s/_template/_$targetplatform/g; +$pkgoutputbasename =~ s/_installer\.pkg/_installer___temp\.pkg/g; +$pkgoutputbasename =~ s/\.pkg//g; + +# Store output file names to variables +my ($dummy1, $dummy2, $pkgoutput) = File::Spec->splitpath($pkgoutputbasename.".pkg"); +$pkgoutput = $tempPackageDir."/".$pkgoutput; +my $sisoutputbasename; +if ($signed_sis_name eq "") { + $sisoutputbasename = $pkgoutputbasename; + $sisoutputbasename =~ s/_$targetplatform//g; + $sisoutputbasename =~ s/_installer___temp/_installer/g; + $signed_sis_name = $sisoutputbasename.".sis"; +} else { + $sisoutputbasename = $signed_sis_name; + if ($sisoutputbasename =~ m/(\.sis$|\.sisx$)/i) { + $sisoutputbasename =~ s/$1//i; + } else { + $signed_sis_name = $signed_sis_name.".sis"; + } +} + +my $installer_unsigned_app_sis_name = ""; +my $installer_app_sis_name = ""; + +if ($templatepkg =~ m/_installer\.pkg$/i && $onlyUnsigned) { + $installer_unsigned_app_sis_name = $templatepkg; + $installer_unsigned_app_sis_name =~ s/_installer.pkg$/_unsigned.sis/i; + $installer_app_sis_name = $installer_unsigned_app_sis_name; + $installer_app_sis_name =~ s/_unsigned.sis$/.sis/; +} + +my $unsigned_sis_name = $sisoutputbasename."_unsigned.sis"; +my $stub_sis_name = $sisoutputbasename.".sis"; + +# Store some utility variables +my $scriptpath = dirname(__FILE__); +my $certtext = $certificate; +# certificates are one step up in hierarchy +my $certpath = File::Spec->catdir($scriptpath, File::Spec->updir(), "src/s60installs/"); + +# Check some pre-conditions and print error messages if needed. +unless (length($templatepkg)) { + print "\nERROR: Template PKG filename is not defined!\n"; + Usage(); +} + +# Check template exist +stat($templatepkg); +unless( -e _ ) { + print "\nERROR: Package description file '$templatepkg' does not exist!\n"; + Usage(); +} + +# Check certifcate preconditions and set default certificate variables if needed +if (length($certificate)) { + unless(length($key)) { + print "\nERROR: Custom certificate key file parameter missing.!\n"; + Usage(); + } +} else { + #If no certificate is given, check default options + $certtext = "RnD"; + $certificate = File::Spec->catfile($certpath, "rd.cer"); + $key = File::Spec->catfile($certpath, "rd-key.pem"); + + stat($certificate); + unless( -e _ ) { + $certtext = "Self Signed"; + $certificate = File::Spec->catfile($certpath, "selfsigned.cer"); + $key = File::Spec->catfile($certpath, "selfsigned.key"); + } +} + +# Read the certificates from file to two dimensional array +my @certificates; +if (length($certfile)) { + open CERTFILE, "<$certfile" or die $!; + while(<CERTFILE>){ + s/#.*//; # ignore comments by erasing them + next if /^(\s)*$/; # skip blank lines + chomp; # remove trailing newline characters + my @certinfo = split(';', $_); # split row to certinfo + + # Trim spaces + for(@certinfo) { + s/^\s+//; + s/\s+$//; + } + + # Do some validation + unless(scalar(@certinfo) >= 2 && scalar(@certinfo) <= 3 && length($certinfo[0]) && length($certinfo[1]) ) { + print "\nERROR: $certfile line '$_' does not contain valid information!\n"; + Usage(); + } + + push @certificates, [@certinfo]; # push data to two dimensional array + } +} + +# Remove any existing .sis packages +unlink $unsigned_sis_name; +if (!$onlyUnsigned) { + unlink $signed_sis_name; +} +unlink $pkgoutput; + +# Preprocess PKG + +local $/; +# read template file +open( TEMPLATE, $templatepkg) or die "ERROR: '$templatepkg': $!"; +$_=<TEMPLATE>; +close (TEMPLATE); + +# If the pkg file does not contain macros, there is no need for platform or target. +if (m/\$\(PLATFORM\)/) { + unless (length($platform) && length($target)) { + print "\nERROR: Platform or target is not defined!\n"; + Usage(); + } +} + +# replace the PKG variables +s/\$\(PLATFORM\)/$platform/gm; +s/\$\(TARGET\)/$target/gm; + +if ($installer_unsigned_app_sis_name ne "") { + s/$installer_app_sis_name\"/$installer_unsigned_app_sis_name\"/; +} + +#write the output +open( OUTPUT, ">$pkgoutput" ) or die "ERROR: '$pkgoutput' $!"; +print OUTPUT $_; +close OUTPUT; + +if ($preprocessonly) { + # Copy preprocessed file from tmp dir to pkg file dir + my ($templateVolume, $templatePath, $templateFileName) = File::Spec->splitpath($templatepkg); + my ($dummy1, $dummy2, $copyFileName) = File::Spec->splitpath($pkgoutput); + my $copyTarget = File::Spec->catpath($templateVolume, $templatePath, $copyFileName); + copy($pkgoutput, $copyTarget) or die "Preprocessed pkg file '$pkgoutput' cannot be copied."; + exit; +} + +if($stub) { + if(!($epocroot)) { die("ERROR: EPOCROOT must be set to create stub sis files"); } + my $systeminstall = "${epocroot}epoc32/data/z/system/install"; + mkpath($systeminstall); + my $stub_sis_name = $systeminstall."/".$stub_sis_name; + # Create stub SIS. + system ("${epocToolsDir}makesis -s $pkgoutput $stub_sis_name"); +} else { + if ($certtext eq "Self Signed" + && !@certificates + && $templatepkg !~ m/_installer\.pkg$/i + && !$onlyUnsigned) { + my $patch_capabilities = File::Spec->catfile(dirname($0), "patch_capabilities"); + if ($dontPatchCaps) { + system ("$patch_capabilities -c $pkgoutput") and print ("Warning: Package check for self-signing viability failed. Installing the package on a device will most likely fail!\n\n"); + } else { + print("Auto-patching self-signed package.\n"); + system ("$patch_capabilities -t $tempPackageDir $pkgoutput") and die ("ERROR: Automatic patching failed"); + } + } + + # Create SIS. + # The 'and' is because system uses 0 to indicate success. + system ("${epocToolsDir}makesis $pkgoutput $unsigned_sis_name") and die ("ERROR: makesis failed"); + + print("\n"); + + my $targetInsert = ""; + if ($targetplatform ne "-") { + $targetInsert = " for $targetplatform"; + } + + if ($onlyUnsigned) { + stat($unsigned_sis_name); + if( -e _ ) { + print ("Successfully created unsigned package ${unsigned_sis_name}${targetInsert}!\n"); + } else { + print ("\nUnsigned package creation failed!\n"); + } + + print ("\n"); + exit; + } + + # Sign SIS with certificate info given as an argument. + my $relcert = File::Spec->abs2rel($certificate); + my $relkey = File::Spec->abs2rel($key); + # The 'and' is because system uses 0 to indicate success. + system ("${epocToolsDir}signsis $unsigned_sis_name $signed_sis_name $relcert $relkey $passphrase") and die ("ERROR: signsis failed"); + + # Check if creating signed SIS Succeeded + stat($signed_sis_name); + if( -e _ ) { + print ("Successfully created signed package ${signed_sis_name}${targetInsert} using certificate: $certtext!\n"); + + # Sign with additional certificates & keys + for my $row ( @certificates ) { + # Get certificate absolute file names, relative paths are relative to certfilepath + my $relcert = File::Spec->abs2rel(File::Spec->rel2abs( $row->[0], $certfilepath)); + my $relkey = File::Spec->abs2rel(File::Spec->rel2abs( $row->[1], $certfilepath)); + + system ("${epocToolsDir}signsis $signed_sis_name $signed_sis_name $relcert $relkey $row->[2]"); + print ("\tAdditionally signed the SIS with certificate: $row->[0]!\n"); + } + + # remove temporary unsigned sis + if (!$preserveUnsigned) { + unlink $unsigned_sis_name; + } + + # Install the sis if requested + if ($install) { + print ("\nInstalling $signed_sis_name...\n"); + system ("$signed_sis_name"); + } + } else { + # Lets leave the generated PKG for problem solving purposes + print ("\nSIS creation failed!\n"); + } + print ("\n"); +} + +#end of file |