Passed
Push — master ( b5ca42...8fe651 )
by Siad
05:05
created

RecorderTask::getRecorder()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 2
dl 0
loc 14
ccs 7
cts 8
cp 0.875
crap 2.0078
rs 10
c 0
b 0
f 0
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
use Phing\Exception\BuildException;
21
use Phing\Listener\BuildEvent;
22
use Phing\Listener\SubBuildListener;
23
use Phing\Project;
24
use Phing\Task;
25
use Phing\Util\StringHelper;
26
27
/**
28
 * Adds a listener to the current build process that records the
29
 * output to a file.
30
 * <p>Several recorders can exist at the same time.  Each recorder is
31
 * associated with a file.  The filename is used as a unique identifier for
32
 * the recorders.  The first call to the recorder task with an unused filename
33
 * will create a recorder (using the parameters provided) and add it to the
34
 * listeners of the build.  All subsequent calls to the recorder task using
35
 * this filename will modify that recorders state (recording or not) or other
36
 * properties (like logging level).</p>
37
 * <p>Some technical issues: the file's print stream is flushed for &quot;finished&quot;
38
 * events (buildFinished, targetFinished and taskFinished), and is closed on
39
 * a buildFinished event.</p>
40
 *
41
 * @author  Siad Ardroumli <[email protected]>
42
 * @package phing.tasks.system
43
 */
