Passed
Push — main ( bd0539...7eff6b )
by Michiel
06:28
created

PatchTask::setQuiet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
/**
4
 *  Patches a file by applying a 'diff' file to it.
5
 *
6
 *  Requires "patch" to be on the execution path.
7
 *
8
 *  Based on Apache Ant PatchTask:
9
 *
10
 *  Licensed to the Apache Software Foundation (ASF) under one or more
11
 *  contributor license agreements.  See the NOTICE file distributed with
12
 *  this work for additional information regarding copyright ownership.
13
 *  The ASF licenses this file to You under the Apache License, Version 2.0
14
 *  (the "License"); you may not use this file except in compliance with
15
 *  the License.  You may obtain a copy of the License at
16
 *
17
 *      http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 *  Unless required by applicable law or agreed to in writing, software
20
 *  distributed under the License is distributed on an "AS IS" BASIS,
21
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 *  See the License for the specific language governing permissions and
23
 *  limitations under the License.
24
 */
25
26
namespace Phing\Task\Optional;
27
28
use Phing\Exception\BuildException;
29
use Phing\Io\File;
30
use Phing\Io\IOException;
31
use Phing\Project;
32
use Phing\Task;
33
use Phing\Task\System\ExecTask;
34
use Phing\Type\Commandline;
35
36
/**
37
 * Patches a file by applying a 'diff' file to it.
38
 *
39
 * Requires "patch" to be on the execution path.
40
 */
