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