releasing/cbrtools/perl/ExportData.pm
changeset 607 378360dbbdba
parent 602 3145852acc89
equal deleted inserted replaced
591:22486c9c7b15 607:378360dbbdba
       
     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 
       
    17 package ExportData;
       
    18 use strict;
       
    19 use Utils;
       
    20 use IniData;
       
    21 
       
    22 use constant BIN_KEYS => 0;
       
    23 use constant RELDATA_KEYS => 1;
       
    24 use constant EXP_KEYS => 2;
       
    25 use constant SRC_KEYS => 3;
       
    26 use constant SRC_EXP_KEYS => 4;
       
    27 
       
    28 #
       
    29 # Constructor
       
    30 #
       
    31 sub New {
       
    32   my $invocant = shift;
       
    33   my $class = ref($invocant) || $invocant;
       
    34   my %args = @_;
       
    35   my $self = {
       
    36 	      exportsFile => $args{exports_file},
       
    37 	      verbose => $args{verbose},
       
    38 	      iniData => IniData->New(),
       
    39 	     };
       
    40   bless $self, $class;
       
    41   
       
    42   $self->ParseExportData();
       
    43   return $self;
       
    44 }
       
    45 
       
    46 #
       
    47 # Public
       
    48 #
       
    49 
       
    50 sub PgpKeysForSource {
       
    51   my $self = shift;
       
    52   my $component = lc(shift);
       
    53   my $category = lc(shift);
       
    54 
       
    55   return $self->ReconstructData($component, SRC_KEYS, $category);
       
    56 }
       
    57 
       
    58 sub PgpKeysForBinaries {
       
    59   my $self = shift;
       
    60   my $component = lc(shift);
       
    61 
       
    62   return $self->ReconstructData($component, BIN_KEYS);
       
    63 }
       
    64 
       
    65 sub PgpKeysForExports {
       
    66   my $self = shift;
       
    67   my $component = lc(shift);
       
    68   my $category = lc(shift);
       
    69 
       
    70   return $self->ReconstructData($component, EXP_KEYS, $category);
       
    71 }
       
    72 
       
    73 sub PgpKeysForRelData {
       
    74   my $self = shift;
       
    75   my $component = lc(shift);
       
    76 
       
    77   return $self->ReconstructData($component, RELDATA_KEYS);
       
    78 }
       
    79 
       
    80 sub AllPgpKeys {
       
    81   my $self = shift;
       
    82   if (exists $self->{pgpKeys}) {
       
    83     return $self->{pgpKeys};
       
    84   }
       
    85   return [];
       
    86 }
       
    87 
       
    88 sub ExportableComponents {
       
    89   my $self = shift;
       
    90 
       
    91   if (exists $self->{components}) {
       
    92     return $self->{components};
       
    93   }
       
    94   return [];
       
    95 }
       
    96 
       
    97 sub ComponentIsExportable {
       
    98   my $self = shift;
       
    99   my $comp = lc(shift);
       
   100 
       
   101   foreach my $exportableComp (@{$self->ExportableComponents()}) {
       
   102     if ($comp eq lc($exportableComp)) {
       
   103       return 1;
       
   104     }
       
   105   }
       
   106   return 0;
       
   107 }
       
   108 
       
   109 
       
   110 #
       
   111 # Private
       
   112 #
       
   113 
       
   114 sub ParseExportData {
       
   115   my $self = shift;
       
   116 
       
   117   unless ($self->{exportsFile}) {
       
   118     die "Error: Export data filename not defined\n";
       
   119   }
       
   120 
       
   121   open EXPORTS, "$self->{exportsFile}" or die "Error: Unable to open $self->{exportsFile} for reading\n";
       
   122 
       
   123   if ($self->{verbose}) {
       
   124     print "Parsing export data file $self->{exportsFile} ...\n";
       
   125   }
       
   126 
       
   127   my $separator = $self->{iniData}->CsvSeparator();
       
   128 
       
   129   my $firstRow = 1;
       
   130   while (my $row = <EXPORTS>) {
       
   131     chomp $row;
       
   132     if ($row =~ /^\s*$/ or $row =~ /^[$separator]*#/) {next;}  #ignore empty rows in table
       
   133     #handle first non empty row
       
   134     if ($firstRow) {
       
   135       $self->HandleFirstRow($row);
       
   136       $firstRow = 0;
       
   137     }
       
   138     #handle subsequent non empty rows
       
   139     else {
       
   140       $self->HandleRow($row);
       
   141     }
       
   142   }
       
   143   close EXPORTS;
       
   144 }
       
   145 
       
   146 sub HandleFirstRow {
       
   147   my $self = shift;
       
   148   my $row = shift;
       
   149 
       
   150   #parse row of delimiter-separated values
       
   151   my @cols = $self->ParseCSV($row);
       
   152 
       
   153   for (my $i = 1; $i <= $#cols; ++$i) {
       
   154     my $cell = $cols[$i];
       
   155     if (defined $cell) {
       
   156       Utils::StripWhiteSpace(\$cell);
       
   157       my ($pgpKeyid) = ($cell =~ /\b(0X[0-9a-fA-F]{8})\b/i);
       
   158       unless ($pgpKeyid) {
       
   159 	die "Error: PGP key ID of the correct format not defined in column header \"$cell\"\n";
       
   160       }
       
   161       push @{$self->{pgpKeys}}, $pgpKeyid;
       
   162       push @{$self->{nonemptyColumns}} ,$i;
       
   163     }
       
   164     else {
       
   165       die "Error: Undefined PGP key in ".$self->{exportsFile}." file.\n";
       
   166     }
       
   167   }
       
   168 }
       
   169 
       
   170 sub HandleRow {
       
   171   my $self = shift;
       
   172   my $row = shift;
       
   173 
       
   174   $row = lc($row);
       
   175 
       
   176   #parse row of delimiter-separated values
       
   177   my @cols = $self->ParseCSV($row);
       
   178 
       
   179   my $component = $cols[0];
       
   180   Utils::StripWhiteSpace(\$component);
       
   181   if ($component =~ /^\s*$/) {
       
   182     die "Error: Export table has wrong format. Must have component name in first column.\n";
       
   183   }
       
   184   push @{$self->{components}}, $component;
       
   185 
       
   186   #iterate over columns which have a nonempty recipient heading and store cell data
       
   187   my @cells = @cols[@{$self->{nonemptyColumns}}];
       
   188   for (my $j = 0; $j < @cells; ++$j) {
       
   189     $self->HandleCell($component, $j, $cells[$j]); #$j is the PGP array index
       
   190   }
       
   191 }
       
   192 
       
   193 sub HandleCell {
       
   194   my $self = shift;
       
   195   my $component = shift;
       
   196   my $pgpKeyIndex = shift;
       
   197   my $cell = shift;
       
   198   
       
   199   my $pgpKey = $self->{pgpKeys}->[$pgpKeyIndex];
       
   200 
       
   201   # cell must not be undef but may be blank
       
   202   if (!defined $cell) {
       
   203     $cell = '';
       
   204   }
       
   205 
       
   206   if ($cell =~ /exclude(?!_)/i) {
       
   207     # Cells containing 'exclude' must not have _any_ release files of this
       
   208     # component exported to this recipient.  However if only you want to stop
       
   209     # binaries, use exclude_bin
       
   210     return;
       
   211   }
       
   212 
       
   213   # Other cells must have the recipient's key added to 'relDataPgpKeys' and
       
   214   # possibly also 'srcPgpKeys', 'expPgpKeys or 'binPgpKeys' for this component.
       
   215   # Concatenating the string save memory, over using an array
       
   216   $self->{keys}->{$component}->[RELDATA_KEYS] .= "$pgpKeyIndex,";
       
   217 
       
   218   # Include binaries unless 'exclude_bin'
       
   219   if ( $cell !~ s/exclude_bin//i ) {
       
   220     $self->{keys}->{$component}->[BIN_KEYS] .= "$pgpKeyIndex,";
       
   221   }
       
   222 
       
   223   # Identify any S() or E() blocks
       
   224   my %blocks;
       
   225   while ($cell =~ s/([a-z])\((.*?)\)//i) {
       
   226     if (!defined $blocks{$1}) {
       
   227       $blocks{$1} = [$1, $2];
       
   228     } else {
       
   229       die "Error: Export table has wrong format. Multiple $1() blocks found in cell for component '$component', PGP key '$pgpKey'\n";
       
   230     }
       
   231   }
       
   232 
       
   233   foreach my $block (keys(%blocks)) {
       
   234     my ($origblock, $cats) = @{$blocks{$block}};
       
   235     my $type;
       
   236     if ($block eq "s") {
       
   237       $type = SRC_KEYS;
       
   238     } elsif ($block eq "e") {
       
   239       $type = EXP_KEYS;
       
   240     }
       
   241     if (defined $type) {
       
   242       while ($cats =~ s/([a-z]-[a-z]|\S)//i) { # a letter range (e.g. A-Z) or any non whitespace character
       
   243         my $cat = $1;
       
   244         
       
   245         if ($cat =~ /(.)-(.)/) {
       
   246           my ($from, $to) = ($1, $2);
       
   247       
       
   248           foreach my $cat (ord($from)..ord($to)) { # convert the characters to numbers so that we can do a foreach on the range
       
   249             $cat -= 96;
       
   250             $self->{keys}->{$component}->[$type]->[$cat] .= "$pgpKeyIndex,";
       
   251           }
       
   252         }
       
   253         elsif ($cat =~ /^[a-z]$/i) {
       
   254           $cat = ord($cat) - 96;         
       
   255           $self->{keys}->{$component}->[$type]->[$cat] .= "$pgpKeyIndex,";
       
   256         } else {
       
   257           die "Error: Export table has wrong format. '$cat' is not a valid IPR category in cell for component '$component', PGP key '$pgpKey'\n";
       
   258         }
       
   259       }
       
   260     } else {
       
   261       die "Error: Export table has wrong format. '$origblock()' is not a valid construct in cell for component '$component', PGP key '$pgpKey'\n";
       
   262     }
       
   263   }
       
   264 
       
   265   # Handle any 'old format' IPR categories not in blocks
       
   266   while ($cell =~ s/([a-z]-[a-z]|\S)//i) { # a letter range (e.g. A-Z) or any non whitespace character
       
   267     my $cat = $1;
       
   268 
       
   269     if ($cat =~ /(.)-(.)/) {
       
   270       my ($from, $to) = ($1, $2);
       
   271 
       
   272       foreach my $cat (ord($from)..ord($to)) { # convert the characters to numbers so that we can do a foreach on the range
       
   273         $cat -= 96;
       
   274         $self->{keys}->{$component}->[SRC_EXP_KEYS]->[$cat] .= "$pgpKeyIndex,";
       
   275       }
       
   276     }
       
   277     elsif ($cat !~ /^[a-z]$/i) {
       
   278       die "Error: Export table has wrong format. '$cat' is not a valid IPR category in cell for component '$component', PGP key '$pgpKey'\n";
       
   279     }
       
   280     else {
       
   281       $cat = ord($cat) - 96;
       
   282       $self->{keys}->{$component}->[SRC_EXP_KEYS]->[$cat] .= "$pgpKeyIndex,";
       
   283     }
       
   284   }
       
   285 }
       
   286 
       
   287 sub ParseCSV {
       
   288   my $self = shift;
       
   289   my $text = shift;      # record containing delimited-separated values
       
   290   my @new ;
       
   291   
       
   292   my $separator = $self->{iniData}->CsvSeparator();
       
   293   
       
   294   while ($text =~ m{"([^\"\\]*(?:\\.[^\"\\]*)*)"$separator?|([^$separator]+)$separator?|$separator}gx) {
       
   295     push(@new, $+);
       
   296   }
       
   297   
       
   298   push(@new, undef) if substr($text, -1,1) eq $separator;
       
   299 
       
   300   return @new;      # list of values that were delimited-separated
       
   301 }
       
   302 
       
   303 sub ReconstructData {
       
   304   my $self = shift;
       
   305   my $component = shift;
       
   306   my $type = shift;
       
   307   my $category = shift;
       
   308   
       
   309   if ($category) {
       
   310     $category = ord($category) - 96;
       
   311   }
       
   312 
       
   313   if (defined $self->{keys}->{$component}) {
       
   314     my @results;
       
   315     my @pgpKeysIndex;
       
   316   
       
   317     if ($type == EXP_KEYS || $type == SRC_KEYS) {
       
   318       # Gets a list of the src or export keys, as well as the list of keys in both source and exports.
       
   319       # Splits the key indexes on ,
       
   320       if (defined $self->{keys}->{$component}->[$type]->[$category]) {
       
   321         @pgpKeysIndex = split /,/, $self->{keys}->{$component}->[$type]->[$category];
       
   322       }
       
   323       if (defined $self->{keys}->{$component}->[SRC_EXP_KEYS]->[$category]) {
       
   324         push @pgpKeysIndex, split /,/, $self->{keys}->{$component}->[SRC_EXP_KEYS]->[$category];
       
   325       }
       
   326     }
       
   327     else { # BIN or RELDATA
       
   328       @pgpKeysIndex = split /,/, $self->{keys}->{$component}->[$type]
       
   329     }
       
   330     
       
   331     @results = map $self->{pgpKeys}->[$_], @pgpKeysIndex;
       
   332     return \@results;
       
   333   }
       
   334   
       
   335   return [];
       
   336 }
       
   337 
       
   338 1;
       
   339 
       
   340 __END__
       
   341 
       
   342 =head1 NAME
       
   343 
       
   344 ExportData.pm - Provides an interface to the contents of the project's export data file.
       
   345 
       
   346 =head1 DESCRIPTION
       
   347 
       
   348 A module used for accessing export restriction information for a component release.
       
   349 
       
   350 =head1 INTERFACE
       
   351 
       
   352 =head2 New
       
   353 
       
   354 Passed a named parameter list in the form of hash key value pairs:
       
   355 
       
   356  exportsFile => $export_data_filename
       
   357  verbose     => $integer_verbosity_value
       
   358 
       
   359 Opens and parses the export data file which should contain lines of delimiter separated values representing a table of component name rows and recipient columns, as in the example below:
       
   360 
       
   361              | pgpkeyid_1 (recipient) | pgpkeyid_2 (recipient) | pgpkeyid_3 (recipient) |
       
   362  ------------+------------------------+------------------------+------------------------+--
       
   363  component_1 |           DE           |            E           |          CDE           |
       
   364  ------------+------------------------+------------------------+------------------------+--
       
   365  component_2 |          S(CDE) E(DE)  |                        |           DE           |
       
   366  ------------+------------------------+------------------------+------------------------+--
       
   367  component_3 |           D-G  T       |           A-F          |         exclude        |
       
   368  ------------+------------------------+------------------------+------------------------+--
       
   369  component_4 |  exclude_bin DEFG      |       DEFG             |       DEFG             |
       
   370 
       
   371 
       
   372 
       
   373 The column headers must contain the recipients PGP key ID - an eight digit hexadecimal number preceeded by C<0x> (e.g C<0xD9A2CE15>). This public PGP key will be used to encrypt all files sent to the recipient. The name of the recipient may also be included in the column header although this is not mandatory.
       
   374 
       
   375 A cell contains a list of IPR categories available to the recipient of the component.
       
   376  Each category must be a single letter or digit or a range (e.g. A-Z). Empty cells imply that the recipient
       
   377  does not have access to any source for the corresponding component but can still receive
       
   378 binaries.
       
   379 
       
   380 Alternatively, different categories may be specified for source files and export files, using the S(...) and E(...) notations respectively, with '...' being a list of IPR categories.
       
   381 
       
   382 To prevent a recipient from receiving both source and binaries for the corresponding component, use the keyword C<exclude>. This can be useful when certain recipients may receive releases of some but not all components.
       
   383 
       
   384 To prevent a recipient from receiving binaries for the corresponding component, use the keyword C<exclude_bin>. Unlike C<exclude>, this does not break any environment.
       
   385 
       
   386 Components which are not listed in the table but exist on the local site will not be exported to any recipients. However, a warning will be issued to alert the exporter of this situation.
       
   387 
       
   388 If a licensee or third party does not use C<DISTRIBUTION.POLICY> files to categorize source then all source will have the category X. In this case, putting X in a cell implies that all source for that component will be sent to the recipient, otherwise none will be sent.
       
   389 
       
   390 Lines starting with a C<#> are treated as comments and ignored.
       
   391 
       
   392 [NOTE: It is recommended that this file is created and maintained using a spreadsheet
       
   393 application (saving as a CSV file) rather than editing it directly.]
       
   394 
       
   395 If your CSV file does not use a comma ',' as the separator you will need to specify the required
       
   396 separator in your reltools.ini, using the syntax F<csv_separator <separator>>, e.g. F<csv_separator ;>.
       
   397 
       
   398 =head2 PgpKeysForRelData
       
   399 
       
   400 Expects a component name. Returns a reference to an array of public PGP key ids (corresponding to different
       
   401 recipients) to be used to encrypt the component's reldata.
       
   402 
       
   403 =head2 PgpKeysForSource
       
   404 
       
   405 Expects a component name and a source category. Returns a reference to an array of public PGP
       
   406  key ids (corresponding to different recipients) to be used to encrypt the component's source of
       
   407  this category.
       
   408 
       
   409 =head2 PgpKeysForBinaries
       
   410 
       
   411 Expects a component name. Returns a reference to an array of public PGP key ids (corresponding to different
       
   412 recipients) to be used to encrypt the component's binaries.
       
   413 
       
   414 =head2 PgpKeysForExports
       
   415 
       
   416 Expects a component name and an IPR category. Returns a reference to an array of public PGP
       
   417  key ids (corresponding to different recipients) to be used to encrypt the component's exports of
       
   418  this category.
       
   419 
       
   420 =head2 AllPgpKeys
       
   421 
       
   422 Returns a reference to an array of all PGP key IDs listed in the export table.
       
   423 
       
   424 =head2 ExportableComponents
       
   425 
       
   426 Returns a reference to an array of all the components listed in the export table
       
   427 
       
   428 =head2 ComponentIsExportable
       
   429 
       
   430 Expects to be passed a component name. Returns true if the component is listed in the
       
   431 export table.
       
   432 
       
   433 =head1 KNOWN BUGS
       
   434 
       
   435 None.
       
   436 
       
   437 =head1 COPYRIGHT
       
   438 
       
   439  Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
   440  All rights reserved.
       
   441  This component and the accompanying materials are made available
       
   442  under the terms of the License "Eclipse Public License v1.0"
       
   443  which accompanies this distribution, and is available
       
   444  at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
   445  
       
   446  Initial Contributors:
       
   447  Nokia Corporation - initial contribution.
       
   448  
       
   449  Contributors:
       
   450  
       
   451  Description:
       
   452  
       
   453 
       
   454 =cut