Skip to content

Instantly share code, notes, and snippets.

@xwero
Created September 3, 2011 08:05
Show Gist options
  • Save xwero/1190837 to your computer and use it in GitHub Desktop.
Save xwero/1190837 to your computer and use it in GitHub Desktop.
Ugling: static site generator with phing (the basics)
<?xml version="1.0" encoding="utf-8"?>
<project name="Ugling" basedir="." default="loop">
<!-- set variables to use in the tasks -->
<property name="dir.raw.content" value="content" />
<property name="dir.www.content" value="online" />
<property name="template.base" value="templates/base.html" />
<taskdef name="markdown" classname="phing.tasks.ext.MarkdownTask" />
<!-- phing gotcha: if you don't put a foreach in a target you get an error -->
<target name="loop">
<foreach param="filename" absparam="absfilename" target="single">
<fileset dir="${dir.raw.content}">
<include name="*.md"/>
<include name="**/*.md"/>
</fileset>
</foreach>
</target>
<target name="single" description="render a single markdown file to HTML and add template">
<php function="str_replace" returnProperty="file">
<param value=".md"/>
<param value=""/>
<param value="${filename}"/>
</php>
<markdown file="${absfilename}" destination="${dir.www.content}/${file}.html" />
<copy file="${dir.www.content}/${file}.html" tofile="${dir.www.content}/${file}2.html"/>
<!-- phing gotcha: expression attribute doen't process the variables -->
<php function="file_get_contents" returnProperty="pagecontent">
<param value="${dir.www.content}/${file}.html"/>
</php>
<php function="file_get_contents" returnProperty="rawtemplate">
<param value="${template.base}"/>
</php>
<php function="str_replace" returnProperty="templatecontent">
<param value="[CONTENT]"/>
<param value="${pagecontent}"/>
<param value="${rawtemplate}"/>
</php>
<php function="file_put_contents">
<param value="${dir.www.content}/${file}2.html"/>
<param value="${templatecontent}"/>
</php>
<move file="${dir.www.content}/${file}2.html" tofile="${dir.www.content}/${file}.html" overwrite="true"/>
</target>
</project>
<?php
require_once 'phing/Task.php';
require_once 'phing/util/FileUtils.php';
require_once 'System.php';
require_once "phing/tasks/ext/markdown/markdown.php";
class MarkdownTask extends Task {
/**
* @var string Taskname for logger
*/
protected $taskName = 'Markdown';
/**
* Result format, defaults to "html".
* @see $supportedFormats for all possible options
*
* @var string
*/
protected $format = 'html';
/**
* Input file in markdown format.
* Required
*
* @var string
*/
protected $file = null;
/**
* Output file or directory. May be omitted.
* When it ends with a slash, it is considered to be a directory
*
* @var string
*/
protected $destination = null;
protected $filesets = array(); // all fileset objects assigned to this task
protected $mapperElement = null;
/**
* all filterchains objects assigned to this task
*
* @var array
*/
protected $filterChains = array();
/**
* mode to create directories with
*
* @var integer
*/
protected $mode = 0755;
/**
* Only render files whole source files are newer than the
* target files
*
* @var boolean
*/
protected $uptodate = false;
/**
* The main entry point method.
*
* @return void
*/
public function main()
{
if (count($this->filterChains)) {
$this->fileUtils = new FileUtils();
}
if ($this->file != '') {
$file = $this->file;
$targetFile = $this->getTargetFile($file, $this->destination);
$this->render($file, $targetFile);
return;
}
if (!count($this->filesets)) {
throw new BuildException(
'"file" attribute or "fileset" subtag required'
);
}
// process filesets
$mapper = null;
if ($this->mapperElement !== null) {
$mapper = $this->mapperElement->getImplementation();
}
$project = $this->getProject();
foreach ($this->filesets as $fs) {
$ds = $fs->getDirectoryScanner($project);
$fromDir = $fs->getDir($project);
$srcFiles = $ds->getIncludedFiles();
foreach ($srcFiles as $src) {
$file = new PhingFile($fromDir, $src);
if ($mapper !== null) {
$results = $mapper->main($file);
if ($results === null) {
throw new BuildException(
sprintf(
'No filename mapper found for "%s"',
$file
)
);
}
$targetFile = reset($results);
} else {
$targetFile = $this->getTargetFile($file, $this->destination);
}
$this->render($file, $targetFile);
}
}
}
/**
* Renders a single file and applies filters on it
*
* @param string $tool conversion tool to use
* @param string $source markdown source file
* @param string $targetFile target file name
*
* @return void
*/
protected function render($source, $targetFile)
{
if (count($this->filterChains) == 0) {
return $this->renderFile($source, $targetFile);
}
$tmpTarget = tempnam(sys_get_temp_dir(), 'tmp-');
$this->renderFile($source, $tmpTarget);
$this->fileUtils->copyFile(
new PhingFile($tmpTarget),
new PhingFile($targetFile),
true, false, $this->filterChains,
$this->getProject(), $this->mode
);
unlink($tmpTarget);
}
/**
* Renders a single file with the markdown tool.
*
* @param string $tool conversion tool to use
* @param string $source markdown source file
* @param string $targetFile target file name
*
* @return void
*
* @throws BuildException When the conversion fails
*/
protected function renderFile($source, $targetFile)
{
if ($this->uptodate && file_exists($targetFile)
&& filemtime($source) <= filemtime($targetFile)
) {
//target is up to date
return;
}
//work around a bug in php by replacing /./ with /
$targetDir = str_replace('/./', '/', dirname($targetFile));
if (!is_dir($targetDir)) {
mkdir($targetDir, $this->mode, true);
}
$arOutput = Markdown(file_get_contents($source));
$retval = file_put_contents($targetFile,$arOutput);
if ( ! $retval) {
$this->log('File not rendered.', Project::MSG_INFO);
throw new BuildException('Rendering markdown failed');
}
$this->log('File rendered.', Project::MSG_DEBUG);
}
/**
* Determines and returns the target file name from the
* input file and the configured destination name.
*
* @param string $file Input file
* @param string $destination Destination file or directory name,
* may be null
*
* @return string Target file name
*
* @uses $format
* @uses $targetExt
*/
public function getTargetFile($file, $destination = null)
{
if ($destination != ''
&& substr($destination, -1) !== '/'
&& substr($destination, -1) !== '\\'
) {
return $destination;
}
if (strtolower(substr($file, -3)) == '.md') {
$file = substr($file, 0, -3);
}
return $destination . $file . '.' . $this->format;
}
/**
* The setter for the attribute "file"
*
* @param string $file Path of file to render
*
* @return void
*/
public function setFile($file)
{
$this->file = $file;
}
/**
* The setter for the attribute "destination"
*
* @param string $destination Output file or directory. When it ends
* with a slash, it is taken as directory.
*
* @return void
*/
public function setDestination($destination)
{
$this->destination = $destination;
}
/**
* The setter for the attribute "uptodate"
*
* @param string $uptodate True/false
*
* @return void
*/
public function setUptodate($uptodate)
{
$this->uptodate = (boolean)$uptodate;
}
/**
* Nested creator, creates a FileSet for this task
*
* @return object The created fileset object
*/
public function createFileSet()
{
$num = array_push($this->filesets, new FileSet());
return $this->filesets[$num-1];
}
/**
* Nested creator, creates one Mapper for this task
*
* @return Mapper The created Mapper type object
*
* @throws BuildException
*/
public function createMapper()
{
if ($this->mapperElement !== null) {
throw new BuildException(
'Cannot define more than one mapper', $this->location
);
}
$this->mapperElement = new Mapper($this->project);
return $this->mapperElement;
}
/**
* Creates a filterchain, stores and returns it
*
* @return FilterChain The created filterchain object
*/
public function createFilterChain()
{
$num = array_push($this->filterChains, new FilterChain($this->project));
return $this->filterChains[$num-1];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment