lilalo
diff l3-frontend @ 23:6d93c5f1d0e5
Выполнен шаг (2) в плане (N05) по построению распределённой системы lilalo.
Программа lm-report разрезана на две: l3-agent и l3-frontend.
Агент выполняет анализ script-файлов и записывает
результаты анализа в файл обмена (cache).
Фронтенд читает данные из файла обмена и представляет
их в требуемом формате (в настоящий момент только html).
Сейчас взаимодействие agent'а и frontend'а выполняется так:
. ^ . +-------+ . ^^ .
/ \ | | / \
( agent )-->| cache |--->( frontend )
\ / | | \ /
' . ' +-------+ ' .. '
Добавлены файлы:
l3-agent - агент
l3-frontend - фронтенд
l3-report - замена lm-report, использующая l3-agent и l3-frontend
l3-config.pm - модуль конфигурации системы
Новые конфигурационные параметры:
cache - Путь к временному XML-файлу, предназначенному
для обмена информацией между агентом и фронтендом
cache_head_lines - Количество строк вывода команды сверху, которые
должны быть сохранены в промежуточном XML-файле
cache_tail_lines - Количество строк вывода команды снизу, которые
должны быть сохранены в промежуточном XML-файле
Устаревшие параметры:
output_mask - Использование output_mask осуждается.
Параметр будет удалён из будущих версий
Использование lm-report осуждается.
В будущих версиях программа lm-report будет удалена из дистрибутива.
Вместо неё нужно использовать l3-report.
Программа lm-report разрезана на две: l3-agent и l3-frontend.
Агент выполняет анализ script-файлов и записывает
результаты анализа в файл обмена (cache).
Фронтенд читает данные из файла обмена и представляет
их в требуемом формате (в настоящий момент только html).
Сейчас взаимодействие agent'а и frontend'а выполняется так:
. ^ . +-------+ . ^^ .
/ \ | | / \
( agent )-->| cache |--->( frontend )
\ / | | \ /
' . ' +-------+ ' .. '
Добавлены файлы:
l3-agent - агент
l3-frontend - фронтенд
l3-report - замена lm-report, использующая l3-agent и l3-frontend
l3-config.pm - модуль конфигурации системы
Новые конфигурационные параметры:
cache - Путь к временному XML-файлу, предназначенному
для обмена информацией между агентом и фронтендом
cache_head_lines - Количество строк вывода команды сверху, которые
должны быть сохранены в промежуточном XML-файле
cache_tail_lines - Количество строк вывода команды снизу, которые
должны быть сохранены в промежуточном XML-файле
Устаревшие параметры:
output_mask - Использование output_mask осуждается.
Параметр будет удалён из будущих версий
Использование lm-report осуждается.
В будущих версиях программа lm-report будет удалена из дистрибутива.
Вместо неё нужно использовать l3-report.
author | devi |
---|---|
date | Wed Nov 02 19:16:11 2005 +0200 (2005-11-02) |
parents | |
children | ba4d6515b8fd |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/l3-frontend Wed Nov 02 19:16:11 2005 +0200 1.3 @@ -0,0 +1,493 @@ 1.4 +#!/usr/bin/perl -w 1.5 + 1.6 +use lib '.'; 1.7 +use l3config; 1.8 + 1.9 +our @Command_Lines; 1.10 + 1.11 +# vvv Инициализация переменных выполняется процедурой init_variables 1.12 +our @Day_Name; 1.13 +our @Month_Name; 1.14 +our @Of_Month_Name; 1.15 +our %Search_Machines; 1.16 +our %Elements_Visibility; 1.17 +# ^^^ 1.18 + 1.19 +sub search_buy; 1.20 +sub make_comment; 1.21 +sub load_command_lines_from_xml; 1.22 +sub print_command_lines; 1.23 +sub init_variables; 1.24 +sub main; 1.25 + 1.26 +main(); 1.27 + 1.28 +sub main 1.29 +{ 1.30 + $| = 1; 1.31 + 1.32 + init_variables(); 1.33 + init_config(); 1.34 + 1.35 + load_command_lines_from_xml($Config{"cache"}); 1.36 + print_command_lines($Config{"output"}); 1.37 +} 1.38 + 1.39 + 1.40 +sub search_by 1.41 +{ 1.42 + my $sm = shift; 1.43 + my $topic = shift; 1.44 + $topic =~ s/ /+/; 1.45 + 1.46 + return "<a href='". $Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='". 1.47 + $Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; 1.48 +} 1.49 + 1.50 +sub make_comment 1.51 +{ 1.52 + my $commands = $_[0]; 1.53 + my $files = $_[1]; 1.54 + chomp $commands; 1.55 + chomp $files; 1.56 + return if (!$commands && !$files); 1.57 + 1.58 + my $comment=""; 1.59 + 1.60 + # Commands 1.61 + for my $command (split /\s+/,$commands) { 1.62 + $command =~ s/'//g; 1.63 + my $description=""; 1.64 + eval { $description=`mywi-client '$command'`; } ; 1.65 + $description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description))); 1.66 + $description =~ s/.*?-//; 1.67 + next if $description =~ /^\s*$/; 1.68 + 1.69 + my $query=$command." ".$Config{"keywords"}; 1.70 + $query =~ s/\ /+/g; 1.71 + my $search= search_by("opennet",$query). 1.72 + search_by("local",$command). 1.73 + search_by("google",$query); 1.74 + 1.75 + $comment .= "<tr><td class='note_title'>$command</td>". 1.76 + "<td class='note_search'>$search</td>". 1.77 + "</tr><tr><td width='100%' colspan='2' class='note_text'>". 1.78 + "$description</td></tr><tr/>"; 1.79 + } 1.80 + 1.81 + # Files 1.82 + for my $file (split /\s+/,$files) { 1.83 + $file =~ s@.*/@@; 1.84 + $file =~ s/'//g; 1.85 + next if $file =~ /^\s*$/; 1.86 + next if $file =~ /^-/; 1.87 + 1.88 + my $description=`mywi '$file'`; 1.89 + $description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description))); 1.90 + next if $description =~ /^\s*$/; 1.91 + 1.92 + my $query=$file." ".$Config{"files_keywords"}; 1.93 + $query =~ s/\ /+/g; 1.94 + my $search= search_by("opennet",$query). 1.95 + search_by("local",$file). 1.96 + search_by("google",$query); 1.97 + 1.98 + $comment .= "<tr><td class='note_title'>$file</td>". 1.99 + "<td class='note_search'>$search</td>". 1.100 + "</tr><tr><td width='100%' colspan='2' class='note_text'>". 1.101 + "$description</td></tr><tr/>"; 1.102 + } 1.103 + 1.104 + 1.105 + return $comment; 1.106 +} 1.107 + 1.108 +=cut 1.109 +Процедура load_command_lines_from_xml выполняет загрузку разобранного lab-скрипта 1.110 +из XML-документа в переменную @Command_Lines 1.111 + 1.112 +Предупреждение! 1.113 +Процедура не в состоянии обрабатывать XML-документ любой структуры. 1.114 +В действительности файл cache из которого загружаются данные 1.115 +просто напоминает XML с виду. 1.116 +=cut 1.117 +sub load_command_lines_from_xml 1.118 +{ 1.119 + my $datafile = $_[0]; 1.120 + 1.121 + open (CLASS, $datafile) 1.122 + or die "Can't open file of the class ",$datafile,"\n"; 1.123 + local $/; 1.124 + $data = <CLASS>; 1.125 + close(CLASS); 1.126 + 1.127 + for $command ($data =~ m@<command>(.*?)</command>@sg) { 1.128 + my %cl; 1.129 + while ($command =~ m@<([^>]*?)>(.*?)</\1>@sg) { 1.130 + $cl{$1} = $2; 1.131 + } 1.132 + push @Command_Lines, \%cl; 1.133 + } 1.134 +} 1.135 + 1.136 +=cut 1.137 +Процедура print_command_lines выводит HTML-представление 1.138 +разобранного lab-скрипта. 1.139 + 1.140 +Разобранный lab-скрипт должен находиться в массиве @Command_Lines 1.141 +=cut 1.142 + 1.143 +sub print_command_lines 1.144 +{ 1.145 + my $output_filename=$_[0]; 1.146 + 1.147 + my $course_name = $Config{"course-name"}; 1.148 + my $course_code = $Config{"course-code"}; 1.149 + my $course_date = $Config{"course-date"}; 1.150 + my $course_center = $Config{"course-center"}; 1.151 + my $course_trainer = $Config{"course-trainer"}; 1.152 + my $course_student = $Config{"course-student"}; 1.153 + 1.154 + 1.155 + # Результат выполнения процедуры равен 1.156 + # join("", @Result{header,body,stat,help,about,footer}) 1.157 + my %Result; 1.158 + my $toc =""; # Хранит оглавление по дням 1.159 + 1.160 + $Result{"body"} = "<table width='100%'>\n"; 1.161 + 1.162 + my $cl; 1.163 + my $last_tty=""; 1.164 + my $last_day=""; 1.165 + my $in_range=0; 1.166 + 1.167 + for my $cl (@Command_Lines) { 1.168 + 1.169 + if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { 1.170 + $in_range=1; 1.171 + next; 1.172 + } 1.173 + if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { 1.174 + $in_range=0; 1.175 + next; 1.176 + } 1.177 + next if ($Config{"from"} && $Config{"to"} && !$in_range) 1.178 + || 1.179 + ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) 1.180 + || 1.181 + ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) 1.182 + || 1.183 + ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); 1.184 + 1.185 + #my @new_commands=@{$cl->{"new_commands"}}; 1.186 + #my @new_files=@{$cl->{"new_files"}}; 1.187 + 1.188 + my $cl_class="cline"; 1.189 + my $out_class="output"; 1.190 + if ($cl->{"class"}) { 1.191 + $cl_class = $cl->{"class"}."_".$cl_class; 1.192 + $out_class = $cl->{"class"}."_".$out_class; 1.193 + } 1.194 + 1.195 + my @new_commands; 1.196 + my @new_files; 1.197 + @new_commands = split (/\s+/, $cl->{"new_commands"}) if defined $cl->{"new_commands"}; 1.198 + @new_files = split (/\s+/, $cl->{"new_files"}) if defined $cl->{"new_files"}; 1.199 + 1.200 + my $output=""; 1.201 + if ($Config{"head_lines"} || $Config{"tail_lines"}) { 1.202 + # Partialy output 1.203 + my @lines = split '\n', $cl->{"output"}; 1.204 + # head 1.205 + my $mark=1; 1.206 + for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { 1.207 + $output .= $lines[$i]."\n"; 1.208 + } 1.209 + # tail 1.210 + my $start=$#lines-$Config{"tail_lines"}+1; 1.211 + if ($start < 0) { 1.212 + $start=0; 1.213 + $mark=0; 1.214 + } 1.215 + if ($start < $Config{"head_lines"}) { 1.216 + $start=$Config{"head_lines"}; 1.217 + $mark=0; 1.218 + } 1.219 + $output .= $Config{"skip_text"}."\n" if $mark; 1.220 + for (my $i=$start; $i<= $#lines; $i++) { 1.221 + $output .= $lines[$i]."\n"; 1.222 + } 1.223 + } 1.224 + else { 1.225 + # Full output 1.226 + $output .= $cl->{"output"}; 1.227 + } 1.228 + #$output .= "^C\n" if ($cl->{"err"} eq "130"); 1.229 + 1.230 + # 1.231 + ## 1.232 + ## Начинается собственно вывод 1.233 + ## 1.234 + # 1.235 + 1.236 + # <command> 1.237 + 1.238 + my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); 1.239 + # Добавляем спереди 0 для удобочитаемости 1.240 + $min = "0".$min if $min =~ /^.$/; 1.241 + $hour = "0".$hour if $hour =~ /^.$/; 1.242 + $sec = "0".$sec if $sec =~ /^.$/; 1.243 + 1.244 + $class=$cl->{"out_class"}; 1.245 + $class =~ s/output$//; 1.246 + 1.247 + 1.248 + $Result{"body"} .= "<tr class='command'>\n"; 1.249 + 1.250 + 1.251 + # DAY CHANGE 1.252 + if ( $last_day ne $day) { 1.253 + #$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>"; 1.254 + $Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>"; 1.255 + $toc .= "<li><a href='#day$day'>".$Day_Name[$wday]."</a></li>\n"; 1.256 + $last_day=$day; 1.257 + } 1.258 + 1.259 + # CONSOLE CHANGE 1.260 + if ( $last_tty ne $cl->{"tty"}) { 1.261 + $Result{"body"} .= "<td colspan='6'><table><tr><td class='ttychange' width='140' align='center'>".$cl->{"tty"}."</td><td/></tr></table></td></tr><tr>"; 1.262 + $last_tty=$cl->{"tty"}; 1.263 + } 1.264 + 1.265 + # TIME 1.266 + if ($Config{"show_time"} =~ /^y/i) { 1.267 + $Result{"body"} .= "<td valign='top' class='time' width='$Config{time_width}'><pre>". 1.268 + $hour. ":". $min. ":". $sec. 1.269 + "</td>"; 1.270 + } else { 1.271 + $Result{"body"} .= "<td width='0'/>" 1.272 + } 1.273 + 1.274 + # COMMAND 1.275 + $Result{"body"} .= "<td class='script'>\n"; 1.276 + $Result{"body"} .= "<pre class='${class}cline'>\n"; 1.277 + my $cline = $cl->{"cline"}; 1.278 + $cline =~ s/\n//; 1.279 + $Result{"body"} .= $cl->{"prompt"}.$cl->{"cline"}; 1.280 + $Result{"body"} .= "</pre>\n"; 1.281 + 1.282 + my $last_command = $cl->{"last_command"}; 1.283 + if (!( 1.284 + $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || 1.285 + $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || 1.286 + $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) 1.287 + )) { 1.288 + 1.289 + $Result{"body"} .= "<pre class='".$cl->{out_class}."'>"; 1.290 + $Result{"body"} .= $output; 1.291 + $Result{"body"} .= "</pre>\n"; 1.292 + } 1.293 + 1.294 + # DIFF 1.295 + if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { 1.296 + $Result{"body"} .= "<table><tr><td width='5'/><td class='diff'><pre>"; 1.297 + $Result{"body"} .= $cl->{"diff"}; 1.298 + $Result{"body"} .= "</pre></td></tr></table>"; 1.299 + } 1.300 + 1.301 + # COMMENT 1.302 + if ( $Config{"show_comments"} =~ /^y/i) { 1.303 + my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files)); 1.304 + if ($comment) { 1.305 + $Result{"body"} .= "<table width='$Config{comment_width}'>". 1.306 + "<tr><td width='5'/><td>"; 1.307 + $Result{"body"} .= "<table class='note' width='100%'>"; 1.308 + $Result{"body"} .= $comment; 1.309 + $Result{"body"} .= "</table>\n"; 1.310 + $Result{"body"} .= "</td></tr></table>"; 1.311 + } 1.312 + else { 1.313 + $Result{"body"} .= "<table width='$Config{comment_width}'>". 1.314 + "<tr><td width='5'/><td>"; 1.315 + $Result{"body"} .= "<table class='note' width='100%'>"; 1.316 + $Result{"body"} .= "commands ".join(" ",@new_commands)."<br/>"; 1.317 + $Result{"body"} .= "files ".join(" ",@new_files)."<br/>"; 1.318 + $Result{"body"} .= "</table>\n"; 1.319 + $Result{"body"} .= "</td></tr></table>"; 1.320 + } 1.321 + } 1.322 + 1.323 + # Вывод очередной команды окончен 1.324 + $Result{"body"} .= "</td>\n"; 1.325 + $Result{"body"} .= "</tr>\n"; 1.326 + } 1.327 + 1.328 + $Result{"body"} .= "</table>\n"; 1.329 + 1.330 + $Result{"stat"} = "<hr/>"; 1.331 + $Result{"stat"} .= "<h2 id='stat'>Статистика</h2>"; 1.332 + $Result{"stat"} .= "Статистическая информация о журнале<br/>"; 1.333 + $Result{"help"} .= "<hr/>"; 1.334 + $Result{"help"} .= "<h2 id='help'>Справка</h2>"; 1.335 + $Result{"help"} .= "$Html_Help<br/>"; 1.336 + $Result{"about"} .= "<hr/>"; 1.337 + $Result{"about"} .= "<h2 id='about'>О программе</h2>"; 1.338 + $Result{"about"} .= "$Html_About"; 1.339 + $Result{"footer"} .= "</body>\n"; 1.340 + $Result{"footer"} .= "</html>\n"; 1.341 + 1.342 + # Заголовок генерируется позже всего 1.343 + # Тогда, когда известно уже, что должно быть написано в 1.344 + # оглавлении 1.345 + $Result{"header"} = <<HEADER; 1.346 + <html> 1.347 + <head> 1.348 + <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> 1.349 + <link rel='stylesheet' href='labmaker.css' type='text/css'/> 1.350 + </head> 1.351 + <body> 1.352 + <script> 1.353 + $Html_JavaScript 1.354 + </script> 1.355 + <h2>Журнал лабораторных работ</h2> 1.356 + 1.357 + <p> 1.358 + Выполнил $course_student<br/> 1.359 + Проверил $course_trainer <br/> 1.360 + Курс $course_name ($course_code), 1.361 + $course_date<br/> 1.362 + Учебный центр $course_center <br/> 1.363 + </p> 1.364 + 1.365 + <ul> 1.366 + <li><a href='#log'>Журнал</a></li> 1.367 + <ul>$toc</ul> 1.368 + <li><a href='#stat'>Статистика</a></li> 1.369 + <li><a href='#help'>Справка</a></li> 1.370 + <li><a href='#about'>О программе</a></li> 1.371 + </ul> 1.372 + 1.373 + <h2 id="log">Журнал</h2> 1.374 +HEADER 1.375 + $Result{"header"} .= "<table class='visibility_form'><tr><td><form>\n"; 1.376 + for my $element (keys %Elements_Visibility) 1.377 + { 1.378 + my @e = split /\s+/, $element; 1.379 + my $showhide = join "", map { "ShowHide('$_');" } @e ; 1.380 + $Result{"header"} .= "<input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>". 1.381 + $Elements_Visibility{$element}. 1.382 + "</input><br>\n"; 1.383 + } 1.384 + 1.385 + $Result{"header"} .= "</form></td></tr></table>\n"; 1.386 + 1.387 + open(OUT, ">", $output_filename) 1.388 + or die "Can't open $output_filename for writing\n"; 1.389 + print OUT $Result{"header"}, $Result{"body"}, $Result{"stat"}, $Result{"help"}, $Result{"about"}, $Result{"footer"}; 1.390 + close(OUT); 1.391 +} 1.392 + 1.393 + 1.394 + 1.395 + 1.396 + 1.397 + 1.398 +sub init_variables 1.399 +{ 1.400 +$Html_Help = <<HELP; 1.401 + Справка по использованию журнала 1.402 +HELP 1.403 + 1.404 +$Html_About = <<ABOUT; 1.405 + <p> 1.406 + LiLaLo (L3) расшифровывается как Live Lab Log.<br/> 1.407 + Программа разработана для повышения эффективности обучения<br/> 1.408 + Unix/Linux-системам.<br/> 1.409 + (c) Игорь Чубин, 2004-2005<br/> 1.410 + </p> 1.411 +ABOUT 1.412 +$Html_About.='$Id$ </p>'; 1.413 + 1.414 +$Html_JavaScript = <<JS; 1.415 + function getElementsByClassName(Class_Name) 1.416 + { 1.417 + var Result=new Array(); 1.418 + var All_Elements=document.all || document.getElementsByTagName('*'); 1.419 + for (i=0; i<All_Elements.length; i++) 1.420 + if (All_Elements[i].className==Class_Name) 1.421 + Result.push(All_Elements[i]); 1.422 + return Result; 1.423 + } 1.424 + function ShowHide (name) 1.425 + { 1.426 + elements=getElementsByClassName(name); 1.427 + for(i=0; i<elements.length; i++) 1.428 + if (elements[i].style.display == "none") 1.429 + elements[i].style.display = ""; 1.430 + else 1.431 + elements[i].style.display = "none"; 1.432 + //if (elements[i].style.visibility == "hidden") 1.433 + // elements[i].style.visibility = "visible"; 1.434 + //else 1.435 + // elements[i].style.visibility = "hidden"; 1.436 + } 1.437 + function filter_by_output(text) 1.438 + { 1.439 + 1.440 + var jjj=0; 1.441 + 1.442 + elements=getElementsByClassName('command'); 1.443 + for(i=0; i<elements.length; i++) { 1.444 + subelems = elements[i].getElementsByTagName('pre'); 1.445 + for(j=0; j<subelems.length; j++) { 1.446 + if (subelems[j].className = 'output') { 1.447 + var str = new String(subelems[j].nodeValue); 1.448 + if (jjj != 1) { 1.449 + alert(str); 1.450 + jjj=1; 1.451 + } 1.452 + if (str.indexOf(text) >0) 1.453 + subelems[j].style.display = "none"; 1.454 + else 1.455 + subelems[j].style.display = ""; 1.456 + 1.457 + } 1.458 + 1.459 + } 1.460 + } 1.461 + 1.462 + } 1.463 +JS 1.464 + 1.465 +%Search_Machines = ( 1.466 + "google" => { "query" => "http://www.google.com/search?q=" , 1.467 + "icon" => "google.ico" }, 1.468 + "freebsd" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", 1.469 + "icon" => "freebsd.ico" }, 1.470 + "linux" => { "query" => "http://man.he.net/?topic=", 1.471 + "icon" => "linux.ico"}, 1.472 + "opennet" => { "query" => "http://www.opennet.ru/search.shtml?words=", 1.473 + "icon" => "opennet.ico"}, 1.474 + "local" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", 1.475 + "icon" => "freebsd.ico" }, 1.476 + 1.477 + ); 1.478 + 1.479 +%Elements_Visibility = ( 1.480 + "note" => "замечания", 1.481 + "diff" => "редактор", 1.482 + "time" => "время", 1.483 + "ttychange" => "терминал", 1.484 + "wrong_output wrong_cline wrong_root_output wrong_root_cline" 1.485 + => "команды с ошибками", 1.486 + "interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" 1.487 + => "прерванные команды", 1.488 + "tab_completion_output tab_completion_cline" 1.489 + => "продолжение с помощью tab" 1.490 +); 1.491 + 1.492 +@Day_Name = qw/ Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота /; 1.493 +@Month_Name = qw/ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь /; 1.494 +@Of_Month_Name = qw/ Января Февраля Марта Апреля Мая Июня Июля Августа Сентября Октября Ноября Декабря /; 1.495 +} 1.496 +