Completed
Push — master ( a670ca...f3dfc7 )
by Siad
13:36
created

MoveTask   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Test Coverage

Coverage 65.74%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 110
c 2
b 0
f 0
dl 0
loc 211
ccs 71
cts 108
cp 0.6574
rs 9.1199
wmc 41

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B validateAttributes() 0 25 9
A deleteDir() 0 21 5
A okToDelete() 0 20 5
D doWork() 0 103 21

How to fix   Complexity   

Complex Class

Complex classes like MoveTask often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MoveTask, and based on these observations, apply Extract Interface, too.

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
 * Moves a file or directory to a new file or directory.
22
 *
23
 * By default, the destination file is overwritten if it
24
 * already exists.  When overwrite is turned off, then files
25
 * are only moved if the source file is newer than the
26
 * destination file, or when the destination file does not
27
 * exist.
28
 *
29
 * Source files and directories are only deleted when the file or
30
 * directory has been copied to the destination successfully.
31
 *
32
 * @package phing.tasks.system
33
 */
34
class MoveTask extends CopyTask
35
{
36 5
    public function __construct()
37
    {
38 5
        parent::__construct();
39 5
        $this->overwrite = true;
40 5
    }
41
42
    /**
43
     * Validates attributes coming in from XML
44
     *
45
     * @return void
46
     *
47
     * @throws BuildException
48
     */
49 5
    protected function validateAttributes()
50
    {
51 5
        if ($this->file !== null && $this->file->isDirectory()) {
52
            if (
53 1
                ($this->destFile !== null
54 1
                && $this->destDir !== null)
55 1
                || ($this->destFile === null
56
                && $this->destDir === null)
57
            ) {
58
                throw new BuildException("One and only one of tofile and todir must be set.");
59
            }
60
61 1
            if ($this->destFile === null) {
62
                $this->destFile = new PhingFile($this->destDir, $this->file->getName());
63
            }
64
65 1
            if ($this->destDir === null) {
66 1
                $this->destDir = $this->destFile->getParentFile();
67
            }
68
69 1
            $this->completeDirMap[$this->file->getAbsolutePath()] = $this->destFile->getAbsolutePath();
70
71 1
            $this->file = null;
72
        } else {
73 4
            parent::validateAttributes();
74
        }
75 5
    }
76
77 5
    protected function doWork()
78
    {
79 5
        if (count($this->completeDirMap) > 0) {
80 1
            foreach ($this->completeDirMap as $from => $to) {
81 1
                $f = new PhingFile($from);
82 1
                $d = new PhingFile($to);
83
84
                try { // try to rename
85 1
                    $this->log("Attempting to rename $from to $to", $this->verbosity);
86 1
                    if (!empty($this->filterChains)) {
87
                        $this->fileUtils->copyFile(
88
                            $f,
89
                            $d,
90
                            $this->getProject(),
91
                            $this->overwrite,
92
                            $this->preserveLMT,
93
                            $this->filterChains,
94
                            $this->mode,
95
                            $this->preservePermissions
96
                        );
97
                        $f->delete(true);
98
                    } else {
99 1
                        $this->fileUtils->renameFile($f, $d, $this->overwrite);
100
                    }
101
                } catch (IOException $ioe) {
102
                    $this->logError("Failed to rename $from to $to: " . $ioe->getMessage());
103
                }
104
            }
105
        }
106
107 5
        $copyMapSize = count($this->fileCopyMap);
108 5
        if ($copyMapSize > 0) {
109
            // files to move
110 3
            $this->log("Moving $copyMapSize files to " . $this->destDir->getAbsolutePath());
111
112 3
            foreach ($this->fileCopyMap as $from => $to) {
113 3
                if ($from == $to) {
114
                    $this->log("Skipping self-move of $from", $this->verbosity);
115
                    continue;
116
                }
117
118 3
                $f = new PhingFile($from);
119 3
                $d = new PhingFile($to);
120
121
                try { // try to move
122 3
                    $this->log("Moving $from to $to", $this->verbosity);
123
124 3
                    $this->fileUtils->copyFile(
125 3
                        $f,
126 3
                        $d,
127 3
                        $this->getProject(),
128 3
                        $this->overwrite,
129 3
                        $this->preserveLMT,
130 3
                        $this->filterChains,
131 3
                        $this->mode,
132 3
                        $this->preservePermissions
133
                    );
134
135 3
                    $f->delete();
136
                } catch (IOException $ioe) {
137
                    $this->logError("Failed to move $from to $to: " . $ioe->getMessage(), $this->getLocation());
138
                }
139
            } // foreach fileCopyMap
140
        } // if copyMapSize
141
142
        // handle empty dirs if appropriate
143 5
        if ($this->includeEmpty) {
144 5
            $count = 0;
145 5
            foreach ($this->dirCopyMap as $srcDir => $destDir) {
146
                $d = new PhingFile((string) $destDir);
147
                if (!$d->exists()) {
148
                    if (!$d->mkdirs()) {
149
                        $this->logError("Unable to create directory " . $d->getAbsolutePath());
150
                    } else {
151
                        $count++;
152
                    }
153
                }
154
            }
155 5
            if ($count > 0) {
156
                $this->log(
157
                    "moved $count empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath(
158
                    )
159
                );
160
            }
161
        }
162
163 5
        if (count($this->filesets) > 0) {
164
            // process filesets
165 1
            foreach ($this->filesets as $fs) {
166 1
                $dir = $fs->getDir($this->project);
167 1
                if ($this->okToDelete($dir)) {
168 1
                    $this->deleteDir($dir);
169
                }
170
            }
171
        }
172
173 5
        $dirsets = $this->getDirSets();
174 5
        if (count($dirsets) > 0) {
175
            // process dirsets
176
            foreach ($dirsets as $ds) {
177
                $dir = $ds->getDir($this->project);
178
                if ($this->okToDelete($dir)) {
179
                    $this->deleteDir($dir);
180
                }
181
            }
182
        }
183 5
    }
