Phing for power users - frOSCon8
-
Upload
stephan-hochdoerfer -
Category
Technology
-
view
601 -
download
2
Transcript of Phing for power users - frOSCon8
Phing for power usersStephan Hochdörfer, bitExpert AG
Phing for power users
About me
Stephan Hochdörfer
Head of IT at bitExpert AG, Germany
enjoying PHP since 1999
@shochdoerfer
Phing for power users
I used to be an Ant fanboy...
What is Phing?
Phing for power users
What is Phing?
Phing for power users
It is a PHP project build system orbuild tool based on Apache Ant.
What is Phing?
Phing for power users
Domain Specific Language for an project build system.
Phing for power users
A build system for PHP code? Srsly?
Glue for all 3rd party tools
Phing for power users
How to install Phing?
Phing for power users
$> pear channeldiscover pear.phing.info$> pear install phing/phing
How to install Phing? The PEAR way...
Phing for power users
Installing Phing
$> phing vPhing 2.5.0
$> pear channeldiscover pear.phing.info$> pear install phing/phing
How to install Phing? The PEAR way...
Phing for power users
Installing Phing
Running Phing:
How to install Phing?
Phing for power users
Installing Phing globally? WTF?!?
How to install Phing?
Phing for power users
Phing is „just another“ dependency for your project.
How to install Phing? The Composer way...
Phing for power users
{"require": {
"phing/phing": "2.5.0"}
}
How to install Phing? The Composer way...
Phing for power users
composer.json:
{"require": {
"phing/phing": "2.5.0"}
}
$> php composer.phar installLoading composer repositories with package informationInstalling dependencies Installing phing/phing (2.5.0) Downloading: 100%
Writing lock fileGenerating autoload files
How to install Phing? The Composer way...
Phing for power users
composer.json:
Running Composer:
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
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 vPhing 2.5.0
Running Phing:
Phing Basics
Phing for power users
Phing Basics
Phing for power users
Project, Target, Task, Properties
Phing Basics: Project
Phing for power users
Root node of a build file containing one or more targets.
Phing Basics: Target
Phing for power users
A group of tasks that run as an entity.
Phing Basics: Task
Phing for power users
Custom piece of code to perform a specific function.
Phing Basics: Properties
Phing for power users
Properties (variables) help to customize execution.
Phing Basics: Built-In Properties
Phing for power users
e.g. host.os, line.separator, phing.version, php.version, …
<?xml version="1.0"?><project name="myproject" default="init">
<target name="init">
<! insert logic here ></target>
</project>
Phing Basics: Sample Build File
Phing for power users
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says Hello, world!">
<echo msg="Hello, world!" /></target>
</project>
Build File – Hello World example
Phing for power users
Why Phing?
Phing for power users
Runs everywhere where PHP runs.
Why Phing?
Phing for power users
No additional depencendies needed(e.g. Java, …).
Why Phing?
Phing for power users
More than 120 predefinedtasks to choose from.
Why Phing?
Phing for power users
Easy to extend by writing custom tasks in PHP.
Enforce Internal Targets
Phing for power users
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>
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
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
Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -lBuildfile: /tmp/myproject/build.xmlDefault target:--------------------------------------------------------- hello
Main targets:--------------------------------------------------------- init Property initialization
Subtargets:--------------------------------------------------------- hello
Enforce Internal Targets
Phing for power users
Internal targets are just helpers like private methods.
<?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
Enforce Internal Targets – The solution
Phing for power users
$> ./vendor/bin/phing -f build.xml -initUnknown argument: -initphing [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 <[email protected]>
Enforce Internal Targets – The solution
Phing for power users
Are the targets really hidden?
Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -lBuildfile: /tmp/myproject/build.xmlDefault target:--------------------------------------------------------- hello
Main targets:--------------------------------------------------------- -init Property initialization
Subtargets:--------------------------------------------------------- hello
Enforce Internal Targets
Phing for power users
$> ./vendor/bin/phing -lBuildfile: /tmp/myproject/build.xmlDefault target:--------------------------------------------------------- hello
Main targets:--------------------------------------------------------- -init Property initialization
Subtargets:--------------------------------------------------------- hello
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>
$> ./vendor/bin/phing -lBuildfile: /tmp/myproject/build.xmlDefault target:--------------------------------------------------------- hello
Subtargets:--------------------------------------------------------- hello
Enforce Internal Targets (Improved Version)
Phing for power users
Custom Tasks
Phing for power users
Custom Tasks
Phing for power users
Phing can do way morethan simple exec calls!
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>
<?phprequire_once 'phing/Task.php';
class MyTask extends Task {/** * (non-PHPdoc) * @see \Task::main() */public function main() {
// Custom code here...}
}
Custom Task (External file)
Phing for power users
<?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
<?phprequire_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
<?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
Properties File
Phing for power users
Properties File
Phing for power users
Use properties to cutomize build behaviour.
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say">
<propertyfile="./build.properties" />
<echo msg="${Hello}" /></target>
</project>
Properties File
Phing for power users
<?xml version="1.0"?><project name="myproject" default="hello">
<target name="hello" description="Says whatever you want to say">
<propertyfile="./build.properties" />
<echo msg="${Hello}" /></target>
</project>
Properties File
Phing for power users
Hello=Hello, world!build.properties:
Properties File
Phing for power users
$> phingBuildfile: /tmp/myproject/build.xml
myproject > hello:
[property] Loading /tmp/myproject/build.properties [echo] Hello, world!
BUILD FINISHED
Total time: 0.0601 seconds
Properties File - Improved version
Phing for power users
Properties File - Improved version
Phing for power users
Requirement: Externalize properties but offer customization capabilities!
<?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
<target name="local-prop"if="local-prop.exists"depends="local-prop-check">
<echo message="Loading custom properties!"/><property
file="local.properties"override="true"/>
</target>
<target name="local-prop-check"><available
file="local.properties"property="local-prop.exists" />
</target></project>
Properties File - Improved version
Phing for power users
$> phingBuildfile: /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
$> phingBuildfile: /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
build.properties example
Phing for power users
phpunit.path=vendor/bin/phpunitphpunit.junit.log=build/logs/junit.xmlphpunit.coverage.clover=build/logs/clover.xmlphpunit.coverage.html=build/coverage
phpcs.path=vendor/bin/phpcsphpcs.log=build/logs/checkstyle.xml
sencha.senchaCmd=/user/local/lib/sencha/senchasencha.jsb3File=app.jsb3
build.properties example
Phing for power users
Use distinct naming conventions for your properties.
Accessing application configuration
Phing for power users
Accessing application configuration
Phing for power users
Duplicating configuration code is a bad habit.
Accessing application configuration
Phing for power users
<?phprequire_once 'phing/Task.php';
class ConfigMapperTask extends Task {/** * @see \Task::main() */public function main() {
// will import $APP_CONF in local contextrequire_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']);}
}
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>
Imports for Targets can help structuring
Phing for power users
<?xml version="1.0"?><project name="myproject" default="app:run">
<!--The following target namespaces exist:db:* - Database specific targetsapp:* - Application specific tasksci:* - 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
<?xml version="1.0"?><project name="myproject" default="app:run">
<!--The following target namespaces exist:lib1:* - Targets imported from lib1lib2:* - Targets imported from lib2app:* - 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
Import Targets: Path handling
Phing for power users
Be aware that imports behave like include in PHP!
<?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
<?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
$> ./vendor/bin/phingBuildfile: /tmp/myproject/build.xml
myproject > lib1:run:
[echo] Local dir: /tmp/myproject/vendor/lib1/build [echo] Global dir: /tmp/myproject
BUILD FINISHED
Total time: 0.0411 seconds
Import Targets: Path handling
Phing for power users
Import Targets: Path handling
Phing for power users
Be aware to always(!) use the projects name in lowercase format!
Import Targets: Path handling
Phing for power users
It`s ${phing.dir.myproject} not ${phing.dir.MyProject}!
Distinct Target Naming
Phing for power users
<?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
<?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
$> phing -lBuildfile: /tmp/myproject/build.xmlDefault 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
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>
Calling PHP functions from Phing
Phing for power users
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>
Restrict user access
Phing for power users
<?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
Path handling
Phing for power users
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>
Phing + Jenkins
Phing for power users
Phing + Jenkins
Phing for power users
Install the Jenkins Phing plugin
Phing for power users
Phing for power users
Phing for power users
Phing + Composer + Jenkins
Phing for power users
Phing + Composer + Jenkins
Phing for power users
Install the Jenkins EnvInject plugin
Phing for power users
Phing for power users
Phing for power users
Phing for power users
Follow conventions
Phing for power users
Follow conventions
Phing for power users
Phing expects your build file to be called build.xml and the build’s properties file
build.properties
Follow conventions
Phing for power users
Pick meaningful, human-readable names for targets and properties.
Follow conventions
Phing for power users
Make build files self-contained.
Thank you!
http://joind.in/9023
Phing for power users
Image Credits
http://www.sxc.hu/photo/629370http://www.sxc.hu/photo/615731