Как стать автором
Обновить

Опыт разработки плагина для Yasca

Время на прочтение4 мин
Количество просмотров2.4K
В этой статье я хочу поделиться опытом использования одной полезной утилиты, позволяющей автоматизировать сборку и анализ качества кода. Речь пойдет о Yasca — свободно распространяемом ПО, представляющем собой небольшой PHP движок и набор утилит для выполнения анализа Java, С++ или PHP кода, включающего в себя PMD, JLint и RATS. Сама интеграция выполнения этих утилит осуществляется путем разработки небольших плагинов, на языке PHP. О процессе разработки такого плагина и пойдет речь далее.

Для начала, нам нужно добиться функционирования самой Yasca. Сделать это — довольно просто. Идем на страницу закачки и скачиваем собственно yasca и какой-нибудь из кодечекеров. создаем локальный каталог (например c:/yasca) и просто распаковываем в него все архивы по очереди. Сразу же после этого, инструмент готов к работе. Набираем в командной строке (или сохраняем в cmd-файл) команду (заменив многоточие на путь к каталогу с каким нибудь Java или C++ проектом):

yasca.exe -o ./Report ...

Проработав некоторое время, Yasca формирует отчет Report.html, содержащий замечания по стилю кодирования нашего проекта. Строки отчета содержат ссылки на исходный код и единственное, что неудобно, это то, что при переходе по ссылке, мы попадаем в начало файла, а искать нужную строку по номеру может быть слегка утомительно. Именно это я и предлагаю исправить. Пусть ссылки позиционируют нас сразу на нужную строку исходного кода.

Понятно, что мы не сможем провернуть такой фокус непосредственно с исходными текстами, но мы можем построить на их основе временные html-файлы, сформировав в каждой строке закладку, в качестве имени которой, используем номер строки. Заодно, слева, мы проставим номера строк, чтобы было удобнее ориентироваться. Звучит страшновато, но на самом деле, делается довольно просто. Сам плагин (его нужно будет, назвав Mirror.php, поместить в папку plugins) будет выглядеть следующим образом:

<?php

/**
 * @extends Plugin
 * @package Yasca
 */
class Plugin_Mirror extends Plugin {
    public $valid_file_types = array("java", "c", "cpp", "h", "cs", "sql");
        function rmdir_recurse($path) {
            $path= rtrim($path, '/').'/';
            $handle = opendir($path);
            for (;false !== ($file = readdir($handle));)
                if($file != "." and $file != ".." ) {
                    $fullpath= $path.$file;
                    if( is_dir($fullpath) ) {
                        $this->rmdir_recurse($fullpath);
                        rmdir($fullpath);
                    }
                    else
                      unlink($fullpath);
                }
            closedir($handle);
        }
    function execute() {
        $yasca =& Yasca::getInstance();
                static $once = true;
                if ($once) {
                    $this->rmdir_recurse('./Mirror');
                }
                $once = false;
                if (!check_in_filetype($this->filename, $this->valid_file_types)) {
                    return;
                }
                $filename = preg_replace('/\w:/', './Mirror', $this->filename) . ".html";
                $dir_name = preg_replace('/[\\\\\\/][^\\\\\\/]+$/', '', $filename);
                if (!file_exists($dir_name)) {
                    if (!mkdir($dir_name, 0777, true)) return;
                }
                if (file_exists($filename)) {
                    unlink($filename);
                }
                if (!$handle = fopen($filename, 'w+', true) ) return;
                fwrite($handle,"<html><meta http-equiv=\"Content-Type\" content=\"text/html;charset=windows-1251\" /><head></head><body><pre>\n");
                $line = 1;
                foreach ($this->file_contents as $file_line) {
                        $str = $line;
                        while (strlen($str)<5) {
                           $str = " " . $str;
                        }
                        fwrite($handle,"<a name=$line></a>$str: $file_line<br>\n");
                        $line++;
                }
                fwrite($handle,"</pre></body></html>");
                fclose($handle);
    }
}
?>

Теперь, после очередного запуска yasca мы получим копии всех проанализированных файлов в каталоге Mirror в препарированном в html виде. Чтобы сделать эти файлы полезными, нам придется вмешаться в ход построения отчета и подменить формируемые им ссылки на наш вариант. К счастью, этот код также написан на PHP. Идем в каталог lib и находим там файл HTMLGroupReport.php используемый для создания отчета, по умолчанию. В этом файле, находим фрагмент:

fwrite($handle,    
       "<a style=\"margin-right: 12px;\" source_code_link=\"true\" href=\"file://$filename\" target=\"_blank\" title=\"$filename\">$filename_base$line_number_field</a>" .
       "</td>");

И заменяем его на:

$chg_file_name = getcwd();
$chg_file_name = preg_replace('/\\\\/', '/', $chg_file_name);
$chg_file_name = preg_replace('/^\w:/', $chg_file_name . '/Mirror', $filename);
       
if (preg_match('/\.java$|\.c$|\.cpp$|\.h$|\.cs$|\.sql$/i', $chg_file_name)) {
    fwrite($handle,       
          "<a style=\"margin-right: 12px;\" source_code_link=\"true\" href=\"file://$chg_file_name.html#$line_number\" target=\"code\" title=\"$filename\">$filename_base$line_number_field</a>" .
          "</td>");
} else {
    fwrite($handle,    
          "<a style=\"margin-right: 12px;\" source_code_link=\"true\" href=\"file://$filename\" target=\"_blank\" title=\"$filename\">$filename_base$line_number_field</a>" .
          "</td>");
}

После чего запускаем Yasca снова и убеждаемся, что все работает. В плане дальнейшей автоматизации, наша фантазия мало чем ограничена. У нас, например, был плагин, автоматизирующий сборку большого C++ проекта под Windows посредством MSBuild. Поскольку сама сборка выполнялась около часа, небольшое замедление, связанное с работой Yasca и кодечекеров роли не играло. Зато на выходе мы получали отчет, содержащий и Warning-и и замечания по Code Style, с удобным позиционированием в исходном коде.
Теги:
Хабы:
Всего голосов 8: ↑4 и ↓40
Комментарии4

Публикации

Истории

Работа

PHP программист
203 вакансии

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
24 сентября
Astra DevConf 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн