1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 *  Displays all the current properties in the build. The output can be sent to
22
 *  a file if desired.
23
 *
24
 *  Attribute "destfile" defines a file to send the properties to. This can be
25
 *  processed as a standard property file later.
26
 *
27
 *  Attribute "prefix" defines a prefix which is used to filter the properties
28
 *  only those properties starting with this prefix will be echoed.
29
 *
30
 *  By default, the "failonerror" attribute is enabled. If an error occurs while
31
 *  writing the properties to a file, and this attribute is enabled, then a
32
 *  BuildException will be thrown. If disabled, then IO errors will be reported
33
 *  as a log statement, but no error will be thrown.
34
 *
35
 *  Examples: <pre>
36
 *  &lt;echoproperties  /&gt;
37
 * </pre> Report the current properties to the log.
38
 *
39
 *  <pre>
40
 *  &lt;echoproperties destfile="my.properties" /&gt;
41
 * </pre> Report the current properties to the file "my.properties", and will
42
 *  fail the build if the file could not be created or written to.
43
 *
44
 *  <pre>
45
 *  &lt;echoproperties destfile="my.properties" failonerror="false"
46
 *      prefix="phing" /&gt;
47
 * </pre> Report all properties beginning with 'phing' to the file
48
 *  "my.properties", and will log a message if the file could not be created or
49
 *  written to, but will still allow the build to continue.
50
 *
51
 * @author  Siad Ardroumli <siad.ardroumli@gmail.com>
52
 * @package phing.tasks.system
53
 */
