Remove gitignore from docs dir, as we now build in a separate directory
[plcapi.git] / pakefile.php
1 <?php
2 /**
3  * Makefile for phpxmlrpc library.
4  * To be used with the Pake tool: https://github.com/indeyets/pake/wiki
5  *
6  * @copyright (c) 2015 G. Giunta
7  *
8  * @todo allow user to specify release number and tag/branch to use
9  * @todo !important allow user to specify location of docbook xslt instead of the one installed via composer
10  */
11
12 namespace PhpXmlRpc {
13
14 class Builder
15 {
16     protected static $buildDir = 'build';
17     protected static $libVersion;
18     protected static $sourceBranch = 'master';
19     protected static $tools = array(
20         'zip' => 'zip',
21         'fop' => 'fop',
22         'php' => 'php'
23     );
24
25     public static function libVersion()
26     {
27         return self::$libVersion;
28     }
29
30     public static function buildDir()
31     {
32         return self::$buildDir;
33     }
34
35     public static function workspaceDir()
36     {
37         return self::buildDir().'/workspace';
38     }
39
40     /// most likely things will break if this one is moved outside of BuildDir
41     public static function distDir()
42     {
43         return self::buildDir().'/xmlrpc-'.self::libVersion();
44     }
45
46     /// these will be generated in BuildDir
47     public static function distFiles()
48     {
49         return array(
50             'xmlrpc-'.self::libVersion().'.tar.gz',
51             'xmlrpc-'.self::libVersion().'.zip',
52         );
53     }
54
55     public static function sourceRepo()
56     {
57         return 'https://github.com/gggeek/phpxmlrpc';
58     }
59
60     /// @todo move git branch to be a named option?
61     public static function getOpts($args=array(), $cliOpts=array())
62     {
63         if (count($args) < 1)
64             throw new \Exception('Missing library version argument');
65         self::$libVersion = $args[0];
66         if (count($args) > 1)
67             self::$sourceBranch = $args[1];
68
69         foreach (self::$tools as $name => $binary) {
70             if (isset($cliOpts[$name])) {
71                 self::$tools[$name] = $cliOpts[$name];
72             }
73         }
74
75         //pake_echo('---'.self::$libVersion.'---');
76     }
77
78     public static function tool($name)
79     {
80         return self::$tools[$name];
81     }
82
83     /**
84      * @param string $inFile
85      * @param string $xssFile
86      * @param string $outFileOrDir
87      * @throws \Exception
88      */
89     public static function applyXslt($inFile, $xssFile, $outFileOrDir)
90     {
91
92         if (!file_exists($inFile)) {
93             throw new \Exception("File $inFile cannot be found");
94         }
95         if (!file_exists($xssFile)) {
96             throw new \Exception("File $xssFile cannot be found");
97         }
98
99         // Load the XML source
100         $xml = new \DOMDocument();
101         $xml->load($inFile);
102         $xsl = new \DOMDocument();
103         $xsl->load($xssFile);
104
105         // Configure the transformer
106         $processor = new \XSLTProcessor();
107         if (version_compare(PHP_VERSION, '5.4', "<")) {
108             if (defined('XSL_SECPREF_WRITE_FILE')) {
109                 ini_set("xsl.security_prefs", XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
110             }
111         } else {
112             // the php online docs only mention setSecurityPrefs, but somehow some installs have setSecurityPreferences...
113             if (method_exists('XSLTProcessor', 'setSecurityPrefs')) {
114                 $processor->setSecurityPrefs(XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
115             } else {
116                 $processor->setSecurityPreferences(XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_FILE);
117             }
118         }
119         $processor->importStyleSheet($xsl); // attach the xsl rules
120
121         if (is_dir($outFileOrDir)) {
122             if (!$processor->setParameter('', 'base.dir', realpath($outFileOrDir))) {
123                 echo "setting param base.dir KO\n";
124             }
125         }
126
127         $out = $processor->transformToXML($xml);
128
129         if (!is_dir($outFileOrDir)) {
130             file_put_contents($outFileOrDir, $out);
131         }
132     }
133
134     public static function highlightPhpInHtml($content)
135     {
136         $startTag = '<pre class="programlisting">';
137         $endTag = '</pre>';
138
139         //$content = file_get_contents($inFile);
140         $last = 0;
141         $out = '';
142         while (($start = strpos($content, $startTag, $last)) !== false) {
143             $end = strpos($content, $endTag, $start);
144             $code = substr($content, $start + strlen($startTag), $end - $start - strlen($startTag));
145             if ($code[strlen($code) - 1] == "\n") {
146                 $code = substr($code, 0, -1);
147             }
148
149             $code = str_replace(array('&gt;', '&lt;'), array('>', '<'), $code);
150             $code = highlight_string('<?php ' . $code, true);
151             $code = str_replace('<span style="color: #0000BB">&lt;?php&nbsp;<br />', '<span style="color: #0000BB">', $code);
152
153             $out = $out . substr($content, $last, $start + strlen($startTag) - $last) . $code . $endTag;
154             $last = $end + strlen($endTag);
155         }
156         $out .= substr($content, $last, strlen($content));
157
158         return $out;
159     }
160 }
161
162 }
163
164 namespace {
165
166 use PhpXmlRpc\Builder;
167
168 function run_default($task=null, $args=array(), $cliOpts=array())
169 {
170     echo "Syntax: pake {\$pake-options} \$task \$lib-version [\$git-tag] {\$task-options}\n";
171     echo "\n";
172     echo "  Run 'pake help' to list all pake options\n";
173     echo "  Run 'pake -T' to list all available tasks\n";
174     echo "  Task options:\n";
175     echo "      --php=\$php";
176     echo "      --fop=\$fop";
177     echo "      --zip=\$zip";
178 }
179
180 function run_getopts($task=null, $args=array(), $cliOpts=array())
181 {
182     Builder::getOpts($args, $cliOpts);
183 }
184
185 /**
186  * Downloads source code in the build workspace directory, optionally checking out the given branch/tag
187  */
188 function run_init($task=null, $args=array(), $cliOpts=array())
189 {
190     // download the current version into the workspace
191     $targetDir = Builder::workspaceDir();
192     $targetBranch = 'php53';
193
194     // check if workspace exists and is not already set to the correct repo
195     if (is_dir($targetDir) && pakeGit::isRepository($targetDir)) {
196         $repo = new pakeGit($targetDir);
197         $remotes = $repo->remotes();
198         if (trim($remotes['origin']['fetch']) != Builder::sourceRepo()) {
199             throw new Exception("Directory '$targetDir' exists and is not linked to correct git repo");
200         }
201
202         /// @todo should we not just fetch instead?
203         $repo->pull();
204     } else {
205         pake_mkdirs(dirname($targetDir));
206         $repo = pakeGit::clone_repository(Builder::sourceRepo(), Builder::workspaceDir());
207     }
208
209     $repo->checkout($targetBranch);
210 }
211
212 /**
213  * Runs all the build steps.
214  *
215  * (does nothing by itself, as all the steps are managed via task dependencies)
216  */
217 function run_build($task=null, $args=array(), $cliOpts=array())
218 {
219 }
220
221 function run_clean_doc()
222 {
223     pake_remove_dir(Builder::workspaceDir().'/doc/out');
224     pake_remove_dir(Builder::workspaceDir().'/doc/javadoc-out');
225 }
226
227 /**
228  * Generates documentation in all formats
229  */
230 function run_doc($task=null, $args=array(), $cliOpts=array())
231 {
232     $docDir = Builder::workspaceDir().'/doc';
233
234     // API docs from phpdoc comments using phpdocumentor
235     $cmd = Builder::tool('php');
236     pake_sh("$cmd vendor/phpdocumentor/phpdocumentor/bin/phpdoc run -d ".Builder::workspaceDir().'/src'." -t ".Builder::workspaceDir().'/doc/javadoc-out --title PHP-XMLRPC');
237
238     # Jade cmd yet to be rebuilt, starting from xml file and putting output in ./out dir, e.g.
239     #   jade -t xml -d custom.dsl xmlrpc_php.xml
240     #
241     # convertdoc command for xmlmind xxe editor
242     #   convertdoc docb.toHTML xmlrpc_php.xml -u out
243     #
244     # saxon + xerces xml parser + saxon extensions + xslthl: adds a little syntax highligting
245     # (bold and italics only, no color) for php source examples...
246     #   java \
247     #   -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 \
248     #   -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl \
249     #   -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl \
250     #   -Dxslthl.config=file:///c:/htdocs/xmlrpc_cvs/docbook-xsl/highlighting/xslthl-config.xml \
251     #   com.icl.saxon.StyleSheet -o xmlrpc_php.fo.xml xmlrpc_php.xml custom.fo.xsl use.extensions=1
252
253     pake_mkdirs($docDir.'/out');
254
255     // HTML files from docbook
256
257     Builder::applyXslt($docDir.'/xmlrpc_php.xml', $docDir.'/custom.xsl', $docDir.'/out/');
258     // post process html files to highlight php code samples
259     foreach(pakeFinder::type('file')->name('*.html')->in($docDir) as $file)
260     {
261         file_put_contents($file, Builder::highlightPhpInHtml(file_get_contents($file)));
262     }
263
264     // PDF file from docbook
265
266     // convert to fo and then to pdf using apache fop
267     Builder::applyXslt($docDir.'/xmlrpc_php.xml', $docDir.'/custom.fo.xsl', $docDir.'/xmlrpc_php.fo.xml');
268     $cmd = Builder::tool('fop');
269     pake_sh("$cmd $docDir/xmlrpc_php.fo.xml $docDir/xmlrpc_php.pdf");
270     unlink($docDir.'/xmlrpc_php.fo.xml');
271 }
272
273 function run_clean_dist()
274 {
275     pake_remove_dir(Builder::distDir());
276     $finder = pakeFinder::type('file')->name(Builder::distFiles());
277     pake_remove($finder, Builder::buildDir());
278 }
279
280 /**
281  * Creates the tarballs for a release
282  */
283 function run_dist($task=null, $args=array(), $cliOpts=array())
284 {
285     // copy workspace dir into dist dir, without git
286     pake_mkdirs(Builder::distDir());
287     $finder = pakeFinder::type('any')->ignore_version_control();
288     pake_mirror($finder, realpath(Builder::workspaceDir()), realpath(Builder::distDir()));
289
290     // remove unwanted files from dist dir
291
292     // also: do we still need to run dos2unix?
293
294     // create tarballs
295     $cwd = getcwd();
296     chdir(dirname(Builder::distDir()));
297     foreach(Builder::distFiles() as $distFile) {
298         // php can not really create good zip files via phar: they are not compressed!
299         if (substr($distFile, -4) == '.zip') {
300             $cmd = Builder::tool('zip');
301             $extra = '-9 -r';
302             pake_sh("$cmd $distFile $extra ".basename(Builder::distDir()));
303         }
304         else {
305             $finder = pakeFinder::type('any')->pattern(basename(Builder::distDir()).'/**');
306             // see https://bugs.php.net/bug.php?id=58852
307             $pharFile = str_replace(Builder::libVersion(), '_LIBVERSION_', $distFile);
308             pakeArchive::createArchive($finder, '.', $pharFile);
309             rename($pharFile, $distFile);
310         }
311     }
312     chdir($cwd);
313 }
314
315 /**
316  * Cleans up the build directory
317  * @todo 'make clean' usually just removes the results of the build, distclean removes all but sources
318  */
319 function run_clean($task=null, $args=array(), $cliOpts=array())
320 {
321     pake_remove_dir(Builder::buildDir());
322 }
323
324 // helper task: display help text
325 pake_task( 'default' );
326 // internal task: parse cli options
327 pake_task('getopts');
328 pake_task('init', 'getopts');
329 pake_task('doc', 'getopts', 'init', 'clean-doc');
330 pake_task('build', 'getopts', 'init', 'doc');
331 pake_task('dist', 'getopts', 'init', 'build', 'clean-dist');
332 pake_task('clean-doc', 'getopts');
333 pake_task('clean-dist', 'getopts');
334 pake_task('clean', 'getopts');
335
336 }