Completed
Pull Request — master (#893)
by Greg
05:57
created

src/Task/Filesystem/CopyDir.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Robo\Task\Filesystem;
3
4
use Robo\Common\ResourceExistenceChecker;
5
use Robo\Result;
6
use Robo\Exception\TaskException;
7
8
/**
9
 * Copies one dir into another
10
 *
11
 * ``` php
12
 * <?php
13
 * $this->taskCopyDir(['dist/config' => 'config'])->run();
14
 * // as shortcut
15
 * $this->_copyDir('dist/config', 'config');
16
 * ?>
17
 * ```
18
 */
19
class CopyDir extends BaseDir
20
{
21
    use ResourceExistenceChecker;
22
23
    /**
24
     * Explicitly declare our consturctor, so that
25
     * our copyDir() method does not look like a php4 constructor.
26
     *
27
     * @param string|string[] $dirs
28
     */
29
    public function __construct($dirs)
30
    {
31
        parent::__construct($dirs);
32
    }
33
34
    /**
35
     * @var int
36
     */
37
    protected $chmod = 0755;
38
39
    /**
40
     * Files to exclude on copying.
41
     *
42
     * @var string[]
43
     */
44
    protected $exclude = [];
45
46
    /**
47
     * Overwrite destination files newer than source files.
48
     */
49
    protected $overwrite = true;
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function run()
55
    {
56
        if (!$this->checkResources($this->dirs, 'dir')) {
57
            return Result::error($this, 'Source directories are missing!');
58
        }
59
        foreach ($this->dirs as $src => $dst) {
60
            $this->copyDir($src, $dst);
61
            $this->printTaskInfo('Copied from {source} to {destination}', ['source' => $src, 'destination' => $dst]);
62
        }
63
        return Result::success($this);
64
    }
65
66
    /**
67
     * Sets the default folder permissions for the destination if it doesn't exist
68
     *
69
     * @link http://en.wikipedia.org/wiki/Chmod
70
     * @link http://php.net/manual/en/function.mkdir.php
71
     * @link http://php.net/manual/en/function.chmod.php
72
     *
73
     * @param int $value
74
     *
75
     * @return $this
76
     */
77
    public function dirPermissions($value)
78
    {
79
        $this->chmod = (int)$value;
80
        return $this;
81
    }
82
83
    /**
84
     * List files to exclude.
85
     *
86
     * @param string[] $exclude
87
     *
88
     * @return $this
89
     */
90
    public function exclude($exclude = [])
91
    {
92
        $this->exclude = $this->simplifyForCompare($exclude);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->simplifyForCompare($exclude) of type string is incompatible with the declared type array<integer,string> of property $exclude.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
93
        return $this;
94
    }
95
96
    /**
97
     * Destination files newer than source files are overwritten.
98
     *
99
     * @param bool $overwrite
100
     *
101
     * @return $this
102
     */
103
    public function overwrite($overwrite)
104
    {
105
        $this->overwrite = $overwrite;
106
        return $this;
107
    }
108
109
    /**
110
     * Copies a directory to another location.
111
     *
112
     * @param string $src Source directory
113
     * @param string $dst Destination directory
114
     * @param string $parent Parent directory
115
     *
116
     * @throws \Robo\Exception\TaskException
117
     */
118
    protected function copyDir($src, $dst, $parent = '')
119
    {
120
        $dir = @opendir($src);
121
        if (false === $dir) {
122
            throw new TaskException($this, "Cannot open source directory '" . $src . "'");
123
        }
124
        if (!is_dir($dst)) {
125
            mkdir($dst, $this->chmod, true);
126
        }
127
        while (false !== ($file = readdir($dir))) {
128
            // Support basename and full path exclusion.
129
            if ($this->excluded($file, $src, $parent)) {
130
                continue;
131
            }
132
            $srcFile = $src . '/' . $file;
133
            $destFile = $dst . '/' . $file;
134
            if (is_dir($srcFile)) {
135
                $this->copyDir($srcFile, $destFile, $parent . $file . DIRECTORY_SEPARATOR);
136
            } else {
137
                $this->fs->copy($srcFile, $destFile, $this->overwrite);
138
            }
139
        }
140
        closedir($dir);
141
    }
142
143
    /**
144
     * Check to see if the current item is excluded.
145
     *
146
     * @param string $file
147
     * @param string $src
148
     * @param string $parent
149
     *
150
     * @return bool
151
     */
152
    protected function excluded($file, $src, $parent)
153
    {
154
        return
155
            ($file == '.') ||
156
            ($file == '..') ||
157
            in_array($file, $this->exclude) ||
158
            in_array($this->simplifyForCompare($parent . $file), $this->exclude) ||
159
            in_array($this->simplifyForCompare($src . DIRECTORY_SEPARATOR . $file), $this->exclude);
160
    }
161
162
    /**
163
     * Avoid problems comparing paths on Windows that may have a
164
     * combination of DIRECTORY_SEPARATOR and /.
165
     *
166
     * @param string$item
167
     *
168
     * @return string
169
     */
170
    protected function simplifyForCompare($item)
171
    {
172
        return str_replace(DIRECTORY_SEPARATOR, '/', $item);
173
    }
174
}
175