为Joomla!自动构建软件包
在我开始着手当前项目之前,我从未想过自己会需要使用自动构建工具。因为我的工作仅限于解释型语言,它们不需要编译。然而,事实证明,它们在PHP开发,尤其是在Joomla!开发中也是很有用的。
以前,在制作任何网站时,我会在本地服务器上的文件和数据库中做出必要的更改,检查一切是否正常运行,然后通过FTP客户端和phpMyAdmin将文件和数据库更改复制到工作网站。如果我忘记了具体修改了哪些文件,通常是这样的,我会复制所有的文件。
在当前的项目中,工作在本地服务器上进行,然后将更改转移到测试服务器,最后再转移到工作服务器。而且,客户应该能够自行执行最后一步操作。Joomla!为此提供了解决方案——扩展的安装文件,以及将所有扩展打包成包。这样,客户只需执行一个操作就可以更新所有扩展。那么,开发者需要做什么呢?对于组件,需要复制:管理端和前端部分,从media目录中的文件夹(以前还需要复制语言文件,但使用新的放置标准可以免除这一步骤)。然后需要将文件清单从管理端文件夹移动到根目录,并将所有内容归档。此外,最好在归档文件名中包含版本号。当所有扩展都已收集完毕时,将它们全部打包,并将包清单文件打包到一个归档中。这听起来并不复杂,但前提是扩展不多。如果扩展超过十个(我的情况是21个,并且数量还在增加)怎么办?如果需要不时快速进行更改并传递更新包怎么办?
正是在这里,我开始考虑自动构建的问题。那时我只知道Ant。开始研究它的功能后,我还了解到Maven。但让我感到不安的是,如果我的需求超出了现有功能,我可能需要用Java编写。因此,我继续寻找,并发现了Phing——一个PHP项目构建工具。了解它的功能后,我很快意识到它具有所有必要的功能:
- 文件和目录操作;
- 处理归档;
- 从XML文件中读取属性(可以使用清单中的数据);
- 与版本控制系统(cvs,svn,git)的操作;
- 支持ftp和http协议;
- 执行外部命令;
- 执行PHP代码;
- 启动单元测试;
- 与数据库操作;
- 还有很多其他功能,这些功能可以通过现成的或自制的PHP插件来扩展。
安装 Phing
最简单的方法是使用 PEAR 安装 Phing。为此,只需要在控制台中输入两个命令即可。
pear channel-discover pear.phing.info
pear install phing/phing
如果您不使用 PEAR,官方网站上有安装 Phing 的说明。
连接到 NetBeans
安装后的下一步是将其连接到所使用的 IDE。我使用 NetBeans,对于它有一个 插件 phingKing 用于从 IDE 中运行任务。从版本 7.3 开始,可以直接从插件管理器中安装。在早期版本中,需要先下载插件然后从文件安装。
安装后,在窗口菜单的“窗口”部分会出现“Phing Targets”菜单项。在此窗口中将显示 Phing 任务。
- 收藏夹 - 收藏的任务;
- 子目标 - 包含在更通用任务中的子任务(执行这些任务的子任务);
- 默认目标 - 默认任务。
在 NetBeans 的设置中,在 PHP 部分,将出现 PhingKing 选项卡,其中需要指定 Phing 的路径。在项目属性中相应的部分,需要指定任务 xml 文件的路径(下面将详细介绍)。
从命令行使用
从命令行使用 Phing 同样简单。将任务放在 build.xml 文件中,然后在同一目录下运行 Phing 脚本,或者通过 -buildfile 参数指定 xml 文件的路径。要获取完整参数集,可以运行 phing -help。
创建任务
Phing 任务的编写是在 xml 文件中(默认为 build.xml)。默认情况下,只启动在项目属性中指定的默认任务,但可以在其中指定其他任务的依赖关系,每个任务也可以有自己的依赖关系,所有这些任务都将执行。整个项目在 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>
乍一看可能有些令人畏惧,但实际上这里并不复杂。对于大多数扩展,代码只需做少量修改即可复制。而且很少需要修改它。只需一点点击,我们就能得到一个包含所有开发扩展最新版本的包。
还可以通过在每次构建时自动增加版本号来改进这个过程,但我没有这样做,以使版本号与数据库迁移文件名称相匹配。如果对此有任何想法,请在评论中提出。
在 Joomla 社区杂志上发表的一些文章代表了作者对特定主题的个人意见或经验,可能不代表 Joomla 项目的官方立场
通过接受,您将访问 https://magazine.joomla.net.cn/ 外部第三方提供的服务
评论