6 minutes reading time (1175 words)

Автоматическая сборка пакетов для Joomla!

Автоматическая сборка пакетов для Joomla!

До того, как я начал работать над текущим проектом, я не думал, что мне когда либо придется использовать инструменты для автоматической сборки проектов. Ведь работаю я исключительно с интерпретируемыми языками, которым не нужна компиляция. Однако, как оказалось, они могут быть полезными и при разработке на PHP, и особенно при работе с Joomla!

Раньше, работая над каким либо сайтом, я вносил необходимые правки в файлы и базу данных на своем локальном сервере, проверял все ли правильно работает, затем посредством ftp-клиента и phpMyAdmin копировал файлы и изменения базы на рабочий сайт. Если я не помнил, какие именно файлы я правил, а обычно так и случается, копировал все.

В текущем проекте работы ведутся на локальном сервере, затем правки переносятся на тестовый, и только затем на рабочий. Причем последнее действие заказчик должен иметь возможность выполнять самостоятельно. Решение для этого в Joomla есть — установочные файлы для расширений плюс упаковка всех расширений в пакет. Таким образом заказчик может обновить все расширения выполнив всего одно действие. А что же должен сделать разработчик? Для компонента надо скопировать: административную и фронтальную части, папку из директории media (раньше надо было копировать еще и языковые файлы, но используя новый стандарт их размещения вы освобождаетесь от этого). Затем надо переместить файл манифеста из административной папки в корень и все заархивировать. Еще, желательно, в имени архива указать номер версии. Когда все расширения собраны, упаковать их все и файл манифеста пакета в один архив. Вроде бы ничего сложного, но только пока расширений не много. А если их больше десятка (в моем случае 21, и их количество растет)? А что если время от времени необходимо оперативно внести правки и передать обновленный пакет?

Вот тут-то я и озадачился вопросом автоматической сборки. На тот момент я знал только об Ant. Начав изучать его возможности, узнал еще про Maven. Но меня смущало, что если вдруг мне не хватит имеющихся возможностей, придется писать на Java. Поэтому я продолжил поиски и нашел Phing — сборщик проектов для PHP. Ознакомившись с его возможностями я быстро понял, что в нем есть все необходимое: 

  • операции с файлами и директориями;
  • работа с архивами;
  • чтение свойств из xml-файлов (можно использовать данные из манифеста);
  • операции для работы с системами контроля версий (cvs, svn, git);
  • поддержка протоколов ftp и http;
  • выполнение внешних команд;
  • выполнение PHP-кода;
  • запуск юнит-тестов;
  • работа с базой данных;
  • много других возможностей которые расширяются при помощи готовых либо самодельных плагинов на PHP.

Установка  Phing

Проще всего установить Phing используя PEAR. Для этого достаточно в консоли ввести всего две команды:

pear channel-discover pear.phing.info
pear install phing/phing

Если вы не используете PEAR, то на официальном сайте есть инструкцию, как установить Phing вручную.

Подключение к NetBeans

Следующий шаг после установки — подключение к используемой IDE. Я использую NetBeans, для него существует плагин phingKing для запуска задач из IDE. Начиная с версии 7.3 его можно установить непосредственно из менеджера плагинов. В более ранних версиях придется предварительно скачать плагин и установить из файла.

После установки в разделе меню Окна появится пункт Phing Targets. В этом окне будут отображаться задачи Phing:

  • Favorites — избранные задачи;
  • Subtargets — подзадачи (задачи выполнение которых включено в более общую задачу);
  • Default target — задача по умолчанию.

В настройках NetBeans в разделе PHP появиться закладка PhingKing в которой необходимо указать путь к Phing. В свойствах проекта в соответствующем разделе необходимо указать путь к xml-файлу с задачами (об этом чуть ниже).

Использование из командной строки

Использовать Phing из командной строки также просто. Разместите задачи в файле build.xml и запустите скрипт Phing в той же директории, либо укажете путь к xml-файлу в параметре -buildfile. Получить полный набор параметров можно запустив phing -help.

Создание задач

Задачи для Phing записываются в xml-файл (по умолчанию build.xml). По умолчанию запускается только одна задача указанная в свойствах проекта как default, но в ней можно указать зависимости от других задач, каждая из которых также может иметь свои зависимости, и все они будут выполнены. Весь проект заключается в тег project, а каждая задача в тег target.

Простейший файл задач выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<project name="test" default="build">
    <target name="task1">
        <echo msg="Task 1" />
    </target>
    <target name="task2">
        <echo msg="Task 2" />
    </target>
    <target name="build" depends="task1, task2">
        <echo msg="Build" />
    </target>
</project>

В результате будет выведено:

Task 1
Task 2
Build

Сборка расширений Joomla 

