Passed
Push — master ( ef6ec0...e80653 )
by Michiel
08:36
created

DeleteTask::removeDir()   B

Complexity

Conditions 10
Paths 26

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 19.3886

Importance

Changes 0
Metric Value
cc 10
eloc 24
c 0
b 0
f 0
nc 26
nop 1
dl 0
loc 35
ccs 12
cts 22
cp 0.5455
crap 19.3886
rs 7.6666

How to fix   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
/**
21
 * Deletes a file or directory, or set of files defined by a fileset.
22
 *
23
 * @package phing.tasks.system
24
 */
25
class DeleteTask extends Task
26
{
27
    use ResourceAware;
28
29
    protected $file;
30
    protected $dir;
31
    protected $includeEmpty = false;
32
33
    protected $quiet = false;
34
    protected $failonerror = false;
35
    protected $verbosity = Project::MSG_VERBOSE;
36
37
    /**
38
     * Set the name of a single file to be removed.
39
     *
40
     * @param PhingFile $file
41
     */
42 45
    public function setFile(PhingFile $file)
43
    {
44 45
        $this->file = $file;
45 45
    }
46
47
    /**
48
     * Set the directory from which files are to be deleted.
49
     *
50
     * @param PhingFile $dir
51
     */
52 123
    public function setDir(PhingFile $dir)
53
    {
54 123
        $this->dir = $dir;
55 123
    }
56
57
    /**
58
     * Used to force listing of all names of deleted files.
59
     *
60
     * @param boolean $verbosity
61
     */
62
    public function setVerbose($verbosity)
63
    {
64
        if ($verbosity) {
65
            $this->verbosity = Project::MSG_INFO;
66
        } else {
67
            $this->verbosity = Project::MSG_VERBOSE;
68
        }
69
    }
70
71
    /**
72
     * If the file does not exist, do not display a diagnostic
73
     * message or modify the exit status to reflect an error.
74
     * This means that if a file or directory cannot be deleted,
75
     * then no error is reported. This setting emulates the
76
     * -f option to the Unix rm command. Default is false
77
     * meaning things are verbose
78
     *
79
     * @param  bool $bool
80
     * @return void
81
     */
82 19
    public function setQuiet($bool)
83
    {
84 19
        $this->quiet = $bool;
85 19
        if ($this->quiet) {
86 19
            $this->failonerror = false;
87
        }
88 19
    }
89
90
    /**
91
     * this flag means 'note errors to the output, but keep going'
92
     *
93
     * @param   bool $bool
94
     * @retujrn void
95
     */
96 2
    public function setFailOnError($bool)
97
    {
98 2
        $this->failonerror = $bool;
99 2
    }
100
101
    /**
102
     * Used to delete empty directories.
103
     *
104
     * @param  bool $includeEmpty
105
     * @return void
106
     */
107
    public function setIncludeEmptyDirs($includeEmpty)
108
    {
109
        $this->includeEmpty = (bool) $includeEmpty;
110
    }
111
112
    /**
113
     * Delete the file(s).
114
     *
115
     * @throws BuildException
116
     */
117 166
    public function main()
118
    {
119 166
        if ($this->file === null && $this->dir === null && count($this->dirsets) === 0
120 166
            && count($this->filesets) === 0 && count($this->filelists) === 0
121
        ) {
122
            throw new BuildException(
123
                "At least one of the file or dir attributes, or a fileset, filelist or dirset element must be set."
124
            );
125
        }
126
127 166
        if ($this->quiet && $this->failonerror) {
128
            throw new BuildException("quiet and failonerror cannot both be set to true", $this->getLocation());
129
        }
130
131
        // delete a single file
132 166
        if ($this->file !== null) {
133 45
            if ($this->file->exists()) {
134 32
                if ($this->file->isDirectory()) {
135 5
                    $this->log(
136 5
                        "Directory " . $this->file->__toString() . " cannot be removed using the file attribute. Use dir instead."
137
                    );
138
                } else {
139 27
                    $this->log("Deleting: " . $this->file->__toString());
140
                    try {
141 27
                        $this->file->delete();
142
                    } catch (Exception $e) {
143
                        $message = "Unable to delete file " . $this->file->__toString() . ": " . $e->getMessage();
144
                        if ($this->failonerror) {
145
                            throw new BuildException($message);
146
                        }
147
148 32
                        $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
149
                    }
150
                }
151
            } else {
152 28
                $message = "Could not find file " . $this->file->getAbsolutePath() . " to delete.";
153
154 28
                if ($this->failonerror) {
155 1
                    throw new BuildException($message);
156
                }
157
158 27
                $this->log($message, ($this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN));
159
            }
160
        }
161
162 166
        if ($this->dir !== null) {
163 123
            $this->dirsets[] = $this->dir;
164
        }
165 166
        foreach ($this->dirsets as $dirset) {
166 123
            if (!$dirset instanceof PhingFile) {
167 1
                $ds = $dirset->getDirectoryScanner($this->getProject());
168 1
                $dirs = $ds->getIncludedDirectories();
169 1
                $baseDir = $ds->getBasedir();
170
            } else {
171 123
                $dirs[0] = $dirset;
172
            }
173 123
            foreach ($dirs as $dir) {
174 123
                if (!$dir instanceof PhingFile) {
175 1
                    $dir = new PhingFile($baseDir, $dir);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $baseDir does not seem to be defined for all execution paths leading up to this point.
Loading history...
176
                }
177 123
                if ($dir->exists() && $dir->isDirectory()) {
178 115
                    if ($this->verbosity === Project::MSG_VERBOSE) {
179 115
                        $this->log("Deleting directory " . $dir->__toString());
180
                    }
181 115
                    $this->removeDir($dir);
182
                } else {
183 10
                    $message = "Directory " . $dir->getAbsolutePath() . " does not exist or is not a directory.";
184
185 10
                    if ($this->failonerror) {
186 1
                        throw new BuildException($message);
187
                    }
188
189 123
                    $this->log($message, ($this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN));
190
                }
191
            }
192
        }
193
194
        // delete the files in the filelists
195 166
        foreach ($this->filelists as $fl) {
196
            try {
197
                $files = $fl->getFiles($this->project);
198
                $this->removeFiles($fl->getDir($this->project), $files, $empty = []);
0 ignored issues
show
Bug introduced by
$empty = array() cannot be passed to DeleteTask::removeFiles() as the parameter $dirs expects a reference. ( Ignorable by Annotation )

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

198
                $this->removeFiles($fl->getDir($this->project), $files, /** @scrutinizer ignore-type */ $empty = []);
Loading history...
199
            } catch (BuildException $be) {
200
                // directory doesn't exist or is not readable
201
                if ($this->failonerror) {
202
                    throw $be;
203
                }
204
205
                $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
206
            }
207
        }
208
209
        // delete the files in the filesets
210 166
        foreach ($this->filesets as $fs) {
211
            try {
212 1
                $ds = $fs->getDirectoryScanner($this->project);
213 1
                $files = $ds->getIncludedFiles();
214 1
                $dirs = $ds->getIncludedDirectories();
215 1
                $this->removeFiles($fs->getDir($this->project), $files, $dirs);
216
            } catch (BuildException $be) {
217
                // directory doesn't exist or is not readable
218
                if ($this->failonerror) {
219
                    throw $be;
220
                }
221
222 1
                $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
223
            }
224
        }
225 166
    }
226
227
    /**
228
     * Recursively removes a directory.
229
     *
230
     * @param  PhingFile $d The directory to remove.
231
     * @throws BuildException
232
     */
233 115
    private function removeDir($d)
234
    {
235 115
        $list = $d->listDir();
236 115
        if ($list === null) {
237
            $list = [];
238
        }
239
240 115
        foreach ($list as $s) {
241 95
            $f = new PhingFile($d, $s);
242 95
            if ($f->isDirectory()) {
243 34
                $this->removeDir($f);
244
            } else {
245 90
                $this->log("Deleting " . $f->__toString(), $this->verbosity);
246
                try {
247 90
                    $f->delete();
248
                } catch (Exception $e) {
249
                    $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage();
250
                    if ($this->failonerror) {
251
                        throw new BuildException($message);
252
                    }
253
254 95
                    $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
255
                }
256
            }
257
        }
258 115
        $this->log("Deleting directory " . $d->getAbsolutePath(), $this->verbosity);
259
        try {
260 115
            $d->delete();
261
        } catch (Exception $e) {
262
            $message = "Unable to delete directory " . $d->__toString() . ": " . $e->getMessage();
263
            if ($this->failonerror) {
264
                throw new BuildException($message);
265
            }
266
267
            $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
268
        }
269 115
    }
270
271
    /**
272
     * remove an array of files in a directory, and a list of subdirectories
273
     * which will only be deleted if 'includeEmpty' is true
274
     *
275
     * @param  PhingFile $d directory to work from
276
     * @param  array     &$files array of files to delete; can be of zero length
277
     * @param  array     &$dirs array of directories to delete; can of zero length
278
     * @throws BuildException
279
     */
280 1
    private function removeFiles(PhingFile $d, &$files, &$dirs)
281
    {
282 1
        if (count($files) > 0) {
283 1
            $this->log("Deleting " . count($files) . " files from " . $d->__toString());
284 1
            for ($j = 0, $_j = count($files); $j < $_j; $j++) {
285 1
                $f = new PhingFile($d, $files[$j]);
286 1
                $this->log("Deleting " . $f->getAbsolutePath(), $this->verbosity);
287
                try {
288 1
                    $f->delete();
289
                } catch (Exception $e) {
290
                    $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage();
291
                    if ($this->failonerror) {
292
                        throw new BuildException($message);
293
                    }
294
295
                    $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
296
                }
297
            }
298
        }
299
300 1
        if (count($dirs) > 0 && $this->includeEmpty) {
301
            $dirCount = 0;
302
            for ($j = count($dirs) - 1; $j >= 0; --$j) {
303
                $dir = new PhingFile($d, $dirs[$j]);
304
                $dirFiles = $dir->listDir();
305
                if ($dirFiles === null || count($dirFiles) === 0) {
306
                    $this->log("Deleting " . $dir->__toString(), $this->verbosity);
307
                    try {
308
                        $dir->delete();
309
                        $dirCount++;
310
                    } catch (Exception $e) {
311
                        $message = "Unable to delete directory " . $dir->__toString();
312
                        if ($this->failonerror) {
313
                            throw new BuildException($message);
314
                        }
315
316
                        $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
317
                    }
318
                }
319
            }
320
            if ($dirCount > 0) {
321
                $this->log("Deleted $dirCount director" . ($dirCount == 1 ? "y" : "ies") . " from " . $d->__toString());
0 ignored issues
show
introduced by
The condition $dirCount == 1 is always false.
Loading history...
322
            }
323
        }
324 1
    }
325
}
326