41
class PatchTask extends Task
42
{
43
    private static $PATCH = 'patch';
44
45
    /**
46
     * File to be patched.
47
     *
48
     * @var File
49
     */
50
    private $originalFile;
51
52
    /**
53
     * @var File
54
     */
55
    private $directory;
56
57
    /**
58
     * Halt on error return value from patch invocation.
59
     *
60
     * @var bool
61
     */
62
    private $failOnError = false;
63
64
    /**
65
     * @var Commandline
66
     */
67
    private $cmd;
68
69
    /**
70
     * @var bool
71
     */
72
    private $havePatchFile = false;
73
74 1
    public function __construct()
75
    {
76 1
        $this->cmd = new Commandline();
77 1
        parent::__construct();
78 1
    }
79
80
    /**
81
     * The file containing the diff output.
82
     *
83
     * Required.
84
     *
85
     * @param File $file File containing the diff output
86
     *
87
     * @throws BuildException if $file not exists
88
     */
89 1
    public function setPatchFile(File $file)
90
    {
91 1
        if (!$file->exists()) {
92
            throw new BuildException('patchfile ' . $file . " doesn't exist", $this->getLocation());
93
        }
94 1
        $this->cmd->createArgument()->setValue('-i');
95 1
        $this->cmd->createArgument()->setFile($file);
96 1
        $this->havePatchFile = true;
97 1
    }
98
99
    /**
100
     * flag to create backups; optional, default=false.
101
     *
102
     * @param bool $backups if true create backups
103
     */
104
    public function setBackups($backups)
105
    {
106
        if ($backups) {
107
            $this->cmd->createArgument()->setValue('-b');
108
        }
109
    }
110
111
    /**
112
     * flag to ignore whitespace differences; default=false.
113
     *
114
     * @param bool $ignore if true ignore whitespace differences
115
     */
116 1
    public function setIgnorewhitespace($ignore)
117
    {
118 1
        if ($ignore) {
119 1
            $this->cmd->createArgument()->setValue('-l');
120
        }
121 1
    }
122
123
    /**
124
     * The file to patch.
125
     *
126
     * Optional if it can be inferred from the diff file.
127
     *
128
     * @param File $file File to patch
129
     */
130 1
    public function setOriginalFile(File $file)
131
    {
132 1
        $this->originalFile = $file;
133 1
    }
134
135
    /**
136
     * The name of a file to send the output to, instead of patching
137
     * the file(s) in place.
138
     *
139
     * Optional.
140
     *
141
     * @param File $file File to send the output to
142
     */
143 1
    public function setDestFile(File $file)
144
    {
145 1
        $this->cmd->createArgument()->setValue('-o');
146 1
        $this->cmd->createArgument()->setFile($file);
147 1
    }
148
149
    /**
150
     * Strip the smallest prefix containing <i>num</i> leading slashes
151
     * from filenames.
152
     *
153
     * patch's <i>--strip</i> option.
154
     *
155
     * @param int $num number of lines to strip
156
     *
157
     * @throws BuildException if num is < 0, or other errors
158
     */
159
    public function setStrip($num)
160
    {
161
        if ($num < 0) {
162
            throw new BuildException('strip has to be >= 0');
163
        }
164
165
        $this->cmd->createArgument()->setValue("--strip {$num}");
166
    }
167
168
    /**
169
     * Work silently unless an error occurs.
170
     *
171
     * Optional, default - false
172
     *
173
     * @param bool $flag If true suppress set the -s option on the patch command
174
     */
175
    public function setQuiet($flag)
176
    {
177
        if ($flag) {
178
            $this->cmd->createArgument()->setValue('-s');
179
        }
180
    }
181
182
    /**
183
     * Assume patch was created with old and new files swapped.
184
     *
185
     * Optional, default - false
186
     *
187
     * @param bool $flag If true set the -R option on the patch command
188
     */
189 1
    public function setReverse($flag)
190
    {
191 1
        if ($flag) {
192 1
            $this->cmd->createArgument('-R');
0 ignored issues
show
Bug introduced by
'-R' of type string is incompatible with the type boolean expected by parameter $insertAtStart of Phing\Type\Commandline::createArgument(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
            $this->cmd->createArgument(/** @scrutinizer ignore-type */ '-R');
Loading history...
193
        }
194 1
    }
195
196
    /**
197
     * The directory to run the patch command in.
198
     *
199
     * Defaults to the project's base directory.
200
     *
201
     * @param File $directory Directory to run the patch command in
202
     */
203
    public function setDir(File $directory)
204
    {
205
        $this->directory = $directory;
206
    }
207
208
    /**
209
     * Ignore patches that seem to be reversed or already applied.
210
     *
211
     * @param bool $flag If true set the -N (--forward) option
212
     */
213
    public function setForward($flag)
214
    {
215
        if ($flag) {
216
            $this->cmd->createArgument()->setValue('-N');
217
        }
218
    }
219
220
    /**
221
     * Set the maximum fuzz factor.
222
     *
223
     * Defaults to 0
224
     *
225
     * @param string $value Value of a fuzz factor
226
     */
227
    public function setFuzz($value)
228
    {
229
        $this->cmd->createArgument()->setValue("-F {$value}");
230
    }
231
232
    /**
233
     * If true, stop the build process if the patch command
234
     * exits with an error status.
235
     *
236
     * The default is "false"
237
     *
238
     * @param bool $value "true" if it should halt, otherwise "false"
239
     */
240 1
    public function setFailOnError($value)
241
    {
242 1
        $this->failOnError = $value;
243 1
    }
244
245
    public function setHaltOnFailure(string $value)
246
    {
247
        $this->failOnError = $value;
0 ignored issues
show
Documentation Bug introduced by
The property $failOnError was declared of type boolean, but $value is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
248
    }
249
250
    /**
251
     * Main task method.
252
     *
253
     * @throws BuildException when it all goes a bit pear shaped
254
     */
255 1
    public function main()
256
    {
257 1
        if (!$this->havePatchFile) {
258
            throw new BuildException('patchfile argument is required', $this->getLocation());
259
        }
260
261 1
        $toExecute = $this->cmd;
262 1
        $toExecute->setExecutable(self::$PATCH);
263
264 1
        if (null !== $this->originalFile) {
265 1
            $toExecute->createArgument()->setFile($this->originalFile);
266
        }
267
268 1
        $exe = new ExecTask();
269 1
        foreach ($toExecute->getArguments() as $part) {
270 1
            $exe->createArg()->setValue($part);
271
        }
272 1
        $exe->setLevel('info');
273 1
        $exe->setExecutable($toExecute->getExecutable());
274
275
        try {
276 1
            if (null === $this->directory) {
277 1
                $exe->setDir($this->getProject()->getBasedir());
278
            } else {
279
                if (!$this->directory->isDirectory()) {
280
                    throw new BuildException($this->directory . ' is not a directory.', $this->getLocation());
281
                }
282
                $exe->setDir($this->directory);
283
            }
284
285 1
            $this->log($toExecute->describeCommand(), Project::MSG_VERBOSE);
286
287 1
            $returnCode = $exe->main();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $returnCode is correct as $exe->main() targeting Phing\Task\System\ExecTask::main() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
288 1
            if ($exe->isFailure($returnCode)) {
289
                $msg = "'" . self::$PATCH . "' failed with exit code " . $returnCode;
290
                if ($this->failOnError) {
291
                    throw new BuildException($msg);
292
                }
293 1
                $this->log($msg, Project::MSG_ERR);
294
            }
295
        } catch (IOException $e) {
296
            if ($this->failOnError) {
297
                throw new BuildException($e, $this->getLocation());
298
            }
299
            $this->log($e->getMessage(), Project::MSG_ERR);
300
        }
301 1
    }
302
}
303