Використання build-систем в PHP проектах

Звичайно, багато хто стикався з проблемами різної конфігурації проекту для розгортання його на dev і production середовищах. Як мінімум потрібно замінити login, password і database name для доступа к СУБД. На практиці відмінностей получається набагато більше.
Хтось вирішує це правлячи константи руками, хтось будує ліс із if'ів, які в залежності від місця де знаходиться скрипт - підставляють відповідні значення в константи конфігурації. А дехто використовує для таких цілей софт, який, власне, і призначений для цього - build системи. Далі в статті розкажу як це робити на прикладі Apache Ant.
Для чого це потрібно
Apache Ant - аналог UNIX-утиліти make. Обидва інструмента дозволяють виконати певну послідовність дій, яка є частиною процесу збірки програмного забезпечення. Оскільки в даній статті мова йде про PHP, нам не потрібно виконувати компіляцію, а лише підготувати код для розгортання в певному середовищі.
Така підготовка може включати в себе:
- Створення тимчасових директорій (наприклад, для логів, кешу, тощо...);
- Встановлення константам значень які відповідають середовищу;
- Наповнення бази даних, або інших ресурсів тестовими значеннями (для dev environment);
- Запуск юніттестів (може бути виконаний як під час збірки проекту, так і після змін в коді);
Що для цього потрібно
Одною із переваг Ant є його кросплатформеність. Він написаний на Java, тому основною вимогою є встановлений в системі JDK. З інсталяцією проблем виникати не повинно, можливі помилки при запуску, які вирішуються встановленням коректного значення для змінної оточення JAVA_HOME.
Після інсталяції можна починати складати файл build.xml. Цей файл в форматі xml описує весь процес збирання вашого проекту. Детально ознайомитися з правилами його складання можна тут.
Приклад
Основними елементами build-файла є properties - властивості, targets - цілі і власне дії. Властивості можут приймати значення та бути використані в інших виразах. Також властивості можуть бути підключені із зовнішніх файлів.
Цілі описують послідовність дій яка має бути виконана. Кожна ціль може залежити від інших, в такому випадку спочатку будуть виконані цілі що вказані в атрибуті depends, а потім залежна ціль, яка їх викликала. В мануалі це все добре розписано, тому краще подивитися на приклад.
<property name="build_dir" location="build"/>
<target name="d.includes">
<property file="${build_dir}/development.properties"/>
</target>
<target name="p.includes">
<property file="${build_dir}/production.properties"/>
</target>
<target name="create_dirs">
<mkdir dir="${temp_dir}/"/>
<mkdir dir="${log_dir}/"/>
</target>
<target name="generate_code">
<copy file="${build_dir}/globalGenSource.php" tofile="${conf_dir}/globalGen.php" />
<replace
file="${conf_dir}/globalGen.php"
value="">
<replacefilter token="@master_db_host@" value="${master_db_host}" />
<replacefilter token="@master_db_name@" value="${master_db_name}" />
<replacefilter token="@master_db_user@" value="${master_db_user}" />
<replacefilter token="@master_db_pass@" value="${master_db_pass}" />
</replace>
</target>
<target name="build" depends="create_dirs, generate_code">
<echo>Starting build.</echo>
</target>
<target name="d.build" depends="d.includes, build" />
<target name="p.build" depends="p.includes, build" />
</project>
Тут описані наступні цілі:
- d.includes - підключення файлу з властивостями для development environment;
- p.includes - підключення файлу з властивостями для production environment;
- create_dirs - створення директорій;
- generate_code - встановлення відповідних значень для PHP констант;
- build - основна ціль, яка включає в себе допоміжні;
- d.build, p.build - точки входу для development і production білдів відповідно.
Ітак, що ж тут відбувається? Після запуску ant d.build шукається файл build.xml в поточній директорії. Далі шукається ціль d.build в тому файлі. Знайшовши її він бачить що вона залежить від цілей d.includes і build. В межах цілі d.includes, Ant підгружає відповідний файл з властивостями, який виглядає таким чином:
server_url=http://someproject
root_dir=/home/soto/public_html/someproject
temp_dir=${root_dir}/tmp
log_dir=${root_dir}/logs
conf_dir=${root_dir}/conf
master_db_host="localhost"
master_db_name="photodeer"
master_db_user="root"
master_db_pass=""
Далі йде ціль build, яка залежить від create_dirs і generate_code. З create_dirs все ясно, а generate_code спочатку копіює globalGenSource.php із ./build в директорію проекту, а далі заміняє мітки типу @label@ на відповідні значення з підключеного property файлу:
<?php
define('MASTER_DB_HOST', @master_db_host@);
define('MASTER_DB_NAME', @master_db_name@);
define('MASTER_DB_USER', @master_db_user@);
define('MASTER_DB_PASS', @master_db_pass@);
soto@y-deer:~/public_html/someproject> cat conf/globalGen.php
<?php
define('MASTER_DB_HOST', "localhost");
define('MASTER_DB_NAME', "photodeer");
define('MASTER_DB_USER', "root");
define('MASTER_DB_PASS', "");
Після цього керування повертається до цілі build, виводиться повідомлення і процес завершується.
Резюме
Звичайно, це далеко не повний перелік дій які можна виконувати за допомогою Ant. Окрім вбудованих типу replace, echo, copy він може виконати будь-яку системну команду. По мірі росту проекту файл build.xml буде також зростати. Не обов'язково виконувати весь процес з початку і до кінця. Деякі цілі такі як створення/видалення таблиць в БД, видалення тимчасових файлів, запуск юніт-тестів, тощо можуть бути виконані на вже розгорнутому проекті під час його розробки.








— Написал: Stas Dovgodko · 2008-11-17 16:56 · #
Собственно для PHP есть Phing – http://phing.info/trac/, явно его не использую но на нем построены билдеры моего любимого ORM Propel :)
Но, вообще имхо тяжелое решение для указанной задачи, использую бутстрап файл с case $ENV
— Написал: Сотомайор · 2008-11-17 19:29 · #
Скажемо так, стаття має лише дати розуміння того що таке є і навіщо воно потрібно. А вибір білдера це справа індивідуальна і залежна від проекту :-)