Changeset 150

Show
Ignore:
Timestamp:
05/31/04 09:15:50 (4 years ago)
Author:
svn
Message:

Plugin overlay seems to work. Any file with a .pm extension is loaded from the
plugins directory. Example plugins are fw.pm, log.pm and nat.pm

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • manage/trunk/CLI/CLI.pm

    r149 r150  
    44use warnings; 
    55use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); 
     6use base qw(Exporter); 
    67 
    78use Getopt::Mixed; 
    89use IO::Handle; 
    910use Net::DNS; 
    10 use Text::Wrap
     11use Text::Format
    1112use Term::ReadKey; 
    1213use POSIX qw(ctermid floor); 
    13  
    14 require Exporter; 
    15  
    16 @ISA = qw(Exporter); 
    1714 
    1815$VERSION = 0.1; 
     
    2219# new CLI( 
    2320#   grammar => $GRAMMAR, 
     21#       stringpattern => '\'(?:\\.|[^\'])*\'|"(?:\\.|[^"])*"', 
     22#       delimiter => '\s+|($stringpattern)', 
    2423# ) 
    2524sub new(%) { 
     
    3029        die("Grammar not defined") unless defined($args{grammar}); 
    3130        $self->{grammar} = $args{grammar}; 
     31        # String pattern 
    3232        if (defined($args{stringpattern})) { 
    3333                $self->{stringpattern} = $args{stringpattern}; 
     
    3535                $self->{stringpattern} = '\'(?:\\.|[^\'])*\'|"(?:\\.|[^"])*"'; 
    3636        } 
     37        # Delimiter 
    3738        if (defined($args{delimiter})) { 
    38                 $self->{tokenpattern} = $args{tokenpattern} 
     39                $self->{tokenpattern} = $args{delimiter}; 
    3940        } else { 
    4041                $self->{tokenpattern} = "\\s+|($self->{stringpattern})"; 
    4142        } 
     43 
     44        # Merge plugins 
     45        if (defined($args{plugins})) { 
     46        my ($width, $height) = GetTerminalSize(*STDIN); 
     47        my $format = new Text::Format( 
     48                columns => $width, 
     49                firstIndent => 0, 
     50                leftMargin => 4, 
     51                ); 
     52 
     53                if (opendir(D, $args{plugins})) { 
     54                        while (my $file = readdir(D)) { 
     55                                if ($file =~ /^[^.].*\.pm$/) { 
     56                                        $file =~ s/\.pm$//; 
     57                                        if (my $plugin = do("$args{plugins}/$file.pm")) { 
     58                                                $self->{plugins}->{$file} = $plugin; 
     59                                                $self->merge($plugin); 
     60                                        } else { 
     61                                                $| = 1; 
     62                                                print("\e[1m\e[31mCLI plugin '$file' error:\e[22m\n" . $format->format($@) . "\e[0m"); 
     63                                                $| = 0; 
     64                                        } 
     65                                } 
     66                        } 
     67                } 
     68                #$self->merge($args{plugins}); 
     69        } 
     70        return $self; 
     71} 
     72 
     73# Merge a grammar 
     74sub merge($) { 
     75my $self = shift; 
     76my $grammar = shift; 
     77 
     78        sub recursive_merge($$); 
     79        sub recursive_merge($$) { 
     80        my ($merge, $grammar) = @_; 
     81 
     82                for my $key (keys(%$merge)) { 
     83                        if (defined($grammar->{$key})) { 
     84                                recursive_merge($merge->{$key}, $grammar->{$key}); 
     85                        } else { 
     86                                $grammar->{$key} = $merge->{$key}; 
     87                        } 
     88                } 
     89        } 
     90 
     91        recursive_merge($grammar, $self->{grammar}); 
    4292        return $self; 
    4393} 
     
    60110        my $help = ""; 
    61111        my %commands = (); 
     112        my $format = new Text::Format( 
     113                columns => $width, 
     114                firstIndent => 0, 
     115                ); 
    62116 
    63117                # Trailing tokens after help 
     
    65119 
    66120                # Construct help string 
    67                 $Text::Wrap::columns = $width; 
    68                 $help .= wrap("", "", $cmd{HELPHEADER}) . "\n" if $cmd{HELPHEADER}; 
     121                $help .= $format->format($cmd{HELPHEADER}) . "\n" if $cmd{HELPHEADER}; 
    69122 
    70123                for my $key (keys %cmd) { 
     
    73126                        if (ref($cmd{$key}) eq 'HASH' and $cmd{$key}->{HELP}) { 
    74127                        my ($name, $hstr); 
     128                        my $type = ref($cmd{$key}->{HELP}); 
    75129                         
    76                                 if (ref($cmd{$key}->{HELP}) eq 'ARRAY') { 
    77                                         ($name, $hstr) = @{$cmd{$key}->{HELP}}; 
    78                                 } else { 
    79                                         $name = $key; 
    80                                         $hstr = $cmd{$key}->{HELP}; 
    81                                 } 
    82  
    83                                 $commands{$name} = $hstr; 
     130                                if ($type eq 'CODE') { 
     131                                        %commands = (%commands, $cmd{$key}->{HELP}->()); 
     132                                } else { 
     133                                        if ($type eq 'ARRAY') { 
     134                                                ($name, $hstr) = @{$cmd{$key}->{HELP}}; 
     135                                        } else { 
     136                                                $name = $key; 
     137                                                $hstr = $cmd{$key}->{HELP}; 
     138                                        } 
     139                                        $commands{$name} = $hstr; 
     140                                } 
    84141                        } else { 
    85142                                $commands{$key} = ''; 
     
    92149                if ($cmd{ACTION}) { 
    93150                        if (ref($cmd{ACTION}) eq 'HASH' and $cmd{ACTION}->{HELP}) { 
    94                                 $commands{'<eol>'} = $cmd{ACTION}->{HELP}; 
     151                                if (ref($cmd{ACTION}->{HELP}) eq 'ARRAY') { 
     152                                        $commands{'<eol>'} = $cmd{ACTION}->{HELP}->[1]; 
     153                                } elsif (ref($cmd{ACTION}->{HELP}) eq 'SCALAR') { 
     154                                        $commands{'<eol>'} = $cmd{ACTION}->{HELP}; 
     155                                } else { 
     156                                        $commands{'<eol>'} = "\e[31m\e[1m(expected SCALAR or ARRAY help, not CODE)\e[0m"; 
     157                                } 
    95158                        } elsif ($cmd{ACTIONHELP}) { 
    96159                                $commands{'<eol>'} = $cmd{ACTIONHELP}; 
    97160                        } elsif ($cmd{HELP}) { 
    98                                 $commands{'<eol>'} = $cmd{HELP}; 
     161                                if (ref($cmd{HELP}) eq 'ARRAY') { 
     162                                        $commands{'<eol>'} = $cmd{HELP}->[1]; 
     163                                } elsif (ref($cmd{HELP}) eq 'SCALAR') { 
     164                                        $commands{'<eol>'} = $cmd{HELP}; 
     165                                } else { 
     166                                        $commands{'<eol>'} = "\e[31m\e[1m(expected SCALAR or ARRAY help, not CODE)\e[0m"; 
     167                                } 
    99168                        } else { 
    100169                                $commands{'<eol>'} = "\e[31m\e[1m(need ACTIONHELP, ACTION->HELP or HELP entry)\e[0m"; 
     
    102171                } 
    103172 
     173        my $keywidth = 0; 
     174                for my $name (sort keys %commands) { 
     175                        $keywidth = length($name) if length($name) > $keywidth; 
     176                } 
     177                $format->leftMargin($keywidth + 2); 
    104178                for my $name (sort keys %commands) { 
    105179                        if ($commands{$name}) { 
    106                                 $help .= wrap(sprintf("  \e[1m%-19s\e[0m ", $name), (" " x 19), $commands{$name}) . "\n"
     180                                $help .= sprintf("  \e[1m%-${keywidth}s\e[0m ", $name) . substr($format->format($commands{$name}), $keywidth + 2)
    107181                        } else { 
    108182                                $help .= sprintf("  \e[1m%-16s\e[0m\n", $name); 
     
    111185 
    112186                $help .= "\n" if $cmd{HELPFOOTER} or $cmd{HELPHEADER}; 
    113                 $help .= "\n" . $cmd{HELPFOOTER} if $cmd{HELPFOOTER}; 
     187                $help .= $cmd{HELPFOOTER} . "\n" if $cmd{HELPFOOTER}; 
    114188                return ('ERROR', 'No help available.') unless defined($help) and $help ne ''; 
    115189                return ('HELP', $help); 
     
    212286} 
    213287 
    214 END { 
    215 } 
    216  
    2172881; 
  • manage/trunk/manage

    r149 r150  
    22 
    33# Add cli-parser to our module include path 
    4 BEGIN { push(@INC, "/root/projects/CLI"); } 
     4BEGIN { push(@INC, "./CLI"); } 
    55 
    66use warnings; 
     
    2121my $BANNER = ''; 
    2222my $SQLSERVER = '127.0.0.1'; 
    23 my $DRIVERS = './drivers'; 
     23my $PLUGINS = './plugins'; 
    2424 
    2525my %CONF = ( 
    26         'prompt' => [ \$PROMPT, '.*', 'CLI prompt.' ], 
    27         'banner' => [ \$BANNER, '.*', 'Startup banner.' ], 
    28         'sqlserver' => [ \$SQLSERVER, '.*', 'SQL server where logs are stored.' ], 
    29         'driverbase' => [ \$DRIVERS, '.*', 'Driver base directory.' ], 
     26        'prompt' => {  
     27                value => \$PROMPT, 
     28                pattern => '.*', 
     29                help => 'CLI prompt.' 
     30        }, 
     31        'banner' => { 
     32                value => \$BANNER, 
     33                pattern => '.*', 
     34                help => 'Startup banner.' 
     35        }, 
     36        'sqlserver' => { 
     37                value => \$SQLSERVER, 
     38                pattern => '.*', 
     39                help => 'SQL server where logs are stored.' 
     40        }, 
     41        'plugins' => { 
     42                value => \$PLUGINS, 
     43                pattern => '.*', 
     44                help => 'Driver base directory.' 
     45        }, 
     46 
    3047); 
    3148my $BREAK = 0; 
     
    140157entered exactly as shown. Words enclosed in \e[1m< >\e[22m are user defined. 
    141158", 
    142         'log' => { 
    143                 HELPHEADER => "Use the \e[1mlog\e[22m command to view, query and filter system logs.\n", 
    144                 HELP => 'Manipulate logs.', 
    145                 'tail' => { 
    146                         HELP => 'Tail the system logs.', 
    147                         ACTION => sub { 
    148                         } 
    149                 }, 
    150                 ACTION => sub { print("Dumping all logs.\n"); }, 
    151                 ACTIONHELP => 'Dump todays logs.', 
    152         }, 
    153159#       'fw' => { 
    154160#               HELP => 'Firewall management.', 
     
    168174 
    169175                                        if ($CONF{$key}) { 
    170                                                 if ($value =~ /$CONF{$key}[1]/) { 
    171                                                         ${$CONF{$key}[0]} = $value; 
     176                                                if ($value =~ /$CONF{$key}->{pattern}/) { 
     177                                                        ${$CONF{$key}->{value}} = $value; 
    172178                                                } else { 
    173179                                                        error("Value for '$key' is invalid."); 
     
    177183                                        } 
    178184                                }, 
    179                                 HELP => [ '<value>', 'Setting value.' ], 
    180                         }, 
    181                         HELP => [ '<key>', 'Setting to query/modify.' ], 
     185                                HELP => [ '<value>', 'Set value.' ], 
     186                        }, 
     187                        HELP => sub { 
     188                        my %help; 
     189 
     190                                for my $key (keys(%CONF)) { 
     191                                        $help{$key} = $CONF{$key}->{help}; 
     192                                } 
     193                                return %help; 
     194                        }, 
    182195                        ACTION => { 
    183196                                ACTION => sub { 
     
    185198 
    186199                                        if ($CONF{$key}) { 
    187                                                 print("\e[1m\e[32m$key='\e[22m${$CONF{$key}[0]}\e[1m'\e[0m\n"); 
     200                                                print("\e[1m\e[32m$key='\e[22m${$CONF{$key}->{value}}\e[1m'\e[0m\n"); 
    188201                                        } else { 
    189202                                                error("No such setting '$key'."); 
     
    201214 
    202215                                for my $key (sort keys %CONF) { 
    203                                         push(@rows, [$ALTCOLOURS[++$row % 2], $key, ${$CONF{$key}[0]}, $CONF{$key}[2]]); 
     216                                        push(@rows, [$ALTCOLOURS[++$row % 2], $key, ${$CONF{$key}->{value}}, $CONF{$key}->{help}]); 
    204217                                }    
    205218                                format_columns( 
     
    218231$term->ornaments(0); 
    219232my $termattribs = $term->Attribs; 
    220 my $cli = new CLI(grammar => $GRAMMAR); 
     233my $CLI = new CLI( 
     234        grammar => $GRAMMAR, 
     235        plugins => ${$CONF{plugins}->{value}}, 
     236        ); 
    221237 
    222238# Turn off filename completion 
     
    224240# Map the ? key to auto-magic help 
    225241$term->add_defun('dns-help', sub { 
    226 my ($type, $action, $args) = $cli->parse($termattribs->{line_buffer} . ' ?'); 
     242my ($type, $action, $args) = $CLI->parse($termattribs->{line_buffer} . ' ?'); 
    227243        if ($type eq 'HELP') { 
    228244                print("\n$action"); 
     
    231247}, ord('?')); 
    232248 
    233 sub load_drivers($;$) { 
    234 my $drivers = shift; 
    235 my $base = shift; 
    236  
    237         $base = $GRAMMAR unless defined($base); 
    238  
    239         if (!opendir(D, $drivers)) { 
    240                 error("Could not load drivers from '$drivers'"); 
    241                 return undef; 
    242         } 
    243         while (my $cmd = readdir(D)) { 
    244                 next if $cmd =~ /^\./; 
    245                 print("$cmd\n"); 
    246         } 
    247         close(D); 
    248 } 
    249  
    250249sub exec_line { 
    251 my ($type, $action, $args) = $cli->parse("@_"); 
     250my ($type, $action, $args) = $CLI->parse("@_"); 
    252251 
    253252        if ($type eq 'HELP') { 
     
    260259} 
    261260 
    262 load_drivers($DRIVERS); 
    263  
    264261# Command line? 
    265262if (@ARGV) {