вторник, 18 октября 2011 г.

Создание pull request-а для GitHub из командной стркоки

Для создания pull request-а на GitHub следует выполнить следующую команду:

curl -i -u "your-name:your-passwd" https://api.github.com/repos/his-name/his-repo/pulls -d '{"title": "Title of pull request", "body": "Body of pull request", "head":"your-repo:your-branch", "base":"his-branch"}'

пятница, 30 сентября 2011 г.

Установка и настройка сервера непрерывной интеграции phpUnderControl

Описание


Сервер непрерывной интеграции (CI - Continuous Integration) предназначен для автоматической периодической сборки проектов, запуска модульных тестов, проверки кода на наличие распространенных ошибок и формирования ряда других отчетов. В качестве CI-сервера будет использоваться CruiseСontrol (CC) с дополнением phpUnderControl. CС запускается в качестве демона, периодически опрашивает SVN-репозиторий и, в случае наличия изменений, создает локальную копию, над которой в дальнейшем производится ряд определенных действий. Для выполнения этих действий в нужной последовательности используется утилита Ant (также поддерживается работа с его php-клоном phing), которая поставляется в комплекте с CC.


Дополнение phpUnderControl предоставляет консольную утилиту phpuc которая дополняет CC рядом шаблонов, а также позволяет быстро добавлять/удалять проекты в CC. В phpUnderControl встроена поддержка проверки синтаксиса php-кода, а также следующих утилит:


phpunit

автоматизированное тестирование приложения

phpdoc

PhpDocumentor - автоматическая генерация документации

phpcb

PHP_CodeBrowser - просмотр кода онлайн (включая подсветку и описание проблемных мест, таких как: нарушение стандартов кодирования, дублирование кода, высокая сложность кода)

phpcs

PHP_CodeSniffer - обнаружение нарушений стандартов кодирования

ezcGraph

простроение графиков изменения контролируемых параметров с течением времени


Кроме того есть возможность добавить поддержку других утилит, таких как:

phpmd

анализ сложности исходного кода

phpcpd

поиск дублирующегося кода


Скриншоты


Главная страница: список проектов, ручной запуск сборок:

Страница с результатами выполнения тестов phpunit:

Страница метрик, изменение контролируемых параметров от сборки к сборке:

Страница, отображающая покрытие кода тестами:

Онлайн-просмотр кода с подсветкой и описанием проблемных участков (оформление, сложность, дублирование и пр.):

Онлайн документация:

Страница отчета о нарушениях стандартов кодирования:

Страница отчета сложности кода, дублирования кода и других проблем:

Просмотр продублированного кода:


Установка CruiseСontrol


Для работы сервера CC нужна java-машина, устанавливаем, если еще не установлена:

sudo apt-get install sun-java6-bin

Затем следует скачать архив с последней версией CC с сайта http://cruisecontrol.sourceforge.net/download.html (на момент написания последней была версия 2.8.4) и распаковать в локальный каталог (в данном примере /opt):

sudo unzip cruisecontrol-bin-2.8.4.zip -d /opt

Для удобства обновлений программы можно создать символическую ссылку cruisecontrol, которая будет указывать на используемую версию данного ПО:

cd /opt
sudo ln -s cruisecontrol-bin-2.8.4 cruisecontrol

Теперь, когда CC-сервер установлен, можно настроить его автоматический запуск при старте системы. Для этого следует добавить нового пользователя, от имени которого будет запускаться процесс CC, разместить стартовый скрипт cruisecontrol (приложение А) в каталоге /etc/init.d/ (для debian-подобных систем), установить необходимые для его запуска права и, собственно, настроить автозапуск:

sudo adduser --system --group --home /opt/cruisecontrol cruisecontrol
sudo chown -R cruisecontrol:cruisecontrol /opt/cruisecontrol-bin-2.8.4 /opt/cruisecontrol
sudo cp cruisecontrol /etc/init.d/cruisecontrol
sudo chmod 755 /etc/init.d/cruisecontrol
sudo update-rc.d cruisecontrol defaults

Теперь вручную сервер CC можно запустить командой

sudo /etc/init.d/cruisecontrol start

Остановить:

sudo /etc/init.d/cruisecontrol stop

Для отладочных целей запуск сервера CC можно выполнить командой (из каталога /opt/cruisecontrol/):

sudo ./cruisecontrol.sh -configfile /opt/cruisecontrol/config.xml -webport 8080 -jmxport 8082 -rmiport

После успешного запуска CC-сервера должен быть доступен адрес http://localhost:8080.


Возможна проблема при запуске CC сервера, когда в файл /opt/cruisecontrol/cruisecontrol.sh из стартового скрипта не передается переменная окружения JAVA_HOME. Одним из вариантов решения данной проблемы может быть запись строки JAVA_HOME=/usr/lib/jvm/java-6-sun в общесистемный файл /etc/environment. Также, в качестве временного решения, можно указать значение этой переменной непосредственно в файле /opt/cruisecontrol/cruisecontrol.sh. Однако при использовании в стартовом скрипте команды su cruisecontrol -p -c ... этой проблемы возникать не должно.


