Thursday, September 24th, 2009...4:14 pm
My First Attempt With Phing
I’ve finally come to the place where I need some help in automated deployments. I’ve got a few weekend PHP projects that are getting large enough that deploying them takes a few minutes — minutes where stuff can break and stay broken until I remember the exact command line call I need to make to fix them. SVN export, symlinks, mkdir’s, etc etc. I want to automate this crap!
My first attempt was with using Capistrano. I’d heard it could be hacked a bit to make it deploy just about anything. So I installed the gem and tinkered. The trouble is, I don’t have time to learn Ruby right now. Furthermore, I don’t like having the Ruby/Capistrano dependencies.
…and in walks Phing — automated deployment using PHP and XML. Hey! I know those!
Installing Phing was a bit more troublesome than Capistrano — mainly because my hosting company (Dreamhost) has some restrictions around installing PEAR modules and also a small issue in that the default command line bin for PHP is v4 — no good for Phing, which requires PHP5.
A few hours later, and viola! Phing is ready to roll.
So here’s my first script (well, I stripped out some duplicate actions — these two are the most interesting). It imports two files: “mysql.properties” and “subversion.properties” as needed. If you have any comments, questions, or suggestions, post a comment.
Also, my xml is a bit wider than my blog here, so here’s the source
-
< ?xml version="1.0"?>
-
<project name="build" default="help">
-
-
<target name="help">
-
<exec command="phing -h" passthru="true" />
-
</target>
-
-
<target name="load.subversion">
-
<property file="subversion.properties" />
-
</target>
-
-
<target name="load.mysql">
-
<property file="mysql.properties" />
-
</target>
-
-
<!–deploy a productionv version of an API I wrote. SVN export with a build number’d folder, then change the symlink –>
-
<target name="api-deploy" depends="load.subversion">
-
<!–setup properties–>
-
<property name="repo" value="http://${svn.username}:${svn.password}@${svn.base}/api/trunk" />
-
<!–display repo info–>
-
<exec command="svn info ${repo}" passthru="true" />
-
<!–ask user for revision num–>
-
<propertyprompt propertyName="svn.exportrevision" promptText="Enter the API revision number to deploy" />
-
<property name="exportdir" value="/www/builds/api/${svn.exportrevision}" />
-
<echo>Will deploy to ${exportdir}</echo>
-
<exec command="svn export -r ${svn.exportrevision} ${repo} ${exportdir}" />
-
-
<!–make sure the export worked –>
-
<available file="${exportdir}" type="dir" property="export.success" />
-
<if>
-
<equals arg1="${export.success}" arg2="TRUE" />
-
<then>
-
<echo message="SVN successfully exported (${export.success})" />
-
</then>
-
<else>
-
<fail message="There was an error with the SVN export. Most likely, you supplied an incorrect revision number" />
-
</else>
-
</if>
-
-
<!–create cache folder –>
-
<mkdir dir="${exportdir}/system/cache" />
-
<exec command="chmod 777 ${exportdir}/system/cache" />
-
<echo>API Revision #${svn.exportrevision} exported to ${exportdir}</echo>
-
-
<!–symlink api.mydomain.com to svn export –>
-
<exec command="ln -nfs ${exportdir} /www/api.mydomain.com" />
-
-
</target>
-
-
-
<target name="api-rollback">
-
<!–display possible rollback dirs–>
-
<echo msg="Possible directories to rollback to:" />
-
<exec command="ls" dir="/www/builds/api/" passthru="true" />
-
<propertyprompt propertyName="svn.rollbackrevision" promptText="Which revision to rollback to?" />
-
<property name="rollbackdir" value="/www/builds/api/${svn.rollbackrevision}" />
-
<!–let’s make sure that directory exists–>
-
<available file="${rollbackdir}" type="dir" property="rollback.available" />
-
<if>
-
<equals arg1="${rollback.available}" arg2="TRUE" />
-
<then>
-
<exec command="ln -nfs ${rollbackdir} /www/api.mydomain.com" />
-
<echo>API rolled back to revision # ${svn.rollbackrevision}</echo>
-
</then>
-
<else>
-
<fail message="The rollback revision folder you specified does not exist" />
-
</else>
-
</if>
-
</target>
-
-
<!–sync my PRD DB and wordpress wp-content/uploads to DEV –>
-
<target name="sync-dev-db" depends="load.mysql">
-
<property name="tmp.folder" value="/www/tmp" />
-
<property name="sql.filename" value="mydomain_prd_tmp.sql" />
-
<property name="sql.file" value="${tmp.folder}/${sql.filename}" />
-
<exec command="mysqldump -u${mysql.username} -p${mysql.password} -h ${mysql.server} mydomain_prd > ${sql.file}" />
-
<reflexive>
-
<fileset dir="${tmp.folder}">
-
<include pattern="${sql.filename}" />
-
</fileset>
-
<filterchain>
-
<replaceregexp>
-
<regexp pattern="prd.mydomain.com" replace="dev.mydomain.com" ignoreCase="true"/>
-
</replaceregexp>
-
</filterchain>
-
</reflexive>
-
<!– next step, MySQL import to mydomain_dev and delete the tmp sql dump –>
-
<exec passthru="true" command="mysql -u${mysql.username} -p${mysql.password} -h ${mysql.server} mydomain_dev < ${sql.file}" />
-
<delete file="${sql.file}" />
-
<!– sync PRD wp-content/uploads to DEV wp-content/uploads –>
-
<exec command="rm -r /www/dev.mydomain.com/wp-content/uploads" />
-
<exec command="cp -rp /www/prd.mydomain.com/wp-content/uploads /www/dev.mydomain.com/wp-content/" />
-
<!– make sure the dev uploads folder exists –>
-
<available file="/www/dev.mydomain.com/wp-content/uploads" type="dir" property="folder.available" />
-
<if>
-
<equals arg1="${folder.available}" arg2="FALSE" />
-
<then>
-
<fail message="Something’s wrong — the dev ‘uploads‘ folder isn’t where it should be." />
-
</then>
-
</if>
-
-
</exec></target>
-
-
</project>
3 Comments
September 24th, 2009 at 8:55 pm
I too am on dreamhost can you share the details of getting this to work.
September 24th, 2009 at 10:27 pm
Hey Steve –
Are you on shared hosting? If so, these instructions may help: http://wiki.dreamhost.com/PEAR
If you’re on a PS, I’m happy to share those instructions. Lemme know.
-Jon
September 25th, 2009 at 4:49 pm
Jon,
For the moment I am on shared hosting. So thanks for the link.
Steve
Leave a Reply