six-rsync 0.3.8 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +2 -2
- data/bin/six-rsync +25 -0
- data/bin/six-rsync-mirror +25 -0
- data/lib/six/rsync/base.rb +1 -1
- data/lib/six/rsync/lib.rb +803 -863
- data/lib/six/rsync/options.rb +4 -0
- data/lib/six/rsync-app.rb +6 -0
- data/lib/six/rsync-mirror.rb +12 -0
- data/lib/six/rsync.rb +1 -1
- metadata +10 -6
data/lib/six/rsync/lib.rb
CHANGED
@@ -1,863 +1,803 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@
|
35
|
-
@
|
36
|
-
|
37
|
-
@
|
38
|
-
@
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@rsync_dir = base
|
45
|
-
@rsync_work_dir = base
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
opts[:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
@logger
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
@
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
@
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
end
|
418
|
-
|
419
|
-
|
420
|
-
arr_opts << esc(
|
421
|
-
arr_opts
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
FileUtils.
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
ar
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
end
|
593
|
-
|
594
|
-
def
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
config
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
end
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
@logger.debug "Error: " + error.chomp
|
805
|
-
# exit
|
806
|
-
end
|
807
|
-
# puts "Result: " + io_out.gets
|
808
|
-
s = waitth.value
|
809
|
-
}
|
810
|
-
# FIXME: This doesn't work with the new popen or is there a way?
|
811
|
-
if s.exitstatus > 0
|
812
|
-
@logger.debug "Exitstatus: #{s.exitstatus}"
|
813
|
-
if (s.exitstatus == 1 && out.size == 0)# || s.exitstatus == 5
|
814
|
-
return ''
|
815
|
-
end
|
816
|
-
if out.to_s =~ /max connections \((.*)\) reached/
|
817
|
-
@logger.warn "Server reached maximum connections."
|
818
|
-
end
|
819
|
-
raise Rsync::RsyncExecuteError.new(rsync_cmd + ':' + out.to_s)
|
820
|
-
end
|
821
|
-
=end
|
822
|
-
status
|
823
|
-
end
|
824
|
-
|
825
|
-
def process_msg(msg)
|
826
|
-
if msg[/[k|m|g]?B\/s/i]
|
827
|
-
msg.gsub!("\n", '')
|
828
|
-
print "#{msg}\r" if @verbose
|
829
|
-
else
|
830
|
-
@logger.debug msg
|
831
|
-
print msg if @verbose
|
832
|
-
end
|
833
|
-
msg
|
834
|
-
|
835
|
-
=begin
|
836
|
-
m = nil
|
837
|
-
if msg[/\r/]
|
838
|
-
# TODO; must still be written even if there is no next message :P
|
839
|
-
|
840
|
-
if @write
|
841
|
-
print msg
|
842
|
-
end
|
843
|
-
m = msg.gsub("\r", '')
|
844
|
-
#@previous = m
|
845
|
-
else
|
846
|
-
m = msg
|
847
|
-
#if @previous
|
848
|
-
# @logger.debug @previous
|
849
|
-
# @previous = nil
|
850
|
-
#end
|
851
|
-
#unless @previous
|
852
|
-
# @logger.debug m
|
853
|
-
#end
|
854
|
-
@logger.debug m
|
855
|
-
puts m if @write
|
856
|
-
end
|
857
|
-
m
|
858
|
-
=end
|
859
|
-
end
|
860
|
-
end
|
861
|
-
end
|
862
|
-
end
|
863
|
-
end
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Six
|
4
|
+
module Repositories
|
5
|
+
module Rsync
|
6
|
+
# TODO: Configure somewhere!
|
7
|
+
KEY = "C:/users/sb/documents/keys/id_rsa.ppk"
|
8
|
+
# TODO: Linux
|
9
|
+
RSH = "-r --rsh=\"'#{File.join(BASE_PATH, "tools", "bin", "cygnative.exe")}' plink.exe -i #{KEY}\""
|
10
|
+
|
11
|
+
DIR_RSYNC = '.rsync'
|
12
|
+
DIR_PACK = File.join(DIR_RSYNC, '.pack')
|
13
|
+
REGEX_FOLDER = /(.*)[\\|\/](.*)/
|
14
|
+
class RsyncExecuteError < StandardError; end
|
15
|
+
class RsyncError < StandardError; end
|
16
|
+
|
17
|
+
class Lib
|
18
|
+
attr_accessor :verbose
|
19
|
+
PROTECTED = false
|
20
|
+
WINDRIVE = /\"(\w)\:/
|
21
|
+
DEFAULT_CONFIG = {:hosts => [], :exclude => []}.to_yaml
|
22
|
+
DEFAULT_TIMEOUT = 60
|
23
|
+
PARAMS = if PROTECTED
|
24
|
+
"--dry-run --times -O --no-whole-file -r --delete --progress -h --exclude=.rsync"
|
25
|
+
else
|
26
|
+
"--times -O --no-whole-file -r --delete --progress -h --exclude=.rsync"
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(base = nil, logger = nil)
|
30
|
+
@rsync_dir = nil
|
31
|
+
@rsync_work_dir = nil
|
32
|
+
@path = nil
|
33
|
+
@stats = false
|
34
|
+
@verbose = true
|
35
|
+
@logger = logger
|
36
|
+
|
37
|
+
@repos_local = {:pack => Hash.new, :wd => Hash.new, :version => 0}
|
38
|
+
@repos_remote = {:pack => Hash.new, :wd => Hash.new, :version => 0}
|
39
|
+
|
40
|
+
if base.is_a?(Rsync::Base)
|
41
|
+
@rsync_dir = base.repo.path
|
42
|
+
@rsync_work_dir = base.dir.path if base.dir
|
43
|
+
elsif base.is_a?(Hash)
|
44
|
+
@rsync_dir = base[:repository]
|
45
|
+
@rsync_work_dir = base[:working_directory]
|
46
|
+
end
|
47
|
+
|
48
|
+
etc = File.join(TOOLS_PATH, 'etc')
|
49
|
+
FileUtils.mkdir_p etc
|
50
|
+
fstab = File.join(etc, 'fstab')
|
51
|
+
str = ""
|
52
|
+
str = File.open(fstab) {|file| file.read} if File.exists?(fstab)
|
53
|
+
unless str[/cygdrive/]
|
54
|
+
str += "\nnone /cygdrive cygdrive user,noacl,posix=0 0 0\n"
|
55
|
+
File.open(fstab, 'w') {|file| file.puts str}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def status
|
60
|
+
@logger.info "Showing changes on #{@rsync_work_dir}"
|
61
|
+
@config = load_config
|
62
|
+
unless @config
|
63
|
+
@logger.error "Not an Rsync repository!"
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
load_repos(:local)
|
68
|
+
load_repos(:remote)
|
69
|
+
|
70
|
+
@logger.info "Calculating Checksums..."
|
71
|
+
@repos_local[:wd] = calc_sums(:wd)
|
72
|
+
# Added or Changed files
|
73
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
74
|
+
|
75
|
+
change = false
|
76
|
+
i = 0
|
77
|
+
@repos_local[:wd].each_pair do |key, value|
|
78
|
+
i += 1
|
79
|
+
if value != @repos_remote[:wd][key]
|
80
|
+
change = true
|
81
|
+
@logger.info "Modified: #{i}/#{@repos_local[:wd].size}: #{key}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deleted files
|
86
|
+
@logger.info "Checking for deleted files..."
|
87
|
+
|
88
|
+
i = 0
|
89
|
+
@repos_remote[:wd].each_pair do |key, value|
|
90
|
+
i += 1
|
91
|
+
if @repos_local[:wd][key].nil?
|
92
|
+
@logger.info "Removed: #{packed}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def init
|
98
|
+
@logger.info "Processing: #{rsync_path}"
|
99
|
+
if File.exists? rsync_path
|
100
|
+
@logger.error "Seems to already be an Rsync repository, Aborting!"
|
101
|
+
raise RsyncError
|
102
|
+
end
|
103
|
+
if File.exists? @rsync_work_dir
|
104
|
+
@logger.error "Seems to already be a folder, Aborting!"
|
105
|
+
raise RsyncError
|
106
|
+
end
|
107
|
+
FileUtils.mkdir_p pack_path
|
108
|
+
save_config(config)
|
109
|
+
save_repos(:local)
|
110
|
+
save_repos(:remote)
|
111
|
+
end
|
112
|
+
|
113
|
+
def clone(repository, name, opts = {})
|
114
|
+
@path = opts[:path] || '.'
|
115
|
+
@rsync_work_dir = opts[:path] ? File.join(@path, name) : name
|
116
|
+
|
117
|
+
# TODO: Solve logger mess completely.
|
118
|
+
@logger = opts[:log] if opts[:log]
|
119
|
+
|
120
|
+
case repository
|
121
|
+
when Array
|
122
|
+
config[:hosts] += repository
|
123
|
+
when String
|
124
|
+
config[:hosts] << repository
|
125
|
+
end
|
126
|
+
|
127
|
+
begin
|
128
|
+
init
|
129
|
+
|
130
|
+
# TODO: Eval move to update?
|
131
|
+
arr_opts = []
|
132
|
+
arr_opts << "-I" if opts[:force]
|
133
|
+
begin
|
134
|
+
update('', arr_opts)
|
135
|
+
rescue RsyncError
|
136
|
+
@logger.error "Unable to sucessfully update, aborting..."
|
137
|
+
@logger.debug "#{$!}"
|
138
|
+
FileUtils.rm_rf @rsync_work_dir if File.exists?(@rsync_work_dir)
|
139
|
+
end
|
140
|
+
rescue RsyncError
|
141
|
+
@logger.error "Unable to initialize"
|
142
|
+
@logger.debug "#{$!}"
|
143
|
+
end
|
144
|
+
|
145
|
+
opts[:bare] ? {:repository => @rsync_work_dir} : {:working_directory => @rsync_work_dir}
|
146
|
+
end
|
147
|
+
|
148
|
+
def update(cmd, x_opts = [], opts = {})
|
149
|
+
@logger.debug "Checking for updates..."
|
150
|
+
@config = load_config
|
151
|
+
unless @config
|
152
|
+
@logger.error "Not an Rsync repository!"
|
153
|
+
raise RsyncError
|
154
|
+
end
|
155
|
+
|
156
|
+
unless config[:hosts].size > 0
|
157
|
+
@logger.error "No hosts configured!"
|
158
|
+
raise RsyncError
|
159
|
+
end
|
160
|
+
|
161
|
+
load_repos(:local)
|
162
|
+
load_repos(:remote)
|
163
|
+
|
164
|
+
hosts = config[:hosts].clone
|
165
|
+
host = hosts.sample
|
166
|
+
|
167
|
+
if opts[:force]
|
168
|
+
done = false
|
169
|
+
b = false
|
170
|
+
verbose = @verbose
|
171
|
+
@verbose = false
|
172
|
+
while hosts.size > 0 && !done do
|
173
|
+
# FIXME: Nasty
|
174
|
+
host = hosts.sample if b
|
175
|
+
b = true
|
176
|
+
hosts -= [host]
|
177
|
+
@logger.info "Trying #{host}"
|
178
|
+
|
179
|
+
begin
|
180
|
+
arr_opts = []
|
181
|
+
arr_opts << PARAMS
|
182
|
+
arr_opts += x_opts
|
183
|
+
if host[/\A(\w)*\@/]
|
184
|
+
arr_opts << RSH #"-e ssh"
|
185
|
+
end
|
186
|
+
arr_opts << esc(File.join(host, '.pack/.'))
|
187
|
+
arr_opts << esc(pack_path)
|
188
|
+
command(cmd, arr_opts)
|
189
|
+
calc
|
190
|
+
save_repos
|
191
|
+
done = true
|
192
|
+
rescue
|
193
|
+
@logger.debug "#{$!}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
@verbose = verbose
|
197
|
+
raise RsyncError if !done
|
198
|
+
else
|
199
|
+
#reset(:hard => true)
|
200
|
+
calc
|
201
|
+
save_repos
|
202
|
+
|
203
|
+
# fetch latest sums and only update when changed
|
204
|
+
compare_sums(true, host)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# TODO: Allow local-self healing, AND remote healing. reset and fetch?
|
209
|
+
def reset(opts = {})
|
210
|
+
@logger.info "Resetting!"
|
211
|
+
if opts[:hard]
|
212
|
+
@config = load_config
|
213
|
+
calc
|
214
|
+
save_repos
|
215
|
+
compare_sums(false)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# TODO: WIP
|
220
|
+
def add(file)
|
221
|
+
@logger.error "Please use commit instead!"
|
222
|
+
return
|
223
|
+
@logger.info "Adding #{file}"
|
224
|
+
if (file == ".")
|
225
|
+
load_repos(:remote)
|
226
|
+
@logger.info "Calculating Checksums..."
|
227
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
228
|
+
|
229
|
+
change = false
|
230
|
+
i = 0
|
231
|
+
ar.each do |file|
|
232
|
+
i += 1
|
233
|
+
unless file[/\.gz\Z/]
|
234
|
+
relative = file.clone
|
235
|
+
relative.gsub!(@rsync_work_dir, '')
|
236
|
+
relative.gsub!(/\A[\\|\/]/, '')
|
237
|
+
|
238
|
+
checksum = md5(file)
|
239
|
+
if checksum != @repos_remote[:wd][relative]
|
240
|
+
change = true
|
241
|
+
@logger.info "Packing #{i}/#{ar.size}: #{file}"
|
242
|
+
gzip(file)
|
243
|
+
@repos_remote[:wd][relative] = checksum
|
244
|
+
@repos_remote[:pack]["#{relative}.gz"] = md5("#{file}.gz")
|
245
|
+
FileUtils.mv("#{file}.gz", pack_path("#{relative}.gz"))
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
save_repos if change
|
250
|
+
else
|
251
|
+
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def commit
|
256
|
+
@logger.info "Committing changes on #{@rsync_work_dir}"
|
257
|
+
@config = load_config
|
258
|
+
unless @config
|
259
|
+
@logger.error "Not an Rsync repository!"
|
260
|
+
return
|
261
|
+
end
|
262
|
+
|
263
|
+
unless config[:hosts].size > 0
|
264
|
+
@logger.error "No hosts configured!"
|
265
|
+
return
|
266
|
+
end
|
267
|
+
|
268
|
+
load_repos(:local)
|
269
|
+
load_repos(:remote)
|
270
|
+
|
271
|
+
@logger.info "Calculating Checksums..."
|
272
|
+
@repos_local[:wd] = calc_sums(:wd)
|
273
|
+
# Added or Changed files
|
274
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
275
|
+
|
276
|
+
change = false
|
277
|
+
i = 0
|
278
|
+
@repos_local[:wd].each_pair do |key, value|
|
279
|
+
i += 1
|
280
|
+
if value != @repos_remote[:wd][key]
|
281
|
+
change = true
|
282
|
+
@logger.info "Packing #{i}/#{@repos_local[:wd].size}: #{key}"
|
283
|
+
file = File.join(@rsync_work_dir, key)
|
284
|
+
file[REGEX_FOLDER]
|
285
|
+
folder = $1
|
286
|
+
folder.gsub!(@rsync_work_dir, '')
|
287
|
+
gzip(file)
|
288
|
+
@repos_local[:pack]["#{key}.gz"] = md5("#{file}.gz")
|
289
|
+
FileUtils.mkdir_p pack_path(folder) if folder
|
290
|
+
FileUtils.mv("#{file}.gz", pack_path("#{key}.gz"))
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Deleted files
|
295
|
+
@logger.info "Checking for deleted files..."
|
296
|
+
|
297
|
+
i = 0
|
298
|
+
@repos_remote[:wd].each_pair do |key, value|
|
299
|
+
i += 1
|
300
|
+
if @repos_local[:wd][key].nil?
|
301
|
+
packed = "#{key}.gz"
|
302
|
+
change = true
|
303
|
+
file = pack_path(packed)
|
304
|
+
file[REGEX_FOLDER]
|
305
|
+
folder = $2
|
306
|
+
|
307
|
+
@logger.info "Removing: #{packed}"
|
308
|
+
@repos_local[:wd].delete key
|
309
|
+
@repos_local[:pack].delete packed
|
310
|
+
FileUtils.rm_f(file) if File.exists?(file)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
if change
|
315
|
+
@logger.info "Changes found!"
|
316
|
+
save_repos(:local)
|
317
|
+
|
318
|
+
host = config[:hosts].sample
|
319
|
+
|
320
|
+
verfile_srv = File.join(".pack", ".repository.yml")
|
321
|
+
verbose = @verbose
|
322
|
+
@verbose = false
|
323
|
+
begin
|
324
|
+
fetch_file(verfile_srv, host)
|
325
|
+
rescue
|
326
|
+
# FIXME: Should never assume that :)
|
327
|
+
@logger.warn "Unable to retrieve version file from server, repository probably doesnt exist!"
|
328
|
+
@logger.debug "#{$!}"
|
329
|
+
# raise RsyncExecuteError
|
330
|
+
end
|
331
|
+
@verbose = verbose
|
332
|
+
|
333
|
+
load_repos(:remote)
|
334
|
+
|
335
|
+
if @repos_local[:version] < @repos_remote[:version] # && !force
|
336
|
+
@logger.warn "WARNING, version on server is NEWER, aborting!"
|
337
|
+
raise RsyncError
|
338
|
+
end
|
339
|
+
@repos_local[:version] += 1
|
340
|
+
@repos_remote[:version] = @repos_local[:version]
|
341
|
+
@repos_remote[:pack] = @repos_local[:pack].clone
|
342
|
+
@repos_remote[:wd] = @repos_local[:wd].clone
|
343
|
+
save_repos(:remote)
|
344
|
+
save_repos(:local)
|
345
|
+
push(host)
|
346
|
+
else
|
347
|
+
@logger.info "No changes found!"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def push(host = nil)
|
352
|
+
@logger.info "Pushing..."
|
353
|
+
@config = load_config
|
354
|
+
host = config[:hosts].sample unless host
|
355
|
+
# TODO: UNCLUSTERFUCK
|
356
|
+
arr_opts = []
|
357
|
+
arr_opts << PARAMS
|
358
|
+
|
359
|
+
# Upload .pack changes
|
360
|
+
if host[/\A(\w)*\@/]
|
361
|
+
arr_opts << RSH
|
362
|
+
end
|
363
|
+
arr_opts << esc(pack_path('.'))
|
364
|
+
arr_opts << esc(File.join(host, '.pack'))
|
365
|
+
|
366
|
+
command('', arr_opts)
|
367
|
+
end
|
368
|
+
|
369
|
+
def compare_set(typ, host, online = true)
|
370
|
+
load_repos(:local)
|
371
|
+
load_repos(:remote)
|
372
|
+
|
373
|
+
#if local[typ][:md5] == remote[typ][:md5]
|
374
|
+
# @logger.info "#{typ} Match!"
|
375
|
+
#else
|
376
|
+
# @logger.info "#{typ} NOT match, updating!"
|
377
|
+
|
378
|
+
mismatch = []
|
379
|
+
@repos_remote[typ].each_pair do |key, value|
|
380
|
+
if value == @repos_local[typ][key]
|
381
|
+
#@logger.info "Match! #{key}"
|
382
|
+
else
|
383
|
+
@logger.debug "Mismatch! #{key}"
|
384
|
+
mismatch << key
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
if mismatch.size > 0
|
389
|
+
case typ
|
390
|
+
when :pack
|
391
|
+
# direct unpack of gz into working folder
|
392
|
+
# Update file
|
393
|
+
if online
|
394
|
+
hosts = config[:hosts].clone
|
395
|
+
done = false
|
396
|
+
|
397
|
+
## Pack
|
398
|
+
if online
|
399
|
+
b = false
|
400
|
+
while hosts.size > 0 && !done do
|
401
|
+
# FIXME: Nasty
|
402
|
+
if b
|
403
|
+
host = hosts.sample
|
404
|
+
@logger.info "Trying #{host}"
|
405
|
+
end
|
406
|
+
slist = nil
|
407
|
+
b = true
|
408
|
+
hosts -= [host]
|
409
|
+
begin
|
410
|
+
# TODO: Progress bar
|
411
|
+
if mismatch.size > (@repos_remote[typ].size / 2)
|
412
|
+
@logger.info "Many files mismatched (#{mismatch.size}), running full update on .pack folder"
|
413
|
+
arr_opts = []
|
414
|
+
arr_opts << PARAMS
|
415
|
+
if host[/\A(\w)*\@/]
|
416
|
+
arr_opts << RSH
|
417
|
+
end
|
418
|
+
|
419
|
+
arr_opts << esc(File.join(host, '.pack/.'))
|
420
|
+
arr_opts << esc(pack_path)
|
421
|
+
command('', arr_opts)
|
422
|
+
else
|
423
|
+
c = mismatch.size
|
424
|
+
@logger.info "Fetching #{mismatch.size} files... Please wait"
|
425
|
+
slist = File.join(TEMP_PATH, ".six-updater_#{rand 9999}-list")
|
426
|
+
slist.gsub!("\\", "/")
|
427
|
+
File.open(slist, 'w') do |f|
|
428
|
+
mismatch.each { |e| f.puts e }
|
429
|
+
end
|
430
|
+
arr_opts = []
|
431
|
+
arr_opts << PARAMS
|
432
|
+
arr_opts << RSH if host[/\A(\w)*\@/]
|
433
|
+
|
434
|
+
cyg_slist = "\"#{slist}\""
|
435
|
+
|
436
|
+
while cyg_slist[WINDRIVE] do
|
437
|
+
drive = cyg_slist[WINDRIVE]
|
438
|
+
cyg_slist.gsub!(drive, "\"/cygdrive/#{$1}")
|
439
|
+
end
|
440
|
+
arr_opts << "--files-from=#{cyg_slist}"
|
441
|
+
|
442
|
+
arr_opts << esc(File.join(host, '.pack/.'))
|
443
|
+
arr_opts << esc(pack_path)
|
444
|
+
|
445
|
+
command('', arr_opts)
|
446
|
+
end
|
447
|
+
done = true
|
448
|
+
rescue
|
449
|
+
@logger.warn "Failure"
|
450
|
+
@logger.debug "#{$!}"
|
451
|
+
ensure
|
452
|
+
FileUtils.rm_f slist if slist
|
453
|
+
end
|
454
|
+
end
|
455
|
+
@logger.warn "There was a problem during updating, please retry!" unless done
|
456
|
+
end
|
457
|
+
end
|
458
|
+
when :wd
|
459
|
+
mismatch.each_with_index do |e, index|
|
460
|
+
# TODO: Nicer progress bar...
|
461
|
+
@logger.info "Unpacking #{index + 1}/#{mismatch.size}: #{e}"
|
462
|
+
unpack(:path => "#{e}.gz")
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
@repos_local[typ].each_pair do |key, value|
|
468
|
+
del_file(key, typ) unless config[:exclude].include?(key) || !@repos_remote[typ][key].nil?
|
469
|
+
end
|
470
|
+
|
471
|
+
@repos_local[typ] = calc_sums(typ)
|
472
|
+
@repos_local[:version] = @repos_remote[:version]
|
473
|
+
save_repos
|
474
|
+
end
|
475
|
+
|
476
|
+
def compare_sums(online = true, host = config[:hosts].sample)
|
477
|
+
hosts = config[:hosts].clone
|
478
|
+
done = false
|
479
|
+
|
480
|
+
## Pack
|
481
|
+
if online
|
482
|
+
b = false
|
483
|
+
verbose = @verbose
|
484
|
+
@verbose = false
|
485
|
+
while hosts.size > 0 && !done do
|
486
|
+
# FIXME: Nasty
|
487
|
+
host = hosts.sample if b
|
488
|
+
b = true
|
489
|
+
hosts -= [host]
|
490
|
+
@logger.info "Trying #{host}"
|
491
|
+
|
492
|
+
begin
|
493
|
+
FileUtils.cp(pack_path(".repository.yml"), rsync_path(".repository-pack.yml"))
|
494
|
+
fetch_file(".pack/.repository.yml", host)
|
495
|
+
|
496
|
+
load_repos(:remote)
|
497
|
+
load_repos(:local)
|
498
|
+
|
499
|
+
if @repos_local[:version] > @repos_remote[:version] # && !force
|
500
|
+
@logger.warn "WARNING, version on server is OLDER, aborting!"
|
501
|
+
FileUtils.cp(rsync_path(".repository-pack.yml"), pack_path(".repository.yml"))
|
502
|
+
raise RsyncError
|
503
|
+
end
|
504
|
+
done = true
|
505
|
+
rescue
|
506
|
+
@logger.debug "#{$!}"
|
507
|
+
ensure
|
508
|
+
FileUtils.rm(rsync_path(".repository-pack.yml"))
|
509
|
+
end
|
510
|
+
end
|
511
|
+
@verbose = verbose
|
512
|
+
end
|
513
|
+
if done && online
|
514
|
+
# TODO: Don't do actions when not online
|
515
|
+
@logger.info "Verifying Packed files..."
|
516
|
+
compare_set(:pack, host)
|
517
|
+
@logger.info "Verifying Unpacked files..."
|
518
|
+
compare_set(:wd, host)
|
519
|
+
save_repos
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
private
|
524
|
+
def esc(val); "\"#{val}\""; end
|
525
|
+
def escape(s); "\"" + s.to_s.gsub('\"', '\"\\\"\"') + "\""; end
|
526
|
+
|
527
|
+
def config
|
528
|
+
cfg = @config ||= YAML::load(DEFAULT_CONFIG)
|
529
|
+
cfg[:exclude] = [] unless cfg[:exclude]
|
530
|
+
cfg[:hosts] = [] unless cfg[:hosts]
|
531
|
+
cfg
|
532
|
+
end
|
533
|
+
|
534
|
+
def rsync_path(path = '')
|
535
|
+
p = File.join(@rsync_work_dir, DIR_RSYNC)
|
536
|
+
p = File.join(p, path) unless path.size == 0
|
537
|
+
p
|
538
|
+
end
|
539
|
+
|
540
|
+
def pack_path(path = '')
|
541
|
+
p = File.join(@rsync_work_dir, DIR_PACK)
|
542
|
+
p = File.join(p, path) unless path.size == 0
|
543
|
+
p
|
544
|
+
end
|
545
|
+
|
546
|
+
def fetch_file(path, host)
|
547
|
+
path[/(.*)\/(.*)/]
|
548
|
+
folder, file = $1, $2
|
549
|
+
folder = "." unless folder
|
550
|
+
file = path unless file
|
551
|
+
# Only fetch a specific file
|
552
|
+
@logger.debug "Fetching #{path} from #{host}"
|
553
|
+
arr_opts = []
|
554
|
+
arr_opts << PARAMS
|
555
|
+
if host[/\A(\w)*\@/]
|
556
|
+
arr_opts << RSH
|
557
|
+
end
|
558
|
+
arr_opts << esc(File.join(host, path))
|
559
|
+
arr_opts << esc(rsync_path(folder))
|
560
|
+
|
561
|
+
command('', arr_opts)
|
562
|
+
end
|
563
|
+
|
564
|
+
def calc
|
565
|
+
@logger.info "Calculating checksums"
|
566
|
+
[:pack, :wd].each { |t| @repos_local[t] = calc_sums(t) }
|
567
|
+
end
|
568
|
+
|
569
|
+
def calc_sums(typ)
|
570
|
+
@logger.debug "Calculating checksums of #{typ} files"
|
571
|
+
ar = []
|
572
|
+
reg = case typ
|
573
|
+
when :pack
|
574
|
+
ar = Dir[pack_path('**/*')]
|
575
|
+
/\A[\\|\/]\.rsync[\\|\/]\.pack[\\|\/]/
|
576
|
+
when :wd
|
577
|
+
ar = Dir[File.join(@rsync_work_dir, '/**/*')]
|
578
|
+
/\A[\\|\/]/
|
579
|
+
end
|
580
|
+
h = Hash.new
|
581
|
+
ar.each do |file|
|
582
|
+
relative = file.clone
|
583
|
+
relative.gsub!(@rsync_work_dir, '')
|
584
|
+
relative.gsub!(reg, '')
|
585
|
+
|
586
|
+
sum = md5(file)
|
587
|
+
h[relative] = sum if sum && !config[:exclude].include?(relative)
|
588
|
+
end
|
589
|
+
h
|
590
|
+
end
|
591
|
+
|
592
|
+
def load_config; load_yaml(File.join(rsync_path, 'config.yml')); end
|
593
|
+
|
594
|
+
def load_yaml(file)
|
595
|
+
if File.exists?(file)
|
596
|
+
YAML::load_file(file)
|
597
|
+
else
|
598
|
+
nil
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def save_default_config
|
603
|
+
FileUtils.mkdir_p rsync_path
|
604
|
+
save_config(config)
|
605
|
+
end
|
606
|
+
|
607
|
+
def save_config(config = YAML::load(DEFAULT_CONFIG))
|
608
|
+
File.open(File.join(rsync_path, 'config.yml'), 'w') { |file| file.puts config.to_yaml }
|
609
|
+
end
|
610
|
+
|
611
|
+
def save_repos(typ = :local)
|
612
|
+
file, config = nil, nil
|
613
|
+
case typ
|
614
|
+
when :local
|
615
|
+
file = rsync_path('.repository.yml')
|
616
|
+
config = @repos_local.clone
|
617
|
+
when :remote
|
618
|
+
file = pack_path('.repository.yml')
|
619
|
+
config = @repos_remote.clone
|
620
|
+
end
|
621
|
+
config[:pack] = config[:pack].sort
|
622
|
+
config[:wd] = config[:wd].sort
|
623
|
+
File.open(file, 'w') { |file| file.puts config.to_yaml }
|
624
|
+
end
|
625
|
+
|
626
|
+
def load_repos(typ)
|
627
|
+
config = Hash.new
|
628
|
+
case typ
|
629
|
+
when :local
|
630
|
+
File.open(rsync_path('.repository.yml')) { |file| config = YAML::load(file) }
|
631
|
+
when :remote
|
632
|
+
File.open(pack_path('.repository.yml')) { |file| config = YAML::load(file) }
|
633
|
+
end
|
634
|
+
|
635
|
+
[:wd, :pack].each do |t|
|
636
|
+
h = Hash.new
|
637
|
+
config[t].each { |e| h[e[0]] = e[1] }
|
638
|
+
config[t] = h
|
639
|
+
end
|
640
|
+
|
641
|
+
case typ
|
642
|
+
when :local
|
643
|
+
@repos_local = config
|
644
|
+
when :remote
|
645
|
+
@repos_remote = config
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
def del_file(file, typ, opts = {})
|
650
|
+
file = case typ
|
651
|
+
when :pack
|
652
|
+
File.join(DIR_PACK, file)
|
653
|
+
when :wd
|
654
|
+
file
|
655
|
+
end
|
656
|
+
if File.exists?(file)
|
657
|
+
FileUtils.rm_f File.join(@rsync_work_dir, file)
|
658
|
+
@logger.info "Removed: #{file}"
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
def md5(path)
|
663
|
+
unless File.directory? path
|
664
|
+
path[/(.*)[\/|\\](.*)/]
|
665
|
+
folder, file = $1, $2
|
666
|
+
Dir.chdir(folder) do
|
667
|
+
r = %x[md5sum #{esc(file)}]
|
668
|
+
@logger.debug r
|
669
|
+
r[/\A\w*/]
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
def zip7(file)
|
675
|
+
out = %x[7z x #{esc(file)} -y]
|
676
|
+
@logger.debug out
|
677
|
+
out
|
678
|
+
end
|
679
|
+
|
680
|
+
def gzip(file)
|
681
|
+
@logger.debug "Gzipping #{file}"
|
682
|
+
out = %x[gzip -f --best --rsyncable --keep #{esc(file)}]
|
683
|
+
@logger.debug out
|
684
|
+
end
|
685
|
+
|
686
|
+
def unpack_file(file, path)
|
687
|
+
Dir.chdir(path) do |dir|
|
688
|
+
zip7(file)
|
689
|
+
# TODO: Evaluate if this is actually wanted / useful at all..
|
690
|
+
=begin
|
691
|
+
if file[/\.tar\.?/]
|
692
|
+
file[/(.*)\/(.*)/]
|
693
|
+
fil = $2
|
694
|
+
fil = file unless fil
|
695
|
+
f2 = fil.gsub('.gz', '')
|
696
|
+
zip7(f2)
|
697
|
+
FileUtils.rm_f f2
|
698
|
+
end
|
699
|
+
=end
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
def unpack(opts = {})
|
704
|
+
items = if opts[:path]
|
705
|
+
[pack_path(opts[:path])]
|
706
|
+
else
|
707
|
+
Dir[pack_path('**/*')]
|
708
|
+
end
|
709
|
+
|
710
|
+
items.each do |file|
|
711
|
+
unless File.directory? file
|
712
|
+
relative = file.clone
|
713
|
+
relative.gsub!(@rsync_work_dir, '')
|
714
|
+
relative.gsub!(/\A[\\|\/]\.rsync[\\|\/]\.pack[\\|\/]/, '')
|
715
|
+
fil = relative
|
716
|
+
folder = "."
|
717
|
+
folder, fil = $1, $2 if relative[/(.*)\/(.*)/]
|
718
|
+
#puts "Relative: #{relative}, Folder: #{folder}, File: #{fil} (Origin: #{file})"
|
719
|
+
|
720
|
+
path = File.join(@rsync_work_dir, folder)
|
721
|
+
FileUtils.mkdir_p path
|
722
|
+
unpack_file(file, path)
|
723
|
+
end
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
def command_lines(cmd, opts = [], chdir = true, redirect = '')
|
728
|
+
command(cmd, opts, chdir).split("\n")
|
729
|
+
end
|
730
|
+
|
731
|
+
def command(cmd, opts = [], chdir = true, redirect = '', &block)
|
732
|
+
path = @rsync_work_dir || @rsync_dir || @path
|
733
|
+
|
734
|
+
opts << "--stats" if @stats
|
735
|
+
opts << "--timeout=#{DEFAULT_TIMEOUT}"
|
736
|
+
|
737
|
+
opts = [opts].flatten.map {|s| s }.join(' ') # escape()
|
738
|
+
rsync_cmd = "rsync #{cmd} #{opts} #{redirect} 2>&1"
|
739
|
+
|
740
|
+
while rsync_cmd[WINDRIVE] do
|
741
|
+
drive = rsync_cmd[WINDRIVE]
|
742
|
+
rsync_cmd.gsub!(drive, "\"/cygdrive/#{$1}")
|
743
|
+
end
|
744
|
+
|
745
|
+
if @logger
|
746
|
+
@logger.debug(rsync_cmd)
|
747
|
+
end
|
748
|
+
|
749
|
+
out = nil
|
750
|
+
if chdir && (Dir.getwd != path)
|
751
|
+
Dir.chdir(path) { out = run_command(rsync_cmd, &block) }
|
752
|
+
else
|
753
|
+
out = run_command(rsync_cmd, &block)
|
754
|
+
end
|
755
|
+
|
756
|
+
out
|
757
|
+
end
|
758
|
+
|
759
|
+
def run_command(rsync_cmd, &block)
|
760
|
+
# TODO: Make this switchable? Verbosity ?
|
761
|
+
# Or actually parse this live for own stats?
|
762
|
+
s = nil
|
763
|
+
out = ''
|
764
|
+
|
765
|
+
# Simpler method but on windows the !? exitstatus is not working properly..
|
766
|
+
# Does nicely display error output in logwindow though
|
767
|
+
io = IO.popen(rsync_cmd)
|
768
|
+
io.sync = true
|
769
|
+
io.each do |buffer|
|
770
|
+
process_msg buffer
|
771
|
+
out << buffer
|
772
|
+
end
|
773
|
+
|
774
|
+
out[/rsync error: .* \(code ([0-9]*)\)/]
|
775
|
+
status = $1 ? $1 : 0
|
776
|
+
|
777
|
+
if status > 0
|
778
|
+
return '' if status == 1 && out == ''
|
779
|
+
case out
|
780
|
+
when /max connections \((.*)\) reached/
|
781
|
+
@logger.warn "Server reached maximum connections."
|
782
|
+
end
|
783
|
+
raise Rsync::RsyncExecuteError.new(rsync_cmd + ':' + out)
|
784
|
+
end
|
785
|
+
|
786
|
+
status
|
787
|
+
end
|
788
|
+
|
789
|
+
def process_msg(msg)
|
790
|
+
if msg[/[k|m|g]?B\/s/i]
|
791
|
+
msg.gsub!("\n", '')
|
792
|
+
print "#{msg}\r" if @verbose
|
793
|
+
else
|
794
|
+
@logger.debug msg
|
795
|
+
print msg if @verbose
|
796
|
+
end
|
797
|
+
msg
|
798
|
+
end
|
799
|
+
|
800
|
+
end
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|