Completed
Push — master ( d3a073...5737c8 )
by Greg
02:21
created

src/Task/Remote/Rsync.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\Remote;
3
4
use Robo\Contract\CommandInterface;
5
use Robo\Task\BaseTask;
6
use Robo\Exception\TaskException;
7
8
/**
9
 * Executes rsync in a flexible manner.
10
 *
11
 * ``` php
12
 * $this->taskRsync()
13
 *   ->fromPath('src/')
14
 *   ->toHost('localhost')
15
 *   ->toUser('dev')
16
 *   ->toPath('/var/www/html/app/')
17
 *   ->remoteShell('ssh -i public_key')
18
 *   ->recursive()
19
 *   ->excludeVcs()
20
 *   ->checksum()
21
 *   ->wholeFile()
22
 *   ->verbose()
23
 *   ->progress()
24
 *   ->humanReadable()
25
 *   ->stats()
26
 *   ->run();
27
 * ```
28
 *
29
 * You could also clone the task and do a dry-run first:
30
 *
31
 * ``` php
32
 * $rsync = $this->taskRsync()
33
 *   ->fromPath('src/')
34
 *   ->toPath('example.com:/var/www/html/app/')
35
 *   ->archive()
36
 *   ->excludeVcs()
37
 *   ->progress()
38
 *   ->stats();
39
 *
40
 * $dryRun = clone $rsync;
41
 * $dryRun->dryRun()->run();
42
 * if ('y' === $this->ask('Do you want to run (y/n)')) {
43
 *   $rsync->run();
44
 * }
45
 * ```
46
 */
