lilalo

diff l3text @ 155:8ee5e59f1bd3

Локальное хранение и анализ данных с помощью SQlite

Очень много изменений, касающихся работы с sqlite
и локального использования результатов записи.
Подробнее:
README.l3text
author Igor Chubin <igor@chub.in>
date Tue Mar 16 20:05:30 2010 +0200 (2010-03-16)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/l3text	Tue Mar 16 20:05:30 2010 +0200
     1.3 @@ -0,0 +1,365 @@
     1.4 +#!/usr/bin/perl -w
     1.5 +
     1.6 +use POSIX qw(strftime);
     1.7 +use lib '/etc/lilalo';
     1.8 +use l3config;
     1.9 +use utf8;
    1.10 +use DBI;
    1.11 +#no warnings;
    1.12 +
    1.13 +our @Fields=qw/id time prompt cline output err last_command tab diff l3cd/;
    1.14 +our $Fields=join(", ",@Fields);
    1.15 +our $db;
    1.16 +
    1.17 +=cut
    1.18 +Множество команд, с которыми выполняется операция,
    1.19 +определяется текущим контекстом и текущей строкой,
    1.20 +а также параметрами:
    1.21 +    * фильтр;
    1.22 +    * регулярное выражение;
    1.23 +    * интервал.
    1.24 +=cut 
    1.25 +our $Filter;
    1.26 +our $Grep;
    1.27 +our $Interval;
    1.28 +our $Command;
    1.29 +
    1.30 +# Если мы используем режим -f, то в этой переменной запоминается
    1.31 +# до какой точки мы дошли
    1.32 +our $Follow=0;
    1.33 +
    1.34 +our $Context;
    1.35 +
    1.36 +our @Commands = qw/head tail cat history/;
    1.37 +
    1.38 +sub main();
    1.39 +sub connect_database();
    1.40 +
    1.41 +main();
    1.42 +
    1.43 +sub main()
    1.44 +{
    1.45 +    $| = 1;
    1.46 +
    1.47 +    init_config_without_command_line_processing();
    1.48 +    $Context=$Config{l3cd};
    1.49 +    connect_database();
    1.50 +# Обработка всех grep'ов
    1.51 +    $Grep="";
    1.52 +    my $i=0;
    1.53 +    my $arg;
    1.54 +    my @argv=();
    1.55 +    while ($i<=$#ARGV) {
    1.56 +        $arg=$ARGV[$i];
    1.57 +        #print "arg=$arg\n";
    1.58 +        if ($arg eq "grep") {
    1.59 +            my $grep_keys="";
    1.60 +            my $grep_regexp="";
    1.61 +            $i++;
    1.62 +            while(defined ($ARGV[$i]) and $ARGV[$i] =~ /^-/) {
    1.63 +                $grep_keys .= " ".$ARGV[$i];
    1.64 +                $i++;
    1.65 +            }
    1.66 +            if (defined($ARGV[$i])) {
    1.67 +                $grep_regexp = $ARGV[$i];
    1.68 +                $i++;
    1.69 +            }
    1.70 +            else {
    1.71 +                die "ERROR: grep argument is not specified";
    1.72 +            }
    1.73 +            $Grep .= grep_options($grep_regexp,$grep_keys);
    1.74 +        }
    1.75 +        else {
    1.76 +            $i++;
    1.77 +            push(@new_argv,$arg);
    1.78 +        }
    1.79 +    }
    1.80 +    @argv=@new_argv;
    1.81 +
    1.82 +    if (grep(/^-f$/, @argv)) {
    1.83 +        $follow=1;
    1.84 +    }
    1.85 +    if (grep(/^history$/, @argv)) {
    1.86 +        my $interval=$argv[0]||"%";
    1.87 +        $interval="%" if $interval eq "history";
    1.88 +        my $exit=0;
    1.89 +        while (not $exit) {
    1.90 +            print_commands(select_interval($interval, $Grep));
    1.91 +            if (not $follow) {
    1.92 +                $exit=1;
    1.93 +            } else {
    1.94 +                sleep(1);
    1.95 +            }
    1.96 +        }
    1.97 +    } else {
    1.98 +        my $exit=0;
    1.99 +        while (not $exit) {
   1.100 +            print_all(select_interval($argv[0]||"%", $Grep));
   1.101 +            if (not $follow) {
   1.102 +                $exit=1;
   1.103 +            } else {
   1.104 +                sleep(1);
   1.105 +            }
   1.106 +        }
   1.107 +    }
   1.108 +    #print_all(select_by_cline("*privet*"));
   1.109 +}
   1.110 +
   1.111 +sub connect_database()
   1.112 +{
   1.113 +    $db = DBI->connect("dbi:SQLite:".$Config{cache_sqlite}, "", "",
   1.114 +                {RaiseError => 1, AutoCommit => 1});
   1.115 +    $db->func('regexp', 2, sub {
   1.116 +            my ($regex, $string) = @_;
   1.117 +                return $string =~ /$regex/;
   1.118 +    }, 'create_function');
   1.119 +}
   1.120 +
   1.121 +sub select_all() {
   1.122 +    $l3cd=$Config{l3cd};
   1.123 +    return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE l3cd='$l3cd'");
   1.124 +}
   1.125 +
   1.126 +sub select_last_n($) {
   1.127 +    my $last=$_[0];
   1.128 +    $count = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
   1.129 +    my $offset=$$count[0][0]-$last;
   1.130 +    return $db->selectall_arrayref("SELECT $Fields FROM commands LIMIT $last OFFSET $offset");
   1.131 +}
   1.132 +
   1.133 +sub select_interval($) {
   1.134 +    my $interval = shift;
   1.135 +    my $grep = shift;
   1.136 +
   1.137 +    my $q;  # Рабочая переменная для запросов
   1.138 +# %
   1.139 +    $interval='1,$' if ($interval eq "%");
   1.140 +#        return $db->selectall_arrayref(
   1.141 +#                "SELECT $Fields FROM commands WHERE l3cd='$Context'");
   1.142 +
   1.143 +# Вычисляем номера начальной и конечной строки
   1.144 +# на основе интервала
   1.145 +    my ($start,$stop);
   1.146 +    my ($start_n, $stop_n, $curr_n) = ("","",""); # номера начальной и конечной строк
   1.147 +    if ($interval =~ /,/) {
   1.148 +        ($start,$stop) = split(/,/,$interval);
   1.149 +    }
   1.150 +    else {
   1.151 +        $start = $interval;
   1.152 +        $stop = $interval;
   1.153 +    }
   1.154 +
   1.155 +    $q = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
   1.156 +    my $count = $$q[0][0];
   1.157 +
   1.158 +# Номер текущей строки
   1.159 +# По умолчанию текущая строка указывает на последнюю
   1.160 +    $curr_n = $count;
   1.161 +    #$curr_n = 2;
   1.162 +
   1.163 +    if ($start =~ /^[0-9]*$/) { $start_n = $start; }
   1.164 +    if ($stop =~ /^[0-9]*$/)  { $stop_n  = $stop; }
   1.165 +    if ($start =~ /^-[0-9]*$/) { $start_n = $curr_n + $start; }
   1.166 +    if ($stop =~ /^-[0-9]*$/)  { $stop_n  = $curr_n + $stop; }
   1.167 +    if ($start =~ /^\+[0-9]*$/) { $start_n = $curr_n + $start; }
   1.168 +    if ($stop =~ /^\+[0-9]*$/)  { $stop_n  = $curr_n + $stop; }
   1.169 +    if ($start eq '.') { $start_n = $curr_n; }
   1.170 +    if ($stop eq '.')  { $stop_n  = $curr_n; }
   1.171 +    if ($start eq '$') { $start_n = $count; }
   1.172 +    if ($stop eq '$')  { $stop_n  = $count; }
   1.173 +    if ($start =~ m@^/(.*)/@ ) {
   1.174 +        $q = $db->selectall_arrayref(
   1.175 +                "SELECT id FROM commands WHERE cline REGEXP '$1' LIMIT 1");
   1.176 +        $start_n=$$q[0][0];
   1.177 +    }
   1.178 +    if ($stop =~ m@^/(.*)/@ ) {
   1.179 +        $q = $db->selectall_arrayref(
   1.180 +                "SELECT id FROM commands 
   1.181 +                 WHERE cline REGEXP '$1' 
   1.182 +                        AND (id >= $start_n) LIMIT 1");
   1.183 +        $stop_n=$$q[0][0];
   1.184 +    }
   1.185 +    if ($start =~ m@^o/(.*)/@ ) {
   1.186 +        $q = $db->selectall_arrayref(
   1.187 +                "SELECT id FROM commands WHERE output REGEXP '$1' LIMIT 1");
   1.188 +        $start_n=$$q[0][0];
   1.189 +    }
   1.190 +    if ($stop =~ m@^o/(.*)/@ && $start_n) {
   1.191 +        $q = $db->selectall_arrayref(
   1.192 +                "SELECT id FROM commands 
   1.193 +                 WHERE output REGEXP '$1' AND (id >= $start_n) LIMIT 1");
   1.194 +        $stop_n=$$q[0][0];
   1.195 +    }
   1.196 +
   1.197 +    if (not $start_n or not $stop_n) {return ""};
   1.198 +
   1.199 +    $stop_n = $count if $count < $stop_n;
   1.200 +    $start_n =1 if 1 > $start_n;
   1.201 +
   1.202 +    my $offset=$start_n-1;
   1.203 +    my $limit = $stop_n - $offset;
   1.204 +
   1.205 +    my $pre_follow=$Follow;
   1.206 +    $q = $db->selectall_arrayref(
   1.207 +            "SELECT id FROM commands 
   1.208 +            WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)
   1.209 +            ORDER BY id DESC");
   1.210 +    $Follow = $$q[0][0] if $$q[0][0];
   1.211 +    return $db->selectall_arrayref(
   1.212 +            "SELECT $Fields FROM commands 
   1.213 +            WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)");
   1.214 +}
   1.215 +
   1.216 +sub grep_options($$) {
   1.217 +=cut
   1.218 +    -c ищем только в комадной строке    # по умолчанию
   1.219 +    -o ищем только в выводе
   1.220 +    -f ищем и там, и там
   1.221 +    -v инверсия
   1.222 +=cut
   1.223 +    my $regexp=shift; return "" if $regexp eq '';
   1.224 +    my $options=shift;
   1.225 +    my @options = split //, $options;
   1.226 +    my $not = "";
   1.227 +    $not = "NOT" if grep(/v/,@options);
   1.228 +
   1.229 +    my $grep ="";
   1.230 +    if (grep(/f/,@options)) {
   1.231 +        $grep = "AND $not ((cline REGEXP '$regexp') OR (output REGEXP '$regexp'))";
   1.232 +    }
   1.233 +    elsif (grep(/o/,@options)) {
   1.234 +        $grep = "AND $not (output REGEXP '$regexp')";
   1.235 +    }
   1.236 +    elsif (1 || grep(/c/,@options)) {
   1.237 +        $grep = "AND $not (cline REGEXP '$regexp')";
   1.238 +    }
   1.239 +
   1.240 +    return $grep;
   1.241 +}
   1.242 +
   1.243 +sub select_by_cline($) {
   1.244 +    my $cline = $_[0];
   1.245 +    return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE cline GLOB '$cline'");
   1.246 +}
   1.247 +
   1.248 +sub print_commands($)
   1.249 +{
   1.250 +    my @fields=@Fields;
   1.251 +    my $fields=join(", ",@fields);
   1.252 +    my $all=$_[0];
   1.253 +    foreach my $row (@$all) {
   1.254 +        my $cl;       #Каждая строка
   1.255 +        my $i=0;
   1.256 +        for my $f (@fields) {
   1.257 +            $cl->{$fields[$i]}=$$row[$i];
   1.258 +            $i++;
   1.259 +        }
   1.260 +        print $cl->{id}." ".strdequot($cl->{cline})."\n";
   1.261 +    }
   1.262 +}
   1.263 +sub print_all($) {
   1.264 +    my @fields=@Fields;
   1.265 +    my $fields=join(", ",@fields);
   1.266 +    my $all=$_[0];
   1.267 +    my $prev_cl; # Предыдущая строка
   1.268 +    my $tab_seq; # Номер в табуляционной последовательности
   1.269 +    foreach my $row (@$all) {
   1.270 +        my $cl;       #Каждая строка
   1.271 +        my @anchor;   #Начальная строка, якорь, по которому привязывается команда
   1.272 +        my $res="";   #Буфер, в который выводится результат вывода каждой строки
   1.273 +        $i=0;
   1.274 +        for my $f (@fields) {
   1.275 +            $cl->{$fields[$i]}=$$row[$i];
   1.276 +            $i++;
   1.277 +        }
   1.278 +        next    if ($Config{"skip_empty"} =~ /^y/i     && $cl->{"cline"} =~ /^\s*$/ )
   1.279 +                || ($Config{"skip_wrong"} =~ /^y/i     && $cl->{"err"} != 0)
   1.280 +                || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
   1.281 +
   1.282 +        # Время
   1.283 +        # Добавляем спереди 0 для удобочитаемости
   1.284 +        my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time});
   1.285 +        $min  = "0".$min  if $min  =~ /^.$/;
   1.286 +        $hour = "0".$hour if $hour =~ /^.$/;
   1.287 +        $sec  = "0".$sec  if $sec  =~ /^.$/;
   1.288 +
   1.289 +        if ($Config{"show_time"} =~ /^y/i) {
   1.290 +            push @anchor,"$hour:$min:$sec ";
   1.291 +        }
   1.292 +
   1.293 +        if ($cl->{"err"}) {
   1.294 +            push @anchor, "err=".$cl->{'err'};
   1.295 +        }
   1.296 +        if ($cl->{"tab"}) {
   1.297 +            push @anchor, "tab=".$cl->{'tab'};
   1.298 +        }
   1.299 +        $res.="#=".join("",@anchor)."\n";
   1.300 +        $res.=$cl->{prompt}.strdequot($cl->{cline})."\n";
   1.301 +
   1.302 +        my $output = ""; # фомируем вывод команды
   1.303 +        my $last_command = $cl->{"last_command"};
   1.304 +        if (!( $Config{"suppress_editors"} =~ /^y/i 
   1.305 +               && grep ($_ eq $last_command, @{$Config{"editors"}}) 
   1.306 +            || $Config{"suppress_pagers"}  =~ /^y/i 
   1.307 +               && grep ($_ eq $last_command, @{$Config{"pagers"}})
   1.308 +            || $Config{"suppress_terminal"}=~ /^y/i 
   1.309 +               && grep ($_ eq $last_command, @{$Config{"terminal"}})
   1.310 +            )) {
   1.311 +            $output = strdequot($cl->{output});
   1.312 +
   1.313 +            # Вырезаем слишком длинные выводы
   1.314 +            my @lines = split '\n', $output;
   1.315 +            if (!$Config{"command_id"} 
   1.316 +                && ( $Config{"head_lines"} || $Config{"tail_lines"})
   1.317 +                && $#lines >  $Config{"head_lines"} + $Config{"tail_lines"}) {
   1.318 +                    $output="";
   1.319 +                    for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) {
   1.320 +                        $output .= $lines[$i]."\n";
   1.321 +                    }
   1.322 +                    $output .= $Config{"skip_text"}."\n";
   1.323 +
   1.324 +                    my $start_line=$#lines-$Config{"tail_lines"}+1;
   1.325 +                    for (my $i=$start_line; $i<= $#lines; $i++) {
   1.326 +                        $output .= $lines[$i]."\n";
   1.327 +                    }
   1.328 +                } 
   1.329 +            }
   1.330 +        $res.=$output;
   1.331 +        if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) {
   1.332 +            $res.= $cl->{"diff"}
   1.333 +        }
   1.334 +        #open(OUTPUT, '|sendxmpp nata_samoylenko@jabber.ru');
   1.335 +        #print OUTPUT $res;
   1.336 +        #close(OUTPUT);
   1.337 +        print $res;
   1.338 +        $res="";
   1.339 +        $prev_cl=$cl;
   1.340 +    }
   1.341 +}
   1.342 +
   1.343 +sub strdequot($)
   1.344 +{
   1.345 +    my $text = join "", @_;
   1.346 +    $text =~ s/&amp;/&/g;
   1.347 +    $text =~ s/&lt;/</g;
   1.348 +    $text =~ s/&gt;/>/g;
   1.349 +    $text =~ s/&quot;/"/g;
   1.350 +    return $text;
   1.351 +}
   1.352 +
   1.353 +sub show_usage()
   1.354 +{
   1.355 +    print <<EOF;
   1.356 +Usage:
   1.357 +    l3 [INTERVAL] [grep [KEYS] REGEXP] [filter [KEYS] FILTER] [COMMAND [KEYS]]
   1.358 +
   1.359 +Commands:
   1.360 +    history
   1.361 +    tail
   1.362 +    head
   1.363 +    cat (default)
   1.364 +
   1.365 +    If COMMAND is not specified, cat assumed.
   1.366 +
   1.367 +EOF
   1.368 +}