Completed
Push — master ( 20b0ec...0fa80a )
by Siad
15:26
created

MoveTask::validateAttributes()   B

Complexity

Conditions 9
Paths 6

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 9.7971

Importance

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