Completed
Push — master ( d52b96...e2f758 )
by Michiel
11:35
created

DeleteTask::setIncludeEmptyDirs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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
                        } else {
147 32
                            $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
148
                        }
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
                } else {
157 27
                    $this->log($message, ($this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN));
158
                }
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
                    } else {
188 9
                        $this->log($message, ($this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN));
189
                    }
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
                } else {
204
                    $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
205
                }
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
                } else {
221
                    $this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
222
                }
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
                    } else {
253
                        $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
254
                    }
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
            } else {
266
                $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
267
            }
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
                    } else {
294
                        $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
295
                    }
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
                        } else {
315
                            $this->log($message, $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN);
316
                        }
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