Показаны сообщения с ярлыком статистика. Показать все сообщения
Показаны сообщения с ярлыком статистика. Показать все сообщения

суббота, 17 ноября 2012 г.

Статистика, diff, подсветка

Здесь я уже рассказывал, как с помощью утилиты diffstat можно выводить статистические данные по коммитам в Subversion, систематизированные по отдельным пользователям. На этот раз я хочу расширить возможности данного подхода путем абстрагирования параметров систематизации и улучшения пользовательского интерфейса. Вторая задача, в частности, означает, что команда-однострочник будет заменена программой с возможностью задания различных опций. Программа представляет собой bash-скрипт и выглядит так:
#!/bin/bash - 

PrintUsage()
{
    echo "Usage: `basename $0` [-m] [-l level] [-p pattern] [-w width] [path]"
    echo "  -m          calulate modifications, insertions and deletions"
    echo "  -l level    history level of svn log command"
    echo "  -p pattern  filter commits according pattern"
    echo "  -w width    width of diffstat histogram"
    echo "  path        in specified file or directory only"
}

while [ $1 ]
do
    case $1 in
        -h|-help|--help)    PrintUsage ; exit 0 ;;
        -m)                 modifications=-m ;;
        -l)                 shift ; level="-l $1" ;;
        -p)                 shift ; pattern=$1 ;;
        -w)                 shift ; width="-w $1" ;;
        *)                  path=$path' '$1 ;;
    esac
    shift
done

for revision in \
    `svn log $level $path | grep '^r[0-9]\+.*'$pattern | awk '{print $1}' |\
     sed 's/r//g'`
do
    svn diff -c$revision $path
done | diffstat -v $modifications -f 4 $width
Львиную долю кода составляет функция PrintUsage() и разбор опций командной строки. Основной код размещен внутри цикла for и представляет собой ту же самую, слегка видоизмененную, однострочную команду. Кстати, PrintUsage() дает полное представления об опциях программы и я не буду на них останавливаться. Я поместил этот код внутрь исполняемого файла svndiffstat в директории $HOME/bin/.

Теперь мы сделаем так, чтобы вывод скрипта был подсвечен. Я показывал, как этого можно добиться с помощью программы hl здесь и здесь. Следуя данной схеме, определим сниппет dstat в $HOME/.hlrc:
snippet dstat   -196 '\++[!-]*$' '(?<=\|)\s*\d+\s*\d+' '\d+ (?=insertion)' \
                '(?<=\()\+(?=\))' \
                -33 '\-+!*$' '(?<=\|)\s*\d+\s*\d+\s*\d+' '\d+ (?=deletion)' \
                '(?<=\()-(?=\))' \
                -30 '!+$' '(?<=\|)\s*\d+\s*\d+\s*\d+\s*\d+' \
                '\d+ (?=modification)' '(?<=\()!(?=\))' \
                -101 '(?<=\|)\s*\d+' -82 '\s+\|\s+' -155 '/' -215 '[^/]+\s+\|' \
                -203 '^\s*[^/]+/' -155 '\d+ (?=file)'
и новую функцию svndiffstat в $HOME/.hl_functions:
function svndiffstat
{
    `env which svndiffstat` $@ | hl -sdstat
}
Результат работы svndiffstat представлен на картинке:


Здесь была запрошена статистика по коммитам за февраль 2011 года. Фактически значение опции -p задает регулярное выражение для поиска внутри строки, выводимой командой svn log и начинающейся с номера ревизии, такая строка включает имя пользователя, дату коммита и число измененных строк: это и есть параметры, по которым можно осуществлять выборку. Представленная статистика была собрана в соответствии с метаданными svn, находящимися внутри текущей директории, кроме того, svndiffstat позволяет изменить директорию для сбора статистики, если таковая будет задана в конце списка аргументов командной строки.

Кстати говоря, поскольку программа hl не включает подсветку при выводе в пайп, то можно изменять правила подсветки вывода svndiffstat, например добавить подсветку слова Energy в примере на картинке:
$ svndiffstat -p 2011-02 -w 60 -m | hl -sdstat -98 Energy
Раз уж речь зашла о diff и подсветке вывода программ, то хотелось бы привести соответствующие настройки .hlrc и .hl_functions. (Кстати, раньше для подсветки diff я использовал программу colordiff. Однако colordiff имела существенный недостаток: невозможность использования всех цветов на 256-цветных терминалах.)

Итак, в .hlrc следует добавить
snippet diff    -155 -b '^Index:\s+.*' '^=+$' '^diff.*' '^Binary.*' \
                -180 '^Только.*' '^\\.*' -76 '^@.*' '^\d.*' -rb -196 '^[+>].*' \
                -26 '^[-<].*'
a в .hl_functions
function diff
{
    `env which diff` $@ | hl -sdiff
}

