qdumpfs 1.9.1 → 1.10.0
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.
- checksums.yaml +4 -4
- data/.idea/qdumpfs.iml +51 -19
- data/Gemfile.lock +2 -2
- data/lib/qdumpfs/option.rb +1 -5
- data/lib/qdumpfs/version.rb +1 -1
- data/lib/qdumpfs.rb +104 -66
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4ace57748311474078255f93323c921f04c1d63ce40f04bb12ec15d0e48a38e8
|
|
4
|
+
data.tar.gz: 7c214b8b293a6f5feee3573d3d87d09be7fb18f43d1db6376b2c521081025bd5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10107064217f62fb81170d3d6a01d8de7e18ec2953aed30c3d6fe0d68d0f0a8b157745b7277b9b92e8a61aa6bf49d7c8f9b42144cc3724f6279d7719caf316ee
|
|
7
|
+
data.tar.gz: d82bc50988880296280b4cf7c6fd47669288ffefa72049829ea9e3219ea2ab2769e33b6dda41f8f847c620f5d1b6e053f9aeb47bb2bbe07b105d21f12945d3a0
|
data/.idea/qdumpfs.iml
CHANGED
|
@@ -10,50 +10,82 @@
|
|
|
10
10
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
11
11
|
<excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
|
|
12
12
|
</content>
|
|
13
|
-
<orderEntry type="
|
|
13
|
+
<orderEntry type="jdk" jdkName="rbenv: 3.1.6" jdkType="RUBY_SDK" />
|
|
14
14
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
15
15
|
<orderEntry type="module-library">
|
|
16
|
-
<library name="minitest (v5.
|
|
16
|
+
<library name="minitest (v5.25.1) [path][gem]" type="rubylib">
|
|
17
17
|
<properties>
|
|
18
|
-
<option name="
|
|
18
|
+
<option name="additionalInfo">
|
|
19
|
+
<AdditionalInfo>
|
|
20
|
+
<option name="authors" value="該当なし" />
|
|
21
|
+
<option name="email" value="該当なし" />
|
|
22
|
+
<option name="homepage" value="該当なし" />
|
|
23
|
+
<option name="summary" value="該当なし" />
|
|
24
|
+
</AdditionalInfo>
|
|
25
|
+
</option>
|
|
26
|
+
<option name="fromPath" value="true" />
|
|
27
|
+
<option name="name" value="minitest" />
|
|
28
|
+
<option name="requirePaths">
|
|
29
|
+
<list>
|
|
30
|
+
<option value="lib" />
|
|
31
|
+
</list>
|
|
32
|
+
</option>
|
|
33
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1" />
|
|
34
|
+
<option name="version" value="5.25.1" />
|
|
19
35
|
</properties>
|
|
20
36
|
<CLASSES>
|
|
21
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
|
22
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
|
37
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/lib" />
|
|
38
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
|
23
39
|
</CLASSES>
|
|
24
40
|
<JAVADOC />
|
|
25
41
|
<SOURCES>
|
|
26
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
|
27
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
|
42
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/lib" />
|
|
43
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
|
28
44
|
</SOURCES>
|
|
29
45
|
<excluded>
|
|
30
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.
|
|
46
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/minitest-5.25.1/test" />
|
|
31
47
|
</excluded>
|
|
32
48
|
</library>
|
|
33
49
|
</orderEntry>
|
|
34
50
|
<orderEntry type="module-library">
|
|
35
|
-
<library name="rake (v13.2.
|
|
51
|
+
<library name="rake (v13.2.1) [path][gem]" type="rubylib">
|
|
36
52
|
<properties>
|
|
37
|
-
<option name="
|
|
53
|
+
<option name="additionalInfo">
|
|
54
|
+
<AdditionalInfo>
|
|
55
|
+
<option name="authors" value="該当なし" />
|
|
56
|
+
<option name="email" value="該当なし" />
|
|
57
|
+
<option name="homepage" value="該当なし" />
|
|
58
|
+
<option name="summary" value="該当なし" />
|
|
59
|
+
</AdditionalInfo>
|
|
60
|
+
</option>
|
|
61
|
+
<option name="fromPath" value="true" />
|
|
62
|
+
<option name="name" value="rake" />
|
|
63
|
+
<option name="requirePaths">
|
|
64
|
+
<list>
|
|
65
|
+
<option value="lib" />
|
|
66
|
+
</list>
|
|
67
|
+
</option>
|
|
68
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1" />
|
|
69
|
+
<option name="version" value="13.2.1" />
|
|
38
70
|
</properties>
|
|
39
71
|
<CLASSES>
|
|
40
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
41
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
42
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
72
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
|
73
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
|
74
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib" />
|
|
43
75
|
</CLASSES>
|
|
44
76
|
<JAVADOC />
|
|
45
77
|
<SOURCES>
|
|
46
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
47
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
48
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
78
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
|
79
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
|
80
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib" />
|
|
49
81
|
</SOURCES>
|
|
50
82
|
<excluded>
|
|
51
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
52
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.
|
|
83
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/doc" />
|
|
84
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe" />
|
|
53
85
|
</excluded>
|
|
54
86
|
</library>
|
|
55
87
|
</orderEntry>
|
|
56
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.
|
|
88
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.3.27, rbenv: 3.1.6) [gem]" level="application" />
|
|
57
89
|
</component>
|
|
58
90
|
<component name="RakeTasksCache-v2">
|
|
59
91
|
<option name="myRootTask">
|
data/Gemfile.lock
CHANGED
data/lib/qdumpfs/option.rb
CHANGED
data/lib/qdumpfs/version.rb
CHANGED
data/lib/qdumpfs.rb
CHANGED
|
@@ -198,6 +198,8 @@ module Qdumpfs
|
|
|
198
198
|
# ファイルのアップデート
|
|
199
199
|
update_file(s, l, t)
|
|
200
200
|
dirs[t] = File.stat(s) if File.ftype(s) == "directory"
|
|
201
|
+
rescue Errno::ENOSPC
|
|
202
|
+
raise
|
|
201
203
|
rescue => e
|
|
202
204
|
report_error(s, e)
|
|
203
205
|
@error_files << [s, e.message]
|
|
@@ -235,6 +237,8 @@ module Qdumpfs
|
|
|
235
237
|
end
|
|
236
238
|
chown_if_root(type, s, t)
|
|
237
239
|
dirs[t] = File.stat(s) if File.ftype(s) == "directory"
|
|
240
|
+
rescue Errno::ENOSPC
|
|
241
|
+
raise
|
|
238
242
|
rescue => e
|
|
239
243
|
report_error(s, e)
|
|
240
244
|
@error_files << [s, e.message]
|
|
@@ -309,7 +313,29 @@ module Qdumpfs
|
|
|
309
313
|
}
|
|
310
314
|
return nil
|
|
311
315
|
end
|
|
312
|
-
|
|
316
|
+
|
|
317
|
+
def incomplete_backup(today)
|
|
318
|
+
# puts "incomplete_backup #{today}"
|
|
319
|
+
# バックアップが途中で終了した場合、そのディレクトリをリネームする
|
|
320
|
+
dirname = File.dirname(today)
|
|
321
|
+
prefix = "_"
|
|
322
|
+
incomplete = dirname.sub(/(\d+)$/, prefix + '\1')
|
|
323
|
+
return unless FileTest.directory?(dirname) # バックアップが途中で途中で終了。ただしまだ日付ディレクトリが存在しない場合はなにもしない。
|
|
324
|
+
|
|
325
|
+
# すでにincompleteが存在する場合はユニークな名前を探す
|
|
326
|
+
0.upto(10) do |i|
|
|
327
|
+
break unless FileTest.exist?(incomplete)
|
|
328
|
+
prefix += "_"
|
|
329
|
+
incomplete = dirname.sub(/(\d+)$/, prefix + '\1')
|
|
330
|
+
end
|
|
331
|
+
if FileTest.directory?(incomplete)
|
|
332
|
+
log("cannot rename incomplete backup: #{incomplete}")
|
|
333
|
+
else
|
|
334
|
+
FileUtils.mv(dirname, incomplete)
|
|
335
|
+
log("rename incomplete backup: #{dirname} -> #{incomplete}")
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
313
339
|
def backup
|
|
314
340
|
##### オリジナルのバックアップルーチン
|
|
315
341
|
@opt.validate_directories(2)
|
|
@@ -336,31 +362,37 @@ module Qdumpfs
|
|
|
336
362
|
base = File.basename(src)
|
|
337
363
|
dirname = File.dirname(src)
|
|
338
364
|
raise RuntimeError unless FileTest.exist?(dirname + '/' + base)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
365
|
+
|
|
366
|
+
begin
|
|
367
|
+
# 存在するバックアップの最新を取得
|
|
368
|
+
latest = latest_snapshot(start_time, src, dst, base)
|
|
369
|
+
# 現在の日付フォルダを取得j:/to/backup1/2019/05/10/home
|
|
370
|
+
today = File.join(dst, datedir(start_time), base)
|
|
371
|
+
File.umask(0077)
|
|
372
|
+
FileUtils.mkpath(today) unless @opt.dry_run
|
|
373
|
+
if windows?
|
|
374
|
+
src = src.sub( /^[A-Za-z]:$/, src + "/" )
|
|
375
|
+
end
|
|
376
|
+
if latest
|
|
377
|
+
# バックアップがすでに存在する場合差分コピー
|
|
378
|
+
log("## update_snapshot #{src} #{latest}=>#{today} ##")
|
|
379
|
+
update_snapshot(src, latest, today)
|
|
380
|
+
else
|
|
381
|
+
# 初回は単純に再帰コピー
|
|
382
|
+
log("## recursive_copy #{src}=>#{today} ##")
|
|
383
|
+
recursive_copy(src, today)
|
|
384
|
+
end
|
|
385
|
+
unless @opt.dry_run
|
|
386
|
+
create_latest_symlink(dst, today)
|
|
387
|
+
elapsed = Time.now - start_time
|
|
388
|
+
log_result(src, today, elapsed)
|
|
389
|
+
end
|
|
390
|
+
log("##### backup end #####")
|
|
391
|
+
rescue Errno::ENOSPC
|
|
392
|
+
# 直前のmkpathでエラーが発生した場合 Errno::ENOSPCが発生する。内部ではIncompleteErrorに変換している
|
|
393
|
+
incomplete_backup(today)
|
|
394
|
+
log("##### backup incomplete(No space left on device) #####")
|
|
362
395
|
end
|
|
363
|
-
log("##### backup end #####")
|
|
364
396
|
end
|
|
365
397
|
|
|
366
398
|
def sync
|
|
@@ -379,49 +411,55 @@ module Qdumpfs
|
|
|
379
411
|
log("##### sync start #{fmt(start_time)} => limit_time=#{fmt(limit_time)} #####")
|
|
380
412
|
count = 0
|
|
381
413
|
last_sync_complete = false
|
|
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
|
-
|
|
414
|
+
|
|
415
|
+
begin
|
|
416
|
+
while true
|
|
417
|
+
count += 1
|
|
418
|
+
log("## sync_latest count=#{count} ##")
|
|
419
|
+
latest_start = Time.now
|
|
420
|
+
sync_result, from, to = sync_latest(src, dst)
|
|
421
|
+
latest_end = Time.now
|
|
422
|
+
|
|
423
|
+
log("## sync_latest result=#{sync_result} from=#{from} to=#{to} ##")
|
|
424
|
+
unless sync_result
|
|
425
|
+
# 同期結果がtrueでない場合ここで終了。ただしsync_result=falseになるのはコピー元フォルダが存在しない場合なので、
|
|
426
|
+
# 中途半端な結果にはならない
|
|
427
|
+
last_sync_complete = true
|
|
428
|
+
break
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
from_count, to_count = do_verify(from, to)
|
|
432
|
+
log("## from_count=#{from_count} to_count=#{to_count} equals=#{from_count == to_count} ##")
|
|
433
|
+
unless from_count == to_count
|
|
434
|
+
# ファイル数が同じでない場合ここで終了
|
|
435
|
+
last_sync_complete = false
|
|
436
|
+
break
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# 次回同期にかかる時間を最終同期時間の半分と予想
|
|
440
|
+
next_sync = (latest_end - latest_start) / 2
|
|
441
|
+
|
|
442
|
+
cur_time = Time.now
|
|
443
|
+
in_limit = (cur_time + next_sync) < limit_time
|
|
444
|
+
log("## cur_time=#{fmt(cur_time)} + next_sync=#{next_sync} < limit_time=#{fmt(limit_time)} in_limit=#{in_limit} ## ")
|
|
445
|
+
unless in_limit
|
|
446
|
+
# 指定時間内ではない場合ここで終了(ただし最終同期は成功)
|
|
447
|
+
last_sync_complete = true
|
|
448
|
+
break
|
|
449
|
+
end
|
|
415
450
|
end
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
end_time = Time.now
|
|
419
|
-
diff = time_diff(start_time, end_time)
|
|
420
451
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
452
|
+
end_time = Time.now
|
|
453
|
+
diff = time_diff(start_time, end_time)
|
|
454
|
+
|
|
455
|
+
elapsed = Time.now - start_time
|
|
456
|
+
log_result(src, dst, elapsed)
|
|
457
|
+
|
|
458
|
+
log("##### sync end #{fmt(end_time)} diff=#{diff} last_sync_complete=#{last_sync_complete} #####")
|
|
459
|
+
rescue Errno::ENOSPC
|
|
460
|
+
incomplete_backup(today)
|
|
461
|
+
log("##### backup incomplete(No space left on device) #####")
|
|
462
|
+
end
|
|
425
463
|
end
|
|
426
464
|
|
|
427
465
|
def verify
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: qdumpfs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- src
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|