Passed
Branch master (d80a5b)
by Anton
03:30
created

Rsync::__toString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
/**
3
 * @Author : a.zinovyev
4
 * @Package: rsync
5
 * @License: http://www.opensource.org/licenses/mit-license.php
6
 */
7
8
namespace xobotyi\rsync;
9
10
11
class Rsync extends Command
12
{
13
14
    /**
15
     * preserve ACLs (implies --perms)
16
     */
17
    public const OPT_ACLS = 'acls';
18
    /**
19
     * bind address for outgoing socket to daemon
20
     */
21
    public const OPT_ADDRESS = 'address';
22
    /**
23
     * append data onto shorter files
24
     */
25
    public const OPT_APPEND = 'append';
26
    /**
27
     * like --append, but with old data in file checksum
28
     */
29
    public const OPT_APPEND_VERIFY = 'append-verify';
30
    /**
31
     * archive mode; equals -rlptgoD (no -H,-A,-X)
32
     */
33
    public const OPT_ARCHIVE = 'archive';
34
    /**
35
     * make backups (see --suffix & --backup-dir)
36
     */
37
    public const OPT_BACKUP = 'backup';
38
    /**
39
     * make backups into hierarchy based in DIR
40
     */
41
    public const OPT_BACKUP_DIR = 'backup-dir';
42
    /**
43
     * use blocking I/O for the remote shell
44
     */
45
    public const OPT_BLOCKING_IO = 'blocking-io';
46
    /**
47
     * force a fixed checksum block-size
48
     */
49
    public const OPT_BLOCK_SIZE = 'block-size';
50
    /**
51
     * limit I/O bandwidth; KBytes per second
52
     */
53
    public const OPT_BWLIMIT = 'bwlimit';
54
    /**
55
     * skip based on checksum, not mod-time & size
56
     */
57
    public const OPT_CHECKSUM = 'checksum';
58
    /**
59
     * affect file and/or directory permissions
60
     */
61
    public const OPT_CHMOD = 'chmod';
62
    /**
63
     * compare destination files relative to DIR
64
     */
65
    public const OPT_COMPARE_DEST = 'compare-dest';
66
    /**
67
     * compress file data during the transfer
68
     */
69
    public const OPT_COMPRESS = 'compress';
70
    /**
71
     * explicitly set compression level
72
     */
73
    public const OPT_COMPRESS_LEVEL = 'compress-level';
74
    /**
75
     * set daemon connection timeout in seconds
76
     */
77
    public const OPT_CONTIMEOUT = 'contimeout';
78
    /**
79
     * include copies of unchanged files
80
     */
81
    public const OPT_COPY_DEST = 'copy-dest';
82
    /**
83
     * copy device contents as regular file
84
     */
85
    public const OPT_COPY_DEVICES = 'copy-devices';
86
    /**
87
     * transform symlink to a dir into referent dir
88
     */
89
    public const OPT_COPY_DIRLINKS = 'copy-dirlinks';
90
    /**
91
     * transform symlink into referent file/dir
92
     */
93
    public const OPT_COPY_LINKS = 'copy-links';
94
    /**
95
     * only "unsafe" symlinks are transformed
96
     */
97
    public const OPT_COPY_UNSAFE_LINKS = 'copy-unsafe-links';
98
    /**
99
     * auto-ignore files the same way CVS does
100
     */
101
    public const OPT_CVS_EXCLUDE = 'cvs-exclude';
102
    /**
103
     * an alias for --delete-during
104
     */
105
    public const OPT_DEL = 'del';
106
    /**
107
     * put all updated files into place at transfer's end
108
     */
109
    public const OPT_DELAY_UPDATES = 'delay-updates';
110
    /**
111
     * delete extraneous files from destination dirs
112
     */
113
    public const OPT_DELETE = 'delete';
114
    /**
115
     * receiver deletes after transfer, not during
116
     */
117
    public const OPT_DELETE_AFTER = 'delete-after';
118
    /**
119
     * receiver deletes before transfer, not during
120
     */
121
    public const OPT_DELETE_BEFORE = 'delete-before';
122
    /**
123
     * find deletions during, delete after
124
     */
125
    public const OPT_DELETE_DELAY = 'delete-delay';
126
    /**
127
     * receiver deletes during transfer (default)
128
     */
129
    public const OPT_DELETE_DURING = 'delete-during';
130
    /**
131
     * delete excluded files from destination dirs
132
     */
133
    public const OPT_DELETE_EXCLUDED = 'delete-excluded';
134
    /**
135
     * preserve device files (super-user only)
136
     */
137
    public const OPT_DEVICES = 'devices';
138
    /**
139
     * transfer directories without recursing
140
     */
141
    public const OPT_DIRS = 'dirs';
142
    /**
143
     * perform a trial run with no changes made
144
     */
145
    public const OPT_DRY_RUN = 'dry-run';
146
    /**
147
     * exclude files matching PATTERN
148
     */
149
    public const OPT_EXCLUDE = 'exclude';
150
    /**
151
     * read exclude patterns from FILE
152
     */
153
    public const OPT_EXCLUDE_FROM = 'exclude-from';
154
    /**
155
     * preserve the file's executability
156
     */
157
    public const OPT_EXECUTABILITY = 'executability';
158
    /**
159
     * skip creating new files on receiver
160
     */
161
    public const OPT_EXISTING = 'existing';
162
    /**
163
     * store/recover privileged attrs using xattrs
164
     */
165
    public const OPT_FAKE_SUPER = 'fake-super';
166
    /**
167
     * read list of source-file names from FILE
168
     */
169
    public const OPT_FILES_FROM = 'files-from';
170
    /**
171
     * add a file-filtering RULE
172
     */
173
    public const OPT_FILTER = 'filter';
174
    /**
175
     * force deletion of directories even if not empty
176
     */
177
    public const OPT_FORCE = 'force';
178
    /**
179
     * all *-from/filter files are delimited by 0s
180
     */
181
    public const OPT_FROM0 = 'from0';
182
    /**
183
     * find similar file for basis if no dest file
184
     */
185
    public const OPT_FUZZY = 'fuzzy';
186
    /**
187
     * preserve group
188
     */
189
    public const OPT_GROUP = 'group';
190
    /**
191
     * preserve hard links
192
     */
193
    public const OPT_HARD_LINKS = 'hard-links';
194
    /**
195
     * show help
196
     */
197
    public const OPT_HELP = 'help';
198
    /**
199
     * output numbers in a human-readable format
200
     */
201
    public const OPT_HUMAN_READABLE = 'human-readable';
202
    /**
203
     * request charset conversion of filenames
204
     */
205
    public const OPT_ICONV = 'iconv';
206
    /**
207
     * delete even if there are I/O errors
208
     */
209
    public const OPT_IGNORE_ERRORS = 'ignore-errors';
210
    /**
211
     * skip updating files that already exist on receiver
212
     */
213
    public const OPT_IGNORE_EXISTING = 'ignore-existing';
214
    /**
215
     * don't skip files that match in size and mod-time
216
     */
217
    public const OPT_IGNORE_TIMES = 'ignore-times';
218
    /**
219
     * don't exclude files matching PATTERN
220
     */
221
    public const OPT_INCLUDE = 'include';
222
    /**
223
     * read include patterns from FILE
224
     */
225
    public const OPT_INCLUDE_FROM = 'include-from';
226
    /**
227
     * update destination files in-place
228
     */
229
    public const OPT_INPLACE = 'inplace';
230
    /**
231
     * prefer IPv4
232
     */
233
    public const OPT_IPV4 = 'ipv4';
234
    /**
235
     * prefer IPv6
236
     */
237
    public const OPT_IPV6 = 'ipv6';
238
    /**
239
     * output a change-summary for all updates
240
     */
241
    public const OPT_ITEMIZE_CHANGES = 'itemize-changes';
242
    /**
243
     * treat symlinked dir on receiver as dir
244
     */
245
    public const OPT_KEEP_DIRLINKS = 'keep-dirlinks';
246
    /**
247
     * copy symlinks as symlinks
248
     */
249
    public const OPT_LINKS = 'links';
250
    /**
251
     * hardlink to files in DIR when unchanged
252
     */
253
    public const OPT_LINK_DEST = 'link-dest';
254
    /**
255
     * list the files instead of copying them
256
     */
257
    public const OPT_LIST_ONLY = 'list-only';
258
    /**
259
     * log what we're doing to the specified FILE
260
     */
261
    public const OPT_LOG_FILE = 'log-file';
262
    /**
263
     * log updates using the specified FMT
264
     */
265
    public const OPT_LOG_FILE_FORMAT = 'log-file-format';
266
    /**
267
     * don't delete more than NUM files
268
     */
269
    public const OPT_MAX_DELETE = 'max-delete';
270
    /**
271
     * don't transfer any file larger than SIZE
272
     */
273
    public const OPT_MAX_SIZE = 'max-size';
274
    /**
275
     * don't transfer any file smaller than SIZE
276
     */
277
    public const OPT_MIN_SIZE = 'min-size';
278
    /**
279
     * compare mod-times with reduced accuracy
280
     */
281
    public const OPT_MODIFY_WINDOW = 'modify-window';
282
    /**
283
     * don't send implied dirs with --relative
284
     */
285
    public const OPT_NO_IMPLIED_DIRS = 'no-implied-dirs';
286
    /**
287
     * suppress daemon-mode MOTD
288
     */
289
    public const OPT_NO_MOTD = 'no-motd';
290
    /**
291
     * turn off an implied OPTION (e.g. --no-D)
292
     */
293
    public const OPT_NO_OPTION = 'no-OPTION';
294
    /**
295
     * don't map uid/gid values by user/group name
296
     */
297
    public const OPT_NUMERIC_IDS = 'numeric-ids';
298
    /**
299
     * omit directories from --times
300
     */
301
    public const OPT_OMIT_DIR_TIMES = 'omit-dir-times';
302
    /**
303
     * omit symlinks from --times
304
     */
305
    public const OPT_OMIT_LINK_TIMES = 'omit-link-times';
306
    /**
307
     * don't cross filesystem boundaries
308
     */
309
    public const OPT_ONE_FILE_SYSTEM = 'one-file-system';
310
    /**
311
     * like --write-batch but w/o updating destination
312
     */
313
    public const OPT_ONLY_WRITE_BATCH = 'only-write-batch';
314
    /**
315
     * leave high-bit chars unescaped in output
316
     */
317
    public const OPT_OUTPUT_8_BIT = '8-bit-output';
318
    /**
319
     * output updates using the specified FORMAT
320
     */
321
    public const OPT_OUT_FORMAT = 'out-format';
322
    /**
323
     * preserve owner (super-user only)
324
     */
325
    public const OPT_OWNER = 'owner';
326
    /**
327
     * keep partially transferred files
328
     */
329
    public const OPT_PARTIAL = 'partial';
330
    /**
331
     * put a partially transferred file into DIR
332
     */
333
    public const OPT_PARTIAL_DIR = 'partial-dir';
334
    /**
335
     * read daemon-access password from FILE
336
     */
337
    public const OPT_PASSWORD_FILE = 'password-file';
338
    /**
339
     * preserve permissions
340
     */
341
    public const OPT_PERMS = 'perms';
342
    /**
343
     * specify double-colon alternate port number
344
     */
345
    public const OPT_PORT = 'port';
346
    /**
347
     * show progress during transfer
348
     */
349
    public const OPT_PROGRESS = 'progress';
350
    /**
351
     * no space-splitting; only wildcard special-chars
352
     */
353
    public const OPT_PROTECT_ARGS = 'protect-args';
354
    /**
355
     * force an older protocol version to be used
356
     */
357
    public const OPT_PROTOCOL = 'protocol';
358
    /**
359
     * prune empty directory chains from the file-list
360
     */
361
    public const OPT_PRUNE_EMPTY_DIRS = 'prune-empty-dirs';
362
    /**
363
     * suppress non-error messages
364
     */
365
    public const OPT_QUIET = 'quiet';
366
    /**
367
     * read a batched update from FILE
368
     */
369
    public const OPT_READ_BATCH = 'read-batch';
370
    /**
371
     * send OPTION to the remote side only
372
     */
373
    public const OPT_REMOTE_OPTION = 'remote-option';
374
    /**
375
     * recurse into directories
376
     */
377
    public const OPT_RECURSIVE = 'recursive';
378
    /**
379
     * use relative path names
380
     */
381
    public const OPT_RELATIVE = 'relative';
382
    /**
383
     * sender removes synchronized files (non-dirs)
384
     */
385
    public const OPT_REMOVE_SOURCE_FILES = 'remove-source-files';
386
    /**
387
     * specify the remote shell to use
388
     */
389
    public const OPT_RSH = 'rsh';
390
    /**
391
     * specify the rsync to run on the remote machine
392
     */
393
    public const OPT_RSYNC_PATH = 'rsync-path';
394
    /**
395
     * ignore symlinks that point outside the source tree
396
     */
397
    public const OPT_SAFE_LINKS = 'safe-links';
398
    /**
399
     * skip files that match in size
400
     */
401
    public const OPT_SIZE_ONLY = 'size-only';
402
    /**
403
     * skip compressing files with a suffix in LIST
404
     */
405
    public const OPT_SKIP_COMPRESS = 'skip-compress';
406
    /**
407
     * specify custom TCP options
408
     */
409
    public const OPT_SOCKOPTS = 'sockopts';
410
    /**
411
     * handle sparse files efficiently
412
     */
413
    public const OPT_SPARSE = 'sparse';
414
    /**
415
     * preserve special files
416
     */
417
    public const OPT_SPECIALS = 'specials';
418
    /**
419
     * give some file-transfer stats
420
     */
421
    public const OPT_STATS = 'stats';
422
    /**
423
     * set backup suffix (default ~ w/o --backup-dir)
424
     */
425
    public const OPT_SUFFIX = 'suffix';
426
    /**
427
     * receiver attempts super-user activities
428
     */
429
    public const OPT_SUPER = 'super';
430
    /**
431
     * create temporary files in directory DIR
432
     */
433
    public const OPT_TEMP_DIR = 'temp-dir';
434
    /**
435
     * set I/O timeout in seconds
436
     */
437
    public const OPT_TIMEOUT = 'timeout';
438
    /**
439
     * preserve modification times
440
     */
441
    public const OPT_TIMES = 'times';
442
    /**
443
     * skip files that are newer on the receiver
444
     */
445
    public const OPT_UPDATE = 'update';
446
    /**
447
     * increase verbosity
448
     */
449
    public const OPT_VERBOSE = 'verbose';
450
    /**
451
     * print version number
452
     */
453
    public const OPT_VERSION = 'version';
454
    /**
455
     * copy files whole (without delta-xfer algorithm)
456
     */
457
    public const OPT_WHOLE_FILE = 'whole-file';
458
    /**
459
     * write a batched update to FILE
460
     */
461
    public const OPT_WRITE_BATCH = 'write-batch';
462
    /**
463
     * preserve extended attributes
464
     */
465
    public const OPT_XATTRS = 'xattrs';
466
467
    public const CONF_EXECUTABLE = 'executable';
468
    public const CONF_CWD        = 'cwd';
469
    public const CONF_SSH        = 'ssh';
470
    public const CONF_OPTIONS    = 'options';
471
472
    protected $OPTIONS_LIST = [
473
        self::OPT_ACLS                => ['option' => 'A'],
474
        self::OPT_ADDRESS             => ['option' => 'address', 'argument' => true],
475
        self::OPT_APPEND              => ['option' => 'append'],
476
        self::OPT_APPEND_VERIFY       => ['option' => 'append-verify'],
477
        self::OPT_ARCHIVE             => ['option' => 'a'],
478
        self::OPT_BACKUP              => ['option' => 'b'],
479
        self::OPT_BACKUP_DIR          => ['option' => 'backup-dir', 'argument' => true],
480
        self::OPT_BLOCKING_IO         => ['option' => 'blocking-io'],
481
        self::OPT_BLOCK_SIZE          => ['option' => 'B', 'argument' => true],
482
        self::OPT_BWLIMIT             => ['option' => 'bwlimit', 'argument' => true],
483
        self::OPT_CHECKSUM            => ['option' => 'c'],
484
        self::OPT_CHMOD               => ['option' => 'chmod', 'argument' => true],
485
        self::OPT_COMPARE_DEST        => ['option' => 'compare-dest', 'argument' => true],
486
        self::OPT_COMPRESS            => ['option' => 'z'],
487
        self::OPT_COMPRESS_LEVEL      => ['option' => 'compress-level', 'argument' => true],
488
        self::OPT_CONTIMEOUT          => ['option' => 'contimeout', 'argument' => true],
489
        self::OPT_COPY_DEST           => ['option' => 'copy-dest', 'argument' => true],
490
        self::OPT_COPY_DEVICES        => ['option' => 'copy-devices'],
491
        self::OPT_COPY_DIRLINKS       => ['option' => 'k'],
492
        self::OPT_COPY_LINKS          => ['option' => 'L'],
493
        self::OPT_COPY_UNSAFE_LINKS   => ['option' => 'copy-unsafe-links'],
494
        self::OPT_CVS_EXCLUDE         => ['option' => 'C'],
495
        self::OPT_DEL                 => ['option' => 'del'],
496
        self::OPT_DELAY_UPDATES       => ['option' => 'delay-updates'],
497
        self::OPT_DELETE              => ['option' => 'delete'],
498
        self::OPT_DELETE_AFTER        => ['option' => 'delete-after'],
499
        self::OPT_DELETE_BEFORE       => ['option' => 'delete-before'],
500
        self::OPT_DELETE_DELAY        => ['option' => 'delete-delay'],
501
        self::OPT_DELETE_DURING       => ['option' => 'delete-during'],
502
        self::OPT_DELETE_EXCLUDED     => ['option' => 'delete-excluded'],
503
        self::OPT_DEVICES             => ['option' => 'devices'],
504
        self::OPT_DIRS                => ['option' => 'd'],
505
        self::OPT_DRY_RUN             => ['option' => 'n'],
506
        self::OPT_EXCLUDE             => ['option' => 'exclude', 'argument' => true],
507
        self::OPT_EXCLUDE_FROM        => ['option' => 'exclude-from', 'argument' => true],
508
        self::OPT_EXECUTABILITY       => ['option' => 'E'],
509
        self::OPT_EXISTING            => ['option' => 'existing'],
510
        self::OPT_FAKE_SUPER          => ['option' => 'fake-super'],
511
        self::OPT_FILES_FROM          => ['option' => 'files-from', 'argument' => true],
512
        self::OPT_FILTER              => ['option' => 'f', 'argument' => true],
513
        self::OPT_FORCE               => ['option' => 'force'],
514
        self::OPT_FROM0               => ['option' => '0'],
515
        self::OPT_FUZZY               => ['option' => 'y'],
516
        self::OPT_GROUP               => ['option' => 'g'],
517
        self::OPT_HARD_LINKS          => ['option' => 'H'],
518
        self::OPT_HELP                => ['option' => 'help'],
519
        self::OPT_HUMAN_READABLE      => ['option' => 'h'],
520
        self::OPT_ICONV               => ['option' => 'iconv', 'argument' => true],
521
        self::OPT_IGNORE_ERRORS       => ['option' => 'ignore-errors'],
522
        self::OPT_IGNORE_EXISTING     => ['option' => 'ignore-existing'],
523
        self::OPT_IGNORE_TIMES        => ['option' => 'I'],
524
        self::OPT_INCLUDE             => ['option' => 'include', 'argument' => true],
525
        self::OPT_INCLUDE_FROM        => ['option' => 'include-from', 'argument' => true],
526
        self::OPT_INPLACE             => ['option' => 'inplace'],
527
        self::OPT_IPV4                => ['option' => '4'],
528
        self::OPT_IPV6                => ['option' => '6'],
529
        self::OPT_ITEMIZE_CHANGES     => ['option' => 'i'],
530
        self::OPT_KEEP_DIRLINKS       => ['option' => 'K'],
531
        self::OPT_LINKS               => ['option' => 'l'],
532
        self::OPT_LINK_DEST           => ['option' => 'link-dest', 'argument' => true],
533
        self::OPT_LIST_ONLY           => ['option' => 'list-only'],
534
        self::OPT_LOG_FILE            => ['option' => 'log-file', 'argument' => true],
535
        self::OPT_LOG_FILE_FORMAT     => ['option' => 'log-file-format', 'argument' => true],
536
        self::OPT_MAX_DELETE          => ['option' => 'max-delete', 'argument' => true],
537
        self::OPT_MAX_SIZE            => ['option' => 'max-size', 'argument' => true],
538
        self::OPT_MIN_SIZE            => ['option' => 'min-size', 'argument' => true],
539
        self::OPT_MODIFY_WINDOW       => ['option' => 'modify-window', 'argument' => true],
540
        self::OPT_NO_IMPLIED_DIRS     => ['option' => 'no-implied-dirs'],
541
        self::OPT_NO_MOTD             => ['option' => 'no-motd'],
542
        self::OPT_NO_OPTION           => ['option' => 'no-OPTION'],
543
        self::OPT_NUMERIC_IDS         => ['option' => 'numeric-ids'],
544
        self::OPT_OMIT_DIR_TIMES      => ['option' => 'O'],
545
        self::OPT_OMIT_LINK_TIMES     => ['option' => 'J'],
546
        self::OPT_ONE_FILE_SYSTEM     => ['option' => 'x'],
547
        self::OPT_ONLY_WRITE_BATCH    => ['option' => 'only-write-batch', 'argument' => true],
548
        self::OPT_OUTPUT_8_BIT        => ['option' => '8'],
549
        self::OPT_OUT_FORMAT          => ['option' => 'out-format', 'argument' => true],
550
        self::OPT_OWNER               => ['option' => 'o'],
551
        self::OPT_PARTIAL             => ['option' => 'partial'],
552
        self::OPT_PARTIAL_DIR         => ['option' => 'partial-dir', 'argument' => true],
553
        self::OPT_PASSWORD_FILE       => ['option' => 'password-file', 'argument' => true],
554
        self::OPT_PERMS               => ['option' => 'p'],
555
        self::OPT_PORT                => ['option' => 'port', 'argument' => true],
556
        self::OPT_PROGRESS            => ['option' => 'progress'],
557
        self::OPT_PROTECT_ARGS        => ['option' => 's'],
558
        self::OPT_PROTOCOL            => ['option' => 'protocol', 'argument' => true],
559
        self::OPT_PRUNE_EMPTY_DIRS    => ['option' => 'm'],
560
        self::OPT_QUIET               => ['option' => 'q'],
561
        self::OPT_READ_BATCH          => ['option' => 'read-batch', 'argument' => true],
562
        self::OPT_RECURSIVE           => ['option' => 'r'],
563
        self::OPT_RELATIVE            => ['option' => 'R'],
564
        self::OPT_REMOVE_SOURCE_FILES => ['option' => 'remove-source-files'],
565
        self::OPT_REMOTE_OPTION       => ['option' => 'M', 'argument' => true],
566
        self::OPT_RSH                 => ['option' => 'e', 'argument' => true],
567
        self::OPT_RSYNC_PATH          => ['option' => 'rsync-path', 'argument' => true],
568
        self::OPT_SAFE_LINKS          => ['option' => 'safe-links'],
569
        self::OPT_SIZE_ONLY           => ['option' => 'size-only'],
570
        self::OPT_SKIP_COMPRESS       => ['option' => 'skip-compress', 'argument' => true],
571
        self::OPT_SOCKOPTS            => ['option' => 'sockopts', 'argument' => true],
572
        self::OPT_SPARSE              => ['option' => 'S'],
573
        self::OPT_SPECIALS            => ['option' => 'specials'],
574
        self::OPT_STATS               => ['option' => 'stats'],
575
        self::OPT_SUFFIX              => ['option' => 'suffix', 'argument' => true],
576
        self::OPT_SUPER               => ['option' => 'super'],
577
        self::OPT_TEMP_DIR            => ['option' => 'T', 'argument' => true],
578
        self::OPT_TIMEOUT             => ['option' => 'timeout', 'argument' => true],
579
        self::OPT_TIMES               => ['option' => 't'],
580
        self::OPT_UPDATE              => ['option' => 'u'],
581
        self::OPT_VERBOSE             => ['option' => 'v'],
582
        self::OPT_VERSION             => ['option' => 'version'],
583
        self::OPT_WHOLE_FILE          => ['option' => 'W'],
584
        self::OPT_WRITE_BATCH         => ['option' => 'write-batch', 'argument' => true],
585
        self::OPT_XATTRS              => ['option' => 'xattrs'],
586
    ];
587
588
    private $config = [
589
        self::CONF_EXECUTABLE => 'rsync',
590
        self::CONF_CWD        => './',
591
        self::CONF_SSH        => null,
592
        self::CONF_OPTIONS    => [],
593
    ];
594
595
    public function __construct(?array $config = null) {
596
        $this->config = array_merge($this->config, $config ?: []);
597
598
        $this->setOptions($this->config[self::CONF_OPTIONS])
599
             ->setSSH($this->config[self::CONF_SSH]);
600
601
        parent::__construct($this->config[self::CONF_EXECUTABLE], $this->config[self::CONF_CWD]);
602
    }
603
604
    public function getSSH() :?SSH {
605
        return $this->config[self::CONF_SSH];
606
    }
607
608
    public function setOption(string $optName, $val = true) :self {
609
        switch ($optName) {
610
            case self::OPT_READ_BATCH:
611
            case self::OPT_PASSWORD_FILE:
612
            case self::OPT_EXCLUDE_FROM:
613
            case self::OPT_INCLUDE_FROM:
614
            case self::OPT_FILES_FROM:
615
                if (!is_readable($val)) {
616
                    throw new Exception\Command("File {$val} for option {$optName} is not readable");
617
                }
618
619
                $val = realpath($val);
620
                break;
621
        }
622
623
        parent::setOption($optName, $val);
624
625
        return $this;
626
    }
627
628
    public function setSSH($ssh) :self {
629
        if ($ssh instanceof SSH) {
630
            $this->config[self::CONF_SSH] = $ssh;
631
        }
632
        else if (is_array($ssh)) {
633
            $this->config[self::CONF_SSH] = new SSH($ssh);
634
        }
635
        else if ($ssh === null) {
636
            $this->config[self::CONF_SSH] = null;
637
        }
638
        else {
639
            throw new Exception\Command('ssh config has to be an instance of \xobotyi\rsync\SSH, array or null, got ' . gettype($ssh));
640
        }
641
642
        return $this;
643
    }
644
645
    public function __toString() :string {
646
        if (isset($this->config[self::CONF_SSH])) {
647
            $this->setOption(self::OPT_RSH, (string)$this->config[self::CONF_SSH]);
648
        }
649
650
        return parent::__toString();
651
    }
652
653
    public function sync(string $from, string $to) :self {
654
655
        $this->setParameters([$from, $to]);
656
        $this->execute()
657
             ->clearParameters();
658
659
        return $this;
660
    }
661
}