Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
/*
4
 *  $Id: CapsuleTask.php 144 2007-02-05 15:19:00Z hans $
5
 *
6
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
7
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
8
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
9
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
12
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
14
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17
 *
18
 * This software consists of voluntary contributions made by many individuals
19
 * and is licensed under the LGPL. For more information please see
20
 * <http://phing.info>.
21
 */
22
 
23
include_once 'phing/Task.php';
24
include_once 'phing/BuildException.php';
25
include_once 'phing/lib/Capsule.php';
26
include_once 'phing/util/StringHelper.php';
27
 
28
/**
29
 * A phing task for generating output by using Capsule.
30
 *
31
 * This is based on the interface to TexenTask from Apache's Velocity engine.
32
 *
33
 * @author    Hans Lellelid <hans@xmpl.org>
34
 * @version   $Revision: 1.17 $
35
 * @package   phing.tasks.ext
36
 */
37
class CapsuleTask extends Task {
38
 
39
    /**
40
     * Capsule "template" engine.
41
     * @var Capsule
42
     */
43
    protected $context;
44
 
45
    /**
46
     * Any vars assigned via the build file.
47
     * @var array AssignedVar[]
48
     */
49
    protected $assignedVars = array();
50
 
51
    /**
52
     * This is the control template that governs the output.
53
     * It may or may not invoke the services of worker
54
     * templates.
55
     * @var string
56
     */
57
    protected $controlTemplate;
58
 
59
    /**
60
     * This is where Velocity will look for templates
61
     * using the file template loader.
62
     * @var string
63
     */
64
    protected $templatePath;
65
 
66
    /**
67
     * This is where texen will place all the output
68
     * that is a product of the generation process.
69
     * @var string
70
     */
71
    protected $outputDirectory;
72
 
73
    /**
74
     * This is the file where the generated text
75
     * will be placed.
76
     * @var string
77
     */
78
    protected $outputFile;
79
 
80
    /**
81
     * <p>
82
     * These are properties that are fed into the
83
     * initial context from a properties file. This
84
     * is simply a convenient way to set some values
85
     * that you wish to make available in the context.
86
     * </p>
87
     * <p>
88
     * These values are not critical, like the template path
89
     * or output path, but allow a convenient way to
90
     * set a value that may be specific to a particular
91
     * generation task.
92
     * </p>
93
     * <p>
94
     * For example, if you are generating scripts to allow
95
     * user to automatically create a database, then
96
     * you might want the <code>$databaseName</code>
97
     * to be placed
98
     * in the initial context so that it is available
99
     * in a script that might look something like the
100
     * following:
101
     * <code><pre>
102
     * #!bin/sh
103
     *
104
     * echo y | mysqladmin create $databaseName
105
     * </pre></code>
106
     * The value of <code>$databaseName</code> isn't critical to
107
     * output, and you obviously don't want to change
108
     * the ant task to simply take a database name.
109
     * So initial context values can be set with
110
     * properties file.
111
     *
112
     * @var array
113
     */
114
    protected $contextProperties;
115
 
116
    // -----------------------------------------------------------------------
117
    // The following getters & setters are used by phing to set properties
118
    // specified in the XML for the capsule task.
119
    // -----------------------------------------------------------------------
120
 
121
    /**
122
     * [REQUIRED] Set the control template for the
123
     * generating process.
124
     * @param string $controlTemplate
125
     * @return void
126
     */
127
    public function setControlTemplate ($controlTemplate) {
128
        $this->controlTemplate = $controlTemplate;
129
    }
130
 
131
    /**
132
     * Get the control template for the
133
     * generating process.
134
     * @return string
135
     */
136
    public function getControlTemplate() {
137
        return $this->controlTemplate;
138
    }
139
 
140
    /**
141
     * [REQUIRED] Set the path where Velocity will look
142
     * for templates using the file template
143
     * loader.
144
     * @return void
145
     * @throws Exception
146
     */
147
    public function setTemplatePath($templatePath) {
148
        $resolvedPath = "";
149
        $tok = strtok($templatePath, ",");
150
        while ( $tok ) {
151
            // resolve relative path from basedir and leave
152
            // absolute path untouched.
153
            $fullPath = $this->project->resolveFile($tok);
154
            $cpath = $fullPath->getCanonicalPath();
155
            if ($cpath === false) {
156
                $this->log("Template directory does not exist: " . $fullPath->getAbsolutePath());
157
            } else {
158
                $resolvedPath .= $cpath;
159
            }
160
            $tok = strtok(",");
161
            if ( $tok ) {
162
                $resolvedPath .= ",";
163
            }
164
        }
165
        $this->templatePath = $resolvedPath;
166
     }
167
 
168
    /**
169
     * Get the path where Velocity will look
170
     * for templates using the file template
171
     * loader.
172
     * @return string
173
     */
174
    public function getTemplatePath() {
175
        return $this->templatePath;
176
    }
177
 
178
    /**
179
     * [REQUIRED] Set the output directory. It will be
180
     * created if it doesn't exist.
181
     * @param PhingFile $outputDirectory
182
     * @return void
183
     * @throws Exception
184
     */
185
    public function setOutputDirectory(PhingFile $outputDirectory) {
186
        try {
187
            if (!$outputDirectory->exists()) {
188
                $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),Project::MSG_VERBOSE);
189
                if (!$outputDirectory->mkdirs()) {
190
                    throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath());
191
                }
192
            }
193
            $this->outputDirectory = $outputDirectory->getCanonicalPath();
194
        } catch (IOException $ioe) {
195
            throw new BuildException($ioe);
196
        }
197
    }
198
 
199
    /**
200
     * Get the output directory.
201
     * @return string
202
     */
203
    public function getOutputDirectory() {
204
        return $this->outputDirectory;
205
    }
206
 
207
    /**
208
     * [REQUIRED] Set the output file for the
209
     * generation process.
210
     * @param string $outputFile (TODO: change this to File)
211
     * @return void
212
     */
213
    public function setOutputFile($outputFile) {
214
        $this->outputFile = $outputFile;
215
    }
216
 
217
    /**
218
     * Get the output file for the
219
     * generation process.
220
     * @return string
221
     */
222
    public function getOutputFile() {
223
        return $this->outputFile;
224
    }
225
 
226
    /**
227
     * Set the context properties that will be
228
     * fed into the initial context be the
229
     * generating process starts.
230
     * @param string $file
231
     * @return void
232
     */
233
    public function setContextProperties($file) {
234
        $sources = explode(",", $file);
235
        $this->contextProperties = new Properties();
236
 
237
        // Always try to get the context properties resource
238
        // from a file first. Templates may be taken from a JAR
239
        // file but the context properties resource may be a
240
        // resource in the filesystem. If this fails than attempt
241
        // to get the context properties resource from the
242
        // classpath.
243
        for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) {
244
            $source = new Properties();
245
 
246
            try {
247
 
248
                // resolve relative path from basedir and leave
249
                // absolute path untouched.
250
                $fullPath = $this->project->resolveFile($sources[$i]);
251
                $this->log("Using contextProperties file: " . $fullPath->toString());
252
                $source->load($fullPath);
253
 
254
            } catch (Exception $e) {
255
 
256
              throw new BuildException("Context properties file " . $sources[$i] .
257
                            " could not be found in the file system!");
258
 
259
            }
260
 
261
            $keys = $source->keys();
262
 
263
            foreach ($keys as $key) {
264
                $name = $key;
265
                $value = $this->project->replaceProperties($source->getProperty($name));
266
                $this->contextProperties->setProperty($name, $value);
267
            }
268
        }
269
    }
270
 
271
    /**
272
     * Get the context properties that will be
273
     * fed into the initial context be the
274
     * generating process starts.
275
     * @return Properties
276
     */
277
    public function getContextProperties() {
278
        return $this->contextProperties;
279
    }
280
 
281
    /**
282
     * Creates an "AssignedVar" class.
283
     */
284
    public function createAssign() {
285
        $a = new AssignedVar();
286
        $this->assignedVars[] = $a;
287
        return $a;
288
    }
289
 
290
    // ---------------------------------------------------------------
291
    // End of XML setters & getters
292
    // ---------------------------------------------------------------
293
 
294
    /**
295
     * Creates a Smarty object.
296
     *
297
     * @return Smarty initialized (cleared) Smarty context.
298
     * @throws Exception the execute method will catch
299
     *         and rethrow as a <code>BuildException</code>
300
     */
301
    public function initControlContext() {
302
        $this->context->clear();
303
        foreach($this->assignedVars as $var) {
304
            $this->context->put($var->getName(), $var->getValue());
305
        }
306
        return $this->context;
307
    }
308
 
309
    /**
310
     * Execute the input script with Velocity
311
     *
312
     * @throws BuildException
313
     * BuildExceptions are thrown when required attributes are missing.
314
     * Exceptions thrown by Velocity are rethrown as BuildExceptions.
315
     */
316
    public function main() {
317
 
318
        // Make sure the template path is set.
319
        if (empty($this->templatePath)) {
320
            throw new BuildException("The template path needs to be defined!");
321
        }
322
 
323
        // Make sure the control template is set.
324
        if ($this->controlTemplate === null) {
325
            throw new BuildException("The control template needs to be defined!");
326
        }
327
 
328
        // Make sure the output directory is set.
329
        if ($this->outputDirectory === null) {
330
            throw new BuildException("The output directory needs to be defined!");
331
        }
332
 
333
        // Make sure there is an output file.
334
        if ($this->outputFile === null) {
335
            throw new BuildException("The output file needs to be defined!");
336
        }
337
 
338
        // Setup Smarty runtime.
339
 
340
        // Smarty uses one object to store properties and to store
341
        // the context for the template (unlike Velocity).  We setup this object, calling it
342
        // $this->context, and then initControlContext simply zeros out
343
        // any assigned variables.
344
        $this->context = new Capsule();
345
 
346
        if ($this->templatePath !== null) {
347
            $this->log("Using templatePath: " . $this->templatePath);
348
            $this->context->setTemplatePath($this->templatePath);
349
        }
350
 
351
        // Make sure the output directory exists, if it doesn't
352
        // then create it.
353
        $outputDir = new PhingFile($this->outputDirectory);
354
        if (!$outputDir->exists()) {
355
            $this->log("Output directory does not exist, creating: " . $outputDir->getAbsolutePath());
356
            $outputDir->mkdirs();
357
        }
358
 
359
        $this->context->setOutputDirectory($outputDir->getAbsolutePath());
360
 
361
        $path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile;
362
        $this->log("Generating to file " . $path);
363
 
364
        //$writer = new FileWriter($path);
365
 
366
        // The generator and the output path should
367
        // be placed in the init context here and
368
        // not in the generator class itself.
369
        $c = $this->initControlContext();
370
 
371
        // Set any variables that need to always
372
        // be loaded
373
        $this->populateInitialContext($c);
374
 
375
        // Feed all the options into the initial
376
        // control context so they are available
377
        // in the control/worker templates.
378
        if ($this->contextProperties !== null) {
379
 
380
            foreach($this->contextProperties->keys() as $property) {
381
 
382
            $value = $this->contextProperties->getProperty($property);
383
 
384
            // Special exception (from Texen)
385
            // for properties ending in file.contents:
386
            // in that case we dump the contents of the file
387
            // as the "value" for the Property.
388
            if (preg_match('/file\.contents$/', $property)) {
389
                // pull in contents of file specified
390
 
391
                $property = substr($property, 0, strpos($property, "file.contents") - 1);
392
 
393
                // reset value, and then
394
                // read in teh contents of the file into that var
395
                $value = "";
396
                $f = new PhingFile($project->resolveFile($value)->getCanonicalPath());
397
                if ($f->exists()) {
398
                    $fr = new FileReader($f);
399
                    $fr->readInto($value);
400
                }
401
 
402
            } // if ends with file.contents
403
 
404
            if (StringHelper::isBoolean($value)) {
405
                $value = StringHelper::booleanValue($value);
406
            }
407
 
408
            $c->put($property, $value);
409
 
410
            } // foreach property
411
 
412
        } // if contextProperties !== null
413
 
414
        try {
415
            $this->log("Parsing control template: " . $this->controlTemplate);
416
            $c->parse($this->controlTemplate, $path);
417
        } catch (Exception $ioe) {
418
            throw new BuildException("Cannot write parsed template: ". $ioe->getMessage());
419
        }
420
 
421
        $this->cleanup();
422
    }
423
 
424
    /**
425
     * Place useful objects into the initial context.
426
     *
427
     *
428
     * @param Capsule $context The context to populate, as retrieved from
429
     * {@link #initControlContext()}.
430
     * @return void
431
     * @throws Exception Error while populating context.  The {@link
432
     * #main()} method will catch and rethrow as a
433
     * <code>BuildException</code>.
434
     */
435
    protected function populateInitialContext(Capsule $context) {
436
        $this->context->put("now", strftime("%c", time()));
437
        $this->context->put("task", $this);
438
    }
439
 
440
    /**
441
     * A hook method called at the end of {@link #execute()} which can
442
     * be overridden to perform any necessary cleanup activities (such
443
     * as the release of database connections, etc.).  By default,
444
     * does nothing.
445
     * @return void
446
     * @throws Exception Problem cleaning up.
447
     */
448
    protected function cleanup() {
449
    }
450
}
451
 
452
 
453
/**
454
 * An "inner" class for holding assigned var values.
455
 * May be need to expand beyond name/value in the future.
456
 */
457
class AssignedVar {
458
 
459
    private $name;
460
    private $value;
461
 
462
    function setName($v) {
463
        $this->name = $v;
464
    }
465
 
466
    function setValue($v) {
467
        $this->value = $v;
468
    }
469
 
470
    function getName() {
471
        return $this->name;
472
    }
473
 
474
    function getValue() {
475
        return $this->value;
476
    }
477
 
478
}