47
class Rsync extends BaseTask implements CommandInterface
48
{
49
    use \Robo\Common\ExecOneCommand;
50
51
    /**
52
     * @var string
53
     */
54
    protected $command;
55
56
    /**
57
     * @var string
58
     */
59
    protected $fromUser;
60
61
    /**
62
     * @var string
63
     */
64
    protected $fromHost;
65
66
    /**
67
     * @var string
68
     */
69
    protected $fromPath;
70
71
    /**
72
     * @var string
73
     */
74
    protected $toUser;
75
76
    /**
77
     * @var string
78
     */
79
    protected $toHost;
80
81
    /**
82
     * @var string
83
     */
84
    protected $toPath;
85
86
    /**
87
     * @return static
88
     */
89
    public static function init()
90
    {
91
        return new static();
92
    }
93
94
    public function __construct()
95
    {
96
        $this->command = 'rsync';
97
    }
98
99
    /**
100
     * This can either be a full rsync path spec (user@host:path) or just a path.
101
     * In case of the former do not specify host and user.
102
     *
103
     * @param string|array $path
104
     *
105
     * @return $this
106
     */
107
    public function fromPath($path)
108
    {
109
        $this->fromPath = $path;
0 ignored issues
show
Documentation Bug introduced by
It seems like $path can also be of type array. However, the property $fromPath is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
110
111
        return $this;
112
    }
113
114
    /**
115
     * This can either be a full rsync path spec (user@host:path) or just a path.
116
     * In case of the former do not specify host and user.
117
     *
118
     * @param string $path
119
     *
120
     * @return $this
121
     */
122
    public function toPath($path)
123
    {
124
        $this->toPath = $path;
125
126
        return $this;
127
    }
128
129
    /**
130
     * @param string $fromUser
131
     *
132
     * @return $this
133
     */
134
    public function fromUser($fromUser)
135
    {
136
        $this->fromUser = $fromUser;
137
        return $this;
138
    }
139
140
    /**
141
     * @param string $fromHost
142
     *
143
     * @return $this
144
     */
145
    public function fromHost($fromHost)
146
    {
147
        $this->fromHost = $fromHost;
148
        return $this;
149
    }
150
151
    /**
152
     * @param string $toUser
153
     *
154
     * @return $this
155
     */
156
    public function toUser($toUser)
157
    {
158
        $this->toUser = $toUser;
159
        return $this;
160
    }
161
162
    /**
163
     * @param string $toHost
164
     *
165
     * @return $this
166
     */
167
    public function toHost($toHost)
168
    {
169
        $this->toHost = $toHost;
170
        return $this;
171
    }
172
173
    /**
174
     * @return $this
175
     */
176
    public function progress()
177
    {
178
        $this->option(__FUNCTION__);
179
180
        return $this;
181
    }
182
183
    /**
184
     * @return $this
185
     */
186
    public function stats()
187
    {
188
        $this->option(__FUNCTION__);
189
190
        return $this;
191
    }
192
193
    /**
194
     * @return $this
195
     */
196
    public function recursive()
197
    {
198
        $this->option(__FUNCTION__);
199
200
        return $this;
201
    }
202
203
    /**
204
     * @return $this
205
     */
206
    public function verbose()
207
    {
208
        $this->option(__FUNCTION__);
209
210
        return $this;
211
    }
212
213
    /**
214
     * @return $this
215
     */
216
    public function checksum()
217
    {
218
        $this->option(__FUNCTION__);
219
220
        return $this;
221
    }
222
223
    /**
224
     * @return $this
225
     */
226
    public function archive()
227
    {
228
        $this->option(__FUNCTION__);
229
230
        return $this;
231
    }
232
233
    /**
234
     * @return $this
235
     */
236
    public function compress()
237
    {
238
        $this->option(__FUNCTION__);
239
240
        return $this;
241
    }
242
243
    /**
244
     * @return $this
245
     */
246
    public function owner()
247
    {
248
        $this->option(__FUNCTION__);
249
250
        return $this;
251
    }
252
253
    /**
254
     * @return $this
255
     */
256
    public function group()
257
    {
258
        $this->option(__FUNCTION__);
259
260
        return $this;
261
    }
262
263
    /**
264
     * @return $this
265
     */
266
    public function times()
267
    {
268
        $this->option(__FUNCTION__);
269
270
        return $this;
271
    }
272
273
    /**
274
     * @return $this
275
     */
276
    public function delete()
277
    {
278
        $this->option(__FUNCTION__);
279
280
        return $this;
281
    }
282
283
    /**
284
     * @param int $seconds
285
     *
286
     * @return $this
287
     */
288
    public function timeout($seconds)
289
    {
290
        $this->option(__FUNCTION__, $seconds);
291
292
        return $this;
293
    }
294
295
    /**
296
     * @return $this
297
     */
298
    public function humanReadable()
299
    {
300
        $this->option('human-readable');
301
302
        return $this;
303
    }
304
305
    /**
306
     * @return $this
307
     */
308
    public function wholeFile()
309
    {
310
        $this->option('whole-file');
311
312
        return $this;
313
    }
314
315
    /**
316
     * @return $this
317
     */
318
    public function dryRun()
319
    {
320
        $this->option('dry-run');
321
322
        return $this;
323
    }
324
325
    /**
326
     * @return $this
327
     */
328
    public function itemizeChanges()
329
    {
330
        $this->option('itemize-changes');
331
332
        return $this;
333
    }
334
335
    /**
336
     * Excludes .git, .svn and .hg items at any depth.
337
     *
338
     * @return $this
339
     */
340
    public function excludeVcs()
341
    {
342
        return $this->exclude([
343
            '.git',
344
            '.svn',
345
            '.hg',
346
        ]);
347
    }
348
349
    /**
350
     * @param array|string $pattern
351
     *
352
     * @return $this
353
     */
354
    public function exclude($pattern)
355
    {
356
        return $this->optionList(__FUNCTION__, $pattern);
357
    }
358
359
    /**
360
     * @param string $file
361
     *
362
     * @return $this
363
     *
364
     * @throws \Robo\Exception\TaskException
365
     */
366
    public function excludeFrom($file)
367
    {
368
        if (!is_readable($file)) {
369
            throw new TaskException($this, "Exclude file $file is not readable");
370
        }
371
372
        return $this->option('exclude-from', $file);
373
    }
374
375
    /**
376
     * @param array|string $pattern
377
     *
378
     * @return $this
379
     */
380
    public function includeFilter($pattern)
381
    {
382
        return $this->optionList('include', $pattern);
383
    }
384
385
    /**
386
     * @param array|string $pattern
387
     *
388
     * @return $this
389
     */
390
    public function filter($pattern)
391
    {
392
        return $this->optionList(__FUNCTION__, $pattern);
393
    }
394
395
    /**
396
     * @param string $file
397
     *
398
     * @return $this
399
     *
400
     * @throws \Robo\Exception\TaskException
401
     */
402
    public function filesFrom($file)
403
    {
404
        if (!is_readable($file)) {
405
            throw new TaskException($this, "Files-from file $file is not readable");
406
        }
407
408
        return $this->option('files-from', $file);
409
    }
410
411
    /**
412
     * @param string $command
413
     *
414
     * @return $this
415
     */
416
    public function remoteShell($command)
417
    {
418
        $this->option('rsh', "$command");
419
420
        return $this;
421
    }
422
423
    /**
424
     * {@inheritdoc}
425
     */
426
    public function run()
427
    {
428
        $command = $this->getCommand();
429
430
        return $this->executeCommand($command);
431
    }
432
433
    /**
434
     * Returns command that can be executed.
435
     * This method is used to pass generated command from one task to another.
436
     *
437
     * @return string
438
     */
439
    public function getCommand()
440
    {
441
        foreach ((array)$this->fromPath as $from) {
442
            $this->option(null, $this->getFromPathSpec($from));
443
        }
444
        $this->option(null, $this->getToPathSpec());
445
446
        return $this->command . $this->arguments;
447
    }
448
449
    /**
450
     * @return string
451
     */
452
    protected function getFromPathSpec($from)
453
    {
454
        return $this->getPathSpec($this->fromHost, $this->fromUser, $from);
455
    }
456
457
    /**
458
     * @return string
459
     */
460
    protected function getToPathSpec()
461
    {
462
        return $this->getPathSpec($this->toHost, $this->toUser, $this->toPath);
463
    }
464
465
    /**
466
     * @param string $host
467
     * @param string $user
468
     * @param string $path
469
     *
470
     * @return string
471
     */
472
    protected function getPathSpec($host, $user, $path)
473
    {
474
        $spec = isset($path) ? $path : '';
475
        if (!empty($host)) {
476
            $spec = "{$host}:{$spec}";
477
        }
478
        if (!empty($user)) {
479
            $spec = "{$user}@{$spec}";
480
        }
481
482
        return $spec;
483
    }
484
}
485