qdumpfs 1.10.0 → 1.12.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/.DS_Store +0 -0
- data/.gitignore +1 -2
- data/.idea/copilot.data.migration.agent.xml +6 -0
- data/.idea/qdumpfs.iml +19 -19
- data/CLAUDE.md +71 -0
- data/Gemfile.lock +5 -6
- data/README.html +54 -0
- data/README.md +122 -44
- data/README_ja.md +210 -0
- data/lib/.DS_Store +0 -0
- data/lib/qdumpfs/option.rb +21 -14
- data/lib/qdumpfs/util.rb +32 -11
- data/lib/qdumpfs/version.rb +1 -1
- data/lib/qdumpfs.rb +5 -3
- data/tag +32 -0
- data/test.sh +15 -0
- data/test_pdumpfs/.DS_Store +0 -0
- data/test_pdumpfs/data/.DS_Store +0 -0
- metadata +13 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60995f56e6f0f6bb889d010c905717c1ba0a1d635ac57694d59d4b67d05959e4
|
|
4
|
+
data.tar.gz: a099f94ae4b88194872e5932f3223916c9c3f50ccc1aec558b03d72d92030107
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c07cbd31079b3df414dcee306f6ff5e216c851c5df462242cee1a0e4711dce053f8073d70ee43e2d4a4ab43392061068b6d2c66148942c3084e82709ed732a0d
|
|
7
|
+
data.tar.gz: f3cdd3683ca7b8db8089fc645ce1b2b4163e6983e5b3a00cc1f0c246c9305eca429ce619f2f0561351abc57ef3da31869013062d6d90b3623f9c69bb3e43c9c3
|
data/.DS_Store
ADDED
|
Binary file
|
data/.gitignore
CHANGED
data/.idea/qdumpfs.iml
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
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="jdk" jdkName="rbenv: 3.
|
|
13
|
+
<orderEntry type="jdk" jdkName="rbenv: 3.2.6" jdkType="RUBY_SDK" />
|
|
14
14
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
15
15
|
<orderEntry type="module-library">
|
|
16
|
-
<library name="minitest (v5.25.
|
|
16
|
+
<library name="minitest (v5.25.4) [path][gem]" type="rubylib">
|
|
17
17
|
<properties>
|
|
18
18
|
<option name="additionalInfo">
|
|
19
19
|
<AdditionalInfo>
|
|
@@ -30,20 +30,20 @@
|
|
|
30
30
|
<option value="lib" />
|
|
31
31
|
</list>
|
|
32
32
|
</option>
|
|
33
|
-
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
34
|
-
<option name="version" value="5.25.
|
|
33
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4" />
|
|
34
|
+
<option name="version" value="5.25.4" />
|
|
35
35
|
</properties>
|
|
36
36
|
<CLASSES>
|
|
37
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
38
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
37
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4/lib" />
|
|
38
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4/test" />
|
|
39
39
|
</CLASSES>
|
|
40
40
|
<JAVADOC />
|
|
41
41
|
<SOURCES>
|
|
42
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
43
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
42
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4/lib" />
|
|
43
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4/test" />
|
|
44
44
|
</SOURCES>
|
|
45
45
|
<excluded>
|
|
46
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
46
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/minitest-5.25.4/test" />
|
|
47
47
|
</excluded>
|
|
48
48
|
</library>
|
|
49
49
|
</orderEntry>
|
|
@@ -65,27 +65,27 @@
|
|
|
65
65
|
<option value="lib" />
|
|
66
66
|
</list>
|
|
67
67
|
</option>
|
|
68
|
-
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
68
|
+
<option name="url" value="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1" />
|
|
69
69
|
<option name="version" value="13.2.1" />
|
|
70
70
|
</properties>
|
|
71
71
|
<CLASSES>
|
|
72
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
73
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
74
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
72
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/doc" />
|
|
73
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/exe" />
|
|
74
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/lib" />
|
|
75
75
|
</CLASSES>
|
|
76
76
|
<JAVADOC />
|
|
77
77
|
<SOURCES>
|
|
78
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
79
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
80
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
78
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/doc" />
|
|
79
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/exe" />
|
|
80
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/lib" />
|
|
81
81
|
</SOURCES>
|
|
82
82
|
<excluded>
|
|
83
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
84
|
-
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.
|
|
83
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/doc" />
|
|
84
|
+
<root url="file://$MODULE_DIR$/vendor/bundle/ruby/3.2.0/gems/rake-13.2.1/exe" />
|
|
85
85
|
</excluded>
|
|
86
86
|
</library>
|
|
87
87
|
</orderEntry>
|
|
88
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.
|
|
88
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.4.19, rbenv: 3.2.6) [gem]" level="application" />
|
|
89
89
|
</component>
|
|
90
90
|
<component name="RakeTasksCache-v2">
|
|
91
91
|
<option name="myRootTask">
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## プロジェクト概要
|
|
6
|
+
|
|
7
|
+
QdumpfsはpdumpfsのRuby Gem改良版で、差分バックアップツールです。指定されたディレクトリを日付ベース(YYYY/MM/DD形式)でバックアップし、変更されたファイルのみをコピーする効率的なバックアップシステムを提供します。
|
|
8
|
+
|
|
9
|
+
## 開発コマンド
|
|
10
|
+
|
|
11
|
+
### テスト実行
|
|
12
|
+
```bash
|
|
13
|
+
# 全テスト実行
|
|
14
|
+
./test.sh
|
|
15
|
+
# または
|
|
16
|
+
bundle exec rake test
|
|
17
|
+
|
|
18
|
+
# 特定のテストファイル実行
|
|
19
|
+
./test.sh test/qdumpfs_test.rb
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Gem関連
|
|
23
|
+
```bash
|
|
24
|
+
# 依存関係インストール
|
|
25
|
+
bundle install
|
|
26
|
+
|
|
27
|
+
# Gemビルド
|
|
28
|
+
bundle exec rake build
|
|
29
|
+
|
|
30
|
+
# Gem公開(注意: メタデータで制限されている場合あり)
|
|
31
|
+
bundle exec rake release
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## コード構造
|
|
35
|
+
|
|
36
|
+
### メインコンポーネント
|
|
37
|
+
|
|
38
|
+
- **exe/qdumpfs**: エントリーポイント実行ファイル
|
|
39
|
+
- **lib/qdumpfs.rb**: メインモジュールとCommandクラス
|
|
40
|
+
- **lib/qdumpfs/option.rb**: オプション解析とBackupDirクラス
|
|
41
|
+
- **lib/qdumpfs/util.rb**: ユーティリティ関数群
|
|
42
|
+
- **lib/qdumpfs/win32.rb**: Windows固有の機能
|
|
43
|
+
- **lib/qdumpfs/version.rb**: バージョン情報
|
|
44
|
+
|
|
45
|
+
### 主要機能
|
|
46
|
+
|
|
47
|
+
1. **backup**: 差分バックアップ作成(デフォルト)
|
|
48
|
+
2. **sync**: バックアップフォルダ間の同期
|
|
49
|
+
3. **list**: バックアップ内容の一覧表示
|
|
50
|
+
4. **verify**: バックアップの検証
|
|
51
|
+
5. **expire**: 保持ポリシーに基づく古いバックアップの削除
|
|
52
|
+
6. **delete**: 指定パターンの削除
|
|
53
|
+
|
|
54
|
+
### バックアップの仕組み
|
|
55
|
+
|
|
56
|
+
- 日付ベースディレクトリ構造: `dest/YYYY/MM/DD/`
|
|
57
|
+
- 差分バックアップ: 変更されたファイルのみコピー、未変更ファイルはハードリンク
|
|
58
|
+
- `latest`シンボリックリンクで最新バックアップを指示
|
|
59
|
+
- Windows/Unix両対応
|
|
60
|
+
|
|
61
|
+
### 除外機能
|
|
62
|
+
|
|
63
|
+
- `--exclude=PATTERN`: 正規表現パターンで除外
|
|
64
|
+
- `--exclude-by-size=SIZE`: ファイルサイズで除外
|
|
65
|
+
- `--exclude-by-glob=GLOB`: Globパターンで除外
|
|
66
|
+
|
|
67
|
+
## 注意点
|
|
68
|
+
|
|
69
|
+
- Ruby 3.2系対応済み(taint/untaintメソッド削除対応済み)
|
|
70
|
+
- クロスプラットフォーム対応(Windows/Unix)
|
|
71
|
+
- ファイルシステムの容量不足時の不完全バックアップ処理対応
|
data/Gemfile.lock
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
qdumpfs (1.
|
|
4
|
+
qdumpfs (1.12.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
minitest (5.25.
|
|
9
|
+
minitest (5.25.4)
|
|
10
10
|
rake (13.2.1)
|
|
11
11
|
|
|
12
12
|
PLATFORMS
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
x86_64-darwin-23
|
|
13
|
+
arm64-darwin-24
|
|
14
|
+
arm64-darwin-25
|
|
16
15
|
x86_64-darwin-24
|
|
17
16
|
|
|
18
17
|
DEPENDENCIES
|
|
@@ -22,4 +21,4 @@ DEPENDENCIES
|
|
|
22
21
|
rake (>= 12.3.3)
|
|
23
22
|
|
|
24
23
|
BUNDLED WITH
|
|
25
|
-
2.
|
|
24
|
+
2.4.19
|
data/README.html
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<h1 id="qdumpfs">Qdumpfs</h1>
|
|
2
|
+
<p>pdumpfsの個人的改良版です。</p>
|
|
3
|
+
<p>Gem化して最近のバージョンのバージョンのRubyに対応。コマンドの拡張などを行っています。</p>
|
|
4
|
+
<h2 id="インストール">インストール</h2>
|
|
5
|
+
<p>gem install qdumpfs</p>
|
|
6
|
+
<h2 id="使用方法">使用方法</h2>
|
|
7
|
+
<pre><code>Usage: qdumpfs [options] <source> <dest>
|
|
8
|
+
-h, --help show this message
|
|
9
|
+
Options
|
|
10
|
+
-v, --verbose verbose message
|
|
11
|
+
-r, --report report message
|
|
12
|
+
-n, --dry-run don't actually run any commands
|
|
13
|
+
-e, --exclude=PATTERN exclude files/directories matching PATTERN
|
|
14
|
+
-s, --exclude-by-size=SIZE exclude files larger than SIZE
|
|
15
|
+
-w, --exclude-by-glob=GLOB exclude files matching GLOB
|
|
16
|
+
-c, --command=COMMAND backup|sync|list|expire|verify|delete
|
|
17
|
+
-l, --limit=HOURS limit hours
|
|
18
|
+
-k, --keep=KEEPARG ex: --keep 100Y12M12W30D (100years, 12months, 12weeks, 30days, default)</code></pre>
|
|
19
|
+
<h2 id="実行例">実行例</h2>
|
|
20
|
+
<h3 id="バックアップ">バックアップ</h3>
|
|
21
|
+
<p>バックアップを実行する場合。</p>
|
|
22
|
+
<p><code>qdumpfs コピー元 コピー先</code>でバックアップを作成することができます。コピー先が存在する場合差分バックアップとなります。</p>
|
|
23
|
+
<pre><code>qdumpfs /home/foo /backup</code></pre>
|
|
24
|
+
<p><code>--command backup</code>オプションを明示することもできます。</p>
|
|
25
|
+
<pre><code>qdumpfs --command=backup /home/foo /backup</code></pre>
|
|
26
|
+
<h3 id="バックアップフォルダの同期">バックアップフォルダの同期</h3>
|
|
27
|
+
<p>バックアップフォルダを同期することもできます。バックアップディスクが手狭になり、新しいディスクに移行したい場合に便利です。</p>
|
|
28
|
+
<p><code>--command sync</code>オプションを指定することでバックアップフォルダを同期できます。</p>
|
|
29
|
+
<pre><code>qdumpfs --command=sync /backup1 /backup2</code></pre>
|
|
30
|
+
<p>バックアップフォルダの同期には膨大な時間が必要な場合があるため、実行時間を制限できます。以下は例えば1時間に制限する場合です。</p>
|
|
31
|
+
<p>実行時間が1時間を超えるとそこで処理が終了しますそこから次回継続することができます。</p>
|
|
32
|
+
<pre><code>qdumpfs --command=sync --limit=1 /backup1 /backup2</code></pre>
|
|
33
|
+
<p>バックアップフォルダを間引きたい場合、<code>--keep=</code>オプションを指定することができます。“100Y12M12W30D”を指定すると、100年間は年に1つ、12ヶ月間は月に1つ、12週間は週に1つ、直近30日間のバックアップを保持します。条件に該当しないバックアップは同期されません。</p>
|
|
34
|
+
<pre><code>qdumpfs --command=sync --limit=1 --keep=5Y6M7W10D backup1 /backup2</code></pre>
|
|
35
|
+
<p>バックアップの同期は、コピー先の最新の日付より新しいコピー元を選択して実行されます。これはバックアップの同期が途中で中断された場合、再開することができるようにするためです。</p>
|
|
36
|
+
<p>例えばコピー先に2024/11/01のバックアップが存在する場合、コピー元の2024/11/01より後のバックアップデータ(例えば2024/11/02)があれば、それが同期されます(同じ日付は同期されません)。</p>
|
|
37
|
+
<h3 id="バックアップフォルダの削除">バックアップフォルダの削除</h3>
|
|
38
|
+
<p><code>--command expire</code>で、<code>--keep=パターン</code>に該当しないバックアップを削除できます。</p>
|
|
39
|
+
<pre><code>qdumpfs --command=expire --limit=1 --keep=5Y6M7W10D backup1 /backup2</code></pre>
|
|
40
|
+
<h3 id="バックアップフォルダから指定パターンを削除">バックアップフォルダから指定パターンを削除</h3>
|
|
41
|
+
<p><code>--command delete</code>で、バックアップに存在する指定したパスを削除できます(間違えてバックアップした内容を削除したい場合などに使用)。</p>
|
|
42
|
+
<pre><code>qdumpfs --command=delete --delete-dir=backup1 --limit=1 r:/backup2</code></pre>
|
|
43
|
+
<h3 id="バックアップの比較">バックアップの比較</h3>
|
|
44
|
+
<p><code>--command verify</code>でバックアップを比較することができます。</p>
|
|
45
|
+
<pre><code>qdumpfs --command=verify j:/backup/2024/11/01 k:/backup/2024/11/01</code></pre>
|
|
46
|
+
<h3 id="バックアップファイルの一覧">バックアップファイルの一覧</h3>
|
|
47
|
+
<p><code>--command list</code>でバックアップファイルを一覧表示することができます。</p>
|
|
48
|
+
<pre><code>qdumpfs --command=list j:/backup/2024/11/01 </code></pre>
|
|
49
|
+
<p>例えばverifyで異なる結果が表示された場合、listした結果をdiffすることができます。</p>
|
|
50
|
+
<pre><code>qdumpfs --command=list j:/backup/2024/11/01
|
|
51
|
+
qdumpfs --command=list k:/backup/2024/11/01
|
|
52
|
+
diff list_j__backup_2024_11_01.txt list_k__backup_2024_11_01.txt</code></pre>
|
|
53
|
+
<h2 id="license">License</h2>
|
|
54
|
+
<p>qdumpfs is a free software with ABSOLUTELY NO WARRANTY under the terms of the GNU General Public License version 2.</p>
|
data/README.md
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
# Qdumpfs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Language**: [English](#) | [日本語](README_ja.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Qdumpfs is an efficient incremental backup tool developed as a personal improvement of pdumpfs.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This tool modernizes pdumpfs as a Ruby Gem, supporting recent Ruby versions (Ruby 3.2+ compatible). It creates incremental backups with date-based directory structure (YYYY/MM/DD format), copying only changed files and using hard links for unchanged files to maximize storage efficiency.
|
|
8
8
|
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Efficient Incremental Backup**: Copies only changed files, saves space with hard links for unchanged files
|
|
12
|
+
- **Date-based Management**: Organized backups in YYYY/MM/DD directory structure
|
|
13
|
+
- **Cross-platform Support**: Works on Windows/Unix/macOS environments
|
|
14
|
+
- **Ruby 3.2+ Compatible**: Supports latest Ruby versions (taint/untaint methods removed)
|
|
15
|
+
- **Rich Exclusion Options**: Flexible exclusion settings with regex patterns, file size, and glob patterns
|
|
16
|
+
- **Comprehensive Backup Management**: Sync, verify, delete, list and other management functions
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
9
21
|
gem install qdumpfs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
10
25
|
|
|
11
|
-
|
|
26
|
+
- **Ruby**: 3.0 or higher (Ruby 3.2+ compatible)
|
|
27
|
+
- **OS**: Windows, Linux, macOS
|
|
28
|
+
- **Dependencies**: Standard library only (no additional gems required)
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
12
31
|
|
|
13
32
|
```
|
|
14
33
|
Usage: qdumpfs [options] <source> <dest>
|
|
@@ -20,106 +39,165 @@ Options
|
|
|
20
39
|
-e, --exclude=PATTERN exclude files/directories matching PATTERN
|
|
21
40
|
-s, --exclude-by-size=SIZE exclude files larger than SIZE
|
|
22
41
|
-w, --exclude-by-glob=GLOB exclude files matching GLOB
|
|
42
|
+
-x, --one-file-system don't cross filesystem boundaries
|
|
23
43
|
-c, --command=COMMAND backup|sync|list|expire|verify|delete
|
|
24
44
|
-l, --limit=HOURS limit hours
|
|
25
45
|
-k, --keep=KEEPARG ex: --keep 100Y12M12W30D (100years, 12months, 12weeks, 30days, default)
|
|
26
46
|
```
|
|
27
47
|
|
|
28
|
-
##
|
|
48
|
+
## Examples
|
|
29
49
|
|
|
30
|
-
###
|
|
50
|
+
### Backup
|
|
31
51
|
|
|
32
|
-
|
|
52
|
+
To perform a backup operation:
|
|
33
53
|
|
|
34
|
-
|
|
54
|
+
You can create a backup with `qdumpfs source destination`. If the destination exists, it becomes an incremental backup.
|
|
35
55
|
|
|
36
|
-
```
|
|
56
|
+
```bash
|
|
37
57
|
qdumpfs /home/foo /backup
|
|
38
58
|
```
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
You can also explicitly specify the `--command backup` option:
|
|
41
61
|
|
|
42
|
-
```
|
|
62
|
+
```bash
|
|
43
63
|
qdumpfs --command=backup /home/foo /backup
|
|
44
64
|
```
|
|
45
65
|
|
|
46
|
-
###
|
|
66
|
+
### Backup Folder Synchronization
|
|
47
67
|
|
|
48
|
-
|
|
68
|
+
You can also synchronize backup folders. This is useful when your backup disk becomes tight and you want to migrate to a new disk.
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
You can synchronize backup folders by specifying the `--command sync` option:
|
|
51
71
|
|
|
52
|
-
```
|
|
72
|
+
```bash
|
|
53
73
|
qdumpfs --command=sync /backup1 /backup2
|
|
54
74
|
```
|
|
55
75
|
|
|
56
|
-
|
|
76
|
+
Since synchronization of backup folders may require an enormous amount of time, you can limit the execution time. For example, to limit to 1 hour:
|
|
57
77
|
|
|
58
|
-
|
|
78
|
+
When the execution time exceeds 1 hour, the process ends there and can be resumed from there next time.
|
|
59
79
|
|
|
60
|
-
```
|
|
80
|
+
```bash
|
|
61
81
|
qdumpfs --command=sync --limit=1 /backup1 /backup2
|
|
62
82
|
```
|
|
63
83
|
|
|
64
|
-
|
|
65
|
-
条件に該当しないバックアップは同期されません。
|
|
84
|
+
When you want to thin out backup folders, you can specify the `--keep=` option. Specifying "100Y12M12W30D" will keep one backup per year for 100 years, one per month for 12 months, one per week for 12 weeks, and all backups for the last 30 days. Backups that don't meet these conditions will not be synchronized.
|
|
66
85
|
|
|
67
|
-
```
|
|
86
|
+
```bash
|
|
68
87
|
qdumpfs --command=sync --limit=1 --keep=5Y6M7W10D backup1 /backup2
|
|
69
88
|
```
|
|
70
89
|
|
|
71
|
-
|
|
72
|
-
例えばコピー先に2024/11/01のバックアップが存在する場合、コピー元の2024/11/01より後のバックアップデータ(例えば2024/11/02)があれば、それが同期されます(同じ日付は同期されません)。
|
|
73
|
-
|
|
90
|
+
To sync only the first backup of each year (e.g., for long-term archiving), set month, week, and day retention to 0:
|
|
74
91
|
|
|
92
|
+
```bash
|
|
93
|
+
qdumpfs --command=sync --keep=100Y0M0W0D /backup1 /backup2
|
|
75
94
|
```
|
|
76
95
|
|
|
96
|
+
This keeps the first backup per year for the last 100 years, while skipping monthly, weekly, and daily backups. Only backups matching the `--keep` retention policy are selected for synchronization.
|
|
77
97
|
|
|
78
|
-
|
|
98
|
+
Backup synchronization is performed by selecting source backups newer than the latest date in the destination. This allows backup synchronization to resume if interrupted midway.
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
100
|
+
For example, if a backup from 2024/11/01 exists in the destination, and there is backup data after 2024/11/01 in the source (e.g., 2024/11/02), it will be synchronized (backups with the same date are not synchronized).
|
|
101
|
+
|
|
102
|
+
### Backup Folder Deletion
|
|
103
|
+
|
|
104
|
+
With `--command expire`, you can delete backups that don't match the `--keep=pattern`.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
82
107
|
qdumpfs --command=expire --limit=1 --keep=5Y6M7W10D backup1 /backup2
|
|
83
108
|
```
|
|
84
109
|
|
|
110
|
+
### Delete Specified Patterns from Backup Folders
|
|
85
111
|
|
|
86
|
-
|
|
112
|
+
With `--command delete`, you can delete specified paths that exist in backups (useful for deleting content that was mistakenly backed up).
|
|
87
113
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
qdumpfs --command=delete --delete-dir=backup1 --limit=1 r:/backup2
|
|
114
|
+
```bash
|
|
115
|
+
qdumpfs --command=delete --delete-dir=backup1 --limit=1 r:/backup2
|
|
91
116
|
```
|
|
92
117
|
|
|
93
|
-
###
|
|
118
|
+
### Backup Comparison
|
|
94
119
|
|
|
95
|
-
|
|
120
|
+
You can compare backups with `--command verify`:
|
|
96
121
|
|
|
97
|
-
```
|
|
98
|
-
qdumpfs
|
|
122
|
+
```bash
|
|
123
|
+
qdumpfs --command=verify j:/backup/2024/11/01 k:/backup/2024/11/01
|
|
99
124
|
```
|
|
100
125
|
|
|
101
|
-
###
|
|
126
|
+
### Backup File Listing
|
|
102
127
|
|
|
103
|
-
|
|
128
|
+
You can list backup files with `--command list`:
|
|
104
129
|
|
|
130
|
+
```bash
|
|
131
|
+
qdumpfs --command=list j:/backup/2024/11/01
|
|
105
132
|
```
|
|
106
|
-
|
|
133
|
+
|
|
134
|
+
For example, if verify shows different results, you can diff the list results:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
qdumpfs --command=list j:/backup/2024/11/01
|
|
138
|
+
qdumpfs --command=list k:/backup/2024/11/01
|
|
139
|
+
diff list_j__backup_2024_11_01.txt list_k__backup_2024_11_01.txt
|
|
107
140
|
```
|
|
108
141
|
|
|
109
|
-
|
|
142
|
+
## How Backup Works
|
|
143
|
+
|
|
144
|
+
Qdumpfs achieves efficient backup through the following mechanisms:
|
|
145
|
+
|
|
146
|
+
### Directory Structure
|
|
110
147
|
|
|
111
148
|
```
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
149
|
+
backup_destination/
|
|
150
|
+
├── 2024/
|
|
151
|
+
│ ├── 01/
|
|
152
|
+
│ │ ├── 15/ # Backup from January 15, 2024
|
|
153
|
+
│ │ └── 16/ # Backup from January 16, 2024
|
|
154
|
+
│ └── 02/
|
|
155
|
+
│ └── 01/ # Backup from February 1, 2024
|
|
156
|
+
└── latest -> 2024/02/01 # Symbolic link to latest backup
|
|
115
157
|
```
|
|
116
158
|
|
|
159
|
+
### Incremental Backup
|
|
117
160
|
|
|
161
|
+
- **New files**: Full copy from source to destination
|
|
162
|
+
- **Modified files**: Overwrite copy with latest content
|
|
163
|
+
- **Unchanged files**: Create hard link from previous backup (saves space)
|
|
164
|
+
- **Deleted files**: Not deleted from backup, preserved as history
|
|
118
165
|
|
|
166
|
+
### Retention Policy
|
|
119
167
|
|
|
168
|
+
The `--keep` option allows fine-grained control of backup retention periods:
|
|
120
169
|
|
|
121
|
-
|
|
170
|
+
- `Y` (Years): Retention by year
|
|
171
|
+
- `M` (Months): Retention by month
|
|
172
|
+
- `W` (Weeks): Retention by week
|
|
173
|
+
- `D` (Days): Retention by day
|
|
174
|
+
|
|
175
|
+
Example: `--keep=5Y12M12W30D`
|
|
176
|
+
- For 5 years: Keep one backup per year
|
|
177
|
+
- For last 12 months: Keep one backup per month
|
|
178
|
+
- For last 12 weeks: Keep one backup per week
|
|
179
|
+
- For last 30 days: Keep all backups
|
|
122
180
|
|
|
123
|
-
|
|
181
|
+
## Development & Testing
|
|
124
182
|
|
|
183
|
+
```bash
|
|
184
|
+
# Run tests
|
|
185
|
+
./test.sh
|
|
186
|
+
|
|
187
|
+
# Run specific test file
|
|
188
|
+
./test.sh test/qdumpfs_test.rb
|
|
189
|
+
|
|
190
|
+
# Install dependencies
|
|
191
|
+
bundle install
|
|
192
|
+
|
|
193
|
+
# Build gem
|
|
194
|
+
bundle exec rake build
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
Bug reports and feature requests are welcome at [GitHub Issues](https://github.com/src256/qdumpfs/issues).
|
|
200
|
+
|
|
201
|
+
## License
|
|
125
202
|
|
|
203
|
+
qdumpfs is a free software with ABSOLUTELY NO WARRANTY under the terms of the GNU General Public License version 2.
|
data/README_ja.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Qdumpfs
|
|
2
|
+
|
|
3
|
+
**Language**: [English](README.md) | [日本語](#)
|
|
4
|
+
|
|
5
|
+
Qdumpfsは、pdumpfsの個人的改良版として開発された効率的な差分バックアップツールです。
|
|
6
|
+
|
|
7
|
+
pdumpfsをRuby Gemとして現代化し、最近のRubyバージョン(Ruby 3.2系対応)に対応しています。日付ベース(YYYY/MM/DD形式)のディレクトリ構造で差分バックアップを作成し、変更されたファイルのみをコピーして、未変更ファイルはハードリンクを利用することで、ストレージ効率を最大化します。
|
|
8
|
+
|
|
9
|
+
## 特徴
|
|
10
|
+
|
|
11
|
+
- **効率的な差分バックアップ**: 変更されたファイルのみをコピーし、未変更ファイルはハードリンクで容量を節約
|
|
12
|
+
- **日付ベース管理**: YYYY/MM/DD形式のディレクトリ構造で整理されたバックアップ
|
|
13
|
+
- **クロスプラットフォーム対応**: Windows/Unix/macOS環境での動作をサポート
|
|
14
|
+
- **Ruby 3.2系対応**: 最新のRubyバージョンに対応(taint/untaintメソッド削除済み)
|
|
15
|
+
- **豊富な除外オプション**: 正規表現、ファイルサイズ、Globパターンによる柔軟な除外設定
|
|
16
|
+
- **バックアップ管理機能**: 同期、検証、削除、一覧表示など包括的な管理機能
|
|
17
|
+
|
|
18
|
+
## インストール
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gem install qdumpfs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 動作環境
|
|
25
|
+
|
|
26
|
+
- **Ruby**: 3.0以上(Ruby 3.2系対応済み)
|
|
27
|
+
- **OS**: Windows、Linux、macOS
|
|
28
|
+
- **依存関係**: 標準ライブラリのみ(追加のgemは不要)
|
|
29
|
+
|
|
30
|
+
## 使用方法
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Usage: qdumpfs [options] <source> <dest>
|
|
34
|
+
-h, --help show this message
|
|
35
|
+
Options
|
|
36
|
+
-v, --verbose verbose message
|
|
37
|
+
-r, --report report message
|
|
38
|
+
-n, --dry-run don't actually run any commands
|
|
39
|
+
-e, --exclude=PATTERN exclude files/directories matching PATTERN
|
|
40
|
+
-s, --exclude-by-size=SIZE exclude files larger than SIZE
|
|
41
|
+
-w, --exclude-by-glob=GLOB exclude files matching GLOB
|
|
42
|
+
-x, --one-file-system don't cross filesystem boundaries
|
|
43
|
+
-c, --command=COMMAND backup|sync|list|expire|verify|delete
|
|
44
|
+
-l, --limit=HOURS limit hours
|
|
45
|
+
-k, --keep=KEEPARG ex: --keep 100Y12M12W30D (100years, 12months, 12weeks, 30days, default)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 実行例
|
|
49
|
+
|
|
50
|
+
### バックアップ
|
|
51
|
+
|
|
52
|
+
バックアップを実行する場合。
|
|
53
|
+
|
|
54
|
+
`qdumpfs コピー元 コピー先`でバックアップを作成することができます。コピー先が存在する場合差分バックアップとなります。
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
qdumpfs /home/foo /backup
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`--command backup`オプションを明示することもできます。
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
qdumpfs --command=backup /home/foo /backup
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### バックアップフォルダの同期
|
|
67
|
+
|
|
68
|
+
バックアップフォルダを同期することもできます。バックアップディスクが手狭になり、新しいディスクに移行したい場合に便利です。
|
|
69
|
+
|
|
70
|
+
`--command sync`オプションを指定することでバックアップフォルダを同期できます。
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
qdumpfs --command=sync /backup1 /backup2
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
バックアップフォルダの同期には膨大な時間が必要な場合があるため、実行時間を制限できます。以下は例えば1時間に制限する場合です。
|
|
77
|
+
|
|
78
|
+
実行時間が1時間を超えるとそこで処理が終了しますそこから次回継続することができます。
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
qdumpfs --command=sync --limit=1 /backup1 /backup2
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
バックアップフォルダを間引きたい場合、`--keep=`オプションを指定することができます。"100Y12M12W30D"を指定すると、100年間は年に1つ、12ヶ月間は月に1つ、12週間は週に1つ、直近30日間のバックアップを保持します。条件に該当しないバックアップは同期されません。
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
qdumpfs --command=sync --limit=1 --keep=5Y6M7W10D backup1 /backup2
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
各年の最初のバックアップのみを同期したい場合(長期アーカイブ用途など)、月・週・日の保持数を0に設定します:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
qdumpfs --command=sync --keep=100Y0M0W0D /backup1 /backup2
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
この例では過去100年間の各年の最初のバックアップのみを保持し、月・週・日単位の保持は行いません。`--keep`の保持ポリシーに該当するバックアップのみが同期対象として選択されます。
|
|
97
|
+
|
|
98
|
+
バックアップの同期は、コピー先の最新の日付より新しいコピー元を選択して実行されます。これはバックアップの同期が途中で中断された場合、再開することができるようにするためです。
|
|
99
|
+
|
|
100
|
+
例えばコピー先に2024/11/01のバックアップが存在する場合、コピー元の2024/11/01より後のバックアップデータ(例えば2024/11/02)があれば、それが同期されます(同じ日付は同期されません)。
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### バックアップフォルダの削除
|
|
106
|
+
|
|
107
|
+
`--command expire`で、`--keep=パターン`に該当しないバックアップを削除できます。
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
qdumpfs --command=expire --limit=1 --keep=5Y6M7W10D backup1 /backup2
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### バックアップフォルダから指定パターンを削除
|
|
115
|
+
|
|
116
|
+
`--command delete`で、バックアップに存在する指定したパスを削除できます(間違えてバックアップした内容を削除したい場合などに使用)。
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
qdumpfs --command=delete --delete-dir=backup1 --limit=1 r:/backup2
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### バックアップの比較
|
|
124
|
+
|
|
125
|
+
`--command verify`でバックアップを比較することができます。
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
qdumpfs --command=verify j:/backup/2024/11/01 k:/backup/2024/11/01
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### バックアップファイルの一覧
|
|
132
|
+
|
|
133
|
+
`--command list`でバックアップファイルを一覧表示することができます。
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
qdumpfs --command=list j:/backup/2024/11/01
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
例えばverifyで異なる結果が表示された場合、listした結果をdiffすることができます。
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
qdumpfs --command=list j:/backup/2024/11/01
|
|
143
|
+
qdumpfs --command=list k:/backup/2024/11/01
|
|
144
|
+
diff list_j__backup_2024_11_01.txt list_k__backup_2024_11_01.txt
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## バックアップの仕組み
|
|
148
|
+
|
|
149
|
+
Qdumpfsは以下の仕組みで効率的なバックアップを実現しています:
|
|
150
|
+
|
|
151
|
+
### ディレクトリ構造
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
バックアップ先/
|
|
155
|
+
├── 2024/
|
|
156
|
+
│ ├── 01/
|
|
157
|
+
│ │ ├── 15/ # 2024年1月15日のバックアップ
|
|
158
|
+
│ │ └── 16/ # 2024年1月16日のバックアップ
|
|
159
|
+
│ └── 02/
|
|
160
|
+
│ └── 01/ # 2024年2月1日のバックアップ
|
|
161
|
+
└── latest -> 2024/02/01 # 最新バックアップへのシンボリックリンク
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 差分バックアップ
|
|
165
|
+
|
|
166
|
+
- **新規ファイル**: コピー元からコピー先へ完全コピー
|
|
167
|
+
- **変更されたファイル**: 最新の内容で上書きコピー
|
|
168
|
+
- **未変更ファイル**: 前回のバックアップからハードリンクを作成(容量節約)
|
|
169
|
+
- **削除されたファイル**: バックアップからは削除されず履歴として保持
|
|
170
|
+
|
|
171
|
+
### 保持ポリシー
|
|
172
|
+
|
|
173
|
+
`--keep`オプションでバックアップの保持期間を細かく制御できます:
|
|
174
|
+
|
|
175
|
+
- `Y` (Years): 年単位での保持
|
|
176
|
+
- `M` (Months): 月単位での保持
|
|
177
|
+
- `W` (Weeks): 週単位での保持
|
|
178
|
+
- `D` (Days): 日単位での保持
|
|
179
|
+
|
|
180
|
+
例: `--keep=5Y12M12W30D`
|
|
181
|
+
- 5年間: 年に1つのバックアップを保持
|
|
182
|
+
- 直近12ヶ月: 月に1つのバックアップを保持
|
|
183
|
+
- 直近12週間: 週に1つのバックアップを保持
|
|
184
|
+
- 直近30日間: 全てのバックアップを保持
|
|
185
|
+
|
|
186
|
+
## 開発・テスト
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# テスト実行
|
|
190
|
+
./test.sh
|
|
191
|
+
|
|
192
|
+
# 特定のテストファイル実行
|
|
193
|
+
./test.sh test/qdumpfs_test.rb
|
|
194
|
+
|
|
195
|
+
# 依存関係インストール
|
|
196
|
+
bundle install
|
|
197
|
+
|
|
198
|
+
# Gemビルド
|
|
199
|
+
bundle exec rake build
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 貢献
|
|
203
|
+
|
|
204
|
+
バグ報告や機能要望は[GitHub Issues](https://github.com/src256/qdumpfs/issues)まで。
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
qdumpfs is a free software with ABSOLUTELY NO WARRANTY under the terms of the GNU General Public License version 2.
|
|
209
|
+
|
|
210
|
+
|
data/lib/.DS_Store
ADDED
|
Binary file
|
data/lib/qdumpfs/option.rb
CHANGED
|
@@ -116,22 +116,25 @@ module Qdumpfs
|
|
|
116
116
|
@dst = dirs[1] if dirs.size > 1
|
|
117
117
|
@cmd = @opts[:c] || 'backup'
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
@logpath = @opts[:logpath]
|
|
122
|
-
@logdir = File.dirname(@logpath)
|
|
119
|
+
if @opts[:q]
|
|
120
|
+
@logger = NullLogger.new
|
|
123
121
|
else
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
if @opts[:logpath]
|
|
123
|
+
@logpath = @opts[:logpath]
|
|
124
|
+
@logdir = File.dirname(@logpath)
|
|
125
|
+
else
|
|
126
|
+
logname = @opts[:logname] || 'qdumpfs.log'
|
|
127
|
+
#ログディレクトリの作成
|
|
128
|
+
@logdir = @opts[:logdir] || Dir.pwd
|
|
129
|
+
@logpath = File.join(@logdir, logname)
|
|
130
|
+
end
|
|
131
|
+
Dir.mkdir(@logdir) unless FileTest.directory?(@logdir)
|
|
132
|
+
@logger = SimpleLogger.new(@logpath)
|
|
133
|
+
|
|
134
|
+
verifyfile = 'verify.txt'
|
|
135
|
+
@verifypath = File.join(@logdir, verifyfile)
|
|
128
136
|
end
|
|
129
137
|
|
|
130
|
-
Dir.mkdir(@logdir) unless FileTest.directory?(@logdir)
|
|
131
|
-
@logger = SimpleLogger.new(@logpath)
|
|
132
|
-
|
|
133
|
-
verifyfile = 'verify.txt'
|
|
134
|
-
@verifypath = File.join(@logdir, verifyfile)
|
|
135
138
|
|
|
136
139
|
@matcher = NullMatcher.new
|
|
137
140
|
|
|
@@ -208,7 +211,7 @@ module Qdumpfs
|
|
|
208
211
|
|
|
209
212
|
def log(msg, console = true)
|
|
210
213
|
return if (msg.nil? || msg == '')
|
|
211
|
-
puts msg if console
|
|
214
|
+
puts msg if console && !@opts[:q]
|
|
212
215
|
@logger.print(msg)
|
|
213
216
|
end
|
|
214
217
|
|
|
@@ -219,6 +222,10 @@ module Qdumpfs
|
|
|
219
222
|
def verbose
|
|
220
223
|
@opts[:v]
|
|
221
224
|
end
|
|
225
|
+
|
|
226
|
+
def one_file_system
|
|
227
|
+
@opts[:x]
|
|
228
|
+
end
|
|
222
229
|
|
|
223
230
|
def limit_sec
|
|
224
231
|
@limit.to_i * 3600
|
data/lib/qdumpfs/util.rb
CHANGED
|
@@ -67,21 +67,42 @@ end
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
module QdumpfsFind
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
# one_file_system: trueの場合、起点と異なるファイルシステム(マウントポイント)には降りない
|
|
71
|
+
# falseの場合は降りるが、境界をまたいだことをnotifyで警告する
|
|
72
|
+
# notify: 境界に関するメッセージの出力先(省略時はloggerのみ)
|
|
73
|
+
def find(logger, *paths, one_file_system: false, notify: nil)
|
|
74
|
+
block_given? or return enum_for(__method__, *paths, one_file_system: one_file_system, notify: notify)
|
|
75
|
+
paths.each do |d|
|
|
73
76
|
raise Errno::ENOENT unless File.exist?(d)
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
+
end
|
|
78
|
+
notify ||= lambda {|msg| logger.print(msg) }
|
|
79
|
+
# [パス, 親ディレクトリのデバイス番号]のキュー
|
|
80
|
+
queue = paths.map {|d| [d, File.stat(d).dev] }
|
|
81
|
+
while entry = queue.shift
|
|
82
|
+
file, dev = entry
|
|
77
83
|
catch(:prune) do
|
|
78
|
-
yield
|
|
84
|
+
# lstatに失敗した場合は判定せずyieldし、エラー処理は呼び出し側に任せる
|
|
85
|
+
s = File.lstat(file) rescue nil
|
|
86
|
+
if s && s.directory? && s.dev != dev
|
|
87
|
+
if one_file_system
|
|
88
|
+
# 別ファイルシステムは中身に一切触れずにスキップ
|
|
89
|
+
notify.call("skip other filesystem path=#{file}")
|
|
90
|
+
next
|
|
91
|
+
end
|
|
92
|
+
notify.call("warn: crossing filesystem boundary path=#{file} (use --one-file-system to skip)")
|
|
93
|
+
dev = s.dev
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
yield file.dup
|
|
97
|
+
|
|
98
|
+
# yield前に取得できていれば再利用し、lstatの回数を増やさない
|
|
79
99
|
begin
|
|
80
|
-
s
|
|
100
|
+
s ||= File.lstat(file)
|
|
81
101
|
rescue => e
|
|
82
102
|
logger.print("File.lstat path=#{file} error=#{e.message}")
|
|
83
103
|
next
|
|
84
104
|
end
|
|
105
|
+
|
|
85
106
|
if s.directory?
|
|
86
107
|
begin
|
|
87
108
|
fs = Dir.entries(file, :encoding=>'UTF-8')
|
|
@@ -90,11 +111,11 @@ module QdumpfsFind
|
|
|
90
111
|
next
|
|
91
112
|
end
|
|
92
113
|
fs.sort!
|
|
93
|
-
fs.reverse_each
|
|
114
|
+
fs.reverse_each do |f|
|
|
94
115
|
next if f == "." or f == ".."
|
|
95
116
|
f = File.join(file, f)
|
|
96
|
-
|
|
97
|
-
|
|
117
|
+
queue.unshift [f, dev]
|
|
118
|
+
end
|
|
98
119
|
end
|
|
99
120
|
end
|
|
100
121
|
end
|
data/lib/qdumpfs/version.rb
CHANGED
data/lib/qdumpfs.rb
CHANGED
|
@@ -35,6 +35,7 @@ module Qdumpfs
|
|
|
35
35
|
}
|
|
36
36
|
opt.on('-s SIZE', '--exclude-by-size=SIZE', 'exclude files larger than SIZE') {|v| opts[:es] = v }
|
|
37
37
|
opt.on('-w GLOB', '--exclude-by-glob=GLOB', 'exclude files matching GLOB') {|v| opts[:eg] = v }
|
|
38
|
+
opt.on('-x', '--one-file-system', "don't cross filesystem boundaries") {|v| opts[:x] = v }
|
|
38
39
|
commands = ['backup', 'sync', 'list', 'expire', 'verify', 'delete']
|
|
39
40
|
opt.on('-c COMMAND', '--command=COMMAND', commands, commands.join('|')) {|v| opts[:c] = v}
|
|
40
41
|
opt.on('-l HOURS', '--limit=HOURS', 'limit hours') {|v| opts[:limit] = v}
|
|
@@ -55,6 +56,7 @@ module Qdumpfs
|
|
|
55
56
|
opts[:backup_at] = Date.parse(v)
|
|
56
57
|
}
|
|
57
58
|
opt.on('-d', '--debug', 'debug mode') {|v| opts[:d] = v }
|
|
59
|
+
opt.on('-q', '--quiet', 'quiet mode') {|v| opts[:q] = v }
|
|
58
60
|
opt.parse!(argv)
|
|
59
61
|
option = Option.new(opts, argv)
|
|
60
62
|
if opts[:v]
|
|
@@ -183,7 +185,7 @@ module Qdumpfs
|
|
|
183
185
|
# latest: 最新のバックアップディレクトリ ex)j:/to/backup1/2019/05/09/home
|
|
184
186
|
# today: 差分バックアップ先ディレクトリ ex)j:/to/backup1/2019/05/10/home
|
|
185
187
|
dirs = {};
|
|
186
|
-
QdumpfsFind.find(@opt.logger, src) do |s| # path of the source file
|
|
188
|
+
QdumpfsFind.find(@opt.logger, src, one_file_system: @opt.one_file_system, notify: method(:log)) do |s| # path of the source file
|
|
187
189
|
begin
|
|
188
190
|
if @opt.matcher.exclude?(s)
|
|
189
191
|
if File.lstat(s).directory? then Find.prune else next end
|
|
@@ -212,7 +214,7 @@ module Qdumpfs
|
|
|
212
214
|
|
|
213
215
|
def recursive_copy(src, dst)
|
|
214
216
|
dirs = {}
|
|
215
|
-
QdumpfsFind.find(@opt.logger, src) do |s|
|
|
217
|
+
QdumpfsFind.find(@opt.logger, src, one_file_system: @opt.one_file_system, notify: method(:log)) do |s|
|
|
216
218
|
begin
|
|
217
219
|
if @opt.matcher.exclude?(s)
|
|
218
220
|
if File.lstat(s).directory? then Find.prune else next end
|
|
@@ -491,7 +493,7 @@ module Qdumpfs
|
|
|
491
493
|
log("##### list start #{fmt(start_time)} #####")
|
|
492
494
|
|
|
493
495
|
src = @opt.src
|
|
494
|
-
QdumpfsFind.find(@opt.logger, src) do |path|
|
|
496
|
+
QdumpfsFind.find(@opt.logger, src, one_file_system: @opt.one_file_system, notify: method(:log)) do |path|
|
|
495
497
|
short_path = path.sub(/^#{src}/, '.')
|
|
496
498
|
log("#{File.ftype(path)} #{path}")
|
|
497
499
|
if FileTest.file?(path)
|
data/tag
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
def find_version
|
|
4
|
+
file = File.expand_path(File.dirname(__FILE__) + '/lib/qdumpfs/version.rb')
|
|
5
|
+
File.readlines(file).each do |line|
|
|
6
|
+
# puts line
|
|
7
|
+
if line =~ /VERSION\s*=\s*['"]([^'"]+)['"]/
|
|
8
|
+
return $1
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
return nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run_cmd(cmd)
|
|
15
|
+
puts cmd
|
|
16
|
+
system(cmd)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
version = find_version
|
|
20
|
+
if version.nil?
|
|
21
|
+
puts "Version not found"
|
|
22
|
+
exit(1)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
tagname = "v#{version}"
|
|
27
|
+
cmd = "git tag #{tagname}"
|
|
28
|
+
run_cmd(cmd)
|
|
29
|
+
cmd = "git push origin #{tagname}"
|
|
30
|
+
run_cmd(cmd)
|
|
31
|
+
|
|
32
|
+
#
|
data/test.sh
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
if [ "$1" = "" ]; then
|
|
4
|
+
# bundle exec rspec
|
|
5
|
+
bundle exec rake test
|
|
6
|
+
else
|
|
7
|
+
# 以下のように実行
|
|
8
|
+
# ./test.sh test/unit/checker_test.rb
|
|
9
|
+
#bundle exec rake test TEST=test/models/entry_test.rb TESTOPTS="--name=test_sample_2"
|
|
10
|
+
bundle exec rake test "$1"
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
Binary file
|
|
Binary file
|
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.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- src
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-09-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -61,8 +61,10 @@ executables:
|
|
|
61
61
|
extensions: []
|
|
62
62
|
extra_rdoc_files: []
|
|
63
63
|
files:
|
|
64
|
+
- ".DS_Store"
|
|
64
65
|
- ".gitignore"
|
|
65
66
|
- ".idea/.gitignore"
|
|
67
|
+
- ".idea/copilot.data.migration.agent.xml"
|
|
66
68
|
- ".idea/inspectionProfiles/Project_Default.xml"
|
|
67
69
|
- ".idea/misc.xml"
|
|
68
70
|
- ".idea/modules.xml"
|
|
@@ -70,11 +72,14 @@ files:
|
|
|
70
72
|
- ".idea/vcs.xml"
|
|
71
73
|
- ".travis.yml"
|
|
72
74
|
- ".vscode/settings.json"
|
|
75
|
+
- CLAUDE.md
|
|
73
76
|
- CODE_OF_CONDUCT.md
|
|
74
77
|
- Gemfile
|
|
75
78
|
- Gemfile.lock
|
|
76
79
|
- LICENSE.txt
|
|
80
|
+
- README.html
|
|
77
81
|
- README.md
|
|
82
|
+
- README_ja.md
|
|
78
83
|
- Rakefile
|
|
79
84
|
- TODO.txt
|
|
80
85
|
- bin/console
|
|
@@ -85,6 +90,7 @@ files:
|
|
|
85
90
|
- data/from/a/1.txt
|
|
86
91
|
- exe/qdumpfs
|
|
87
92
|
- exe/sample
|
|
93
|
+
- lib/.DS_Store
|
|
88
94
|
- lib/qdumpfs.rb
|
|
89
95
|
- lib/qdumpfs/option.rb
|
|
90
96
|
- lib/qdumpfs/util.rb
|
|
@@ -98,6 +104,10 @@ files:
|
|
|
98
104
|
- run_qdumpfs.sh
|
|
99
105
|
- run_sync.cmd
|
|
100
106
|
- sample.sh
|
|
107
|
+
- tag
|
|
108
|
+
- test.sh
|
|
109
|
+
- test_pdumpfs/.DS_Store
|
|
110
|
+
- test_pdumpfs/data/.DS_Store
|
|
101
111
|
- test_pdumpfs/data/bar
|
|
102
112
|
- test_pdumpfs/data/baz/quux
|
|
103
113
|
- test_pdumpfs/data/file
|
|
@@ -127,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
127
137
|
- !ruby/object:Gem::Version
|
|
128
138
|
version: '0'
|
|
129
139
|
requirements: []
|
|
130
|
-
rubygems_version: 3.
|
|
140
|
+
rubygems_version: 3.5.22
|
|
131
141
|
signing_key:
|
|
132
142
|
specification_version: 4
|
|
133
143
|
summary: qdumpfs
|