#!/usr/bin/env perl #----------------------------------------------------------------------------------------------- # xmlquery # # This utility allows the CIME user to view a field in a env_*xml file via a commandline interface. #----------------------------------------------------------------------------------------------- use strict; use English; use Cwd qw( getcwd abs_path chdir); use Getopt::Long; use IO::File; use IO::Handle; use XML::LibXML; #----------------------------------------------------------------------------------------------- sub usage { die < xmlquery CASE [options] (2) A comma-seperated list of ids to query [NO-WHITESPACE] - for example > xmlquery CASE,GRID,MACH [options] (3) Set to list ALL variables - for example > xmlquery list [options] OPTIONS User supplied values are denoted in angle brackets (<>). Any value that contains white-space must be quoted. Long option names may be supplied with either single or double leading dashes. A consequence of this is that single letter options may NOT be bundled. -fileonly Only print the filename that the field is in. -valonly Only print the value of the field. -file Only consider variables in the specified file -value Only print the value of the field without any equal or identifier. -noexpandxml Do not expand any xml variables that the value is dependent on. -help [or -h] Print usage to STDOUT. -loglevel Stdout verbosity level EOF } #----------------------------------------------------------------------------------------------- if ($#ARGV == -1) { print "ERROR: no arguments sent in -- id name is REQUIRED\n"; usage(); } # Set the directory that contains the CIME configuration scripts. If the create_newcase command was # issued using a relative or absolute path, that path is in $ProgDir. Otherwise assume the # command was issued from the current working directory. (my $ProgName = $0) =~ s!(.*)/!!; # name of this script my $ProgDir = $1; # name of directory containing this script -- may be a # relative or absolute path, or null if the script is in # the user's PATH my $cwd = getcwd(); # current working directory my $cfgdir; # absolute pathname of directory that contains this script if ($ProgDir) { $cfgdir = abs_path($ProgDir); } else { $cfgdir = $cwd; } # First determine CIMEROOT my $xml = XML::LibXML->new( no_blanks => 1)->parse_file("env_case.xml"); my @nodes = $xml->findnodes(".//entry[\@id=\"CIMEROOT\"]"); my $cimeroot = $nodes[0]->getAttribute('value'); unshift @INC, "$cimeroot/utils/perl5lib"; require Config::SetupTools; require Log::Log4perl; # Parse command-line options. my %opts = ( fileonly =>0, valonly =>0, value =>0, file =>0, noexpandxml =>0, help =>0, listall =>0, loglevel =>"INFO", ); GetOptions( "fileonly" => \$opts{'fileonly'}, "valonly" => \$opts{'valonly'}, "value" => \$opts{'value'}, "file=s" => \$opts{'file'}, "noexpandxml" => \$opts{'noexpandxml'}, "h|help" => \$opts{'help'}, "loglevel=s" => \$opts{loglevel}, ) or usage(); # Give usage message. usage() if $opts{'help'}; my $level = Log::Log4perl::Level::to_priority($opts{loglevel}); Log::Log4perl->easy_init({level=>$level, layout=>'%m%n'}); my $logger = Log::Log4perl::get_logger(); # Error checks on arguments if ($opts{'value'} && $opts{'fileonly'} ) { $logger->logdie ("value and fileonly modes can NOT both be set"); } if ($opts{'valonly'} && $opts{'fileonly'} ) { $logger->logdie ("valonly and fileonly modes can NOT both be set"); } # Determine the required input "id" my $idlist = shift( @ARGV ); # Check for unparsed arguments if (@ARGV) { $logger->logdie( "ERROR: unrecognized arguments: @ARGV A list of ID's needs to be comma-delimited with NO-WHITESPACE!"); usage(); } # *** Print out requested variables - first get requested id from anything left over*** if ( $idlist eq "list" ) { _listall(); } else { _listids($idlist) } $logger->debug( "xmlquery completed successfully."); exit; #----------------------------------------------------------------------------------------------- # Private Routines #----------------------------------------------------------------------------------------------- sub _listids { my ($idlist) = @_; # First create the hash %xmlvars and %xmlfile in order to call # expand_xml_var if needed my %xmlvars; my %xmlfile; my @files; if($opts{file}){ @files = ( $opts{file} ); }else{ @files = ('env_build.xml', 'env_case.xml', 'env_mach_pes.xml', 'env_mach_specific.xml', 'env_run.xml', 'env_test.xml', 'env_batch.xml'); } foreach my $file (@files) { if (-f $file) { $logger->debug("Reading $file"); my $xml = XML::LibXML->new( no_blanks => 1)->parse_file($file); my @nodes = $xml->findnodes(".//entry"); if (@nodes) { foreach my $node (@nodes) { my $id = $node->getAttribute('id'); my $value = $node->getAttribute('value'); $xmlvars{$id} = $value; $xmlfile{$id} = $file; } } } } # Now print out the values of the requested ids my @ids = split( /,/, $idlist ); foreach my $id ( @ids ) { my $file = $xmlfile{$id}; my $value = $xmlvars{$id}; $value =~ s/'/'/g; $value =~ s/</\logdie ("ERROR xmlquery: id $id not found in any of the xml files: @files "); } } if (! $opts{'noexpandxml'} ) { $value = SetupTools::expand_xml_var( $value, \%xmlvars ); } if ( $opts{'valonly'} ) { print "$id $value \n"; } elsif ( $opts{'fileonly'} ) { print "$file: $id \n"; } elsif ( $opts{'value'} ) { print "$value"; } else { print "$file: $id $value \n"; } } } #----------------------------------------------------------------------------------------------- sub _listall { # First create the hash %xmlvars and %xmlfile in order to call # expand_xml_var if needed my %xmlvars; my %xmlfile; my @ids; my @files = ('env_build.xml', 'env_case.xml', 'env_mach_pes.xml', 'env_mach_specific.xml', 'env_run.xml', 'env_test.xml'); foreach my $file (@files) { if(-f $file){ my $xml = XML::LibXML->new( no_blanks => 1)->parse_file($file); my @nodes = $xml->findnodes(".//entry"); if (@nodes) { foreach my $node (@nodes) { my $id = $node->getAttribute('id'); my $value = $node->getAttribute('value'); push (@ids, $id); $xmlvars{$id} = $value; $xmlfile{$id} = $file; } } } } # Now print out the values of all ids foreach my $id ( @ids ) { my $file = $xmlfile{$id}; my $value = $xmlvars{$id}; $value =~ s/'/'/g; $value =~ s/</\