Passed
Push — master ( b5ca42...8fe651 )
by Siad
05:05
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
cc 16
eloc 38
nc 961
nop 0
dl 0
loc 67
ccs 35
cts 37
cp 0.9459
crap 16.0405
rs 1.4541
c 0
b 0
f 0

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