44
class RecorderTask extends Task implements SubBuildListener
45
{
46
    /**
47
     * The name of the file to record to.
48
     */
49
    private $filename = null;
50
    /**
51
     * Whether or not to append. Need Boolean to record an unset state (null).
52
     */
53
    private $append = null;
54
    /**
55
     * Whether to start or stop recording. Need Boolean to record an unset
56
     * state (null).
57
     */
58
    private $start = null;
59
    /**
60
     * The level to log at. A level of -1 means not initialized yet.
61
     */
62
    private $loglevel = -1;
63
    /**
64
     * Strip task banners if true.
65
     */
66
    private $emacsMode = false;
67
68
    private $logLevelChoices = [
69
        'error' => 0,
70
        'warn' => 1,
71
        'info' => 2,
72
        'verbose' => 3,
73
        'debug' => 4
74
    ];
75
76
    /**
77
     * The list of recorder entries.
78
     *
79
     * @var RecorderEntry[]
80
     */
81
    private static $recorderEntries = [];
82
83
    /**
84
     * Overridden so we can add the task as build listener.
85
     */
86 1
    public function init()
87
    {
88 1
        $this->getProject()->addBuildListener($this);
89 1
    }
90
91
    /**
92
     * Sets the name of the file to log to, and the name of the recorder
93
     * entry.
94
     *
95
     * @param string $fname File name of logfile.
96
     */
97 1
    public function setName($fname)
98
    {
99 1
        $this->filename = $fname;
100 1
    }
101
102
    /**
103
     * Sets the action for the associated recorder entry.
104
     *
105
     * @param string $action The action for the entry to take: start or stop.
106
     */
107 1
    public function setAction($action)
108
    {
109 1
        $this->start = strtolower($action) === "start";
110 1
    }
111
112
113
    /**
114
     * Whether or not the logger should append to a previous file.
115
     *
116
     * @param bool $append if true, append to a previous file.
117
     */
118
    public function setAppend(bool $append)
119
    {
120
        $this->append = $append;
121
    }
122
123
124
    /**
125
     * Set emacs mode.
126
     *
127
     * @param bool $emacsMode if true use emacs mode
128
     */
129
    public function setEmacsMode($emacsMode)
130
    {
131
        $this->emacsMode = $emacsMode;
132
    }
133
134
    /**
135
     * Sets the level to which this recorder entry should log to.
136
     *
137
     * @param string $level the level to set.
138
     */
139
    public function setLoglevel($level)
140
    {
141
        $this->loglevel = $level;
142
    }
143
144
    /**
145
     * The main execution.
146
     *
147
     * @throws BuildException on error
148
     */
149 1
    public function main()
150
    {
151 1
        if ($this->filename == null) {
152
            throw new BuildException("No filename specified");
153
        }
154
155 1
        $this->getProject()->log("setting a recorder for name " . $this->filename, Project::MSG_DEBUG);
156
157
        // get the recorder entry
158 1
        $recorder = $this->getRecorder($this->filename, $this->getProject());
159
        // set the values on the recorder
160 1
        if ($this->loglevel === -1) {
161 1
            $recorder->setMessageOutputLevel($this->loglevel);
162
        } elseif (isset($this->logLevelChoices[$this->loglevel])) {
163
            $recorder->setMessageOutputLevel($this->logLevelChoices[$this->loglevel]);
164
        } else {
165
            throw new BuildException('Loglevel should be one of (error|warn|info|verbose|debug).');
166
        }
167
168 1
        $recorder->setEmacsMode(StringHelper::booleanValue($this->emacsMode));
169 1
        if ($this->start != null) {
170 1
            if (StringHelper::booleanValue($this->start)) {
171 1
                $recorder->reopenFile();
172 1
                $recorder->setRecordState($this->start);
173
            } else {
174
                $recorder->setRecordState($this->start);
175
                $recorder->closeFile();
176
            }
177
        }
178 1
    }
179
180
    /**
181
     * Gets the recorder that's associated with the passed in name. If the
182
     * recorder doesn't exist, then a new one is created.
183
     *
184
     * @param  string $name the name of the recorder
185
     * @param  Project $proj the current project
186
     * @return RecorderEntry a recorder
187
     * @throws BuildException on error
188
     */
189 1
    protected function getRecorder($name, Project $proj)
190
    {
191
        // create a recorder entry
192 1
        $entry = self::$recorderEntries[$name] ?? new RecorderEntry($name);
193
194 1
        if ($this->append == null) {
195 1
            $entry->openFile(false);
196
        } else {
197
            $entry->openFile(StringHelper::booleanValue($this->append));
198
        }
199 1
        $entry->setProject($proj);
200 1
        self::$recorderEntries[$name] = $entry;
201
202 1
        return $entry;
203
    }
204
205
    /**
206
     * Empty implementation required by SubBuildListener interface.
207
     *
208
     * @param BuildEvent $event ignored.
209
     */
210
    public function buildStarted(BuildEvent $event)
211
    {
212
    }
213
214
    /**
215
     * Empty implementation required by SubBuildListener interface.
216
     *
217
     * @param BuildEvent $event ignored.
218
     */
219
    public function subBuildStarted(BuildEvent $event)
220
    {
221
    }
222
223
    /**
224
     * Empty implementation required by SubBuildListener interface.
225
     *
226
     * @param BuildEvent $event ignored.
227
     */
228 1
    public function targetStarted(BuildEvent $event)
229
    {
230 1
    }
231
232
    /**
233
     * Empty implementation required by SubBuildListener interface.
234
     *
235
     * @param BuildEvent $event ignored.
236
     */
237 1
    public function targetFinished(BuildEvent $event)
238
    {
239 1
    }
240
241
    /**
242
     * Empty implementation required by SubBuildListener interface.
243
     *
244
     * @param BuildEvent $event ignored.
245
     */
246 1
    public function taskStarted(BuildEvent $event)
247
    {
248 1
    }
249
250
    /**
251
     * Empty implementation required by SubBuildListener interface.
252
     *
253
     * @param BuildEvent $event ignored.
254
     */
255 1
    public function taskFinished(BuildEvent $event)
256
    {
257 1
    }
258
259
    /**
260
     * Empty implementation required by SubBuildListener interface.
261
     *
262
     * @param BuildEvent $event ignored.
263
     */
264 1
    public function messageLogged(BuildEvent $event)
265
    {
266 1
    }
267
268
    /**
269
     * Cleans recorder registry.
270
     *
271
     * @param BuildEvent $event ignored.
272
     */
273
    public function buildFinished(BuildEvent $event)
274
    {
275
        $this->cleanup();
276
    }
277
278
    /**
279
     * Cleans recorder registry, if this is the subbuild the task has
280
     * been created in.
281
     *
282
     * @param BuildEvent $event ignored.
283
     */
284
    public function subBuildFinished(BuildEvent $event)
285
    {
286
        if ($event->getProject() == $this->getProject()) {
287
            $this->cleanup();
288
        }
289
    }
290
291
    /**
292
     * cleans recorder registry and removes itself from BuildListener list.
293
     */
294
    private function cleanup()
295
    {
296
        $entries = self::$recorderEntries;
297
        foreach ($entries as $key => $entry) {
298
            if ($entry->getProject() == $this->getProject()) {
299
                unset(self::$recorderEntries[$key]);
300
            }
301
        }
302
        $this->getProject()->removeBuildListener($this);
303
    }
304
}
305