Ignore:
Timestamp:
2013-05-06T15:27:37+12:00 (11 years ago)
Author:
jmt12
Message:

Add code to allow importing and building to load overriding versions of inexport.pm and buildcolutils.pm from extensions at runtime. When an extension provides a possible override, Greenstone will dynamically detect and add additional options (visible in the --help). When a user specifies one of these options the appropriate inexport/buildcolutils subclass will be loaded

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/bin/script/import.pl

    r26536 r27305  
    6767}
    6868
     69# Pragma
    6970use strict;
     71use warnings;
     72
     73# Modules
     74use Symbol qw<qualify>; # Needed for runtime loading of modules [jmt12]
     75
     76# Greenstone Modules
     77use FileUtils;
    7078use inexport;
    71 
    72 my $oidtype_list =
     79use util;
     80
     81my $oidtype_list =
    7382    [ { 'name' => "hash",
    7483        'desc' => "{import.OIDtype.hash}" },
     
    129138    'type' => "string",
    130139    # parsearg left "" as default
    131     #'deft' => &util::filename_cat ($ENV{'GSDLHOME'}, "collect"),
     140    #'deft' => &FileUtils::filenameConcatenate($ENV{'GSDLHOME'}, "collect"),
    132141    'deft' => "",
    133142    'reqd' => "no",
     
    154163    'type' => "string",
    155164    # parsearg left "" as default
    156     #'deft' => &util::filename_cat("&lt;collectdir&gt;", "colname", "etc", "fail.log"),
     165    #'deft' => &FileUtils::filenameConcatenate("&lt;collectdir&gt;", "colname", "etc", "fail.log"),
    157166    'deft' => "",
    158167    'reqd' => "no",
     
    267276        'args' => $arguments };
    268277
    269 
    270 
    271 sub main 
     278my $function_to_inexport_subclass_mappings = {};
     279
     280sub main
    272281{
    273     my $inexport = new inexport("import",\@ARGV,$options);
    274    
    275     my $collection = $inexport->get_collection();
    276 
    277     if (defined $collection) {
    278     my ($config_filename,$collect_cfg)
    279         = $inexport->read_collection_cfg($collection,$options);   
    280 
    281     $inexport->set_collection_options($collect_cfg);
    282    
    283     my $pluginfo = $inexport->process_files($config_filename,$collect_cfg);
    284    
    285     $inexport->generate_statistics($pluginfo);
     282  # Dynamically include arguments from any subclasses of inexport we find
     283  # in the extensions directory
     284  if (defined $ENV{'GSDLEXTS'})
     285  {
     286    &_scanForSubclasses($ENV{'GSDLHOME'}, $ENV{'GSDLEXTS'});
     287  }
     288  if (defined $ENV{'GSDL3EXTS'})
     289  {
     290    &_scanForSubclasses($ENV{'GSDL3SRCHOME'}, $ENV{'GSDL3EXTS'});
     291  }
     292
     293  # Loop through arguments, checking to see if any depend on a specific
     294  # subclass of InExport. Note that we load the first subclass we encounter
     295  # so only support a single 'override' ATM.
     296  my $inexport_subclass;
     297  foreach my $argument (@ARGV)
     298  {
     299    # proper arguments start with a hyphen
     300    if ($argument =~ /^-/ && defined $function_to_inexport_subclass_mappings->{$argument})
     301    {
     302      my $required_inexport_subclass = $function_to_inexport_subclass_mappings->{$argument};
     303      if (!defined $inexport_subclass)
     304      {
     305        $inexport_subclass = $required_inexport_subclass;
     306      }
     307      # Oh noes! The user has included specific arguments from two different
     308      # inexport subclasses... this isn't supported
     309      elsif ($inexport_subclass ne $required_inexport_subclass)
     310      {
     311        print STDERR "Error! You cannot specify arguments from two different extention specific inexport modules: " . $inexport_subclass . " != " . $required_inexport_subclass . "\n";
     312        exit;
     313      }
    286314    }
     315  }
     316
     317  my $inexport;
     318  if (defined $inexport_subclass)
     319  {
     320    print "* Loading Overriding InExport Module: " . $inexport_subclass . "\n";
     321    require $inexport_subclass . '.pm';
     322    $inexport = new $inexport_subclass("import",\@ARGV,$options);
     323  }
     324  # We don't have a overridden inexport, or the above command failed somehow
     325  # so load the base inexport class
     326  if (!defined $inexport)
     327  {
     328    $inexport = new inexport("import",\@ARGV,$options);
     329  }
     330
     331  my $collection = $inexport->get_collection();
     332
     333  if (defined $collection)
     334  {
     335    my ($config_filename,$collect_cfg) = $inexport->read_collection_cfg($collection,$options);
     336
     337    $inexport->set_collection_options($collect_cfg);
     338
     339    my $pluginfo = $inexport->process_files($config_filename,$collect_cfg);
     340
     341    $inexport->generate_statistics($pluginfo);
     342  }
     343
     344  $inexport->deinit();
    287345}
    288 
     346# main()
     347
     348# @function _scanForSubclasses()
     349# @param $dir The extension directory to look within
     350# @param $exts A list of the available extensions (as a colon separated string)
     351# @return The number of subclasses of InExport found as an Integer
     352sub _scanForSubclasses
     353{
     354  my ($dir, $exts) = @_;
     355  my $inexport_class_count = 0;
     356  my $ext_prefix = &FileUtils::filenameConcatenate($dir, "ext");
     357  my @extensions = split(/:/, $exts);
     358  foreach my $e (@extensions)
     359  {
     360    # - any subclass of InExport must be prefixed with the name of the ext
     361    my $package_name = $e . 'inexport';
     362    $package_name =~ s/[^a-z]//gi; # package names have limited characters
     363    my $inexport_filename = $package_name . '.pm';
     364    my $inexport_path = &FileUtils::filenameConcatenate($ext_prefix, $e, 'perllib', $inexport_filename);
     365    # see if we have a subclass of InExport lurking in that extension folder
     366    if (-f $inexport_path)
     367    {
     368      # - note we load the filename (with pm) unlike normal modules
     369      require $inexport_filename;
     370      # - make call to the newly created package
     371      my $symbol = qualify('getSupportedArguments', $package_name);
     372      # - strict prevents strings being used as function calls, so temporarily
     373      #   disable that pragma
     374      no strict;
     375      # - lets check that the function we are about to call actually exists
     376      if ( defined &{$symbol} )
     377      {
     378        my $extra_arguments = &{$symbol}();
     379        foreach my $argument (@{$extra_arguments})
     380        {
     381          # - record a mapping from each extra arguments to the inexport class
     382          #   that supports it. We put the hyphen on here to make comparing
     383          #   with command line arguments even easier
     384          $function_to_inexport_subclass_mappings->{'-' . $argument->{'name'}} = $package_name;
     385          # - and them add them as acceptable arguments to import.pl
     386          push(@{$options->{'args'}}, $argument);
     387        }
     388        $inexport_class_count++;
     389      }
     390      else
     391      {
     392        print "Warning! A subclass of InExport module (named '" . $inexport_filename . "') does not implement the required getSupportedArguments() function - ignoring. Found in: " . $inexport_path . "\n";
     393      }
     394    }
     395  }
     396  return $inexport_class_count;
     397}
     398# _scanForInExportModules()
    289399
    290400&main();
Note: See TracChangeset for help on using the changeset viewer.