For those of you not familiar with Apache ant, I've also done a script which works for me, under Fedora Linux. YMMV
See the references for a full list of files, but the basics
follow the ant idea. It is called build.sh, uses
an external file (build.properties.sh) to hold
most of the variables (exepting the website user name and password),
also a couple of odd functions I've developed. Each part (action) of
the ant script is created as a bash function so they can be tested
from the bottom of the main script.
@@TODO. Create some sort of case statement which will call up an appropriate function, e.g. when I want to upload, I can call the appropriate function. Done, first pass. Could be refined further.
$build.sh upload
Something like that. Then a help screen if you don't pass any parameters to the script.
It is also included here (xIncluded) so you can see the ideas. Since this is the actual file used, it contains some very long lines which are wrapped using the \ line terminator. This works in bash version 3.
There are a couple of statements worthy of note for those
unfamiliar with bash. The source command includes
or imports another bash script, here
build.properties.sh and
website.properties.sh. These then become
accessible to this and any called scripts (see
tmp.sh which is created and executed later
on).
There are a few helper functions, not very nicely mixed between
this file and build.properties.sh. The functions
are (hopefully) self evident, I don't want to document them here in
case they change. Of note (and something that trips me up regularly)
is the defined function, which tests that a
variable both is defined and non-empty. Bash isn't very forgiving on
empty variables, so I found this necessary. The intent is to test
every variable in this manner. Perhaps I could/should have done it
once, rather than at each function call, but that's a mod you can put
in if the time constraint bothers you.
Dependencies are managed by having a function which calls up a
sequence of other functions necessary for them to run, e.g. to build
the main html output, I first expand all xIncludes then validate the
result. I've commented out the testing sequences I ran. The file is
build.sh xIncluded below
#!/bin/bash
# Rev 1.1 2009-05-21T08:51:36Z
# externalized all variable testing - see testvars.sh
# variable definitions
source build.properties.sh
# properties for my website. See website.properties.dummy
source website.properties.sh
# functions
# todays date
#
TODAY(){
echo `date -u '+%Y-%m-%dT%H:%M:%S'`
}
#
# Get filename, no extension
#
namename()
{
name=${1##*/}
name0="${name%.*}"
echo "${name0:-$name}"
}
#
# Test if a variable us set, does not test for an empty value
defined()
{
if [ ! "${!1-one}" == "${!1-two}" ]
then
echo variable ${1} does not exist! Quitting
exit 2
fi
: "${!1:? "Variable $1 is empty, aborting."}"
}
basedir=`pwd`
properties=${basedir}/build.properties.sh
#Main input file
main_infile=setup.xml
# ================================================
# Main input file
# ================================================
infile_basename=`namename ${main_infile}`
# name of zip file
zip_filename=${infile_basename}.zip
# ================================================
# assert that a variable is set and is not empty
#
#source http://stackoverflow.com/questions/874389/
#bash-test-for-a-variable-unset-using-a-function
# ================================================
assertIsSet2() {
if [[ ! ${!1} && ${!1-_} ]]
then
echo "$1 is not set, aborting." >&2
exit 1
#else
# echo ${1} is set, value [${1}]
fi
: "${!1:? "$1 is empty, aborting."}"
}
# ================================================
#Test exit status of last process, quit if non-zero
# ================================================
exitOK(){
if [ $? -ne 0 ]
then
echo ${1} failed, quitting
exit 2
fi
}
# ================================================
# Initialisation
# ================================================
init(){
echo Do initialisational things
# Run the python script to generate the testvars.sh
rm -f testvars.sh
touch testvars.sh
python antvars.sh.py -in build.properties.sh -out testvars.sh
# include the created shell script
source testvars.sh
# Now run the function
testvars
echo building on `TODAY`. All variables tested
}
# ================================================
#Clean out the ${out_dir} directory: If needed.
# ================================================
clean_html(){
if [ ! -d ${out_html_dir} ]
then
echo directory ${out_html_dir} does not exist, quitting
exit 2
fi
echo Clean out ${out_html_dir} directory
rm -v -f ${out_html_dir}/*.html
}
# ================================================
# Clean out the pdf directory
# ================================================
clean_pdf(){
if [ ! -d ${out_pdf_dir} ]
then
echo directory ${out_pdf_dir} does not exist, quitting
exit 2
fi
echo Clean out the ${out_pdf_dir} directory
rm -v -f ${out_pdf_dir}/*.fo
rm -v -f ${out_pdf_dir}/*.pdf
}
# ================================================
# Expand any xincludes in the source file
# ================================================
Xinclude(){
echo Expand Xincludes in $main_infile
xmllint -o ${xincluded_file} --xinclude ${basedir}/$main_infile
if [ $? -ne 0 ]
then
echo $xmllint fail, xincludes incorrect
fi
}
# ================================================
# Validate. Depends on Xinclude
# ================================================
Jing() {
echo Validate using Jing
# Check variables -->
java -cp ${jing_classpath} \
-Dorg.apache.xerces.xni.parser.XMLParserConfiguration=org.apache.xerces.parsers.XIncludeParserConfiguration \
com.thaiopensource.relaxng.util.Driver $my_schema_rng ${xincluded_file}
exitOK Jing
echo $main_infile is valid
}
# ================================================
#Generate a script to move all used images
# into either html or PDF directory
# ================================================
listimages(){
echo List all images in ${main_infile}
java -cp ${xslt1_processor_classpath} \
-Dorg.apache.xerces.xni.parser.XMLParserConfiguration=\
org.apache.xerces.parsers.XIncludeParserConfiguration \
-Djavax.xml.parsers.DocumentBuilderFactory=\
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
${xslt1_processor} -l -o ${out_dir}/${copy_cmd} \
-x org.apache.xml.resolver.tools.ResolvingXMLReader \
-y org.apache.xml.resolver.tools.ResolvingXMLReader \
-r org.apache.xml.resolver.tools.CatalogResolver \
${in_dir}/${xincluded_file} ${listimages_sh_stylesheet} ${param_args_post}
exitOK
echo Finished at `TODAY`. See ${out_dir}/${copy_cmd}
chmod +x ${out_dir}/${copy_cmd}
}
# ================================================
# Copy the images over to the target
# ================================================
copyimages (){
${copy_cmd} $1
}
# ================================================
# Generic XSLT-processor call (main docbook transform)
# ================================================
# Depends on init, clean, validate, listimages
docbook() {
#echo ${xslt1_processor_classpath}
java -cp ${xslt1_processor_classpath} \
-Dorg.apache.xerces.xni.parser.XMLParserConfiguration=\
org.apache.xerces.parsers.XIncludeParserConfiguration \
-Djavax.xml.parsers.DocumentBuilderFactory=\
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
${xslt1_processor} -l -o ${out_dir}/${main_outfile} \
-x org.apache.xml.resolver.tools.ResolvingXMLReader \
-y org.apache.xml.resolver.tools.ResolvingXMLReader \
-r org.apache.xml.resolver.tools.CatalogResolver \
${in_dir}/${xincluded_file} ${html_stylesheet} ${param_args_post}
exitOK
echo Finished at `TODAY`
}
# ================================================
# Process xIncluded source to xsl-fo
# ================================================
fo() { # depends="init, validate, clean_pdf"
echo Generate the fo output
java -cp ${xslt1_processor_classpath} \
-Dorg.apache.xerces.xni.parser.XMLParserConfiguration=\
org.apache.xerces.parsers.XIncludeParserConfiguration \
-Djavax.xml.parsers.DocumentBuilderFactory=\
org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
${xslt1_processor} \
-x org.apache.xml.resolver.tools.ResolvingXMLReader \
-y org.apache.xml.resolver.tools.ResolvingXMLReader \
-r org.apache.xml.resolver.tools.CatalogResolver -l \
-o ${out_pdf_dir}/${main_fo_outfile} \
${in_dir}/${xincluded_file} ${main_fo_stylesheet}
exitOK
echo Finished at `TODAY`
}
# ================================================
# Generate PDF from fo, using XEP
# ================================================
pdf() { #depends="fo"
echo Generate the pdf in $out_pdf_dir from ${out_pdf_dir}/${main_fo_outfile}
#echo cp is ${fo_processor_classpath}
java -cp ${fo_processor_classpath} \
-Dcom.renderx.xep.CONFIG=${xephome}/xep.xml \
${fo_processor_class} -quiet \
-fo ${out_pdf_dir}/${main_fo_outfile} \
-pdf ${out_pdf_dir}/${infile_basename}.pdf
echo Finished at `TODAY`
}
# ================================================
# zip task. Zip up a list of files
# ================================================
zip(){
rm -rf ${zip_src_directory}
mkdir ${zip_src_directory}
echo creating ${zip_filename} from ${infile_basename}
#zip <zipfile> file file file # zips up a directory into zipfile
# -f freshen existing zip
# -r recurse into directories
# -u update as determined by dates
echo -n zip ${zip_src_directory}/${zip_filename} > tmp.sh
echo -n " " >> tmp.sh
for f in ${zip_file_list}
do
echo -n $f >> tmp.sh
echo -n " " >> tmp.sh
done
cat tmp.sh
chmod +x tmp.sh
#Now run the zip command
echo Creating ${zip_src_directory}/${zip_filename}
tmp.sh
rm -f tmp.sh
# List it if needed
#unzip -l ${zip_src_directory}/${zip_filename}
}
#================================================
# upload all files to website, ftp
#================================================
uploadhtml ()
{
echo sending from ${out_html_dir} to ${myroot}
ftp -in ${website_tgt} <<ENDFTP
verbose
user ${user_id} ${user_password}
cd ${froot}
cd ${ftp_tgt}
lcd ${out_html_dir}
mput *.html
mput *.css
mkdir graphics
mput graphics/*.*
bye
ENDFTP
}
#
# Validate. Depends on Xinclude
#
validate (){
Xinclude
Jing
}
#
#Docbook with all dependencies
#
docbookGroup(){
init
clean_html
validate
listimages
copyimages ${local_graphics_html_tgt}
docbook
}
pdfGroup(){
init
clean_pdf
validate
listimages
copyimages ${local_graphics_pdf_tgt}
fo
pdf
}
#
# Basic Show help function
#
usage(){
echo Usage:
echo "validate - Validate the source against docbook v5"
echo "docbook - Produce an html output of the source"
echo "pdf - Produce a PDF output of the source"
echo "zip - Zip up the associated working files"
echo "upload html|pdf - Upload to the website"
echo "help - Produce this help message"
exit 2
}
#
# Handle command line parameters
#
if [ $# -lt 1 ]
then
usage
exit 2
fi
echo $1 is "[${1}]"
case $1 in
init)
init
;;
(validate|valid)
validate
;;
(docbook|docbookGroup|html)
docbookGroup
;;
("pdf|pdfGroup|print")
pdfGroup
;;
zip)
zip
;;
upload)
if [ $# = 2 ]
then
if [ $2 = "html" ]
then
uploadhtml
else
if [ $2 = "pdf" ]
then
uploadpdf
else
echo "Invalid parameter $2"
exit 2
fi
fi
else
echo "Second Parameter needed to upload,"
echo "Either html or pdf. Quitting"
exit 2
fi
;;
*)
help
exit 2
esac
#zip
#upload
#pdfGroup
#bname=`namename ${in_dir}/docbook.fo.xsl`
#echo $bname
#clean_html
#'clean_pdf
#defined xmllint
#docbookGroup
#assertIsSet2 docbookX
#assertIsSet2 docbook
#x=
#defined x
#
#echo \$docbook has value $docbook
#assertIsSet2 docbook
#assertIsSet2 x
#defined docbook
#defined x
@TODO As per the ant script, one action which would tidy this up is to collate the variable checking into a single place. I made this harder by using two forms of variables (using underscore and period to isolate words in variable names).
That's it folks. The included file
build.properties.sh (holding the variables) is
below
#properties file for generic docbook ant script.
#Avoids all build specific values!
#Version 1.0
#Date 2009-05-17T06:30:00Z
#Author Dave Pawson
#
#Version 1.1
#Date: 2009-05-28T07:37:24Z
#Author Dave Pawson
# Adopted for use with ant as well, for common defs
TODAY_UK=
fintim=
# docbook location: Everything taken relative to this for docbook stuff
docbook=/sgml/docbook
# Main stylesheets
stylesheets=${docbook}/docbook-xsl-ns
html_stylesheets=${stylesheets}/html
fo_stylesheets=${stylesheets}/fo
# Main Docbook stylesheet is imported via my customization layer
# (docbook.html.xsl)
html_stylesheet=docbook.html.xsl
# saxon extensions which come with docbook
dbsaxonextensions=${stylesheets}/extensions/saxon65.jar
# Docbook v5 Schema
db_schema_rng=$docbook/v5/rng/docbookxi.rng
my_schema_rng=poem.rng
#
# Working files, used for zip and upload, see ${zip_file_list}
#
#
#
docbook_html_xsl=docbook.html.xsl
poem_rng=poem.rng
docbook_fo_xsl=docbook.fo.xsl
listimages_sh_xsl=listimages.sh.xsl
dpawson_css=dpawson.css
build_properties=build.properties
build_properties_sh=build.properties.sh
build_sh=build.sh
build_xml=build.xml
cp_images_sh=cp.images.sh
docbook_html_xsl=docbook.html.xsl
listimages_sh_xsl=listimages.sh.xsl
listimages_stylesheet=listimages.xsl
imagelist_anttask=copyimages.xml
test_docbook_xml=test.docbook.xml
testvars_xsl=testvars.xsl
testprops_xsl=testprops.xsl
antvars_py=antvars.py
antvars_sh_py=antvars.sh.py
example_catalog=db5.catalog.xml
catalog_manager=CatalogManager.properties
# Input properties:
basedir=`pwd`
# all xml files should be in this directry
in_dir=${basedir}
# source file for doLayout target
autolayout_infile=newlayout.xml
# source file for website transform on second pass
website_infile=autolayout.xml
# Output Properties: Output directory
out_dir=${basedir}
out_html_dir=${out_dir}/html
# Main output file used for docbook html transform
main_outfile=${infile_basename}.html
# fo output
out_pdf_dir=${out_dir}/pdf
out_pdf_dir=${out_dir}/pdf
main_fo_stylesheet=${in_dir}/docbook.fo.xsl
main_fo_outfile=test.fo
#pdf output
main_pdf_outfile=${infile_basename}.pdf
# global Styles directory, on disk and on website
global_styles=/styles
#local graphics source
local_graphics_src=${in_dir}/graphics
#local graphics target - html
local_graphics_html_tgt=${out_html_dir}/graphics
#local graphics target - pdf
local_graphics_pdf_tgt=${out_pdf_dir}/graphics
# task to copy images to local target
#XSLT stylesheet used to generate copy command (html and fo)
listimages_sh_stylesheet=listimages.sh.xsl
# copy command - used for both html and fo
copy_cmd=cp.images.sh
#CSS stylesheet
css_stylesheet=dpawson.css
# Java locations
java=/myjava
# zip file build target directory
zip_src_directory=${out_dir}/upload
# zip filename - define in bash.sh or build.xml
# Post XSLT transform parameter. Leave as is for Saxon
param_args_post="saxon.extensions=1"
# XSLT properties
xslt1_processor=com.icl.saxon.StyleSheet
xslt2_processor=net.sf.saxon.Transform
xslt1_jar=saxon655.jar
xslt2_jar=saxon9.jar
# xsl-fo processing
fo_processor_class=com.renderx.xep.XSLDriver
xephome=$java/xep
# Catalog resolver
resolver_jar=resolver.jar
xmlcatalog=/sgml/catalog.xml
# XML parser
xerces_jar=xerces.jar
xerces_impl_jar=xercesImpl.jar
xml_apis_jar=xml-api
#xerces api
xerces_api_jar=xml-apis.jar
#xinclude processor
xmllint=/usr/bin/xmllint
# Temporary xincluded file
xincluded_file=tmp.xml
#Jing parser
jing_jar=jing.jar
#zip file list of required files
zip_file_list="${docbook_html_xsl} ${poem_rng} ${docbook_fo_xsl} \
${listimages_sh_xsl} ${dpawson_css} ${xmlcatalog} \
${build_properties_sh} ${build_sh} ${build_xml} ${cp_images_sh} \
${docbook_html_xsl} ${listimages_sh_xsl} ${listimages_stylesheet} \
${test_docbook_xml} ${antvars_py} ${antvars_sh_py} ${testvars_xsl} \
${example_catalog} ${catalog_manager}"
# local directory for uploading
uploaddir=${basedir}/upload
#classpath for Jing, relax NG validator from James Clark
jing_classpath=${java}/jing.jar:${java}/${xslt1_jar}:$java/${xerces_jar}:\
$java/${xerces_api_jar}
# xslt 1 class
xslt1_processor_class=com.icl.saxon.StyleSheet
xslt2_processor=net.sf.saxon.Transform
# path for xslt processor.
#Includes resolver and extensions and catalogManager.properties file.
xslt1_processor_classpath=\
${java}/${xslt1_jar}:\
${java}/${resolver_jar}:\
${java}/${xerces_jar}:\
${java}/${xerces_impl_jar}\
${java}/${xml_apis_jar}\
${dbsaxonextensions}:\
/sgml
# path for xslt 2.processor.
#Includes resolver and extensions and catalogManager.properties file. -->
xslt2_processor_classpath=$java/saxon9.jar:$java/resolver.jar:\
${dbsaxonextensions}:$java/xercesImpl.jar:/sgml:.
#Location of the XML catalog, see
#http://www.asios-open.org/committees/entity/spec-2001-08-06.html
catalogpath=$xmlcatalog
# Paths for xsl-fo processing
fo_processor_classpath=/usr/java/default/lib/tools.jar:\
$java/xep/lib/xep.jar:$xephome/lib/saxon.jar:$xephome/lib/xt.jar