54
class EchoProperties extends Task
55
{
56
    /**
57
     * the properties element.
58
     */
59
    private static $PROPERTIES = "properties";
60

61
    /**
62
     * the property element.
63
     */
64
    private static $PROPERTY = "property";
65

66
    /**
67
     * name attribute for property, testcase and testsuite elements.
68
     */
69
    private static $ATTR_NAME = "name";
70

71
    /**
72
     * value attribute for property elements.
73
     */
74
    private static $ATTR_VALUE = "value";
75
    /**
76
     * the input file.
77
     *
78
     * @var PhingFile
79
     */
80
    private $inFile = null;
81

82
    /**
83
     * File object pointing to the output file. If this is null, then
84
     * we output to the project log, not to a file.
85
     *
86
     * @var PhingFile
87
     */
88
    private $destfile = null;
89

90
    /**
91
     * If this is true, then errors generated during file output will become
92
     * build errors, and if false, then such errors will be logged, but not
93
     * thrown.
94
     *
95
     * @var boolean
96
     */
97
    private $failonerror = true;
98

99
    /**
100
     * @var string $format
101
     */
102
    private $format = "text";
103

104
    /**
105
     * @var string $prefix
106
     */
107
    private $prefix = '';
108

109
    /**
110
     * @var string $regex
111
     */
112
    private $regex = '';
113

114
    /**
115
     * Sets the input file.
116
     *
117
     * @param string|PhingFile $file the input file
118
     */
119 0
    public function setSrcfile($file)
120
    {
121 0
        if (is_string($file)) {
122 0
            $this->inFile = new PhingFile($file);
123
        } else {
124 0
            $this->inFile = $file;
125
        }
126
    }
127

128
    /**
129
     *  Set a file to store the property output.  If this is never specified,
130
     *  then the output will be sent to the Phing log.
131
     *
132
     * @param string|PhingFile $destfile file to store the property output
133
     */
134 1
    public function setDestfile($destfile)
135
    {
136 1
        if (is_string($destfile)) {
137 1
            $this->destfile = new PhingFile($destfile);
138
        } else {
139 0
            $this->destfile = $destfile;
140
        }
141
    }
142

143

144
    /**
145
     * If true, the task will fail if an error occurs writing the properties
146
     * file, otherwise errors are just logged.
147
     *
148
     * @param failonerror <tt>true</tt> if IO exceptions are reported as build
149
     *      exceptions, or <tt>false</tt> if IO exceptions are ignored.
150
     */
151 1
    public function setFailOnError($failonerror)
152
    {
153 1
        $this->failonerror = $failonerror;
154
    }
155

156

157
    /**
158
     *  If the prefix is set, then only properties which start with this
159
     *  prefix string will be recorded. If regex is not set and  if this
160
     *  is never set, or it is set to an empty string or <tt>null</tt>,
161
     *  then all properties will be recorded. <P>
162
     *
163
     *  For example, if the attribute is set as:
164
     *    <PRE>&lt;echoproperties  prefix="phing." /&gt;</PRE>
165
     *  then the property "phing.home" will be recorded, but "phing-example"
166
     *  will not.
167
     *
168
     * @param string $prefix The new prefix value
169
     */
170 1
    public function setPrefix($prefix)
171
    {
172 1
        if ($prefix != null && strlen($prefix) != 0) {
173 1
            $this->prefix = $prefix;
174
        }
175
    }
176

177
    /**
178
     *  If the regex is set, then only properties whose names match it
179
     *  will be recorded.  If prefix is not set and if this is never set,
180
     *  or it is set to an empty string or <tt>null</tt>, then all
181
     *  properties will be recorded.<P>
182
     *
183
     *  For example, if the attribute is set as:
184
     *    <PRE>&lt;echoproperties  prefix=".*phing.*" /&gt;</PRE>
185
     *  then the properties "phing.home" and "user.phing" will be recorded,
186
     *  but "phing-example" will not.
187
     *
188
     * @param string $regex The new regex value
189
     */
190 0
    public function setRegex($regex)
191
    {
192 0
        if ($regex != null && strlen($regex) != 0) {
193 0
            $this->regex = $regex;
194
        }
195
    }
196

197
    /**
198
     * Set the output format - xml or text.
199
     *
200
     * @param string $ea an enumerated <code>FormatAttribute</code> value
201
     */
202 1
    public function setFormat($ea)
203
    {
204 1
        $this->format = $ea;
205
    }
206

207
    /**
208
     *  Run the task.
209
     *
210
     * @throws BuildException  trouble, probably file IO
211
     */
212 1
    public function main()
213
    {
214 1
        if ($this->prefix != null && $this->regex != null) {
215 0
            throw new BuildException("Please specify either prefix or regex, but not both", $this->getLocation());
216
        }
217

218
        //copy the properties file
219 1
        $allProps = [];
220

221
        /* load properties from file if specified, otherwise use Phing's properties */
222 1
        if ($this->inFile == null) {
223
            // add phing properties
224 1
            $allProps = $this->getProject()->getProperties();
225 0
        } elseif ($this->inFile != null) {
226 0
            if ($this->inFile->exists() && $this->inFile->isDirectory()) {
227 0
                $message = "srcfile is a directory!";
228 0
                $this->failOnErrorAction(null, $message, Project::MSG_ERR);
229 0
                return;
230
            }
231

232 0
            if ($this->inFile->exists() && !$this->inFile->canRead()) {
233 0
                $message = "Can not read from the specified srcfile!";
234 0
                $this->failOnErrorAction(null, $message, Project::MSG_ERR);
235 0
                return;
236
            }
237

238
            try {
239 0
                $props = new Properties();
240 0
                $props->load(new PhingFile($this->inFile));
241 0
                $allProps = $props->getProperties();
242 0
            } catch (IOException $ioe) {
243 0
                $message = "Could not read file " . $this->inFile->getAbsolutePath();
244 0
                $this->failOnErrorAction($ioe, $message, Project::MSG_WARN);
245 0
                return;
246
            }
247
        }
248

249 1
        $os = null;
250
        try {
251 1
            if ($this->destfile == null) {
252 0
                $os = Phing::getOutputStream();
253 0
                $this->saveProperties($allProps, $os);
254 0
                $this->log($os, Project::MSG_INFO);
255
            } else {
256 1
                if ($this->destfile->exists() && $this->destfile->isDirectory()) {
257 0
                    $message = "destfile is a directory!";
258 0
                    $this->failOnErrorAction(null, $message, Project::MSG_ERR);
259 0
                    return;
260
                }
261

262 1
                if ($this->destfile->exists() && !$this->destfile->canWrite()) {
263 0
                    $message = "Can not write to the specified destfile!";
264 0
                    $this->failOnErrorAction(null, $message, Project::MSG_ERR);
265 0
                    return;
266
                }
267 1
                $os = new FileOutputStream($this->destfile);
268 1
                $this->saveProperties($allProps, $os);
269
            }
270 0
        } catch (IOException $ioe) {
271 0
            $this->failOnErrorAction($ioe);
272
        }
273
    }
274

275
    /**
276
     * @param Exception $exception
277
     * @param string $message
278
     * @param int $level
279
     * @throws BuildException
280
     */
281 0
    private function failOnErrorAction(Exception $exception = null, $message = '', $level = Project::MSG_INFO)
282
    {
283 0
        if ($this->failonerror) {
284 0
            throw new BuildException(
285 0
                $exception ?? $message,
286 0
                $this->getLocation()
287
            );
288
        }
289

290 0
        $this->log(
291 0
            $exception !== null && $message === ''
292 0
                ? $exception->getMessage()
293 0
                : $message,
294
            $level
295
        );
296
    }
297

298
    /**
299
     *  Send the key/value pairs in the hashtable to the given output stream.
300
     *  Only those properties matching the <tt>prefix</tt> constraint will be
301
     *  sent to the output stream.
302
     *  The output stream will be closed when this method returns.
303
     *
304
     * @param  array $allProps propfile to save
305
     * @param  OutputStream $os output stream
306
     * @throws IOException      on output errors
307
     * @throws BuildException   on other errors
308
     */
309 1
    protected function saveProperties($allProps, $os)
310
    {
311 1
        ksort($allProps);
312 1
        $props = new Properties();
313

314 1
        if ($this->regex !== '') {
315 0
            $a = new ArrayIterator($allProps);
316 0
            $i = new RegexIterator($a, $this->regex, RegexIterator::MATCH, RegexIterator::USE_KEY);
317 0
            $allProps = iterator_to_array($i);
318
        }
319 1
        if ($this->prefix !== '') {
320 1
            $a = new ArrayIterator($allProps);
321 1
            $i = new RegexIterator(
322 1
                $a,
323 1
                '~^' . preg_quote($this->prefix, '~') . '.*~',
324 1
                RegexIterator::MATCH,
325 1
                RegexIterator::USE_KEY
326
            );
327 1
            $allProps = iterator_to_array($i);
328
        }
329

330 1
        foreach ($allProps as $name => $value) {
331 1
            $props->setProperty($name, $value);
332
        }
333

334 1
        if ($this->format === "text") {
335 0
            $this->textSaveProperties($props, $os, "Phing properties");
336 1
        } elseif ($this->format === "xml") {
337 1
            $this->xmlSaveProperties($props, $os);
338
        }
339
    }
340

341
    /**
342
     * Output the properties as xml output.
343
     *
344
     * @param  Properties $props the properties to save
345
     * @param  OutputStream $os the output stream to write to (Note this gets closed)
346
     * @throws BuildException
347
     */
348 1
    protected function xmlSaveProperties(Properties $props, OutputStream $os)
349
    {
350 1
        $doc = new DOMDocument('1.0', 'UTF-8');
351 1
        $doc->formatOutput = true;
352 1
        $rootElement = $doc->createElement(self::$PROPERTIES);
353

354 1
        $properties = $props->getProperties();
355 1
        ksort($properties);
356 1
        foreach ($properties as $key => $value) {
357 1
            $propElement = $doc->createElement(self::$PROPERTY);
358 1
            $propElement->setAttribute(self::$ATTR_NAME, $key);
359 1
            $propElement->setAttribute(self::$ATTR_VALUE, $value);
360 1
            $rootElement->appendChild($propElement);
361
        }
362

363
        try {
364 1
            $doc->appendChild($rootElement);
365 1
            $os->write($doc->saveXML());
366 0
        } catch (IOException $ioe) {
367 0
            throw new BuildException("Unable to write XML file", $ioe);
368
        }
369
    }
370

371
    /**
372
     * @param Properties $props the properties to record
373
     * @param OutputStream $os record the properties to this output stream
374
     * @param string $header prepend this header to the property output
375
     * @throws BuildException on an I/O error during a write.
376
     */
377 0
    protected function textSaveProperties(Properties $props, OutputStream $os, $header)
378
    {
379
        try {
380 0
            $props->storeOutputStream($os, $header);
381 0
        } catch (IOException $ioe) {
382 0
            throw new BuildException($ioe, $this->getLocation());
383
        }
384
    }
385
}

Read our documentation on viewing source code .

Loading