Установка phpUnderControl и необходимых модулей


Прежде чем переходить к установке phpuc следует проверить наличие требуемых модулей, и установить/обновить недостающие (может потребоваться обновление xdebug и pear installer):

sudo apt-get install php5-xdebug
sudo pear install PhpDocumentor
sudo pear install PHP_CodeSniffer
sudo pecl install pecl/xdebug
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit
sudo pear install phpunit/phpcpd
sudo pear upgrade pear
sudo pear install phpunit/PHP_CodeBrowser

Далее можно перейти к установке phpuc (на момент написания использовалась версия 0.6.1beta1):

sudo pear channel-discover components.ez.no
sudo pear channel-discover pear.phpundercontrol.org
sudo pear install --alldeps phpuc/phpUnderControl-beta

А также установить дополнительные модули, поддержка которых в phpUnderControl на данный момент реализована лишь частично (требуется ручная правка конфигов):

sudo pear channel-discover pear.phpmd.org
sudo pear channel-discover pear.pdepend.org
sudo pear install --alldeps phpmd/PHP_PMD
sudo pear install --alldeps phpunit/PHPCPD

phpuc представляет собой консольную утилиту для взаимодействия с установленной версией CC. Следующая команда скопирует набор дополнительных файлов и шаблонов для веб-интерфейса в каталоги с установленной копией CC:

sudo phpuc install /opt/cruisecontrol


Добавление проектов


Утилита phpuc также предоставляет команды для быстрого добавления проектов под управление ci-сервера (следующая команда - это одна строка, отформатированная для удобства чтения):


sudo phpuc project
--ant-script /opt/cruisecontrol/apache-ant-1.7.0/bin/ant
--version-control svn
--version-control-url file://localhost/home/user/svn/myProjectName/trunk
--coding-guideline Zend
--source-dir application
--test-dir tests
--project-name myProjectName
/opt/cruisecontrol


В результате работы данной команды


  1. в каталоге projects CC-сервера будут созданы подкаталоги для указанного проекта

  2. в конфигурационный файл СС будет добавлена новая секция <project/> (см. приложение Б). Стоит отметить что нода <shedule/> отвечает за выполнение запланированных для проекта действий (в данном примере каждые 300 сек. будет запускаться указанный ant-скрипт)

  3. в каталоге проекта будет создан файл build.xml (см. приложение В), содержащий ряд заданий для последующих регулярных сборок проекта

  4. выполнена команда svn checkout

Для удаления проекта следует использовать команду

sudo phpuc delete myProjectName


Настройка проектов


На данном этапе мы должны получить готовую автоматическую систему сборки и тестирования проектов, однако она может нуждаться в дополнительных доработках. В частности для цели lint (файл build.xml проекта) можно исключить из списка проверяемых путей некоторые каталоги (например каталог с дистрибутивом Zend) - это уменьшит время сборки:


<target name="lint">
<apply executable="php" dir="${basedir}/source" failonerror="on" logerror="on">
<arg line="-l"/>
<fileset dir="${basedir}/source">
<include name="**/*.php"/>
<exclude name="library/Zend/**/*.php"/>
</fileset>
</apply>
</target>


Для публикации отчетов о проблемах кода (phpmd) следует добавить новую цель:


...
<target name="phpmd">
<exec executable="phpmd" dir="${basedir}/source">
<arg line="application
xml
codesize,unusedcode,naming
--reportfile ${basedir}/build/logs/phpmd.xml"/>
</exec>
</target>
...

А также не забыть указать её в зависимостях цели сборки по умолчанию:

<target name="build" depends="checkout,lint,php-documentor,php-codesniffer,phpunit,phpcpd,phpmd,pdepend"/>


Для публикации отчетов о дублировании кода (phpcpd) нужно также добавить вручную новую цель в файл build.xml:


...
<target name="phpcpd" >
<exec executable="phpcpd" failonerror="false">
<arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml
${basedir}/source/application" />
</exec>
</target>
...

А также не забыть указать её в зависимостях цели сборки по умолчанию:

<target name="build" depends="checkout,lint,php-documentor,php-codesniffer,phpunit,phpcpd,phpmd,pdepend"/>


Для построении графиков внутренних зависимостей кода (pdepend) нужно добавить следующую цель в build.xml:


...
<target name="pdepend" depends="lint">
<exec executable="pdepend" dir="${basedir}/source" logerror="on">
<arg line="--summary-xml=${basedir}/build/logs/pdepend.xml
--jdepend-chart=${basedir}/build/graph/jdepend.svg
--overview-pyramid=${basedir}/build/graph/overview-pyramid.svg
--coderank-mode=inheritance,property,method
application" />
</exec>
</target>
...

А также не забыть указать её в зависимостях цели сборки по умолчанию:

<target name="build" depends="checkout,lint,php-documentor,php-codesniffer,phpunit,phpcpd,phpmd,pdepend"/>

Кроме того, для публикации этих графиков на странице метрик, следует добавить в ноду <publishers/> соответствующего проекта в файле config.xml следующую строку:

<publishers>
...
<artifactspublisher subdirectory="graph" dest="artifacts/${project.name}" dir="projects/${project.name}/build/graph"/>
...
</publishers>


Можно добавить и другие цели, которые могут потребоваться для сборки проекта, например создание необходимых каталогов, установка прав на файлы и каталоги, подготовка БД, выполнение других скриптов, минимизация css, js и др.


Наконец, есть возможность рассылать уведомления об удачных и неудачных сборках на email, jabber и др. Ниже пример для рассылки e-mail уведомлений:


<publishers>
...
<email mailhost="localhost"
returnaddress="cruisecontrol@my.marketgid.net"
buildresultsurl="http://localhost:8080/cruisecontrol/buildresults/mgtest"
skipusers="true" spamwhilebroken="true">
<map alias="management" address="root@localhost" />
<map alias="qa" address="user@localhost" />
<map alias="developer" address="user@my.marketgid.net" />
<always address="management" />
<success address="qa" />
<failure address="developer" reportWhenFixed="true" />
</email>
...
</publishers>

В данном случае определены 3 группы получателей; первая группа management получает уведомления о всех сборках, вторая группа qa только об удачных сборках, и третья группа developer о неудачных.


Примеры окончательного варианта файлов настроек config.xml и build.xml в приложении Г и приложении Д.




http://habrahabr.ru/blogs/php/68571/

на русском, есть неточности

http://nohn.net/blog/view/id/cruisecontrol_ant_and_phpunit

настройка phpunit+ant, рассылка email-ов

http://www.phpunit.de/manual/3.2/en/continuous-integration.html

пример cli для phpuc (создание проекта в сс)

http://recursive-design.com/blog/2011/05/13/continuous-integration-for-php-with-php-under-control/

подробное руководство

http://techportal.ibuildings.com/2009/03/03/getting-started-with-phpundercontrol/

неполный мануал и пример выполнения sql-кода в ant

http://topecoders.blogspot.com/2010/05/how-to-configure-phpundercontrol.html

пример cli phpuc для zend, добавление нового таба

http://criticallog.thornet.net/2010/03/02/integrate-php_depend-with-phpundercontrol/

настройка pdepend (+см. комментарии)

http://zendframework.ru/articles/continuous-integration-and-cruisecontrol

CC с учетом специфики zf


Приложение А - скрипт для автоматического запуска CC при загрузке ОС


Скрипт отличается от источника установленными значениями переменных, а также опцией команды su -p, что решает проблему передачи переменной окружения JAVA_HOME серверу CC. Стоить отметить что инициализацию переменных можно вынести в отдельный файл /etc/default/cruisecontrol. Значения, указанные в этом файле, будут иметь приоритет (имеет смысл воспользоваться этой возможностью, если принято решение собрать deb-пакет для установки сервера CC).


#!/bin/sh
#content of /opt/cruisecontrol/init script
# chkconfig: 345 99 05
# description: CruiseControl build loop (see /home/tools)

# CruiseControl Unix Startup Script Version 2.1
#
# based on http://confluence.public.thoughtworks.org/display/CC/UnixStartupScriptVersion1.x
# adapted for multiple projects
# also based on the file attached to the above page created by Jerome Lacoste

#
# CruiseControl startup: Startup and kill script for Cruise Control
#


###################################################################################################
# USER CONFIGURATION
#
# Fill in these values for your Cruise Control setup

# What user will Cruise Control run as? The user will need permission to write and modify files
# in the next entries.
CC_USER=cruisecontrol


# Where is the CC startup script located?
CC_INSTALL_DIR=/opt/cruisecontrol

# In what directory is the config.xml file located for CC?
# default: CC_WORK_DIR=$CC_INSTALL_DIR
CC_WORK_DIR=$CC_INSTALL_DIR

# Where will the cruisecontrol.log file be located?
# default: CC_LOGFILE_DIR=$CC_INSTALL_DIR
CC_LOGFILE_DIR=$CC_INSTALL_DIR


#######################
# ENVIRONMENT ADDITIONS

# Add environement variables here that are needed by your build.
# example:
# export JAVA_HOME=/usr/local/java
#
# or like this for local variables ONLY used in this file:
# JAVA_HOME=/usr/local/java
JAVA_HOME=/usr/lib/jvm/java-6-sun
export JAVA_HOME

# Add path to additional executables needed for project build. See PATH entry below for base config.
# No additional action taken when blank.
PATH_ADDITIONS=



##############################
# CRUISE CONTROL PORT SETTINGS

# Port for Jetty reporting application. You can access it by going to http://localhost:8080
# default CC_WEBPORT=8080
CC_WEBPORT=8080

# JMX port for webapp and Java Management eXtensions (JMX). You can access it by going to http://localhost:8080
# Change only if this port is in use as the webapp will also need modification.
# default CC_JMXPORT=8082
CC_JMXPORT=8082

# RMI port for control via Java's Remote Management Interface (RMI)
# Leave blank to disable.
CC_RMIPORT=



###################################################################################################
# DO NOT MODIFY ENTRIES BELOW THIS LINE

NAME=cruisecontrol
DESC="CruiseControl - continuous integration build loop"


PATH=/sbin:/usr/sbin:/usr/bin:/bin
# add additions if variable has text defined
if [ -n "$PATH_ADDITIONS" ]; then
PATH=$PATH_ADDITIONS:$PATH
fi
export PATH


CC_DAEMON=$CC_INSTALL_DIR/cruisecontrol.sh

CC_CONFIG_FILE=$CC_WORK_DIR/config.xml

CC_LOG_FILE=$CC_LOGFILE_DIR/cruisecontrol.log

CC_COMMAND="$CC_DAEMON -configfile $CC_CONFIG_FILE -webport $CC_WEBPORT -jmxport $CC_JMXPORT -rmiport $CC_RMIPORT"

# overwrite settings from default file
if [ -f /etc/default/cruisecontrol ]; then
. /etc/default/cruisecontrol
fi

# does the executable exist?
test -f $CC_DAEMON || (echo "The executable $CC_DAEMON does not exist!" && exit 0)

if [ `id -u` -ne 0 ]; then
echo "Not starting/stopping $DESC, you are not root."
exit 4
fi

# Get the PID output from the startup script
if [ -f $CC_INSTALL_DIR/cc.pid ]; then
CC_PID=`cat $CC_INSTALL_DIR/cc.pid`
else
echo "No cc.pid file found. CC process may not be controllable from this script!"
fi


case "$1" in

'start')
cd $CC_INSTALL_DIR
# echo "CC environtment at startup" &gt; cc.startup.env
# env &gt;&gt; cc.startup.env
su $CC_USER -p -c "/bin/sh -c \"$CC_COMMAND &gt;&gt; $CC_LOG_FILE 2&gt;&1\"" & RETVAL=$?
echo "$NAME started with jmx on port ${CC_JMXPORT}"
;;

'stop')
if [ -n "$CC_PID" ] && ps -p ${CC_PID} &gt; /dev/null ; then
kill -9 ${CC_PID}
$0 status
RETVAL=$?
else
echo "$NAME is not running"
RETVAL=1
fi
;;

'status')
if [ -n "$CC_PID" ] && ps -p ${CC_PID} &gt; /dev/null ; then
echo $NAME \(pids $CC_PID\) is running
RETVAL=0
else
echo "$NAME is stopped"
RETVAL=1
fi
;;

'restart')
$0 stop && $0 start
RETVAL=$?
;;

*)
echo "Usage: $0 { start | stop | status | restart }"
exit 1
;;
esac
#echo ending $0 $$....
exit 0;


Приложение Б - project-секция config.xml для проекта myProjectName



<cruisecontrol>
...
<project name="myProjectName" buildafterfailed="false">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<modificationset>
<svn localWorkingCopy="/opt/cruisecontrol/projects/myProjectName/source"/>
</modificationset>
<bootstrappers>
<svnbootstrapper localWorkingCopy="/opt/cruisecontrol/projects/myProjectName/source"/>
</bootstrappers>
<schedule interval="300">
<ant buildfile="projects/${project.name}/build.xml" antscript="/opt/cruisecontrol/apache-ant-1.7.0/bin/ant"/>
</schedule>
<log dir="logs/${project.name}">
<merge dir="projects/${project.name}/build/logs/"/>
</log>
<publishers>
<artifactspublisher dir="projects/${project.name}/build/api" dest="artifacts/${project.name}" subdirectory="api"/>
<artifactspublisher dir="projects/${project.name}/build/coverage" dest="artifacts/${project.name}" subdirectory="coverage"/>
<execute command="phpcb --log projects/${project.name}/build/logs --source projects/${project.name}/source/application --output projects/${project.name}/build/php-code-browser"/>
<artifactspublisher dir="projects/${project.name}/build/php-code-browser" dest="artifacts/${project.name}" subdirectory="php-code-browser"/>
<execute command="/usr/bin/phpuc graph logs/${project.name} artifacts/${project.name}"/>
</publishers>
</project>
...
</cruisecontrol>


Приложение В - сгенерированный конфигурационный файл build.xml для проекта myProjectName



<?xml version="1.0" encoding="UTF-8"?>
<project name="myProjectName" default="build" basedir=".">
<target name="build" depends="checkout,lint,php-documentor,php-codesniffer,phpunit"/>
<target name="checkout">
<exec executable="svn" dir="${basedir}/source" failonerror="on">
<arg line="up"/>
</exec>
</target>
<target name="lint">
<apply executable="php" dir="${basedir}/source" failonerror="on" logerror="on">
<arg line="-l"/>
<fileset dir="${basedir}/source">
<include name="**/*.php"/>
</fileset>
</apply>
</target>
<target name="php-documentor" depends="lint">
<exec executable="phpdoc" dir="${basedir}/source" logerror="on">
<arg line="--title '${ant.project.name}' -ue on -t ${basedir}/build/api -d application -tb '/usr/share/php/data/phpUnderControl/data/phpdoc' -o HTML:Phpuc:phpuc"/>
</exec>
</target>
<target name="php-codesniffer" depends="lint">
<exec executable="phpcs" dir="${basedir}/source" output="${basedir}/build/logs/checkstyle.xml" error="/tmp/checkstyle.error.log">
<arg line="--report=checkstyle --standard=Zend application"/>
</exec>
</target>
<target name="phpunit" depends="lint">
<exec executable="phpunit" dir="${basedir}/source" failonerror="on">
<arg line=" --log-junit ${basedir}/build/logs/phpunit.xml --coverage-clover ${basedir}/build/logs/phpunit.coverage.xml --coverage-html ${basedir}/build/coverage tests"/>
</exec>
</target>
</project>


Приложение Г - пример окончательного варианта файла настройки проекта в config.xml



<?xml version="1.0"?>
<cruisecontrol>
...
<project name="myProjectName" buildafterfailed="false">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<modificationset>
<svn localWorkingCopy="/opt/cruisecontrol/projects/myProjectName/source"/>
</modificationset>
<bootstrappers>
<svnbootstrapper localWorkingCopy="/opt/cruisecontrol/projects/myProjectName/source"/>
</bootstrappers>
<schedule interval="300">
<ant buildfile="projects/${project.name}/build.xml" antscript="/opt/cruisecontrol/apache-ant-1.7.0/bin/ant"/>
</schedule>
<log dir="logs/${project.name}">
<merge dir="projects/${project.name}/build/logs/"/>
</log>
<publishers>
<artifactspublisher dir="projects/${project.name}/build/api" dest="artifacts/${project.name}" subdirectory="api"/>
<artifactspublisher dir="projects/${project.name}/build/coverage" dest="artifacts/${project.name}" subdirectory="coverage"/>
<execute command="phpcb --log projects/${project.name}/build/logs --source projects/${project.name}/source --output projects/${project.name}/build/php-code-browser"/>
<artifactspublisher dir="projects/${project.name}/build/php-code-browser" dest="artifacts/${project.name}" subdirectory="php-code-browser"/>
<execute command="/usr/bin/phpuc graph logs/${project.name} artifacts/${project.name}"/>
<artifactspublisher subdirectory="graph" dest="artifacts/${project.name}" dir="projects/${project.name}/build/graph"/>
<email mailhost="localhost"
returnaddress="cruisecontrol@my.marketgid.net"
buildresultsurl="http://localhost:8080/cruisecontrol/buildresults/myProjectName"
skipusers="true" spamwhilebroken="true">
<map alias="management" address="root@localhost" />
<map alias="qa" address="user@localhost" />
<map alias="developer" address="user@my.marketgid.net" />
<always address="management" />
<success address="qa" />
<failure address="developer" reportWhenFixed="true" />
</email>
</publishers>
</project>
...
</cruisecontrol>


Приложение Д - пример окончательного варианта файла build.xml



<?xml version="1.0" encoding="UTF-8"?>
<project name="mgtest" default="build" basedir=".">
<target name="build" depends="checkout,mkdirs,lint,php-documentor,php-codesniffer,phpunit,phpcpd,phpmd,pdepend"/>
<target name="checkout">
<exec executable="svn" dir="${basedir}/source" failonerror="on">
<arg line="up"/>
</exec>
</target>
<target name="lint">
<apply executable="php" dir="${basedir}/source" failonerror="on" logerror="on">
<arg line="-l"/>
<fileset dir="${basedir}/source">
<include name="**/*.php"/>
<exclude name="library/Zend/**/*.php"/>
</fileset>
</apply>
</target>
<target name="mkdirs">
<mkdir dir="${basedir}/source/cache/models"/>
</target>
<target name="php-documentor" depends="lint">
<exec executable="phpdoc" dir="${basedir}/source" logerror="on">
<arg line="--title '${ant.project.name}'
-ue on
-t ${basedir}/build/api
-d application
-tb '/usr/share/php/data/phpUnderControl/data/phpdoc'
-o HTML:Phpuc:phpuc"/>
</exec>
</target>
<target name="php-codesniffer" depends="lint">
<exec executable="phpcs" dir="${basedir}/source" output="${basedir}/build/logs/checkstyle.xml" error="/tmp/checkstyle.error.log">
<arg line="--report=checkstyle
--standard=Zend
application"/>
</exec>
</target>
<target name="phpmd">
<exec executable="phpmd" dir="${basedir}/source">
<arg line="application
xml
codesize,unusedcode,naming
--reportfile ${basedir}/build/logs/phpmd.xml"/>
</exec>
</target>
<target name="phpunit" depends="lint">
<exec executable="phpunit" dir="${basedir}/source/tests" failonerror="false">
<arg line="--bootstrap ${basedir}/source/tests/bootstrap.php
--log-junit ${basedir}/build/logs/phpunit.xml
--coverage-clover ${basedir}/build/logs/phpunit.coverage.xml
--coverage-html ${basedir}/build/coverage
."/>
</exec>
</target>
<target name="phpcpd" >
<exec executable="phpcpd" failonerror="false">
<arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml
${basedir}/source/application" />
</exec>
</target>
<target name="pdepend" depends="lint">
<exec executable="pdepend" dir="${basedir}/source" logerror="on">
<arg line="--summary-xml=${basedir}/build/logs/pdepend.xml
--jdepend-chart=${basedir}/build/graph/jdepend.svg
--overview-pyramid=${basedir}/build/graph/overview-pyramid.svg
--coderank-mode=inheritance,property,method
application" />
</exec>
</target>
</project>

вторник, 18 января 2011 г.

Отправка e-mail сообщений на несколько smtp-серверов с помощью masqmail и msmtp

Я придерживаюсь мнения, что провайдер должен предоставлять почтовый relay-сервер для корреспонденции своих клиентов. Однако встречаются провайдеры, у которых на этот счет другое мнение (один из таких - Укртелеком). С другой стороны, большинство бесплатных почтовых серверов принимают почту по smtp (с указанием имени и пароля пользователя). Но так как к моменту подключения ноутбука к сети интернет, в очереди будут сообщения написанные с нескольких почтовых аккаунтов, то, соответственно, потребуется отправка через несколько smtp-серверов. С этой задачей хорошо справляется msmtp. Чтобы добавить такую возможность к masqmail, следует написать route-файл следующего вида:

sudo cat > /etc/masqmail/route.utel-unlim
# mail_host="relay.ukrpost.ua"
protocol="pipe"
pipe="/usr/bin/msmtp -f ${return_path} -- ${rcpt}"
^C

Так как будет использоваться общесистемный конфиг msmtp, то потребуется создать (или скопировать из домашнего каталога) файл /etc/msmtprc с нужными настройками.

см. также

понедельник, 17 января 2011 г.

Автоматическая отправка почты на комьютере без постоянного подключения к интернет (masqmail, procmail)

Данный метод отправки почты лучше всего подойдет для компьютеров, работа за которыми производится под несколькими учетными записями, и которые не имеют постоянного подключения к сети интернет, а подключаются к различным провайдерам лишь периодически (например через ppp). В таком случае, после отправки сообщения пользователем, если подключение к интернет активно, оно будет отправлено незамедлительно, в противном случае оно попадет в очередь сообщений, а затем, при активации подключения, будет передано почтовому серверу провайдера (настройки подключения к серверу указываются отдельно для каждого провайдера).
За прием и обработку очереди сообщений отвечает почтовый сервер masqmail, который был создан именно для таких случаев. В debian начальная настройка производится при установке этого пакета (в дальнейшем его можно повторно перенастроить выполнив команду dpkg-reconfigure masqmail). Часть опций, отвечающих за интеграцию в систему debian записывается в файл /etc/default/masqmail:

$ cat /etc/default/masqmail
#
# better use 'dpkg-reconfigure masqmail'
# instead of editing by hand
#
INIT_SMTP_DAEMON="false"
INIT_QUEUE_DAEMON="false"
INIT_FETCH_DAEMON="false"
#
QUEUE_DAEMON_IVAL="-q10m"
FETCH_DAEMON_IVAL="-go5m"
#
IPUP_RUNQUEUE="true"
IPUP_FETCH="false"
IFUP_IFACES="all"


В моем случае при старте системы smtp-демон не запускается (стартует из inetd при запросе), получение почты с других серверов также отключено (для этих целей используется fetchmail). Обработка очереди производится при поднятии любого интерфейса (отрабатывают скрипты, установленные в /etc/network/if-up.d/ и /etc/ppp/ip-up.d/).
Главный конфиг masqmail выглядит так:

$ cat /etc/masqmail/masqmail.conf
### BEGIN DEBCONF SECTION
# Do not edit within this region if you want your changes to be preserved by
# debconf. Instead, make changes after the "### END DEBCONF SECTION" line.
host_name="kirill-u100"
local_hosts="localhost;kirill-u100;localhost.localdomain"
local_nets=""
listen_addresses="localhost:25"
spool_dir="/var/spool/masqmail"
mail_dir="/var/mail"
log_dir="/var/log/masqmail"
do_queue=false
use_syslog=false
online_detect=file
online_file="/var/run/masqmail-route"
mbox_default=mda
mda="/usr/bin/procmail -Y -d ${rcpt_local}"
alias_file=/etc/aliases
alias_local_caseless="false"
### END DEBCONF SECTION
#
# include the locations of your route and get configurations here.
# Examples:
# online_routes.default = "/etc/masqmail/default.route"
# online_gets.default = "/etc/masqmail/default.get"
# You can have more of those, with '.default' replaced with other
# names. See man 8 masqmail.conf.
#

online_routes.kyivstar-xl = "/etc/masqmail/route.kyivstar-xl"
online_routes.utel-unlim = "/etc/masqmail/route.utel-unlim"


Файлы настроек для передачи почты разным провайдерам перечислены в конце файла (строки вида online_routes.<provider_name> = <config_file>). Где <provider_name> устанавливается опцией ipparam при запуске ppp (в соответствующем файле из /etc/ppp/peers/).

Простейший пример одного из таких файлов:

$ sudo cat /etc/masqmail/route.kyivstar-xl
mail_host="relay.kyivstar.net"


Запуск masqmail из inetd производится следующим образом:

$ cat /etc/inetd.conf | grep masqmail
127.0.0.1:25 stream tcp nowait mail /usr/sbin/masqmail masqmail -bd -q -bs

см. также:

четверг, 13 января 2011 г.

Автоматическое получение почты на компьютере без постоянного подключения к интернет (debian, fetchmail, procmail)

см также:

Часть 2 - общесистемное получение почты


Для автоматического получения почты с помощью fetchmail необходимо изменить несколько конфигурационных файлов.
$ vi /etc/default/fetchmail
указать START_DAEMON=yes

Создать общесистемный конфигурационный файл для fetchmail (его можно скопировать из каталога с примерами):
$ sudo cp /usr/share/doc/fetchmail/examples/fetchmailrc.example /etc/fetchmailrc

Установить владельца и разумные права доступа к конфигурационному файлу с паролями:
$ sudo chown fetchmail:root /etc/fetchmailrc
$ sudo chmod 0600 /etc/fetchmailrc

Добавить в этот конфиг правила приема почты из всех почтовых ящиков для всех пользователей (пример полного конфига выглядит так):
$ sudo cat /etc/fetchmailrc

# /etc/fetchmailrc for system-wide daemon mode
# This file must be chmod 0600, owner fetchmail

set daemon 600
set no bouncemail
defaults:
antispam -1
batchlimit 100

poll freemail.ukr.net with proto POP3
user 'r*******@ukr.net' there with password '********' is 'reel' here options keep
mda 'procmail -d %T'
user 'm*********@ukr.net' there with password '********' is 'reel' here options keep
mda 'procmail -d %T'

poll imap.gmail.com with proto IMAP
user 'kirill.zabarniuk@gmail.com' there with password '********' is 'reel' here options keep ssl
mda 'procmail -d %T'

Основное отличие от правил, находящихся в ~/.fetchmailrc - это команда запуска mda 'procmail -d %T'. Ключ -d переключает procmail в режим доставки с правами получателя и с использьзованием конфига из его домашнего каталога (имя получателя будет подставлено вместо переменной %T).

На данный момент fetchmail будет запускаться при старте системы в режиме демона и периодически проверять доступность почтовых серверов. Можно перенастроить его так, чтобы демон запускался при поднятии сетевого интерфейса и завершал свою работу при пропадании сети. Инструкции можно найти в /usr/share/doc/fetchmail/README.Debian.gz (описаны шаги только для отслеживания состояния интерфейсов ppp, без учета возможности подключения через eth; возможно поэтому там же говорится что такой режим работы fetchmail особых преимуществ не имеет :)).

среда, 12 января 2011 г.

Доставка и чтение почты: fetchmail, procmail, kmail

До недавнего момента за доставку (и отправку) почты, при подключении ноутбука к интернет, у меня отвечал masqmail. И, если я правильно ошибаюсь, в новых версиях этой программы возможность доставки решили выпилить, и порекомендовали для этих целей воспользоваться специализированными утилитами. Я решил не дожидаться момента, когда в репозиториях debian-а появится новый masqmail, и сразу перейти на рекомендуемый способ получения почты.
Среди найденного списка программ ($ apt-cache search fetch mail) наиболее подходящими оказались getmail4 и fetchmail. В итоге установил старый добрый fetchmail, несмотря на то что питоновский getmail4 позиционируется как более простой, и даже поддерживает Maildir из коробки.
Итак почту я храню в ящике формата maildir:

~/Mail/
 drafts/
 inbox/
  cur/
  new/
  tmp/
 outbox/
 sent-mail/
 templates/
 trash/

За обработку полученной корреспонденции (распихивание её по ящикам) будет отвечать procmail (в качестве альтернативы можно выбрать maildrop, как рекомендуется в man fetchmail или другой mda).

Часть 1 - получение почты вручную от имени пользователя