Теперь заставим сделать Phing что-то полезное — собрать пакет с расширениями для Joomla.
Исходные условия:

  • разработка ведется в директории /opt/lampp/htdocs/mysite
  • готовый пакет поместим в /home/user1/mysite
  • исходные файлы расширений в /home/user1/mysite/src
  • установочные файлы расширений с номерами версий в /home/user1/mysite/zip
  • установочные файлы расширений без номеров версий в /home/user1/mysite/cache

Примечание: файлы с номерами версий удобно использовать как самостоятельные, а без номеров для упрощения сборки пакета.

<project name="make_project" default="build">
<!-- Пути храним в переменных, так удобнее -->
<property name="src_dir" value="/opt/lampp/htdocs/mysite" />
<property name="res_dir" value="/home/user1/mysite" />
<target name="clear">
<echo>============= Удаление старых версий =============</echo>
<!-- Команда delete удаляет указанные в ней наборы файлов fileset -->
<delete includeemptydirs="true">
<!-- Вместо ${res_dir} будет подставлено значение res_dir -->
<fileset dir="${res_dir}">
<!-- Можно перечислить файлы и/или указать маску -->
<include name="**"/>
</fileset>
</delete>
</target>
<target name="com_test">
<echo>============= Компонент Test =============</echo>
<!-- Прочитать установочный xml-файл. Префикс нужен для разграничения расширений. -->
<xmlproperty file="${src_dir}/administrator/components/com_test/test.xml" prefix="com_test." keepRoot="false" />
<!-- Копировать файлы в папку исходников компонента →
<!-- Пользовательская часть -->
<copy todir="${res_dir}/src/com_test/site" overwrite="true">
<fileset dir="${src_dir}/components/com_test">
<include name="**" />
</fileset>
</copy>
<!-- Административная часть -->
<copy todir="${res_dir}/src/com_test/admin" overwrite="true">
<fileset dir="${src_dir}/administrator/components/com_test">
<!-- Копировать все, кроме файла манифеста -->
<exclude name="${src_dir}/administrator/test.xml" />
</fileset>
</copy>
<!-- Файл манифеста копируем в корень папки расширения -->
<copy file="${src_dir}/administrator/components/com_test/test.xml" tofile="${res_dir}/src/com_test/test.xml" overwrite="true"/>
<!-- Файлы из папки media -->
<copy todir="${res_dir}/src/com_test/media" overwrite="true">
<fileset dir="${src_dir}/media/com_test">
<include name="**" />
</fileset>
</copy>
<!-- Упаковать исходники в архив -->
<zip destfile="${res_dir}/cache/com_test.zip" basedir="${res_dir}/src/com_test"/>
<!-- Создать установочный файл с номером версии. Номер прочтен из xml-файла -->
<copy file="${res_dir}/cache/com_test.zip" tofile="${res_dir}/zip/com_test-${com_test.version}.zip" overwrite="true"/>
</target>
<!-- Задание на сборку модуля. Здесь все аналогично предыдущему -->
<target name="mod_test">
<echo>============= Модуль Test =============</echo>
<xmlproperty file="${src_dir}/modules/mod_test/mod_test .xml" prefix="mod_test." keepRoot="false"/>
<copy todir="${res_dir}/src/mod_test" overwrite="true">
<fileset dir="${src_dir}/modules/mod_test">
<include name="**" />
</fileset>
</copy>
<zip destfile="${res_dir}/cache/mod_test.zip" basedir="${res_dir}/src/mod_test"/>
<copy file="${res_dir}/cache/mod_test .zip" tofile="${res_dir}/zip/mod_test-${mod_calendar.version}.zip" overwrite="true"/>
</target>
<target name="build" depends="clear, com_test, mod_test">
<echo>============= Сборка пакета =============</echo>
<!-- build/pkg_test.xml — это установочный файл пакета -->
<xmlproperty file="${src_dir}/build/pkg_test.xml" prefix="pkg." keepRoot="false" />
<copy file="${src_dir}/build/pkg_test.xml" tofile="${res_dir}/cache/pkg_test.xml" overwrite="true"/>
<zip destfile="${res_dir}/pkg_test-${pkg.version}.zip" basedir="${res_dir}/cache"/>
</target>
</project>

На первый взгляд выглядит немного устрашающе, но на самом деле здесь нет ничего сложного. Для большинства расширений код можно копировать лишь с небольшими изменениями. Да и править его приходится крайне редко. Зато всего в один клик мы получаем пакет с актуальными версиями всех разрабатываемых расширений.

Можно еще улучшить процесс добавив автоматическое увеличение номеров версий при каждой сборке, но я не стал этого делать ради совпадения номеров версий с именами файлов миграций базы данных. Если у кого-то есть соображения по этому поводу, пишите в комментариях.

Some articles published on the Joomla Community Magazine represent the personal opinion or experience of the Author on the specific topic and might not be aligned to the official position of the Joomla Project

0
To SEO or Not to SEO
 

Comments

Already Registered? Login Here
No comments made yet. Be the first to submit a comment

By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/