More Related Content Similar to Phing for power users - frOSCon8 (20) More from Stephan Hochdörfer (17) Phing for power users - frOSCon82. Phing for power users
About me
Stephan Hochdörfer
Head of IT at bitExpert AG, Germany
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
5. What is Phing?
Phing for power users
It is a PHP project build system or
build tool based on Apache Ant.
12. How to install Phing?
Phing for power users
Installing Phing globally? WTF?!?
13. How to install Phing?
Phing for power users
Phing is „just another“
dependency for your project.
17. How to install Phing? The Composer way...
Phing for power users
/tmp/myproject
|vendor
|bin
|@phing
|composer
|phing
|phing
|bin
|phing
|build
|classes
|docs
|etc
|test
18. How to install Phing? The Composer way...
Phing for power users
/tmp/myproject
|vendor
|bin
|@phing
|composer
|phing
|phing
|bin
|phing
|build
|classes
|docs
|etc
|test
$> ./vendor/bin/phing v
Phing 2.5.0
Running Phing:
25. Phing Basics: Built-In Properties
Phing for power users
e.g. host.os, line.separator,
phing.version, php.version, …
33. Enforce Internal Targets
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="init"
description="Property initialization">
<property name="Hello" value="Hello, world!" />
</target>
<target name="hello"
depends="init">
<echo msg="${Hello}" />
</target>
</project>
34. Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -f build.xml hello
/tmp/myproject/build.xml
myproject > init:
myproject > hello:
[echo] Hello, world!
BUILD FINISHED
Total time: 0.0474 seconds
35. Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -f build.xml init
/tmp/myproject/build.xml
myproject > init:
BUILD FINISHED
Total time: 0.0476 seconds
36. Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -l
Buildfile: /tmp/myproject/build.xml
Default target:
---------------------------------------------------------
hello
Main targets:
---------------------------------------------------------
init Property initialization
Subtargets:
---------------------------------------------------------
hello
38. <?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="-init"
description="Property initialization">
<property name="Hello" value="Hello, world!" />
</target>
<target name="hello"
depends="-init">
<echo msg="${Hello}" />
</target>
</project>
Enforce Internal Targets – The solution
Phing for power users
39. Enforce Internal Targets – The solution
Phing for power users
$> ./vendor/bin/phing -f build.xml -init
Unknown argument: -init
phing [options] [target [target2 [target3] ...]]
Options:
-h -help print this message
-l -list list available targets
-v -version print the version information
-q -quiet be extra quiet
-verbose be extra verbose
-debug print debugging information
Report bugs to <dev@phing.tigris.org>
41. Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -l
Buildfile: /tmp/myproject/build.xml
Default target:
---------------------------------------------------------
hello
Main targets:
---------------------------------------------------------
-init Property initialization
Subtargets:
---------------------------------------------------------
hello
42. Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -l
Buildfile: /tmp/myproject/build.xml
Default target:
---------------------------------------------------------
hello
Main targets:
---------------------------------------------------------
-init Property initialization
Subtargets:
---------------------------------------------------------
hello
43. Enforce Internal Targets (Improved Version)
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="-init"
hidden="true"
description="Property initialization">
<property name="Hello" value="Hello, world!" />
</target>
<target name="hello"
depends="-init">
<echo msg="${Hello}" />
</target>
</project>
44. $> ./vendor/bin/phing -l
Buildfile: /tmp/myproject/build.xml
Default target:
---------------------------------------------------------
hello
Subtargets:
---------------------------------------------------------
hello
Enforce Internal Targets (Improved Version)
Phing for power users
47. Custom Task (Adhoc definition)
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="init">
<adhoc-task name="mytask"><![CDATA[
class MyTask extends Task {
/**
* (non-PHPdoc)
* @see Task::main()
*/
public function main() {
// Custom code here...
}
}
]]></adhoc-task>
</target>
<target name="hello"
depends="init">
<mytask />
</target>
</project>
49. <?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="init">
<taskdef
name="mytask"
classpath="${project.basedir}"
classname="MyApp.Common.Phing.MyTask" />
</target>
<target name="hello"
depends="init">
<mytask />
</target>
</project>
Custom Task (External file)
Phing for power users
50. <?php
require_once 'phing/Task.php';
class MyTask extends Task {
protected $file;
/**
* @param string $file
*/
public function setFile($file) {
$this->file = $file;
}
/**
* @see Task::main()
*/
public function main() {
// Custom code here...
}
}
Custom Task with Parameters
Phing for power users
51. <?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="init">
<taskdef
name="mytask"
classpath="${project.basedir}"
classname="MyApp.Common.Phing.MyTask" />
</target>
<target name="hello"
depends="init">
<mytask file="myfile.txt" />
</target>
</project>
Custom Task with Parameters
Phing for power users
56. Properties File
Phing for power users
$> phing
Buildfile: /tmp/myproject/build.xml
myproject > hello:
[property] Loading /tmp/myproject/build.properties
[echo] Hello, world!
BUILD FINISHED
Total time: 0.0601 seconds
58. Properties File - Improved version
Phing for power users
Requirement: Externalize properties
but offer customization capabilities!
59. <?xml version="1.0"?>
<project name="myproject" default="hello">
<target name="hello" depends="init">
<echo msg="${Hello}" />
</target>
<target name="init" depends="prop, local-prop">
<!-- some more init logic -->
</target>
<target name="prop">
<echo
message="Loading default build.properties"/>
<property
file="build.properties" />
</target>
Properties File - Improved version
Phing for power users
61. $> phing
Buildfile: /tmp/myproject/build.xml
myproject > prop:
[echo] Loading default build.properties
[property] Loading /tmp/myproject/build.properties
myproject > local-prop-check:
myproject > local-prop:
myproject > init:
myproject > hello:
[echo] Hello, world!
BUILD FINISHED
Total time: 0.1383 seconds
Properties File - Improved version
Phing for power users
62. $> phing
Buildfile: /tmp/myproject/build.xml
myproject > prop:
[echo] Loading default build.properties
[property] Loading /tmp/myproject/build.properties
myproject > local-prop-check:
myproject > local-prop:
[echo] Loading custom properties!
[property] Loading /tmp/myproject/local.properties
myproject > init:
myproject > hello:
[echo] Hello my world!
BUILD FINISHED
Total time: 0.0493 seconds
Properties File - Improved version
Phing for power users
63. build.properties example
Phing for power users
phpunit.path=vendor/bin/phpunit
phpunit.junit.log=build/logs/junit.xml
phpunit.coverage.clover=build/logs/clover.xml
phpunit.coverage.html=build/coverage
phpcs.path=vendor/bin/phpcs
phpcs.log=build/logs/checkstyle.xml
sencha.senchaCmd=/user/local/lib/sencha/sencha
sencha.jsb3File=app.jsb3
67. Accessing application configuration
Phing for power users
<?php
require_once 'phing/Task.php';
class ConfigMapperTask extends Task {
/**
* @see Task::main()
*/
public function main() {
// will import $APP_CONF in local context
require_once('src/bootstrap.php');
$project = $this->project;
$project->setProperty(
'db.host', $APP_CONF['db_host']);
$project->setProperty(
'db.database', $APP_CONF['db_database']);
$project->setProperty(
'db.user', $APP_CONF['db_user']);
$project->setProperty(
'db.password', $APP_CONF['db_passwd']);
}
}
68. Accessing application configuration
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="hello">
<taskdef name="readAppConfig"
classpath="${phing.dir}/src/"
classname="MyApp.Common.Phing.AppConfigTask" />
<target name="init" depends="prop, local-prop">
<readAppConfig />
</target>
<target name="prop">
<echo message="Load default build.properties"/>
<property file="build.properties" />
</target>
<target name="local-prop"
if="local-prop.exists"
depends="local-prop-check">
<!-- […] -->
</project>
70. <?xml version="1.0"?>
<project name="myproject" default="app:run">
<!--
The following target namespaces exist:
db:* - Database specific targets
app:* - Application specific tasks
ci:* - CI server specific tasks
-->
<import file="build/build.db.xml" />
<import file="build/build.app.xml" />
<import file="build/build.ci.xml" />
</project>
Imports for Targets can help structuring
Phing for power users
71. <?xml version="1.0"?>
<project name="myproject" default="app:run">
<!--
The following target namespaces exist:
lib1:* - Targets imported from lib1
lib2:* - Targets imported from lib2
app:* - Local application targets
-->
<import file="vendor/vendor1/lib1/build/build.xml" />
<import file="vendor/vendor2/lib2/build/build.xml" />
<import file="build/build.app.xml" />
</project>
Import Targets: Composer packages
Phing for power users
72. Import Targets: Path handling
Phing for power users
Be aware that imports behave
like include in PHP!
73. <?xml version="1.0"?>
<project name="myproject" default="lib1:run">
<!--
The following target namespaces exist:
lib1:* - Targets imported from lib1
-->
<import file="vendor/lib1/build/build.xml" />
</project>
Import Targets: Path handling
Phing for power users
build.xml
74. <?xml version="1.0"?>
<project name="lib1" default="lib1:run">
<target name="lib1:run">
<echo msg="Local dir: ${phing.dir.lib1}" />
<echo msg="Global dir: ${phing.dir}" />
</target>
</project>
<?xml version="1.0"?>
<project name="myproject" default="lib1:run">
<!--
The following target namespaces exist:
lib1:* - Targets imported from lib1
-->
<import file="vendor/lib1/build/build.xml" />
</project>
Import Targets: Path handling
Phing for power users
build.xml
vendor/lib1/build/build.xml
76. Import Targets: Path handling
Phing for power users
Be aware to always(!) use the
projects name in lowercase format!
77. Import Targets: Path handling
Phing for power users
It`s ${phing.dir.myproject}
not ${phing.dir.MyProject}!
79. <?xml version="1.0"?>
<project name="myproject" default="ci:run-tests">
<target name="app:clean-cache">
</target>
<target name="app:create-cache">
</target>
<target name="db:migrate">
</target>
<target name="js:minifiy">
</target>
<target name="ci:lint">
</target>
<target name="ci:run-tests">
</target>
</project>
Distinct Target Naming
Phing for power users
80. <?xml version="1.0"?>
<project name="myproject" default="app:create-cache">
<target name="app:clean-cache"
description="Removes all cache files.">
</target>
<target name="app:create-cache"
description="Builds the cache files from the
xml configuration.">
</target>
</project>
Adding meaningful descriptions
Phing for power users
81. $> phing -l
Buildfile: /tmp/myproject/build.xml
Default target:
-----------------------------------------------------
app:create-cache Builds the cache files from the xml
configuration.
Main targets:
------------------------------------------------------
app:clean-cache Removes all cache files.
app:create-cache Builds the cache files from the xml
configuration.
Adding meaningful descriptions
Phing for power users
82. Prompt user for input
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="run">
<target name="run">
<!-- tag the database -->
<input
propertyname="tag"
defaultValue="mytag">Tag to create?</input>
<liquibase-tag
tag="${tag}"
jar="/opt/liquibase/liquibase.jar"
classpathref="/opt/liquibase/lib/mysql.jar"
changelogFile="${project.basedir}/diff.xml"
username="liquibase"
password="liquibase"
url="jdbc:mysql://localhost/myproject"/>
</target>
</project>
84. Calling PHP functions from Phing
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="run">
<target name="run">
<!--
Returns canonicalized absolute pathname
-->
<php function="realpath"
returnProperty="app.dir">
<param value="${app.dir}"/>
</php>
</target>
</project>
86. <?xml version="1.0"?>
<project name="myproject" default="run">
<target name="run">
<!--
Check for root user
-->
<if>
<not>
<equals arg1="${env.USER}"
arg2="root" />
</not>
<then>
<fail message="Wrong user!" />
</then>
</if>
</target>
</project>
Restrict user access
Phing for power users
88. Path handling
Phing for power users
<?xml version="1.0"?>
<project name="myproject" default="ci:phpunit">
<!--
...
-->
<target name="ci:phpunit"
depends="-init, -ci:prepare">
<resolvepath propertyName="phpunit.path.abs"
dir="${phing.dir}"
file="${phpunit.path}"/>
<exec executable="${phpunit.path.abs}" />
</target>
</project>
95. Phing + Composer + Jenkins
Phing for power users
Install the Jenkins EnvInject plugin
101. Follow conventions
Phing for power users
Phing expects your build file to be called
build.xml and the build’s properties file
build.properties
106. Phing for power users
Image Credits
http://www.sxc.hu/photo/629370
http://www.sxc.hu/photo/615731