Completed
Push — master ( c4c6a2...1fc5e4 )
by Siad
12:41
created

MoveTask   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Test Coverage

Coverage 65.45%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 112
dl 0
loc 213
rs 9.1199
c 2
b 0
f 0
ccs 72
cts 110
cp 0.6545
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 105 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 6
    public function __construct()
37
    {
38 6
        parent::__construct();
39 6
        $this->overwrite = true;
40 6
    }
41
42
    /**
43
     * Validates attributes coming in from XML
44
     *
45
     * @return void
46
     *
47
     * @throws BuildException
48
     */
49 6
    protected function validateAttributes()
50
    {
51 6
        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 5
            parent::validateAttributes();
74
        }
75 6
    }
76
77 6
    protected function doWork()
78
    {
79 6
        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
                            $this->granularity
97
                        );
98
                        $f->delete(true);
99
                    } else {
100 1
                        $this->fileUtils->renameFile($f, $d, $this->overwrite);
101
                    }
102
                } catch (IOException $ioe) {
103
                    $this->logError("Failed to rename $from to $to: " . $ioe->getMessage());
104
                }
105
            }
106
        }
107
108 6
        $copyMapSize = count($this->fileCopyMap);
109 6
        if ($copyMapSize > 0) {
110
            // files to move
111 3
            $this->log("Moving $copyMapSize files to " . $this->destDir->getAbsolutePath());
112
113 3
            foreach ($this->fileCopyMap as $from => $to) {
114 3
                if ($from == $to) {
115
                    $this->log("Skipping self-move of $from", $this->verbosity);
116
                    continue;
117
                }
118
119 3
                $f = new PhingFile($from);
120 3
                $d = new PhingFile($to);
121
122
                try { // try to move
123 3
                    $this->log("Moving $from to $to", $this->verbosity);
124
125 3
                    $this->fileUtils->copyFile(
126 3
                        $f,
127 3
                        $d,
128 3
                        $this->getProject(),
129 3
                        $this->overwrite,
130 3
                        $this->preserveLMT,
131 3
                        $this->filterChains,
132 3
                        $this->mode,
133 3
                        $this->preservePermissions,
134 3
                        $this->granularity
135
                    );
136
137 3
                    $f->delete();
138
                } catch (IOException $ioe) {
139
                    $this->logError("Failed to move $from to $to: " . $ioe->getMessage(), $this->getLocation());
140
                }
141
            } // foreach fileCopyMap
142
        } // if copyMapSize
143
144
        // handle empty dirs if appropriate
145 6
        if ($this->includeEmpty) {
146 6
            $count = 0;
147 6
            foreach ($this->dirCopyMap as $srcDir => $destDir) {
148
                $d = new PhingFile((string) $destDir);
149
                if (!$d->exists()) {
150
                    if (!$d->mkdirs()) {
151
                        $this->logError("Unable to create directory " . $d->getAbsolutePath());
152
                    } else {
153
                        $count++;
154
                    }
155
                }
156
            }
157 6
            if ($count > 0) {
158
                $this->log(
159
                    "moved $count empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath(
160
                    )
161
                );
162
            }
163
        }
164
165 6
        if (count($this->filesets) > 0) {
166
            // process filesets
167 1
            foreach ($this->filesets as $fs) {
168 1
                $dir = $fs->getDir($this->project);
169 1
                if ($this->okToDelete($dir)) {
170 1
                    $this->deleteDir($dir);
171
                }
172
            }
173
        }
174
175 6
        $dirsets = $this->getDirSets();
176 6
        if (count($dirsets) > 0) {
177
            // process dirsets
178
            foreach ($dirsets as $ds) {
179
                $dir = $ds->getDir($this->project);
180
                if ($this->okToDelete($dir)) {
181
                    $this->deleteDir($dir);
182
                }
183
            }
184
        }
185 6
    }
186
187
    /**
188
     * Its only ok to delete a dir tree if there are no files in it.
189
     *
190
     * @param $d
191
     *
192
     * @throws IOException
193
     *
194
     * @return bool
195
     */
196 1
    private function okToDelete(PhingFile $d)
197
    {
198 1
        $list = $d->listDir();
199 1
        if ($list === null) {
200
            return false; // maybe io error?
201
        }
202
203 1
        foreach ($list as $s) {
204 1
            $f = new PhingFile($d, $s);
205 1
            if ($f->isDirectory()) {
206 1
                if (!$this->okToDelete($f)) {
207
                    return false;
208
                }
209
            } else {
210
                // found a file
211
                return false;
212
            }
213
        }
214
215 1
        return true;
216
    }
217
218
    /**
219
     * Go and delete the directory tree.
220
     *
221
     * @param $d
222
     *
223
     * @throws BuildException
224
     * @throws IOException
225
     */
226 1
    private function deleteDir(PhingFile $d)
227
    {
228 1
        $list = $d->listDir();
229 1
        if ($list === null) {
230
            return; // on an io error list() can return null
231
        }
232
233 1
        foreach ($list as $fname) {
234 1
            $f = new PhingFile($d, $fname);
235 1
            if ($f->isDirectory()) {
236 1
                $this->deleteDir($f);
237
            } else {
238
                throw new BuildException("UNEXPECTED ERROR - The file " . $f->getAbsolutePath() . " should not exist!");
239
            }
240
        }
241
242 1
        $this->log("Deleting directory " . $d->getPath(), $this->verbosity);
243
        try {
244 1
            $d->delete();
245
        } catch (Exception $e) {
246
            $this->logError("Unable to delete directory " . $d->__toString() . ": " . $e->getMessage());
247
        }
248 1
    }
249
}
250