function svndiff
{
    svn diff $@ | hl -sdiff
}
Теперь вывод diff будет всегда подсвечиваться на экране терминала. Кроме того, здесь определена еще одна функция svndiff для подсветки, как не трудно догадаться, вывода команды svn diff. Кстати, наверняка нам понадобятся аналогичные определения cvsdiff, gitdiff, hgdiff и т.п. Чтобы не плодить множество подобных функций, можно воспользоваться командой оболочки eval внутри цикла for по всем типам VCS, которая определит все функции за нас:
for vcs in cvs svn hg git ; do
    eval "function ${vcs}diff
    {
        $vcs diff \$@ | hl -sdiff
    }"
done
В дополнение к сказанному, хочу затронуть тему вывода на экран терминала подсвеченного программного кода. Универсальные подсветчики типа hl или grc здесь не очень подходят, так как писать сложные правила подсветки для множества языков программирования с использованием одних только регулярных выражений - задача нереальная. Поэтому для этой цели я использую программу GNU source-highlight, обернув ее, как обычно, в новую функцию оболочки. Функцию я назвал cathl и поместил ее в $HOME/.bashrc.
function cathl
{
    source-highlight -f esc -q -i $@
}
Функция cathl выводит на экран терминала содержимое своего аргумента - исходного файла. Если нужно вывести подсвеченный код в другой файл, то следует добавить в список аргументов после (здесь это важно) имени исходного файла опцию -o output-file. Кроме этого в cathl в принципе доступны другие опции source-highlight, например указание языка исходного текста там где это нужно. Однако изменить формат вывода (опция -f) в cathl не получится, так как он уже закреплен за цветовыми escape последовательностями терминала (-f esc).

Главным недостатком source-highlight лично для меня является недоступность всей 256-цветовой палитры для подсветки. Однако в последней версии 3.1.7 этот недостаток отсутствует. У меня в Fedora 17 стоит более старая версия 3.1.4, ну а если вам повезло, или вы сами решите собрать source-highlight из исходников, то можете смело заменять -f esc в cathl на -f esc256.

вторник, 17 августа 2010 г.

Приемы визуализации состояния кода под управлением Subversion

