Passed
Push — master ( b9bc63...f1e2bc )
by Michiel
06:23
created

TouchTask::_touch()   F

Complexity

Conditions 16
Paths 961

Size

Total Lines 67
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 16.0405

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 67
ccs 35
cts 37
cp 0.9459
rs 1.4541
c 0
b 0
f 0
cc 16
nc 961
nop 0
crap 16.0405

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
namespace Phing\Task\System;
21
22
use Phing\Exception\BuildException;
23
use Phing\Io\File;
24
use Phing\Io\FileUtils;
25
use Phing\Io\IOException;
26
use Phing\Phing;
27
use Phing\Project;
28
use Phing\Task;
29
use Phing\Type\Element\FileListAware;
30
use Phing\Type\Element\FileSetAware;
31
use Phing\Type\Mapper;
32
33
/**
34
 * Touch a file and/or fileset(s); corresponds to the Unix touch command.
35
 *
36
 * If the file to touch doesn't exist, an empty one is created.
37
 *
38
 * @package phing.tasks.system
39
 */
40
class TouchTask extends Task
41
{
42
    use FileListAware;
43
    use FileSetAware;
44
45
    /**
46
     * @var File $file
47
     */
48
    private $file;
49
    private $seconds = -1;
50
    private $dateTime;
51
    private $fileUtils;
52
    private $mkdirs = false;
53
    private $verbose = true;
54
55
    /** @var Mapper $mapperElement */
56
    private $mapperElement;
57
58
    /**
59
     *
60
     */
61 82
    public function __construct()
62
    {
63 82
        parent::__construct();
64 82
        $this->fileUtils = new FileUtils();
65 82
    }
66
67
    /**
68
     * Sets a single source file to touch.  If the file does not exist
69
     * an empty file will be created.
70
     *
71
     * @param  File $file
72
     * @return void
73
     */
74 73
    public function setFile(File $file)
75
    {
76 73
        $this->file = $file;
77 73
    }
78
79
    /**
80
     * The new modification time of the file in milliseconds since midnight
81
     * Jan 1 1970. Negative values are not accepted nor are values less than
82
     * 1000. Note that PHP is actually based on seconds so the value passed
83
     * in will be divided by 1000.
84
     *
85
     * Optional, default=now
86
     *
87
     * @param  $millis
88
     * @return void
89
     */
90 6
    public function setMillis($millis)
91
    {
92 6
        if ($millis >= 0) {
93 4
            if ($millis >= 1000) {
94 3
                $this->seconds = (int) $millis / 1000;
95
            } else {
96 4
                throw new BuildException("Millis less than 1000 would be treated as 0");
97
            }
98
        } else {
99 2
            throw new BuildException("Millis attribute cannot be negative");
100
        }
101 3
    }
102
103
    /**
104
     * the new modification time of the file
105
     * in seconds since midnight Jan 1 1970.
106
     * Optional, default=now
107
     *
108
     * @param  $seconds
109
     * @return void
110
     */
111 9
    public function setSeconds($seconds)
112
    {
113 9
        if ($seconds >= 0) {
114 8
            $this->seconds = (int) $seconds;
115
        } else {
116 1
            throw new BuildException("Seconds attribute cannot be negative");
117
        }
118 8
    }
119
120
    /**
121
     * the new modification time of the file
122
     * in the format MM/DD/YYYY HH:MM AM or PM;
123
     * Optional, default=now
124
     *
125
     * @param  $dateTime
126
     * @return void
127
     */
128 9
    public function setDatetime($dateTime)
129
    {
130 9
        $timestmap = strtotime($dateTime);
131 9
        if (false !== $timestmap) {
132 8
            $this->dateTime = (string) $dateTime;
133 8
            $this->setSeconds($timestmap);
134
        } else {
135 1
            throw new BuildException("Date of ${dateTime} cannot be parsed correctly. It should be in a format parsable by PHP's strtotime() function." . PHP_EOL);
136
        }
137 7
    }
138
139
    /**
140
     * Set whether nonexistent parent directories should be created
141
     * when touching new files.
142
     *
143
     * @param boolean $mkdirs whether to create parent directories.
144
     */
145 8
    public function setMkdirs($mkdirs)
146
    {
147 8
        $this->mkdirs = $mkdirs;
148 8
    }
149
150
    /**
151
     * Set whether the touch task will report every file it creates;
152
     * defaults to <code>true</code>.
153
     *
154
     * @param boolean $verbose flag.
155
     */
156
    public function setVerbose($verbose)
157
    {
158
        $this->verbose = $verbose;
159
    }
160
161
    /**
162
     * Execute the touch operation.
163
     *
164
     * @throws BuildException
165
     * @throws IOException
166
     */
167 2
    public function createMapper()
168
    {
169 2
        if ($this->mapperElement !== null) {
170
            throw new BuildException("Cannot define more than one mapper", $this->getLocation());
171
        }
172 2
        $this->mapperElement = new Mapper($this->project);
173
174 2
        return $this->mapperElement;
175
    }
176
177 77
    protected function checkConfiguration()
178
    {
179 77
        $savedSeconds = $this->seconds;
180
181 77
        if ($this->file === null && count($this->filesets) === 0 && count($this->filelists) === 0) {
182 1
            throw new BuildException("Specify at least one source - a file, a fileset or a filelist.");
183
        }
184
185 76
        if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) {
186 1
            throw new BuildException("Use a fileset to touch directories.");
187
        }
188
189 75
        $this->log(
190 75
            "Setting seconds to " . $savedSeconds . " from datetime attribute",
191 75
            ($this->seconds < 0 ? Project::MSG_DEBUG : Project::MSG_VERBOSE)
192
        );
193
194 75
        $this->seconds = $savedSeconds;
195 75
    }
