1 | <?php |
||
2 | /* |
||
3 | ## Installing |
||
4 | |||
5 | Add to your _deploy.php_ |
||
6 | |||
7 | ```php |
||
8 | require 'contrib/rsync.php'; |
||
9 | ``` |
||
10 | |||
11 | ## Configuration options |
||
12 | |||
13 | - **rsync**: Accepts an array with following rsync options (all are optional and defaults are ok): |
||
14 | - *exclude*: accepts an *array* with patterns to be excluded from sending to server |
||
15 | - *exclude-file*: accepts a *string* containing absolute path to file, which contains exclude patterns |
||
16 | - *include*: accepts an *array* with patterns to be included in sending to server |
||
17 | - *include-file*: accepts a *string* containing absolute path to file, which contains include patterns |
||
18 | - *filter*: accepts an *array* of rsync filter rules |
||
19 | - *filter-file*: accepts a *string* containing merge-file filename. |
||
20 | - *filter-perdir*: accepts a *string* containing merge-file filename to be scanned and merger per each directory in rsync list on files to send |
||
21 | - *flags*: accepts a *string* of flags to set when calling rsync command. Please **avoid** flags that accept params, and use *options* instead. |
||
22 | - *options*: accepts an *array* of options to set when calling rsync command. **DO NOT** prefix options with `--` as it's automatically added. |
||
23 | - *timeout*: accepts an *int* defining timeout for rsync command to run locally. |
||
24 | |||
25 | ### Sample Configuration: |
||
26 | |||
27 | Following is default configuration. By default rsync ignores only git dir and `deploy.php` file. |
||
28 | |||
29 | ```php |
||
30 | // deploy.php |
||
31 | |||
32 | set('rsync',[ |
||
33 | 'exclude' => [ |
||
34 | '.git', |
||
35 | 'deploy.php', |
||
36 | ], |
||
37 | 'exclude-file' => false, |
||
38 | 'include' => [], |
||
39 | 'include-file' => false, |
||
40 | 'filter' => [], |
||
41 | 'filter-file' => false, |
||
42 | 'filter-perdir'=> false, |
||
43 | 'flags' => 'rz', // Recursive, with compress |
||
44 | 'options' => ['delete'], |
||
45 | 'timeout' => 60, |
||
46 | ]); |
||
47 | ``` |
||
48 | |||
49 | If You have multiple excludes, You can put them in file and reference that instead. If You use `deploy:rsync_warmup` You could set additional options that could speed-up and/or affect way things are working. For example: |
||
50 | |||
51 | ```php |
||
52 | // deploy.php |
||
53 | |||
54 | set('rsync',[ |
||
55 | 'exclude' => ['excludes_file'], |
||
56 | 'exclude-file' => '/tmp/localdeploys/excludes_file', //Use absolute path to avoid possible rsync problems |
||
57 | 'include' => [], |
||
58 | 'include-file' => false, |
||
59 | 'filter' => [], |
||
60 | 'filter-file' => false, |
||
61 | 'filter-perdir' => false, |
||
62 | 'flags' => 'rzcE', // Recursive, with compress, check based on checksum rather than time/size, preserve Executable flag |
||
63 | 'options' => ['delete', 'delete-after', 'force'], //Delete after successful transfer, delete even if deleted dir is not empty |
||
64 | 'timeout' => 3600, //for those huge repos or crappy connection |
||
65 | ]); |
||
66 | ``` |
||
67 | |||
68 | |||
69 | ### Parameter |
||
70 | |||
71 | - **rsync_src**: per-host rsync source. This can be server, stage or whatever-dependent. By default it's set to current directory |
||
72 | - **rsync_dest**: per-host rsync destination. This can be server, stage or whatever-dependent. by default it's equivalent to release deploy destination. |
||
73 | |||
74 | ### Sample configurations: |
||
75 | |||
76 | This is default configuration: |
||
77 | |||
78 | ```php |
||
79 | set('rsync_src', __DIR__); |
||
80 | set('rsync_dest','{{release_path}}'); |
||
81 | ``` |
||
82 | |||
83 | If You use local deploy recipe You can set src to local release: |
||
84 | |||
85 | ```php |
||
86 | host('hostname') |
||
87 | ->hostname('10.10.10.10') |
||
88 | ->port(22) |
||
89 | ->set('deploy_path','/your/remote/path/app') |
||
90 | ->set('rsync_src', '/your/local/path/app') |
||
91 | ->set('rsync_dest','{{release_path}}'); |
||
92 | ``` |
||
93 | |||
94 | ## Usage |
||
95 | |||
96 | - `rsync` task |
||
97 | |||
98 | Set `rsync_src` to locally cloned repository and rsync to `rsync_dest`. Then set this task instead of `deploy:update_code` in Your `deploy` task if Your hosting provider does not allow git. |
||
99 | |||
100 | - `rsync:warmup` task |
||
101 | |||
102 | If Your deploy task looks like: |
||
103 | |||
104 | ```php |
||
105 | task('deploy', [ |
||
106 | 'deploy:prepare', |
||
107 | 'deploy:release', |
||
108 | 'rsync', |
||
109 | 'deploy:vendors', |
||
110 | 'deploy:symlink', |
||
111 | 'cleanup', |
||
112 | ])->desc('Deploy your project'); |
||
113 | ``` |
||
114 | |||
115 | And Your `rsync_dest` is set to `{{release_path}}` then You could add this task to run before `rsync` task or after `deploy:release`, whatever is more convenient. |
||
116 | |||
117 | */ |
||
118 | namespace Deployer; |
||
119 | |||
120 | set('rsync', [ |
||
121 | 'exclude' => [ |
||
122 | '.git', |
||
123 | 'deploy.php', |
||
124 | ], |
||
125 | 'exclude-file' => false, |
||
126 | 'include' => [], |
||
127 | 'include-file' => false, |
||
128 | 'filter' => [], |
||
129 | 'filter-file' => false, |
||
130 | 'filter-perdir' => false, |
||
131 | 'flags' => 'rz', |
||
132 | 'options' => ['delete'], |
||
133 | 'timeout' => 300, |
||
134 | ]); |
||
135 | |||
136 | set('rsync_src', __DIR__); |
||
137 | set('rsync_dest', '{{release_path}}'); |
||
138 | |||
139 | set('rsync_excludes', function () { |
||
140 | $config = get('rsync'); |
||
141 | $excludes = $config['exclude']; |
||
142 | $excludeFile = $config['exclude-file']; |
||
143 | $excludesRsync = ''; |
||
144 | foreach ($excludes as $exclude) { |
||
145 | $excludesRsync.=' --exclude=' . escapeshellarg($exclude); |
||
146 | } |
||
147 | if (!empty($excludeFile) && file_exists($excludeFile) && is_file($excludeFile) && is_readable($excludeFile)) { |
||
148 | $excludesRsync .= ' --exclude-from=' . escapeshellarg($excludeFile); |
||
149 | } |
||
150 | |||
151 | return $excludesRsync; |
||
152 | }); |
||
153 | |||
154 | set('rsync_includes', function () { |
||
155 | $config = get('rsync'); |
||
156 | $includes = $config['include']; |
||
157 | $includeFile = $config['include-file']; |
||
158 | $includesRsync = ''; |
||
159 | foreach ($includes as $include) { |
||
160 | $includesRsync.=' --include=' . escapeshellarg($include); |
||
161 | } |
||
162 | if (!empty($includeFile) && file_exists($includeFile) && is_file($includeFile) && is_readable($includeFile)) { |
||
163 | $includesRsync .= ' --include-from=' . escapeshellarg($includeFile); |
||
164 | } |
||
165 | |||
166 | return $includesRsync; |
||
167 | }); |
||
168 | |||
169 | set('rsync_filter', function () { |
||
170 | $config = get('rsync'); |
||
171 | $filters = $config['filter']; |
||
172 | $filterFile = $config['filter-file']; |
||
173 | $filterPerDir = $config['filter-perdir']; |
||
174 | $filtersRsync = ''; |
||
175 | foreach ($filters as $filter) { |
||
176 | $filtersRsync.=" --filter='$filter'"; |
||
177 | } |
||
178 | if (!empty($filterFile)) { |
||
179 | $filtersRsync .= " --filter='merge $filterFile'"; |
||
180 | } |
||
181 | if (!empty($filterPerDir)) { |
||
182 | $filtersRsync .= " --filter='dir-merge $filterPerDir'"; |
||
183 | } |
||
184 | return $filtersRsync; |
||
185 | }); |
||
186 | |||
187 | set('rsync_options', function () { |
||
188 | $config = get('rsync'); |
||
189 | $options = $config['options']; |
||
190 | $optionsRsync = []; |
||
191 | foreach ($options as $option) { |
||
192 | $optionsRsync[] = "--$option"; |
||
193 | } |
||
194 | return implode(' ', $optionsRsync); |
||
195 | }); |
||
196 | |||
197 | |||
198 | desc('Warmup remote Rsync target'); |
||
199 | task('rsync:warmup', function() { |
||
200 | $config = get('rsync'); |
||
201 | |||
202 | $source = "{{deploy_path}}/current"; |
||
203 | $destination = "{{deploy_path}}/release"; |
||
204 | |||
205 | if (test("[ -d $(echo $source) ]")) { |
||
206 | run("rsync -{$config['flags']} {{rsync_options}}{{rsync_excludes}}{{rsync_includes}}{{rsync_filter}} $source/ $destination/"); |
||
207 | } else { |
||
208 | writeln("<comment>No way to warmup rsync.</comment>"); |
||
209 | } |
||
210 | }); |
||
211 | |||
212 | |||
213 | desc('Rsync local->remote'); |
||
214 | task('rsync', function() { |
||
215 | $config = get('rsync'); |
||
216 | |||
217 | $src = get('rsync_src'); |
||
218 | while (is_callable($src)) { |
||
219 | $src = $src(); |
||
220 | } |
||
221 | |||
222 | if (!trim($src)) { |
||
223 | // if $src is not set here rsync is going to do a directory listing |
||
224 | // exiting with code 0, since only doing a directory listing clearly |
||
225 | // is not what we want to achieve we need to throw an exception |
||
226 | throw new \RuntimeException('You need to specify a source path.'); |
||
227 | } |
||
228 | |||
229 | $dst = get('rsync_dest'); |
||
230 | while (is_callable($dst)) { |
||
231 | $dst = $dst(); |
||
232 | } |
||
233 | |||
234 | if (!trim($dst)) { |
||
235 | // if $dst is not set here we are going to sync to root |
||
236 | // and even worse - depending on rsync flags and permission - |
||
237 | // might end up deleting everything we have write permission to |
||
238 | throw new \RuntimeException('You need to specify a destination path.'); |
||
239 | } |
||
240 | |||
241 | $server = \Deployer\Task\Context::get()->getHost(); |
||
242 | if ($server instanceof \Deployer\Host\Localhost) { |
||
243 | runLocally("rsync -{$config['flags']} {{rsync_options}}{{rsync_includes}}{{rsync_excludes}}{{rsync_filter}} '$src/' '$dst/'", $config); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
244 | return; |
||
245 | } |
||
246 | |||
247 | $host = $server->getHostname(); |
||
248 | $port = $server->getPort() ? ' -p' . $server->getPort() : ''; |
||
249 | $sshArguments = $server->getSshArguments(); |
||
250 | $user = !$server->getRemoteUser() ? '' : $server->getRemoteUser() . '@'; |
||
251 | |||
252 | runLocally("rsync -{$config['flags']} -e 'ssh$port $sshArguments' {{rsync_options}}{{rsync_includes}}{{rsync_excludes}}{{rsync_filter}} '$src/' '$user$host:$dst/'", $config); |
||
253 | }); |
||
254 |