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