Здесь я не буду рассматривать стандартные приемы визуализации типа svn log, svn log -v и т.п. Вместо этого я хотел бы показать несколько скриптов-однострочников, которые можно запустить из командной строки оболочки и которые эффективно отражают состояние рабочей версии кода, управляемого системой контроля версий. Поскольку я чаще всего работаю с Subversion, я выбрал именно эту систему контроля версий, хотя это вовсе не обязательное условие и в принципе эти команды при необходимости могут быть адаптированы под любую другую систему, например CVS. В качестве примера рабочей версии кода я взял свой проект sudokurapid. Итак, переходим к приемам.
  1. Самая простая задача. Найти все исходники (например, .cc и .h файлы) в рабочей директории и вывести статистику по количеству строк, слов и символов. В данном случае присутствие какой-либо системы контроля версий вообще не требуется.
    $ find . -name '*.cc' -o -name '*.h' | xargs wc | sort -n
       33    60   651 ./sudokuRapidCommon.h
       62   146  1201 ./sudokuRapidQt/main.cc
       66   129  1277 ./sudokuRapidQt/sudokuForm.h
       66   156  1456 ./sudokuRapidQt/sudokuScene.h
      117   272  2684 ./sudokuRapidQt/sudokuCell.h
      167   373  3654 ./sudokuRapid.h
      171   497  4244 ./sudokuRapidConsole/main.cc
      175   603  4738 ./sudokuRapidQt/sudokuScene.cc
      191   499  4377 ./sudokuRapidQt/sudokuForm.cc
      248   781  6609 ./sudokuRapidQt/sudokuCell.cc
      481  1702 14315 ./sudokuRapid.cc
     1777  5218 45206 итого 
  2. Вывести список всех ревизий, выделив разными цветами имена отдельных пользователей (в данном проекте только один пользователь lyokha, но допустим, что имеется еще один пользователь someone)
    $ svn log | grep '^r[0-9]' | hl -46 lyokha -47 someone
    r16 | lyokha | 2010-08-17 11:40:36 +0400 (Втр, 17 Авг 2010) | 2 lines
    r15 | lyokha | 2009-03-23 16:22:27 +0300 (Пнд, 23 Мар 2009) | 2 lines
    r14 | lyokha | 2009-03-23 15:16:04 +0300 (Пнд, 23 Мар 2009) | 11 lines
    r13 | lyokha | 2009-02-19 22:00:51 +0300 (Чтв, 19 Фев 2009) | 2 lines
    r12 | lyokha | 2009-02-16 14:39:36 +0300 (Пнд, 16 Фев 2009) | 2 lines
    r11 | lyokha | 2009-02-16 14:23:15 +0300 (Пнд, 16 Фев 2009) | 5 lines
    r10 | lyokha | 2009-02-14 17:28:27 +0300 (Сбт, 14 Фев 2009) | 2 lines
    r9 | lyokha | 2009-02-14 16:04:59 +0300 (Сбт, 14 Фев 2009) | 3 lines
    r8 | lyokha | 2009-02-12 19:45:31 +0300 (Чтв, 12 Фев 2009) | 18 lines
    r7 | lyokha | 2009-02-11 23:27:04 +0300 (Срд, 11 Фев 2009) | 2 lines
    r6 | lyokha | 2009-02-11 22:08:13 +0300 (Срд, 11 Фев 2009) | 13 lines
    r5 | lyokha | 2009-02-07 14:39:56 +0300 (Сбт, 07 Фев 2009) | 2 lines
    r4 | lyokha | 2009-02-06 14:06:17 +0300 (Птн, 06 Фев 2009) | 3 lines
    r3 | lyokha | 2009-02-06 11:31:39 +0300 (Птн, 06 Фев 2009) | 2 lines
    r2 | lyokha | 2009-02-06 11:27:49 +0300 (Птн, 06 Фев 2009) | 2 lines
    r1 | lyokha | 2009-02-05 16:24:32 +0300 (Чтв, 05 Фев 2009) | 2 lines

    В данном случае я использовал утилиту hl, которая позволяет подсвечивать разными цветами (46 и 47 - это номера цветов для 256-цветного терминала) шаблоны (lyokha и someone) прямо в терминале. Если бы в списке был пользователь someone, его имя было бы подсвечено другим цветом. 
  3. Вывести статистику работы для определенного пользователя (lyokha) в псевдографическом виде. Здесь я использую замечательную утилиту diffstat:
    $ for i in `svn log | grep lyokha | awk '{print $1}' | sed 's/r//'`
    > do svn diff -c$i
    > done | diffstat -m -f 4 -w 80
     ChangeLog                       |   62    62     0     0 ++++
     Makefile.am                     |   41    36     0     5 ++!
     README                          |   37    37     0     0 ++
     configure.ac                    |   77    72     0     5 +++++
     sudokuRapid.cc                  |  539   507    26     6 +++++++++++++++++++++++++++++++++++++--
     sudokuRapid.h                   |  172   169     2     1 ++++++++++++
     sudokuRapidCommon.h             |   33    33     0     0 ++
     sudokuRapidConsole/Makefile.am  |    4     3     0     1 
     sudokuRapidConsole/configure.ac |   23    23     0     0 +
     sudokuRapidConsole/getStat.sh   |   54    54     0     0 ++++
     sudokuRapidConsole/main.cc      |  172   171     0     1 ++++++++++++
     sudokuRapidQt/main.cc           |   63    62     0     1 ++++
     sudokuRapidQt/sudokuCell.cc     |  346   256     8    82 ++++++++++++++++++-!!!!
     sudokuRapidQt/sudokuCell.h      |  138   117     0    21 ++++++++!!
     sudokuRapidQt/sudokuForm.cc     |  274   215    24    35 +++++++++++++++--!
     sudokuRapidQt/sudokuForm.h      |   72    68     2     2 +++++
     sudokuRapidQt/sudokuForm.ui     |   97    97     0     0 +++++++
     sudokuRapidQt/sudokuRapidQt.pro |   16    15     0     1 +
     sudokuRapidQt/sudokuScene.cc    |  205   182     7    16 +++++++++++++-
     sudokuRapidQt/sudokuScene.h     |   71    67     1     3 ++++-
     sudokurapid.spec                |  103    91     3     9 ++++++
     21 files changed, 2337 insertions(+), 73 deletions(-), 189 modifications(!)
    В первом столбце указано имя файла, в следующих - общее количество измененных строк, количество вставленных, удаленных и измененных строк, а также псевдографическая гистограмма активности изменений. Стоит заметить, что количество измененных строк (отмеченных символом !) определяется эвристически на основе анализа отдельных чанков, и поэтому в редких случаях баланс вставленных/удаленных/измененных строк может немного не соответствовать действительности.
  4. Можно графически визуализировать процесс изменения репозитория во времени с использованием утилиты gource. gource не поддерживает Subversion напрямую, поэтому нам понадобится дополнительный скрипт svn-gource.py. Приготовления включают создание промежуточных файлов:
    svn log --verbose --xml > sudokurapid.log
    svn-gource.py --filter-dirs sudokurapid.log > sudokurapid-gource.log
    После этого запускаем
    gource --log-format custom sudokurapid-gource.log
    откидываемся на спинку кресла и смотрим замечательный фильм. Вот, например, один из кадров: