<?xml version="1.0" encoding="UTF-8" ?><oembed><version>1.0</version><provider_name>Чудо{вищные} заметки</provider_name><provider_url>https://miracle.rpz.name</provider_url><author_name>MiRacLe</author_name><author_url>https://miracle.rpz.name/author/miracle/</author_url><title>phing.tasks.ext.SvnExportRevisionDiffTask</title><html>В последнее время в посещаемых мною форумах и конференциях часто всплывает тема деплоя php-приложений на production-сервер. Я решил поделиться собственным рецептом.

В распоряжении имеется:
&lt;ol&gt;&lt;li&gt;svn-репозитарий с проектом.&lt;/li&gt;&lt;li&gt;ftp-доступ к рабочему серверу.&lt;/li&gt;&lt;li&gt;установленный и готовый к тяжёлой рутине &lt;a href=&quot;http://phing.info&quot;&gt;phing&lt;/a&gt;
&lt;/li&gt;&lt;/ol&gt;

Сценарий работ следующий:
&lt;ol&gt;&lt;li&gt;Сделать экспорт кода из svn&lt;/li&gt;&lt;li&gt;Подготовить его к загрузке (например убрать комментарии, &quot;склеить&quot; мелкие в один большой, удалить лишнее и т.п.)&lt;/li&gt;&lt;li&gt;Проверить на наличие ошибок (они могли попасть в репозитарий или образоваться на предыдущем шаге)&lt;/li&gt;&lt;li&gt;Закачать полученное на рабочий сервер.
&lt;/li&gt;&lt;/ol&gt;Всё вроде бы просто, но смущает один момент - экспорт всего и вся. Со времени последнего обновления на сервере в репозитарии обновились 3 файла, а экспортировать нужно всё? Никак нет! Экспортировать будем только то, что изменилось. То есть первый шаг сценария будет выглядеть так:
&lt;ol&gt;&lt;li&gt;Получить последнюю версию проекта на сервере - &lt;i&gt;RevFrom&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Получить последнюю версию проекта в репозитарии - &lt;i&gt;RevTo&lt;/i&gt;
&lt;/li&gt;&lt;li&gt;Экспортировать файлы, которые изменились или добавились c &lt;i&gt;RevFrom&lt;/i&gt; до &lt;i&gt;RevTo&lt;/i&gt;
&lt;/li&gt;&lt;/ol&gt;
Версию рабочего проекта, не мудрствуя лукаво, предлагаю хранить в текстовом файле. Например revision.txt. Версию проекта в репозитарии поможет узнать SvnLastRevisionTask. Неясным остался лишь момент - каким образом выяснить какие файлы изменились. Те, кто пользовались TortoiseSVN наверняка знают о чудесной его возможности - сравнить две ревизии и экспортировать &quot;разницу&quot;. Но svn в чистом виде такой возможности не предоставляет. Так что пришлось немного поработать.
&lt;!--more--&gt;
Результатом работы стал класс - &lt;a href=&quot;http://miracle.rpz.name/shared/phing/SvnExportRevisionDiffTask.html&quot;&gt;SvnExportRevisionDiffTask&lt;/a&gt; Принцип его работы таков: получаю список файлов для каждой ревизии в виде xml, потом эти списки сравниваются на предмет изменившихся или добавленных файлов. Список получается путём вызова svn, т.к. более удобного способа не нашлось.

Закачивать файлы будем посредством task-а, который я опубликовал ранее - &lt;a href=&quot;http://miracle.rpz.name/2007/11/15/phing-ftpupload-task/&quot;&gt;FtpUploadTask&lt;/a&gt;.

Ну вот все вроде бы в сборе и можно приступать с сборке: раскладываем php-классы в соответствующие места, берём файл example.xml

&lt;pre class=&quot;xml:nocontrols&quot;&gt;
&lt;?xml&nbsp;version=&#039;1.0&#039;?&gt;
&lt;project&nbsp;name=&#039;Deploy&#039;&nbsp;default=&#039;build&#039;&nbsp;basedir=&#039;./&#039;&nbsp;description=&#039;Demo&nbsp;phing-ftp-deploy&#039;&gt;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#039;propset&#039;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;projectUrl&#039;&nbsp;value=&#039;http://example.com/project_root/&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;revisionFile&#039;&nbsp;value=&#039;revision.txt&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;projectlastrev&nbsp;url=&#039;${projectUrl}&#039;&nbsp;revisionFile=&#039;${revisionFile}&#039;&nbsp;propertyName=&#039;fromrev&#039;&nbsp;/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;svnroot&#039;&nbsp;value=&#039;http://svn.example.com/project/branches/stable/&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;svnuser&#039;&nbsp;value=&#039;joe&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;svnpassword&#039;&nbsp;value=&#039;s3cre7&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;outputdir&#039;&nbsp;value=&#039;project-temp&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;svnlastrevision&nbsp;username=&#039;${svnuser}&#039;&nbsp;password=&#039;${svnpassword}&#039;&nbsp;repositoryurl=&#039;${svnroot}&#039;&nbsp;propertyName=&#039;torev&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;hostname&#039;&nbsp;value=&#039;ftp.example.com&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;user&#039;&nbsp;value=&#039;ftpuser@example.com&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;passwd&#039;&nbsp;value=&#039;s3cr3tk3y&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;dstdir&#039;&nbsp;value=&#039;project_root&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property&nbsp;name=&#039;overwrite&#039;&nbsp;value=&#039;true&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#039;build&#039;&nbsp;depends=&#039;propset,diff,lint&#039;&gt;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ftpupload&nbsp;host=&#039;${hostname}&#039;&nbsp;username=&#039;${user}&#039;&nbsp;password=&#039;${passwd}&#039;&nbsp;targetDir=&#039;${dstdir}&#039;&nbsp;mode=&#039;bin&#039;&nbsp;overwriteExisten=&#039;${overwrite}&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#039;${outputdir}&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#039;**&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#039;config.php.dist&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#039;examples/**&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ftpupload&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#039;diff&#039;&nbsp;depends=&#039;propset&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;delete&nbsp;includeemptydirs=&#039;true&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;сначала&nbsp;очистить&nbsp;директорию,&nbsp;в&nbsp;которую&nbsp;будут&nbsp;экспортироваться&nbsp;файлы&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#039;.&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#039;${outputdir}/**&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/delete&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mkdir&nbsp;dir=&#039;${outputdir}&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;сохранить&nbsp;номер&nbsp;текущей&nbsp;ревизии&nbsp;в&nbsp;файл&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;echo&nbsp;file=&#039;${outputdir}/${revisionFile}&#039;&nbsp;message=&#039;${torev}&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;экспортировать&nbsp;нужные&nbsp;файлы&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;svndiff&nbsp;toDir=&#039;${outputdir}&#039;&nbsp;svnpath=&#039;/usr/local/subversion/bin/svn&#039;&nbsp;fromRevision=&#039;${fromrev}&#039;&nbsp;toRevision=&#039;${torev}&#039;&nbsp;force=&#039;true&#039;&nbsp;username=&#039;${svnuser}&#039;&nbsp;password=&#039;${svnpassword}&#039;&nbsp;repositoryurl=&#039;${svnroot}&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;target&nbsp;name=&#039;lint&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;phplint&nbsp;haltOnFailure=&#039;true&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#039;${outputdir}&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#039;**/*.php&#039;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;файлы&nbsp;в&nbsp;pear::php_compat&nbsp;проверять&nbsp;в&nbsp;php5&nbsp;не&nbsp;надо&nbsp;--&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exclude&nbsp;name=&#039;**/Php/Compat/**/*.php&#039;&nbsp;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/phplint&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;jslint&nbsp;haltOnFailure=&#039;true&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fileset&nbsp;dir=&#039;${outputdir}&#039;&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;include&nbsp;name=&#039;**/*.js&#039;/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/jslint&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/target&gt;
&lt;/project&gt;
&lt;/pre&gt;
&lt;p&gt;Открываем консоль, набираем &lt;b&gt;phing -f example.xml &lt;/b&gt; и смотрим как вашу работу выполняет за вас бездушная машина... 
&lt;p&gt;
&lt;blockquote&gt;
Кстати говоря, эту задачу можно запускать не только вручную, но и например с помощью post-commit hook-а на репозитарии...
&lt;/blockquote&gt;
&lt;p&gt;
Данный сценарий не затрагивает изменений в БД и позволяет синхронизировать только файлы, но и это, согласитесь, уже кое-что. А быть может у вас есть идеи, как обновить БД?</html><type>rich</type></oembed>