184
185
    /**
186
     * Its only ok to delete a dir tree if there are no files in it.
187
     *
188
     * @param $d
189
     *
190
     * @throws IOException
191
     *
192
     * @return bool
193
     */
194 1
    private function okToDelete(PhingFile $d)
195
    {
196 1
        $list = $d->listDir();
197 1
        if ($list === null) {
198
            return false; // maybe io error?
199
        }
200
201 1
        foreach ($list as $s) {
202 1
            $f = new PhingFile($d, $s);
203 1
            if ($f->isDirectory()) {
204 1
                if (!$this->okToDelete($f)) {
205
                    return false;
206
                }
207
            } else {
208
                // found a file
209
                return false;
210
            }
211
        }
212
213 1
        return true;
214
    }
215
216
    /**
217
     * Go and delete the directory tree.
218
     *
219
     * @param $d
220
     *
221
     * @throws BuildException
222
     * @throws IOException
223
     */
224 1
    private function deleteDir(PhingFile $d)
225
    {
226 1
        $list = $d->listDir();
227 1
        if ($list === null) {
228
            return; // on an io error list() can return null
229
        }
230
231 1
        foreach ($list as $fname) {
232 1
            $f = new PhingFile($d, $fname);
233 1
            if ($f->isDirectory()) {
234 1
                $this->deleteDir($f);
235
            } else {
236
                throw new BuildException("UNEXPECTED ERROR - The file " . $f->getAbsolutePath() . " should not exist!");
237
            }
238
        }
239
240 1
        $this->log("Deleting directory " . $d->getPath(), $this->verbosity);
241
        try {
242 1
            $d->delete();
243
        } catch (Exception $e) {
244
            $this->logError("Unable to delete directory " . $d->__toString() . ": " . $e->getMessage());
245
        }
246 1
    }
247
}
248