196
197
    /**
198
     * Execute the touch operation.
199
     * @throws BuildException
200
     */
201 77
    public function main()
202
    {
203 77
        $this->checkConfiguration();
204 75
        $this->_touch();
205 73
    }
206
207
    /**
208
     * Does the actual work.
209
     */
210 75
    public function _touch()
211
    {
212 75
        if ($this->file !== null) {
213 67
            if (!$this->file->exists()) {
214 59
                $this->log(
215 59
                    "Creating " . $this->file,
216 59
                    $this->verbose ? Project::MSG_INFO : Project::MSG_VERBOSE
217
                );
218
                try { // try to create file
219 59
                    $this->file->createNewFile($this->mkdirs);
220 1
                } catch (IOException  $ioe) {
221 1
                    throw new BuildException(
222 1
                        "Error creating new file " . $this->file,
223
                        $ioe,
224 1
                        $this->getLocation()
225
                    );
226
                }
227
            }
228
        }
229
230 74
        $resetSeconds = false;
231 74
        if ($this->seconds < 0) {
232 65
            $resetSeconds = true;
233
            // Note: this function actually returns seconds, not milliseconds (e.g. 1606505920.2657)
234 65
            $this->seconds = Phing::currentTimeMillis();
235
        }
236
237 74
        if ($this->file !== null) {
238 66
            $this->touchFile($this->file);
239
        }
240
241 73
        $project = $this->getProject();
242 73
        foreach ($this->filesets as $fs) {
243 2
            $ds = $fs->getDirectoryScanner($project);
244 2
            $fromDir = $fs->getDir($project);
245
246 2
            $srcFiles = $ds->getIncludedFiles();
247 2
            $srcDirs = $ds->getIncludedDirectories();
248
249 2
            for ($j = 0, $_j = count($srcFiles); $j < $_j; $j++) {
250 2
                foreach ($this->getMappedFileNames((string) $srcFiles[$j]) as $fileName) {
251 2
                    $this->touchFile(new File($fromDir, $fileName));
252
                }
253
            }
254
255 2
            for ($j = 0, $_j = count($srcDirs); $j < $_j; $j++) {
256
                foreach ($this->getMappedFileNames((string) $srcDirs[$j]) as $fileName) {
257
                    $this->touchFile(new File($fromDir, $fileName));
258
                }
259
            }
260
        }
261
262
        // deal with the filelists
263 73
        foreach ($this->filelists as $fl) {
264 8
            $fromDir = $fl->getDir($this->getProject());
265
266 8
            $srcFiles = $fl->getFiles($this->getProject());
267
268 8
            for ($j = 0, $_j = count($srcFiles); $j < $_j; $j++) {
269 8
                foreach ($this->getMappedFileNames((string) $srcFiles[$j]) as $fileName) {
270 8
                    $this->touchFile(new File($fromDir, $fileName));
271
                }
272
            }
273
        }
274
275 73
        if ($resetSeconds) {
276 64
            $this->seconds = -1;
277
        }
278 73
    }
279
280 10
    private function getMappedFileNames($file)
281
    {
282 10
        if ($this->mapperElement !== null) {
283 2
            $mapper = $this->mapperElement->getImplementation();
284 2
            $results = $mapper->main($file);
285 2
            if ($results === null) {
0 ignored issues
show
introduced by
The condition $results === null is always false.
Loading history...
286
                return '';
287
            }
288 2
            $fileNames = $results;
289
        } else {
290 8
            $fileNames = [$file];
291
        }
292
293 10
        return $fileNames;
294
    }
295
296
    /**
297
     * @param $file
298
     * @throws BuildException
299
     */
300 74
    private function touchFile(File $file)
301
    {
302 74
        if (!$file->canWrite()) {
303 1
            throw new BuildException("Can not change modification date of read-only file " . (string) $file);
304
        }
305 73
        $file->setLastModified($this->seconds);
306 73
    }
307
}
308