Создаем простейший конфигурационный файл для procmail (слэш в конце имени ящика указывает на то, что это ящик maildir):

$ cat > ~/.procmailrc
MAILDIR=$HOME/Mail/

:0
inbox/
^C

В результате вся обрабатываемая почта будет складываться в каталог inbox/.
Конфиг для fetchmail можно создать при помощи утилиты fetchmailconf; вот итог её работы, подходящий под мои требования:

$ cat > ~/.fetchmailrc
# Configuration created Wed Jan 12 11:10:56 2011 by fetchmailconf 1.57
set postmaster "reel"
set bouncemail
set no spambounce
set softbounce
set properties ""
set invisible

poll freemail.ukr.net with proto POP3
 user 'r*******@ukr.net' there with password '**********' is 'reel' here options keep stripcr
 mda 'procmail'
 user 'm*******@ukr.net' there with password '**********' is 'reel' here options keep
 mda 'procmail'

poll imap.gmail.com with proto IMAP
 user 'kirill.zabarniuk@gmail.com' there with password '**********' is 'reel' here options keep ssl
 mda 'procmail'
^C

При запуске, fetchmail будет получать почту из двух почтовых ящиков на сервере ukr.net (по протоколу pop3), и из одного ящика на gmail (по протоколу imap). Копии всех сообщений будут оставаться на сервере, а сами сообщения будут передаваться для дальнейшей обработки procmail-у.
Имеет смысл написать пару сообщений самому себе и проверить как это работает:

$ fetchmail
1 сообщение (1 просмотрено) для r*******@ukr.net на freemail.ukr.net (1974 октетов).
пропускается сообщение r*******@ukr.net@new.ukr.net:1 не очищено
1 сообщение (1 просмотрено) для m*********@ukr.net на freemail.ukr.net (1144 октетов).
пропускается сообщение m*********@ukr.net@new.ukr.net:1 не очищено
1 сообщение для kirill.zabarniuk@gmail.com на imap.gmail.com.
считывается сообщение kirill.zabarniuk@gmail.com@wy-in-f109.1e100.net:1 из 1 (1443 октетов в заголовке) (513 октетов в теле) не очищено

Почту я читаю с матом (mutt), но иногда пользуюсь kmail. Обычно kmail сам находит каталоги с почтой пользователя при первом запуске. Но если этого не произошло, и он решил заныкать сообщения у себя (в каталоге по умолчанию ~/.kde/share/apps/kmail/Mail/), то можно попросить его изменить путь к этому каталогу (http://kmail.kde.org/manual/faq.html#id2792815, http://forum.kde.org/viewtopic.php?f=20&t=84335#p140087):

$ kwriteconfig --file kmailrc --group General --key folders $HOME/Mail

см также Автоматическое получение почты на компьютере без постоянного подключения к интернет

вторник, 11 января 2011 г.

Настройка msmtp для отправки сообщений через несколько серверов (ukr.net, gmail.com)

Выкладываю рабочий конфиг с настройками msmtp (он не захотел с пол-пинка отправлять почту через ukr.net, а в инете готовых решений не обнаружилось):

$ cat ~/.msmtprc
defaults
syslog on

account r*******_at_ukr.net
from r*******@ukr.net
host smtp.ukr.net
protocol smtp
auth on
tls on
tls_starttls off
tls_certcheck off
port 465
user r*******@ukr.net
password **********

account m*********_at_ukr.net
from m*********@ukr.net
host smtp.ukr.net
protocol smtp
auth on
tls on
tls_starttls off
tls_certcheck off
port 465
user m*********@ukr.net
password **********

account kirill.zabarniuk_at_gmail.com
from kirill.zabarniuk@gmail.com
host smtp.gmail.com
protocol smtp
auth on
tls on
tls_starttls on
tls_certcheck off
port 587
user kirill.zabarniuk@gmail.com
password ***********

account default
host localhost
port 25
auto_from on
maildomain localhost


Подружить msmtp с ukr.net оказалось просто, ключевое слово: tls_starttls off.

понедельник, 10 января 2011 г.

Просмотр html-содержимого в mutt и правильная кодировка

Есть такой, очень функциональный текстовый браузер, как w3m, который, кроме всего прочего, умеет отображать картинки. Причем не только во фрэймбуффере, но и в окне терминала (в debian нужно установить пакет w3m-img):




Так вот, в debian-е, если этот пакет установлен, mutt будет использовать его при отображении html-содержимого в e-mail сообщениях. Однако, сообщения приходят в различных кодировках, а в mutt все отображается лишь в одной (utf8 по умолчанию), в результате часть сообщений оказываются нечитаемыми. Чтобы это исправить, надо добавить следующую строку в свой .mailcap:

cat >> ~/.mailcap
text/html; /usr/bin/w3m -dump -I %{charset} -T text/html '%s'; copiousoutput; description=HTML Text; nametemplate=%s.html


"Магической" является опция -I %{charset}. Результат - на картинках: