Symbian/SysDefToText/SysDefCollector.pm
changeset 0 beb51793110d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian/SysDefToText/SysDefCollector.pm	Mon Jan 18 21:35:57 2010 +0200
@@ -0,0 +1,610 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+#-------------------------------------------------------------------------------
+# package: SysDefCollector
+#
+# usage: Interacts with the SysDefParser to obtain those parts of the system
+#        definition which are relevant to building a named configuration within the
+#        system definition. Contains a SysDefCollector::ParserClient instance which
+#        acts as the interface to the SysDefParser. This separation reduces the
+#        possibility of a method name clash due to the parser callback mechanism
+#        requiring the client to implement methods of the same name as the XML
+#        element tags of interest.
+#
+# public methods:
+#
+#    new(configname, loghandle): constructs a new instance to collect system 
+#       definition info relating to the configuration name 'configname'.
+#
+#    parserClient(): returns a reference to the SysDefCollector::ParserClient
+#       instance - typically for passing to the parser.
+#
+#    options(): returns a list of the abld options flags as specified in the
+#       'option' elements.
+#
+#    targets(): returns a list of the abld target flags as specified by the
+#       'targetList' attributes for each 'buildLayer' element in the specified
+#       configuration.
+#
+#    specialInstructionsFlag(): returns true/false accordingly as any relevant
+#       'specialInstructions' elements are present/not present. Relevant means
+#       instructions which invoke SETUPPRJ.BAT.
+#
+#    components(): returns a hash of component name and bldFile directories
+#        for each component to be built for the specified configuration.
+#
+#    dump(): debug/development method to dump the internal data structures
+#
+#    test(): debug/development method to dump the results of the methods
+#        'options()', 'targets()', 'specialInstructionsFlag()', 'components()'.
+#
+#-------------------------------------------------------------------------------
+package SysDefCollector;
+use strict;
+
+my $debugFlag = 0;
+
+sub new 
+{
+    my ($class, $configname, $loghandle) = @_;
+    my $self = { client => SysDefCollector::ParserClient->new($configname,$loghandle), loghandle => $loghandle };
+    return bless $self, $class;
+}
+
+sub parserClient
+{
+    my $self = shift;
+    return $self->{client};
+}
+
+#-------------------------------------------------------------------------------
+# sub options() - returns the translated list of options for each 'option' element
+#-------------------------------------------------------------------------------
+sub options
+{
+    my $self = shift;
+    return $self->_collectedList('option');
+}
+
+#-------------------------------------------------------------------------------
+# sub targets() - returns the translated list of targets for each 'buildLayer'
+#    in the named configuration.
+#-------------------------------------------------------------------------------
+sub targets
+{
+    my $self = shift;
+
+    my @targets;
+    my @buildLayerTargetList = $self->_collectedList('buildLayerTargetList');
+
+    for my $layerTarget (@buildLayerTargetList)
+    {
+        my %targetListHash = $self->_collectedHash('targetList');
+        my @targetList = @{ $targetListHash{$layerTarget} };
+        push @targets, @targetList;
+    }
+
+    # eliminate any duplicates by storing as hash keys
+    my %targetHash = map { $_, '' } @targets;
+
+    # now translate via the target mapping
+    my %targetMap = $self->_collectedHash('target');
+    @targets = map { $targetMap{$_} } keys %targetHash;
+
+    return @targets;
+}
+
+#-------------------------------------------------------------------------------
+# sub specialInstructionsFlag() - returns true if 'specialInstructions' elements are present.
+#-------------------------------------------------------------------------------
+sub specialInstructionsFlag
+{
+    my $self = shift;
+    my $flag = 0;
+    $flag = $self->_collected()->{specialInstructions}
+                        if exists $self->_collected()->{specialInstructions};
+    return $flag;
+}
+
+#-------------------------------------------------------------------------------
+# sub components() - returns an array of components to be built for the named
+#    configuration. Each array element is a reference to a further array whose
+#    element[0] is the component name and element[1] is the directory location
+#    of that component's 'bld.inf' file.
+#-------------------------------------------------------------------------------
+sub components
+{
+    my $self = shift;
+    my $loghandle = $self->{loghandle};
+    
+    my @unitNames;
+    my @unitListRef = $self->_collectedList('unitListRef');
+    my %unitList    = $self->_collectedHash('unitList');
+    my %unitListNamesHash;  # Used to detect duplicates and then discarded!
+    my %unitNamesHash;      # Used to detect duplicates and then discarded!
+    my %unitMap = $self->_collectedHash('unit');
+    
+    for my $unitListName (@unitListRef)
+    {
+        if (defined $unitListNamesHash{$unitListName})
+        {    # Duplicate unitListName! Ignore it!
+            print $loghandle "Ignoring duplicated unitList: $unitListName\n";
+            next;
+        }
+        $unitListNamesHash{$unitListName} = 1;
+        unless (defined $unitList{$unitListName})
+        {     # No info for this unitList!
+            print $loghandle "No Unit info for unitList: $unitListName\n";
+            next;
+        }
+        my @units = @{ $unitList{$unitListName} };
+        foreach my $unit (@units)
+        {
+            if (defined $unitNamesHash{$unit})
+            {    # Duplicate unit name! Ignore it!
+                print $loghandle "Ignoring duplicated Unit: $unit\n";
+                next;
+            }
+            $unitNamesHash{$unit} = 1;
+            unless (defined $unitMap{$unit})
+            {      # No bldFile (directory) info for this component!
+                print $loghandle "No bldFile info for Unit: $unit\n";
+                next;
+            }
+            my @unitdef = ($unit, $unitMap{$unit});
+            push @unitNames, \@unitdef;
+        }
+    }
+
+    return @unitNames;
+}
+
+#-------------------------------------------------------------------------------
+#
+#-------------------------------------------------------------------------------
+sub dump
+{
+    my $self = shift;
+    my $fh = shift;
+    $self->parserClient($fh)->dump($fh);
+}
+
+#-------------------------------------------------------------------------------
+#
+#-------------------------------------------------------------------------------
+sub test
+{
+    my $self = shift;
+    my $fh = $self->{loghandle};    # Logfile handle
+
+    my @options    = $self->options();
+    my @targets    = $self->targets();
+    my $special    = $self->specialInstructionsFlag();
+    my @components = $self->components($fh);
+
+    print $fh "\nTest Collected System Definition Query Methods\n";
+    print $fh "==============================================\n";
+
+    print $fh "options: ['", (join "', '", @options), "']\n";
+    print $fh "targets: ['", (join "', '", @targets), "']\n";
+    print $fh "special instructions: '", ($special ? "yes" : "no" ), "'\n";
+    print $fh "components:\n{\n";
+    for my $component (@components)
+    {
+        print $fh "\t'", $component->[0], "' => '", $component->[1], "'\n";
+    }
+    print $fh "}\n";
+    print $fh "==============================================\n";
+}
+
+#-------------------------------------------------------------------------------
+# private methods:
+#-------------------------------------------------------------------------------
+sub _collected
+{
+    my $self = shift;
+    return $self->parserClient()->{collected};
+}
+
+sub _collectedHash
+{
+    my ($self, $slot) = @_;
+    my %hash = ();
+    %hash = %{ $self->_collected()->{$slot} }
+                        if exists $self->_collected()->{$slot};
+    return %hash;
+}
+
+sub _collectedList
+{
+    my ($self, $slot) = @_;
+    my @list = ();
+    @list = @{ $self->_collected()->{$slot} }
+                        if exists $self->_collected()->{$slot};
+    return @list;
+}
+
+#-------------------------------------------------------------------------------
+# package: SysDefCollector::ParserClient
+#
+# usage: Interacts directly with the SysDefParser to obtain those parts of the system
+#        definition which are of interest. Implements the parser callback methods
+#        for the XML elements for which we collect information. Some elements are
+#        of interest only if they are enclosed within an outer element with certain
+#        properties. Other elements are always of interest. The latter style of
+#        element is always collected. The former is only collected when it is known
+#        that we are within an appropriate enclosing element. The 'context' property
+#        is used for testing this condition.
+#
+# methods:
+#
+#    new(configname): constructs a new instance to collect system definition info
+#       relating to the configuration name 'configname'.
+#
+#    parserClient(): returns a reference to the SysDefCollector::ParserClient
+#       instance - typically for passing to the parser.
+#
+#-------------------------------------------------------------------------------
+package SysDefCollector::ParserClient;
+use strict;
+
+sub new
+{
+    my ($class, $configname, $loghandle) = @_;
+    my $self = { configname => $configname, configfound => 0, context => {intask => 0}, collected => {}, loghandle => $loghandle };
+    return bless $self, $class;
+}
+
+#-------------------------------------------------------------------------------
+# The following methods 'configuration()', 'configuration_()' initiate and
+# terminate respectively the collection of element information found inside a
+# 'configuration' element with 'name' attribute matching the objects 'configname'
+# attribute.
+#-------------------------------------------------------------------------------
+sub configuration
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+    my $loghandle = $self->{loghandle};
+
+    # start of a 'configuration' element - if the name of the element matches our
+    # 'configname' attribute then we create contexts so that elements of interest
+    # nested within this 'configuration' element can be collected.
+    unless ($attrs{name} eq $self->{configname}) { return; }
+    
+    if ($self->{configfound})
+    {
+        print $loghandle "Ignoring duplicated configuration: $attrs{name} ($attrs{description})\n";
+    }
+    else
+    {
+        $self->{configfound} = 1;
+        $self->{context}->{unitListRef} = [];
+        $self->{context}->{buildLayerTargetList} = [];
+    }
+}
+
+sub configuration_
+{
+    my ($self, $expat, $element) = @_;
+    $self->_debugout(@_);
+
+    # end of a 'configuration' element - save what we have collected within this
+    # 'configuration' element and delete the context so as to terminate collection
+    # of any subsequently encountered nested elements.
+
+    if (exists $self->{context}->{unitListRef})
+    {
+        $self->{collected}->{unitListRef} = $self->{context}->{unitListRef};
+        delete $self->{context}->{unitListRef};
+    }
+
+    if (exists $self->{context}->{buildLayerTargetList})
+    {
+        # eliminate duplicates
+        my %hash = map { $_, '' } @{$self->{context}->{buildLayerTargetList}};
+        my @unique = keys %hash;
+        $self->{collected}->{buildLayerTargetList} = \@unique;
+        delete $self->{context}->{buildLayerTargetList};
+    }
+}
+
+#-------------------------------------------------------------------------------
+# Method 'unitListRef()' accumulates 'unitListRef' unitList information found
+# within a 'configuration element with matching name.
+#-------------------------------------------------------------------------------
+sub unitListRef
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+    
+    if($self->{context}->{intask})
+        { return; }     # Task-specific unitListRef not supported
+
+    # if there is a previously created context for 'unitListRef's then store this one.
+
+    if (exists $self->{context}->{unitListRef})
+    {
+        push @{$self->{context}->{unitListRef}}, $attrs{unitList};
+    }
+    my $x = 1;
+}
+
+#-------------------------------------------------------------------------------
+# Methods 'task()' and 'task_()' track context (i.e. inside a task or not)
+# because task-specific activities are not supported.
+#-------------------------------------------------------------------------------
+sub task
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+    $self->{context}->{intask} = 1;
+}
+
+sub task_
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugout(@_);
+    $self->{context}->{intask} = 0;
+}
+
+#-------------------------------------------------------------------------------
+# Method 'buildlayer()' accumulates 'buildlayer' targetList information found
+# within a 'configuration element with matching name.
+#-------------------------------------------------------------------------------
+sub buildLayer
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    if (exists $self->{context}->{buildLayerTargetList})
+    {
+        push @{$self->{context}->{buildLayerTargetList}}, (split /\s+/, $attrs{targetList});
+    }
+}
+
+#-------------------------------------------------------------------------------
+# The following three methods 'unitList()', 'unitList_()' and 'unitRef()'
+# accumulate 'unitList' and 'unitRef' information found within the 'build' elements.
+#-------------------------------------------------------------------------------
+sub unitList
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    # start of a 'unitList' element  - create a context so that collection of all
+    # 'unitRef's elements found within this 'unitList' element can be collected.
+
+    die "Fatal: context already has unitList\n" if exists $self->{context}->{unitList};
+    $self->{context}->{unitList} = { name => $attrs{name}, list => [] };
+}
+
+sub unitList_
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugout(@_);
+
+    # end of the current 'unitList' element - save what we have collected
+    # and delete the context
+
+    $self->{collected}->{unitList} = {} if ! exists $self->{collected}->{unitList};
+
+    my $unitList = delete $self->{context}->{unitList};
+    $self->{collected}->{unitList}->{$unitList->{name}} = $unitList->{list};
+
+}
+
+sub unitRef
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    # unitRef found - save unitRef data to current context
+
+    die "Fatal: context requires unitList\n" if ! exists $self->{context}->{unitList};
+    push @{$self->{context}->{unitList}->{list}}, $attrs{unit};
+}
+
+#-------------------------------------------------------------------------------
+# The method 'unit()' accumulates 'unit' information found within the 'systemModel'
+# elements.
+#-------------------------------------------------------------------------------
+sub unit
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    # no need to set up a temporary context to collect these since they have global scope
+    $self->{collected}->{unit} = {} if ! exists $self->{collected}->{unit};
+    $self->{collected}->{unit}->{$attrs{unitID}} = $attrs{bldFile};
+}
+
+#-------------------------------------------------------------------------------
+# sub option() - accumulates 'option' element information found within the
+# 'build' element.
+#-------------------------------------------------------------------------------
+sub option
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    if ($attrs{enable} =~ /[Yy]/)
+    {
+        # no need to set up a temporary context to collect these since they have global scope
+        $self->{collected}->{option} = [] if ! exists $self->{collected}->{option};
+        push @{$self->{collected}->{option}}, $attrs{abldOption};
+    }
+}
+
+#-------------------------------------------------------------------------------
+# sub target() - accumulates 'target' element information found within the
+# 'build' element.
+#-------------------------------------------------------------------------------
+sub target
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    $self->{collected}->{target} = {} if ! exists $self->{collected}->{target};
+    $self->{collected}->{target}->{$attrs{name}} = $attrs{abldTarget};
+}
+
+#-------------------------------------------------------------------------------
+# sub targetList() - accumulates 'targetList' element information found within the
+# 'build' element.
+#-------------------------------------------------------------------------------
+sub targetList
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+
+    $self->{collected}->{targetList} = {} if ! exists $self->{collected}->{targetList};
+    my @list = split /\s+/, $attrs{target};
+    $self->{collected}->{targetList}->{$attrs{name}} = \@list;
+}
+
+#-------------------------------------------------------------------------------
+# sub specialInstructions() - sets the 'specialInstructions' flag if a
+# 'specialInstructions' element is encountered. In practice, we are only
+# interested in instructions which invoke SETUPPRJ.BAT as this will require
+# the inclusion of the "bootstrap" line in the output text file.
+#-------------------------------------------------------------------------------
+sub specialInstructions
+{
+    my ($self, $expat, $element, %attrs) = @_;
+    $self->_debugin(@_);
+    if ($attrs{command} =~ /^setupprj.bat/i)
+        {
+        $self->{collected}->{specialInstructions} = 1;
+        }
+}
+
+#-------------------------------------------------------------------------------
+# utility routines for development/debug purposes.
+#-------------------------------------------------------------------------------
+
+sub _debugin
+{
+##    return;             ## Suppress this debugging!
+    my $self = shift;
+    my ($ignore0, $ignore2, $element, @args) = @_;
+    my $loghandle = $self->{loghandle};
+    if ($debugFlag) { print $loghandle "Enter: $element (", (join ' ', @args), ")\n"; }
+}
+
+sub _debugout
+{
+##    return;             ## Suppress this debugging!
+    my $self = shift;
+    my $loghandle = $self->{loghandle};
+    if ($debugFlag) { print $loghandle "Leave: $_[2]\n"; }
+}
+
+sub dump
+{
+    my $self = shift;
+    my $fh = shift;
+
+    print $fh "\nDump Collected System Definition\n\n";    
+    print $fh "================================\n";    
+
+    if (keys %{$self->{collected}} > 0)
+    {
+        if (exists $self->{collected}->{option})
+        {
+            my @option = @{$self->{collected}->{option}};
+            print $fh "option :[", (join ',', @option), "]\n";
+        }
+
+        if (exists $self->{collected}->{specialInstructions})
+        {
+            my $flag = $self->{collected}->{specialInstructions};
+            print $fh "specialInstructions : '", ($flag ?  "yes" : "no"), "'\n";
+        }
+        else
+        {
+            print $fh "specialInstructions : 'no'\n";
+        }
+
+        if (exists $self->{collected}->{buildLayerTargetList})
+        {
+            my @buildLayerTargetList = @{$self->{collected}->{buildLayerTargetList}};
+            print $fh "buildLayerTargetList :[", (join ',', @buildLayerTargetList), "]\n";
+        }
+
+        if (exists $self->{collected}->{unitListRef})
+        {
+            my @unitListRef = @{$self->{collected}->{unitListRef}};
+            print $fh "unitListRef :[", (join ',', @unitListRef), "]\n";
+        }
+
+        if (exists $self->{collected}->{unitList})
+        {
+            print $fh "unitList:\n{\n";
+            my %unitList = %{$self->{collected}->{unitList}};
+            for my $key (keys %unitList)
+            {
+                 my @list = @{$unitList{$key}};
+                 print $fh "\t'$key' has units:[", (join ',', @list), "]\n";
+            }
+            print $fh "}\n";
+        }
+
+        if (exists $self->{collected}->{target})
+        {
+            print $fh "target:\n{\n";
+            my %target = %{$self->{collected}->{target}};
+            for my $key (keys %target)
+            {
+                 print $fh "\t'$key' => '", $target{$key} , "'\n";
+            }
+            print $fh "}\n";
+        }
+
+        if (exists $self->{collected}->{targetList})
+        {
+            print $fh "targetList:\n{\n";
+            my %targetList = %{$self->{collected}->{targetList}};
+            for my $key (keys %targetList)
+            {
+                 my @list = @{$targetList{$key}};
+                 print $fh "\t'$key' has targets:[", (join ',', @list), "]\n";
+            }
+            print $fh "}\n";
+        }
+
+        if (exists $self->{collected}->{unit})
+        {
+            print $fh "unit:\n{\n";
+            my %unit = %{$self->{collected}->{unit}};
+            for my $key (keys %unit)
+            {
+                 print $fh "\t'$key' => '", $unit{$key} , "'\n";
+            }
+            print $fh "}\n";
+        }
+    }
+    else
+    {
+        print $fh "Nothing collected\n";
+    }
+    print $fh "================================\n";    
+}
+
+#-------------------------------------------------------------------------------
+# -EOF-
+#-------------------------------------------------------------------------------
+1;