Passed
Push — master ( eabf33...342b63 )
by Michiel
05:53
created

RecorderTask   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Test Coverage

Coverage 53.52%

Importance

Changes 0
Metric Value
eloc 53
dl 0
loc 259
ccs 38
cts 71
cp 0.5352
rs 10
c 0
b 0
f 0
wmc 27

18 Methods

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