lilalo
view l3text @ 155:8ee5e59f1bd3
Локальное хранение и анализ данных с помощью SQlite
Очень много изменений, касающихся работы с sqlite
и локального использования результатов записи.
Подробнее:
README.l3text
Очень много изменений, касающихся работы с sqlite
и локального использования результатов записи.
Подробнее:
README.l3text
| author | Igor Chubin <igor@chub.in> | 
|---|---|
| date | Tue Mar 16 20:05:30 2010 +0200 (2010-03-16) | 
| parents | |
| children | 
 line source
     1 #!/usr/bin/perl -w
     3 use POSIX qw(strftime);
     4 use lib '/etc/lilalo';
     5 use l3config;
     6 use utf8;
     7 use DBI;
     8 #no warnings;
    10 our @Fields=qw/id time prompt cline output err last_command tab diff l3cd/;
    11 our $Fields=join(", ",@Fields);
    12 our $db;
    14 =cut
    15 Множество команд, с которыми выполняется операция,
    16 определяется текущим контекстом и текущей строкой,
    17 а также параметрами:
    18     * фильтр;
    19     * регулярное выражение;
    20     * интервал.
    21 =cut 
    22 our $Filter;
    23 our $Grep;
    24 our $Interval;
    25 our $Command;
    27 # Если мы используем режим -f, то в этой переменной запоминается
    28 # до какой точки мы дошли
    29 our $Follow=0;
    31 our $Context;
    33 our @Commands = qw/head tail cat history/;
    35 sub main();
    36 sub connect_database();
    38 main();
    40 sub main()
    41 {
    42     $| = 1;
    44     init_config_without_command_line_processing();
    45     $Context=$Config{l3cd};
    46     connect_database();
    47 # Обработка всех grep'ов
    48     $Grep="";
    49     my $i=0;
    50     my $arg;
    51     my @argv=();
    52     while ($i<=$#ARGV) {
    53         $arg=$ARGV[$i];
    54         #print "arg=$arg\n";
    55         if ($arg eq "grep") {
    56             my $grep_keys="";
    57             my $grep_regexp="";
    58             $i++;
    59             while(defined ($ARGV[$i]) and $ARGV[$i] =~ /^-/) {
    60                 $grep_keys .= " ".$ARGV[$i];
    61                 $i++;
    62             }
    63             if (defined($ARGV[$i])) {
    64                 $grep_regexp = $ARGV[$i];
    65                 $i++;
    66             }
    67             else {
    68                 die "ERROR: grep argument is not specified";
    69             }
    70             $Grep .= grep_options($grep_regexp,$grep_keys);
    71         }
    72         else {
    73             $i++;
    74             push(@new_argv,$arg);
    75         }
    76     }
    77     @argv=@new_argv;
    79     if (grep(/^-f$/, @argv)) {
    80         $follow=1;
    81     }
    82     if (grep(/^history$/, @argv)) {
    83         my $interval=$argv[0]||"%";
    84         $interval="%" if $interval eq "history";
    85         my $exit=0;
    86         while (not $exit) {
    87             print_commands(select_interval($interval, $Grep));
    88             if (not $follow) {
    89                 $exit=1;
    90             } else {
    91                 sleep(1);
    92             }
    93         }
    94     } else {
    95         my $exit=0;
    96         while (not $exit) {
    97             print_all(select_interval($argv[0]||"%", $Grep));
    98             if (not $follow) {
    99                 $exit=1;
   100             } else {
   101                 sleep(1);
   102             }
   103         }
   104     }
   105     #print_all(select_by_cline("*privet*"));
   106 }
   108 sub connect_database()
   109 {
   110     $db = DBI->connect("dbi:SQLite:".$Config{cache_sqlite}, "", "",
   111                 {RaiseError => 1, AutoCommit => 1});
   112     $db->func('regexp', 2, sub {
   113             my ($regex, $string) = @_;
   114                 return $string =~ /$regex/;
   115     }, 'create_function');
   116 }
   118 sub select_all() {
   119     $l3cd=$Config{l3cd};
   120     return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE l3cd='$l3cd'");
   121 }
   123 sub select_last_n($) {
   124     my $last=$_[0];
   125     $count = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
   126     my $offset=$$count[0][0]-$last;
   127     return $db->selectall_arrayref("SELECT $Fields FROM commands LIMIT $last OFFSET $offset");
   128 }
   130 sub select_interval($) {
   131     my $interval = shift;
   132     my $grep = shift;
   134     my $q;  # Рабочая переменная для запросов
   135 # %
   136     $interval='1,$' if ($interval eq "%");
   137 #        return $db->selectall_arrayref(
   138 #                "SELECT $Fields FROM commands WHERE l3cd='$Context'");
   140 # Вычисляем номера начальной и конечной строки
   141 # на основе интервала
   142     my ($start,$stop);
   143     my ($start_n, $stop_n, $curr_n) = ("","",""); # номера начальной и конечной строк
   144     if ($interval =~ /,/) {
   145         ($start,$stop) = split(/,/,$interval);
   146     }
   147     else {
   148         $start = $interval;
   149         $stop = $interval;
   150     }
   152     $q = $db->selectall_arrayref("SELECT COUNT(*) FROM commands");
   153     my $count = $$q[0][0];
   155 # Номер текущей строки
   156 # По умолчанию текущая строка указывает на последнюю
   157     $curr_n = $count;
   158     #$curr_n = 2;
   160     if ($start =~ /^[0-9]*$/) { $start_n = $start; }
   161     if ($stop =~ /^[0-9]*$/)  { $stop_n  = $stop; }
   162     if ($start =~ /^-[0-9]*$/) { $start_n = $curr_n + $start; }
   163     if ($stop =~ /^-[0-9]*$/)  { $stop_n  = $curr_n + $stop; }
   164     if ($start =~ /^\+[0-9]*$/) { $start_n = $curr_n + $start; }
   165     if ($stop =~ /^\+[0-9]*$/)  { $stop_n  = $curr_n + $stop; }
   166     if ($start eq '.') { $start_n = $curr_n; }
   167     if ($stop eq '.')  { $stop_n  = $curr_n; }
   168     if ($start eq '$') { $start_n = $count; }
   169     if ($stop eq '$')  { $stop_n  = $count; }
   170     if ($start =~ m@^/(.*)/@ ) {
   171         $q = $db->selectall_arrayref(
   172                 "SELECT id FROM commands WHERE cline REGEXP '$1' LIMIT 1");
   173         $start_n=$$q[0][0];
   174     }
   175     if ($stop =~ m@^/(.*)/@ ) {
   176         $q = $db->selectall_arrayref(
   177                 "SELECT id FROM commands 
   178                  WHERE cline REGEXP '$1' 
   179                         AND (id >= $start_n) LIMIT 1");
   180         $stop_n=$$q[0][0];
   181     }
   182     if ($start =~ m@^o/(.*)/@ ) {
   183         $q = $db->selectall_arrayref(
   184                 "SELECT id FROM commands WHERE output REGEXP '$1' LIMIT 1");
   185         $start_n=$$q[0][0];
   186     }
   187     if ($stop =~ m@^o/(.*)/@ && $start_n) {
   188         $q = $db->selectall_arrayref(
   189                 "SELECT id FROM commands 
   190                  WHERE output REGEXP '$1' AND (id >= $start_n) LIMIT 1");
   191         $stop_n=$$q[0][0];
   192     }
   194     if (not $start_n or not $stop_n) {return ""};
   196     $stop_n = $count if $count < $stop_n;
   197     $start_n =1 if 1 > $start_n;
   199     my $offset=$start_n-1;
   200     my $limit = $stop_n - $offset;
   202     my $pre_follow=$Follow;
   203     $q = $db->selectall_arrayref(
   204             "SELECT id FROM commands 
   205             WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)
   206             ORDER BY id DESC");
   207     $Follow = $$q[0][0] if $$q[0][0];
   208     return $db->selectall_arrayref(
   209             "SELECT $Fields FROM commands 
   210             WHERE ((id>=$start_n AND id<=$stop_n AND id>$pre_follow) $grep)");
   211 }
   213 sub grep_options($$) {
   214 =cut
   215     -c ищем только в комадной строке    # по умолчанию
   216     -o ищем только в выводе
   217     -f ищем и там, и там
   218     -v инверсия
   219 =cut
   220     my $regexp=shift; return "" if $regexp eq '';
   221     my $options=shift;
   222     my @options = split //, $options;
   223     my $not = "";
   224     $not = "NOT" if grep(/v/,@options);
   226     my $grep ="";
   227     if (grep(/f/,@options)) {
   228         $grep = "AND $not ((cline REGEXP '$regexp') OR (output REGEXP '$regexp'))";
   229     }
   230     elsif (grep(/o/,@options)) {
   231         $grep = "AND $not (output REGEXP '$regexp')";
   232     }
   233     elsif (1 || grep(/c/,@options)) {
   234         $grep = "AND $not (cline REGEXP '$regexp')";
   235     }
   237     return $grep;
   238 }
   240 sub select_by_cline($) {
   241     my $cline = $_[0];
   242     return $db->selectall_arrayref("SELECT $Fields FROM commands WHERE cline GLOB '$cline'");
   243 }
   245 sub print_commands($)
   246 {
   247     my @fields=@Fields;
   248     my $fields=join(", ",@fields);
   249     my $all=$_[0];
   250     foreach my $row (@$all) {
   251         my $cl;       #Каждая строка
   252         my $i=0;
   253         for my $f (@fields) {
   254             $cl->{$fields[$i]}=$$row[$i];
   255             $i++;
   256         }
   257         print $cl->{id}." ".strdequot($cl->{cline})."\n";
   258     }
   259 }
   260 sub print_all($) {
   261     my @fields=@Fields;
   262     my $fields=join(", ",@fields);
   263     my $all=$_[0];
   264     my $prev_cl; # Предыдущая строка
   265     my $tab_seq; # Номер в табуляционной последовательности
   266     foreach my $row (@$all) {
   267         my $cl;       #Каждая строка
   268         my @anchor;   #Начальная строка, якорь, по которому привязывается команда
   269         my $res="";   #Буфер, в который выводится результат вывода каждой строки
   270         $i=0;
   271         for my $f (@fields) {
   272             $cl->{$fields[$i]}=$$row[$i];
   273             $i++;
   274         }
   275         next    if ($Config{"skip_empty"} =~ /^y/i     && $cl->{"cline"} =~ /^\s*$/ )
   276                 || ($Config{"skip_wrong"} =~ /^y/i     && $cl->{"err"} != 0)
   277                 || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
   279         # Время
   280         # Добавляем спереди 0 для удобочитаемости
   281         my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time});
   282         $min  = "0".$min  if $min  =~ /^.$/;
   283         $hour = "0".$hour if $hour =~ /^.$/;
   284         $sec  = "0".$sec  if $sec  =~ /^.$/;
   286         if ($Config{"show_time"} =~ /^y/i) {
   287             push @anchor,"$hour:$min:$sec ";
   288         }
   290         if ($cl->{"err"}) {
   291             push @anchor, "err=".$cl->{'err'};
   292         }
   293         if ($cl->{"tab"}) {
   294             push @anchor, "tab=".$cl->{'tab'};
   295         }
   296         $res.="#=".join("",@anchor)."\n";
   297         $res.=$cl->{prompt}.strdequot($cl->{cline})."\n";
   299         my $output = ""; # фомируем вывод команды
   300         my $last_command = $cl->{"last_command"};
   301         if (!( $Config{"suppress_editors"} =~ /^y/i 
   302                && grep ($_ eq $last_command, @{$Config{"editors"}}) 
   303             || $Config{"suppress_pagers"}  =~ /^y/i 
   304                && grep ($_ eq $last_command, @{$Config{"pagers"}})
   305             || $Config{"suppress_terminal"}=~ /^y/i 
   306                && grep ($_ eq $last_command, @{$Config{"terminal"}})
   307             )) {
   308             $output = strdequot($cl->{output});
   310             # Вырезаем слишком длинные выводы
   311             my @lines = split '\n', $output;
   312             if (!$Config{"command_id"} 
   313                 && ( $Config{"head_lines"} || $Config{"tail_lines"})
   314                 && $#lines >  $Config{"head_lines"} + $Config{"tail_lines"}) {
   315                     $output="";
   316                     for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) {
   317                         $output .= $lines[$i]."\n";
   318                     }
   319                     $output .= $Config{"skip_text"}."\n";
   321                     my $start_line=$#lines-$Config{"tail_lines"}+1;
   322                     for (my $i=$start_line; $i<= $#lines; $i++) {
   323                         $output .= $lines[$i]."\n";
   324                     }
   325                 } 
   326             }
   327         $res.=$output;
   328         if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) {
   329             $res.= $cl->{"diff"}
   330         }
   331         #open(OUTPUT, '|sendxmpp nata_samoylenko@jabber.ru');
   332         #print OUTPUT $res;
   333         #close(OUTPUT);
   334         print $res;
   335         $res="";
   336         $prev_cl=$cl;
   337     }
   338 }
   340 sub strdequot($)
   341 {
   342     my $text = join "", @_;
   343     $text =~ s/&/&/g;
   344     $text =~ s/</</g;
   345     $text =~ s/>/>/g;
   346     $text =~ s/"/"/g;
   347     return $text;
   348 }
   350 sub show_usage()
   351 {
   352     print <<EOF;
   353 Usage:
   354     l3 [INTERVAL] [grep [KEYS] REGEXP] [filter [KEYS] FILTER] [COMMAND [KEYS]]
   356 Commands:
   357     history
   358     tail
   359     head
   360     cat (default)
   362     If COMMAND is not specified, cat assumed.
   364 EOF
   365 }
