3 * Makefile for phpxmlrpc library.
4 * To be used with the Pake tool: https://github.com/indeyets/pake/wiki
6 * @copyright (c) 2015-2021 G. Giunta
8 * @todo !important allow user to specify location of docbook xslt instead of the one installed via composer
15 protected static $buildDir = 'build';
16 protected static $libVersion;
17 protected static $tools = array(
18 'asciidoctor' => 'asciidoctor',
23 protected static $options = array(
24 'repo' => 'https://github.com/gggeek/phpxmlrpc',
28 public static function libVersion()
30 if (self::$libVersion == null)
31 throw new \Exception('Missing library version argument');
32 return self::$libVersion;
35 public static function buildDir()
37 return self::$buildDir;
40 public static function workspaceDir()
42 return self::buildDir().'/workspace';
45 public static function toolsDir()
47 return self::buildDir().'/tools';
50 /// most likely things will break if this one is moved outside of BuildDir
51 public static function distDir()
53 return self::buildDir().'/xmlrpc-'.self::libVersion();
56 /// these will be generated in BuildDir
57 public static function distFiles()
60 'xmlrpc-'.self::libVersion().'.tar.gz',
61 'xmlrpc-'.self::libVersion().'.zip',
65 public static function getOpts($args=array(), $cliOpts=array())
68 // throw new \Exception('Missing library version argument');
69 self::$libVersion = $args[0];
71 foreach (self::$tools as $name => $binary) {
72 if (isset($cliOpts[$name])) {
73 self::$tools[$name] = $cliOpts[$name];
77 foreach (self::$options as $name => $value) {
78 if (isset($cliOpts[$name])) {
79 self::$options[$name] = $cliOpts[$name];
83 //pake_echo('---'.self::$libVersion.'---');
90 public static function tool($name)
92 return self::$tools[$name];
99 public static function option($name)
101 return self::$options[$name];
105 * @param string $inFile
106 * @param string $xssFile
107 * @param string $outFileOrDir
110 public static function applyXslt($inFile, $xssFile, $outFileOrDir)
112 if (!file_exists($inFile)) {
113 throw new \Exception("File $inFile cannot be found");
115 if (!file_exists($xssFile)) {
116 throw new \Exception("File $xssFile cannot be found");
119 // Load the XML source
120 $xml = new \DOMDocument();
122 $xsl = new \DOMDocument();
123 $xsl->load($xssFile);
125 // Configure the transformer
126 $processor = new \XSLTProcessor();
127 if (version_compare(PHP_VERSION, '5.4', "<")) {
128 if (defined('XSL_SECPREF_WRITE_FILE')) {
129 ini_set("xsl.security_prefs", XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
132 // the php online docs only mention setSecurityPrefs, but somehow some installs have setSecurityPreferences...
133 if (method_exists('XSLTProcessor', 'setSecurityPrefs')) {
134 $processor->setSecurityPrefs(XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
136 $processor->setSecurityPreferences(XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
139 $processor->importStyleSheet($xsl); // attach the xsl rules
141 if (is_dir($outFileOrDir)) {
142 if (!$processor->setParameter('', 'base.dir', realpath($outFileOrDir))) {
143 echo "setting param base.dir KO\n";
147 $out = $processor->transformToXML($xml);
149 if (!is_dir($outFileOrDir)) {
150 file_put_contents($outFileOrDir, $out);
154 public static function highlightPhpInHtml($content)
156 $startTag = '<pre class="programlisting">';
159 //$content = file_get_contents($inFile);
162 while (($start = strpos($content, $startTag, $last)) !== false) {
163 $end = strpos($content, $endTag, $start);
164 $code = substr($content, $start + strlen($startTag), $end - $start - strlen($startTag));
165 if ($code[strlen($code) - 1] == "\n") {
166 $code = substr($code, 0, -1);
169 $code = str_replace(array('>', '<'), array('>', '<'), $code);
170 $code = highlight_string('<?php ' . $code, true);
171 $code = str_replace('<span style="color: #0000BB"><?php <br />', '<span style="color: #0000BB">', $code);
173 $out = $out . substr($content, $last, $start + strlen($startTag) - $last) . $code . $endTag;
174 $last = $end + strlen($endTag);
176 $out .= substr($content, $last, strlen($content));
186 use PhpXmlRpc\Builder;
188 function run_default($task=null, $args=array(), $cliOpts=array())
190 echo "Syntax: pake {\$pake-options} \$task \$lib-version [\$git-tag] {\$task-options}\n";
192 echo " Run 'pake help' to list all pake options\n";
193 echo " Run 'pake -T' to list available tasks\n";
194 echo " Run 'pake -P' to list all available tasks (including hidden ones) and their dependencies\n";
196 echo " Task options:\n";
197 echo " --repo=REPO URL of the source repository to clone. Defaults to the github repo.\n";
198 echo " --branch=BRANCH The git branch to build from.\n";
199 echo " --asciidoctor=ASCIIDOCTOR Location of the asciidoctor command-line tool\n";
200 echo " --fop=FOP Location of the apache fop command-line tool\n";
201 echo " --php=PHP Location of the php command-line interpreter\n";
202 echo " --zip=ZIP Location of the zip tool\n";
205 function run_getopts($task=null, $args=array(), $cliOpts=array())
207 Builder::getOpts($args, $cliOpts);
211 * Downloads source code in the build workspace directory, optionally checking out the given branch/tag
212 * @todo allow using current installation as source, bypassing git clone in workspace - at least for doc generation
214 function run_init($task=null, $args=array(), $cliOpts=array())
216 // download the current version into the workspace
217 $targetDir = Builder::workspaceDir();
219 // check if workspace exists and is not already set to the correct repo
220 if (is_dir($targetDir) && pakeGit::isRepository($targetDir)) {
221 $repo = new pakeGit($targetDir);
222 $remotes = $repo->remotes();
223 if (trim($remotes['origin']['fetch']) != Builder::option('repo')) {
224 throw new Exception("Directory '$targetDir' exists and is not linked to correct git repo");
227 /// @todo should we not just fetch instead?
230 pake_mkdirs(dirname($targetDir));
231 $repo = pakeGit::clone_repository(Builder::option('repo'), Builder::workspaceDir());
234 $repo->checkout(Builder::option('branch'));
238 * Runs all the build steps.
240 * (does nothing by itself, as all the steps are managed via task dependencies)
242 function run_build($task=null, $args=array(), $cliOpts=array())
246 function run_clean_doc()
248 pake_remove_dir(Builder::workspaceDir().'/doc/api');
249 $finder = pakeFinder::type('file')->name('*.html');
250 pake_remove($finder, Builder::workspaceDir().'/doc/manual');
251 $finder = pakeFinder::type('file')->name('*.xml');
252 pake_remove($finder, Builder::workspaceDir().'/doc/manual');
256 * Generates documentation in all formats
258 function run_doc($task=null, $args=array(), $cliOpts=array())
261 $srcDir = Builder::workspaceDir();
263 $docDir = Builder::workspaceDir().'/doc';
267 // from phpdoc comments using phpdocumentor
268 $cmd = Builder::tool('php');
269 pake_sh("$cmd " . Builder::toolsDir(). "/vendor/bin/phpdoc run --cache-folder ".Builder::buildDir()."/.phpdoc -d ".$srcDir.'/src'." -t ".$docDir.'/api --title PHP-XMLRPC');
271 // from phpdoc comments using Sami
272 // deprecated on 2021/12, as Sami is abandonware
273 /*$samiConfig = <<<EOT
275 \$iterator = Symfony\Component\Finder\Finder::create()
277 ->exclude('debugger')
281 ->in('./build/workspace');
282 return new Sami\Sami(\$iterator, array(
283 'title' => 'PHP-XMLRPC',
284 'build_dir' => 'build/workspace/doc/api',
285 'cache_dir' => 'build/cache',
288 file_put_contents('build/sami_config.php', $samiConfig);
289 $cmd = Builder::tool('php');
290 pake_sh("$cmd " . Builder::toolsDir(). "/vendor/bin/sami.php update -vvv build/sami_config.php");*/
294 // html (single file) from asciidoc
295 $cmd = Builder::tool('asciidoctor');
296 pake_sh("$cmd -d book -o $docDir/manual/phpxmlrpc_manual.html $srcDir/doc/manual/phpxmlrpc_manual.adoc");
298 // then docbook from asciidoc
299 /// @todo create phpxmlrpc_manual.xml with the good version number
300 /// @todo create phpxmlrpc_manual.xml with the date set to the one of last commit (or today?)
301 pake_sh("$cmd -d book -b docbook -o $docDir/manual/phpxmlrpc_manual.xml $srcDir/doc/manual/phpxmlrpc_manual.adoc");
303 # Other tools for docbook...
305 # jade cmd yet to be rebuilt, starting from xml file and putting output in ./out dir, e.g.
306 # jade -t xml -d custom.dsl xmlrpc_php.xml
308 # convertdoc command for xmlmind xxe editor
309 # convertdoc docb.toHTML xmlrpc_php.xml -u out
311 # saxon + xerces xml parser + saxon extensions + xslthl: adds a little syntax highlighting
312 # (bold and italics only, no color) for php source examples...
314 # -classpath c:\programmi\saxon\saxon.jar\;c:\programmi\saxon\xslthl.jar\;c:\programmi\xerces\xercesImpl.jar\;C:\htdocs\xmlrpc_cvs\docbook-xsl\extensions\saxon65.jar \
315 # -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
316 # -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl \
317 # -Dxslthl.config=file:///c:/htdocs/xmlrpc_cvs/docbook-xsl/highlighting/xslthl-config.xml \
318 # com.icl.saxon.StyleSheet -o xmlrpc_php.fo.xml xmlrpc_php.xml custom.fo.xsl use.extensions=1
320 // HTML (multiple files) from docbook - discontinued, as we use the nicer-looking html gotten from asciidoc
321 /*Builder::applyXslt($docDir.'/manual/phpxmlrpc_manual.xml', $docDir.'/build/custom.xsl', $docDir.'/manual');
322 // post process html files to highlight php code samples
323 foreach(pakeFinder::type('file')->name('*.html')->in($docDir.'/manual') as $file)
325 file_put_contents($file, Builder::highlightPhpInHtml(file_get_contents($file)));
328 // PDF file from docbook
330 // convert to fo and then to pdf using apache fop
331 Builder::applyXslt($docDir.'/manual/phpxmlrpc_manual.xml', $docDir.'/build/custom.fo.xsl', $docDir.'/manual/phpxmlrpc_manual.fo.xml');
332 $cmd = Builder::tool('fop');
333 pake_sh("$cmd $docDir/manual/phpxmlrpc_manual.fo.xml $docDir/manual/phpxmlrpc_manual.pdf");
336 unlink($docDir.'/manual/phpxmlrpc_manual.xml');
337 unlink($docDir.'/manual/phpxmlrpc_manual.fo.xml');
340 function run_clean_dist()
342 pake_remove_dir(Builder::distDir());
343 $finder = pakeFinder::type('file')->name(Builder::distFiles());
344 pake_remove($finder, Builder::buildDir());
348 * Creates the tarballs for a release
350 function run_dist($task=null, $args=array(), $cliOpts=array())
352 // copy workspace dir into dist dir, without git
353 pake_mkdirs(Builder::distDir());
354 $finder = pakeFinder::type('any')->ignore_version_control();
355 pake_mirror($finder, realpath(Builder::workspaceDir()), realpath(Builder::distDir()));
357 // remove unwanted files from dist dir
359 // also: do we still need to run dos2unix?
363 chdir(dirname(Builder::distDir()));
364 foreach(Builder::distFiles() as $distFile) {
365 // php can not really create good zip files via phar: they are not compressed!
366 if (substr($distFile, -4) == '.zip') {
367 $cmd = Builder::tool('zip');
369 pake_sh("$cmd $distFile $extra ".basename(Builder::distDir()));
372 $finder = pakeFinder::type('any')->pattern(basename(Builder::distDir()).'/**');
373 // see https://bugs.php.net/bug.php?id=58852
374 $pharFile = str_replace(Builder::libVersion(), '_LIBVERSION_', $distFile);
375 pakeArchive::createArchive($finder, '.', $pharFile);
376 rename($pharFile, $distFile);
382 function run_clean_workspace($task=null, $args=array(), $cliOpts=array())
384 pake_remove_dir(Builder::workspaceDir());
388 * Cleans up the whole build directory
389 * @todo 'make clean' usually just removes the results of the build, distclean removes all but sources
391 function run_clean($task=null, $args=array(), $cliOpts=array())
393 pake_remove_dir(Builder::buildDir());
396 // helper task: display help text
397 pake_task( 'default' );
398 // internal task: parse cli options
399 pake_task('getopts');
400 pake_task('init', 'getopts');
401 pake_task('doc', 'getopts', 'init', 'clean-doc');
402 pake_task('build', 'getopts', 'init', 'doc');
403 pake_task('dist', 'getopts', 'init', 'build', 'clean-dist');
404 pake_task('clean-doc', 'getopts');
405 pake_task('clean-dist', 'getopts');
406 pake_task('clean-workspace', 'getopts');
407 pake_task('clean', 'getopts');