Rsync::__toString()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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