bitferry 0.0.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.
- checksums.yaml +7 -0
- data/README.md +233 -0
- data/bin/bitferry +3 -0
- data/lib/bitferry/cli.rb +344 -0
- data/lib/bitferry.rb +1370 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 07536a8e52281f9dbe3a085aa9bedff6164f116babcb163149e8a13e2214f771
|
4
|
+
data.tar.gz: a81dbb898d67e9c9e2083871c69bfd6396e56caa12904b085cf8e7c5e85248d5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c8025822e4520ec87254036acd3b7c6f3933949b3a0737cc9d12d91d5ae4d5fa5d98487a9f2d60a18c15cfb9d4009212b35ead99ce415ececdc42b48c03bcd7f
|
7
|
+
data.tar.gz: 1af8e4d44dd64818f78eadb27b62233e33bd4f7f1cc493dfafbcb7ca4defd77e5ea868ad5060ee28e6eefc3f4c122842e7774b4627506305ee553e12157ea3c0
|
data/README.md
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
# Bitferry - file synchronization/backup automation tool
|
2
|
+
|
3
|
+
<div align="right"><i>Ein Backup ist kein Backup</i></div><br><br>
|
4
|
+
|
5
|
+
The [Bitferry](https://github.com/okhlybov/bitferry) is aimed at establishing the automated file synchronization/replication/backup routes between multiple endpoints where the latter can be the local directories, online cloud remotes or portable offline storages.
|
6
|
+
|
7
|
+
The intended usage ranges from maintaining simple directory copy to another location (disk, mount point) to complex many-to-many (online/offline) data replication/backup solution employing portable media as additional data storage and a means of data propagation between the offsites.
|
8
|
+
|
9
|
+
Bitferry is a frontend to the [Rclone](https://rclone.org) and [Restic](https://restic.net) utilities.
|
10
|
+
|
11
|
+
|
12
|
+
## Features
|
13
|
+
|
14
|
+
* Multiplatform (Windows / UNIX / macOSX) operation
|
15
|
+
|
16
|
+
* Automated task-based data processing
|
17
|
+
|
18
|
+
* One way / two way data synchronization
|
19
|
+
|
20
|
+
* Recursive directory copy / update / synchronize
|
21
|
+
|
22
|
+
* Incremental directory backup with snapshotting
|
23
|
+
|
24
|
+
* File/repository password-based end-to-end encryption
|
25
|
+
|
26
|
+
* Online cloud storage relay
|
27
|
+
|
28
|
+
* Offline portable storage (USB flash, HDDs, SSDs etc.) relay
|
29
|
+
|
30
|
+
|
31
|
+
## Use cases
|
32
|
+
|
33
|
+
* Maintain an update-only files copy in a separate location on the same site
|
34
|
+
|
35
|
+
* Maintain offline secure two way file synchronization between two offsites
|
36
|
+
|
37
|
+
* Maintain an incremental files backup on a portable medium with multiple offsite copies of the repository
|
38
|
+
|
39
|
+
|
40
|
+
## Implementation
|
41
|
+
|
42
|
+
The Bitferry itself is written in [Ruby](https://www.ruby-lang.org) programming language. Being a Ruby code, the Bitferry requires the platform-specific Ruby runtime, version 3.0 or higher.
|
43
|
+
|
44
|
+
The source code is hosted on [GitHub](https://github.com/okhlybov/bitferry) and the binary releases in form of a GEM package are distributed through the [RubyGems](https://rubygems.org/gems/bitferry) repository channel.
|
45
|
+
|
46
|
+
In addition, the platform-specific [Rclone](https://github.com/rclone/rclone/releases) and [Restic](https://github.com/restic/restic/releases) executables are required to be accessible through the `PATH` directory list or through the respective `RCLONE` and `RESTIC` environment variables.
|
47
|
+
|
48
|
+
|
49
|
+
## Kickstart
|
50
|
+
|
51
|
+
Install Bitferry
|
52
|
+
|
53
|
+
```shell
|
54
|
+
gem install bitferry
|
55
|
+
```
|
56
|
+
|
57
|
+
Prepare source Bitferry volume for a mounted local filesystem
|
58
|
+
|
59
|
+
```shell
|
60
|
+
bitferry create volume /data
|
61
|
+
```
|
62
|
+
|
63
|
+
Prepare destination Bitferry volume for a mounted portable storage
|
64
|
+
|
65
|
+
```shell
|
66
|
+
bitferry create volume /mnt/usb-drive
|
67
|
+
```
|
68
|
+
|
69
|
+
Ensure the volumes are intact
|
70
|
+
|
71
|
+
```shell
|
72
|
+
bitferry show
|
73
|
+
```
|
74
|
+
|
75
|
+
```
|
76
|
+
# Intact volumes
|
77
|
+
|
78
|
+
d2f10024 /data
|
79
|
+
e42f2d8c /mnt/usb-drive
|
80
|
+
```
|
81
|
+
|
82
|
+
Create a (Rclone) sync task with data encryption
|
83
|
+
|
84
|
+
```shell
|
85
|
+
bitferry create task sync -e /data /mnt/usb-drive/backup
|
86
|
+
```
|
87
|
+
|
88
|
+
Review the changes
|
89
|
+
|
90
|
+
```shell
|
91
|
+
bitferry
|
92
|
+
```
|
93
|
+
|
94
|
+
```
|
95
|
+
# Intact volumes
|
96
|
+
|
97
|
+
d2f10024 /data
|
98
|
+
e42f2d8c /mnt/usb-drive
|
99
|
+
|
100
|
+
|
101
|
+
# Intact tasks
|
102
|
+
|
103
|
+
89e1c119 encrypt+synchronize :d2f10024: --> :e42f2d8c:backup
|
104
|
+
```
|
105
|
+
|
106
|
+
Perform a dry run of the specific task
|
107
|
+
|
108
|
+
```shell
|
109
|
+
bitferry process -vn 89e
|
110
|
+
```
|
111
|
+
|
112
|
+
<details>
|
113
|
+
<summary>...</summary>
|
114
|
+
|
115
|
+
```
|
116
|
+
rclone sync --filter -\ .bitferry --filter -\ .bitferry\~ --verbose --progress --dry-run --metadata --crypt-filename-encoding base32 --crypt-filename-encryption standard --crypt-remote /mnt/usb-drive/backup /data :crypt:
|
117
|
+
2024/03/05 11:46:45 NOTICE: README.md: Skipped copy as --dry-run is set (size 3.073Ki)
|
118
|
+
2024/03/05 11:46:45 NOTICE: LICENSE: Skipped copy as --dry-run is set (size 1.467Ki)
|
119
|
+
2024/03/05 11:46:45 NOTICE: bitferry.gemspec: Skipped copy as --dry-run is set (size 996)
|
120
|
+
Transferred: 5.513 KiB / 5.513 KiB, 100%, 0 B/s, ETA -
|
121
|
+
Transferred: 3 / 3, 100%
|
122
|
+
Elapsed time: 0.0s
|
123
|
+
2024/03/05 11:46:45 NOTICE:
|
124
|
+
Transferred: 5.513 KiB / 5.513 KiB, 100%, 0 B/s, ETA -
|
125
|
+
Transferred: 3 / 3, 100%
|
126
|
+
Elapsed time: 0.0s
|
127
|
+
```
|
128
|
+
|
129
|
+
</details>
|
130
|
+
|
131
|
+
Process all intact tasks in sequence
|
132
|
+
|
133
|
+
```shell
|
134
|
+
bitferry -v x
|
135
|
+
```
|
136
|
+
|
137
|
+
<details>
|
138
|
+
<summary>...</summary>
|
139
|
+
|
140
|
+
```
|
141
|
+
rclone sync --filter -\ .bitferry --filter -\ .bitferry\~ --verbose --progress --metadata --crypt-filename-encoding base32 --crypt-filename-encryption standard --crypt-remote /mnt/usb-drive/backup /data :crypt:
|
142
|
+
2024/03/05 11:44:31 INFO : LICENSE: Copied (new)
|
143
|
+
2024/03/05 11:44:31 INFO : README.md: Copied (new)
|
144
|
+
2024/03/05 11:44:31 INFO : bitferry.gemspec: Copied (new)
|
145
|
+
Transferred: 5.653 KiB / 5.653 KiB, 100%, 0 B/s, ETA -
|
146
|
+
Transferred: 3 / 3, 100%
|
147
|
+
Elapsed time: 0.0s
|
148
|
+
2024/03/05 11:44:31 INFO :
|
149
|
+
Transferred: 5.653 KiB / 5.653 KiB, 100%, 0 B/s, ETA -
|
150
|
+
Transferred: 3 / 3, 100%
|
151
|
+
Elapsed time: 0.0s
|
152
|
+
```
|
153
|
+
|
154
|
+
</details>
|
155
|
+
|
156
|
+
Observe the result
|
157
|
+
|
158
|
+
```shell
|
159
|
+
ls -l /mnt/usb-drive/backup
|
160
|
+
```
|
161
|
+
|
162
|
+
<details>
|
163
|
+
<summary>...</summary>
|
164
|
+
|
165
|
+
```
|
166
|
+
-rw-r--r-- 1 user user 1044 feb 27 17:09 0u1vi7ka5p88u62kof9k6mf2z00354g6fa0c9a0g6di2f0ocds80
|
167
|
+
-rw-r--r-- 1 user user 1550 jan 29 11:57 21dgu5vs2c4rjfkieeemjvaf78
|
168
|
+
-rw-r--r-- 1 user user 3195 mar 5 11:43 m9rhq3q2m5h2q5l1ke00u0gdjc
|
169
|
+
```
|
170
|
+
|
171
|
+
</details>
|
172
|
+
|
173
|
+
Examine the detailed usage instructions
|
174
|
+
|
175
|
+
```shell
|
176
|
+
bitferry c t s -h
|
177
|
+
```
|
178
|
+
|
179
|
+
<details>
|
180
|
+
<summary>...</summary>
|
181
|
+
|
182
|
+
```
|
183
|
+
Usage:
|
184
|
+
bitferry c t s [OPTIONS] SOURCE DESTINATION
|
185
|
+
|
186
|
+
Create source --> destination one way file synchronization task.
|
187
|
+
|
188
|
+
The task operates recursively on two specified endpoints.
|
189
|
+
This task copies newer source files while skipping unchanged files in destination.
|
190
|
+
Also, it deletes destination files which are non-existent in source.
|
191
|
+
|
192
|
+
The endpoint may be one of:
|
193
|
+
* directory -- absolute or relative local directory (/data, ../source, c:\data)
|
194
|
+
* local:directory, :directory -- absolute local directory (:/data, local:c:\data)
|
195
|
+
* :tag:directory -- path relative to the intact volume matched by (partial) tag (:fa2c:source/data)
|
196
|
+
|
197
|
+
The former case resolves specified directory againt an intact volume to make it volume-relative.
|
198
|
+
It is an error if there is no intact volume that encompasses specified directory.
|
199
|
+
The local: directory is left as is (not resolved against volumes).
|
200
|
+
The :tag: directory is bound to the specified volume.
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
The encryption mode is controlled by --encrypt or --decrypt options.
|
205
|
+
The mandatory password will be read from the standard input channel (pipe or keyboard).
|
206
|
+
|
207
|
+
This task employs the Rclone worker.
|
208
|
+
|
209
|
+
Parameters:
|
210
|
+
SOURCE Source endpoint specifier
|
211
|
+
DESTINATION Destination endpoint specifier
|
212
|
+
|
213
|
+
Options:
|
214
|
+
-e Encrypt files in destination using default profile (alias for -E default)
|
215
|
+
-d Decrypt source files using default profile (alias for -D default)
|
216
|
+
-x Use extended encryption profile options (applies to -e, -d)
|
217
|
+
--process, -X OPTIONS Extra task processing profile/options
|
218
|
+
--encrypt, -E OPTIONS Encrypt files in destination using specified profile/options
|
219
|
+
--decrypt, -D OPTIONS Decrypt source files using specified profile/options
|
220
|
+
--version Print version
|
221
|
+
--verbose, -v Extensive logging
|
222
|
+
--quiet, -q Disable logging
|
223
|
+
--dry-run, -n Simulation mode (make no on-disk changes)
|
224
|
+
-h, --help print help
|
225
|
+
```
|
226
|
+
|
227
|
+
</details>
|
228
|
+
|
229
|
+
## The rest is about to come
|
230
|
+
|
231
|
+
*Cheers!*
|
232
|
+
|
233
|
+
Oleg A. Khlybov <fougas@mail.ru>
|
data/bin/bitferry
ADDED
data/lib/bitferry/cli.rb
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
require 'clamp'
|
2
|
+
require 'bitferry'
|
3
|
+
require 'io/console'
|
4
|
+
|
5
|
+
|
6
|
+
Endpoint = %{
|
7
|
+
The endpoint may be one of:
|
8
|
+
* directory -- absolute or relative local directory (/data, ../source, c:\\data)
|
9
|
+
* local:directory, :directory -- absolute local directory (:/data, local:c:\\data)
|
10
|
+
* :tag:directory -- path relative to the intact volume matched by (partial) tag (:fa2c:source/data)
|
11
|
+
|
12
|
+
The former case resolves specified directory againt an intact volume to make it volume-relative.
|
13
|
+
It is an error if there is no intact volume that encompasses specified directory.
|
14
|
+
The local: directory is left as is (not resolved against volumes).
|
15
|
+
The :tag: directory is bound to the specified volume.
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
Encryption = %{
|
20
|
+
The encryption mode is controlled by --encrypt or --decrypt options.
|
21
|
+
The mandatory password will be read from the standard input channel (pipe or keyboard).
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
def setup_rclone_task(x)
|
26
|
+
x.parameter 'SOURCE', 'Source endpoint specifier'
|
27
|
+
x.parameter 'DESTINATION', 'Destination endpoint specifier'
|
28
|
+
x.option '-e', :flag, 'Encrypt files in destination using default profile (alias for -E default)', attribute_name: :e do
|
29
|
+
$encryption = Bitferry::Rclone::Encrypt
|
30
|
+
$profile = :default
|
31
|
+
end
|
32
|
+
x.option '-d', :flag, 'Decrypt source files using default profile (alias for -D default)', attribute_name: :d do
|
33
|
+
$encryption = Bitferry::Rclone::Decrypt
|
34
|
+
$profile = :default
|
35
|
+
end
|
36
|
+
x.option '-x', :flag, 'Use extended encryption profile options (applies to -e, -d)', attribute_name: :x do
|
37
|
+
$extended = true
|
38
|
+
end
|
39
|
+
x.option ['--process', '-X'], 'OPTIONS', 'Extra task processing profile/options' do |opts|
|
40
|
+
$process = opts
|
41
|
+
end
|
42
|
+
x.option ['--encrypt', '-E'], 'OPTIONS', 'Encrypt files in destination using specified profile/options' do |opts|
|
43
|
+
$encryption = Bitferry::Rclone::Encrypt
|
44
|
+
$profile = opts
|
45
|
+
end
|
46
|
+
x.option ['--decrypt', '-D'], 'OPTIONS', 'Decrypt source files using specified profile/options' do |opts|
|
47
|
+
$encryption = Bitferry::Rclone::Decrypt
|
48
|
+
$profile = opts
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def create_rclone_task(task, *args, **opts)
|
54
|
+
task.new(*args,
|
55
|
+
process: $process,
|
56
|
+
encryption: $encryption&.new(obtain_password, process: $extended ? :extended : $profile),
|
57
|
+
**opts
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def bitferry(&code)
|
63
|
+
begin
|
64
|
+
Bitferry.restore
|
65
|
+
result = yield
|
66
|
+
exit(Bitferry.commit && result ? 0 : 1)
|
67
|
+
rescue => e
|
68
|
+
Bitferry.log.fatal(e.message)
|
69
|
+
exit(1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def obtain_password
|
75
|
+
if $stdin.tty?
|
76
|
+
p1 = IO.console.getpass 'Enter password:'
|
77
|
+
p2 = IO.console.getpass 'Repeat password:'
|
78
|
+
raise 'passwords do not match' unless p1 == p2
|
79
|
+
p1
|
80
|
+
else
|
81
|
+
$stdin.readline.strip!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
Bitferry.log.level = Logger::DEBUG if $DEBUG
|
87
|
+
|
88
|
+
|
89
|
+
Clamp do
|
90
|
+
|
91
|
+
|
92
|
+
self.default_subcommand = 'show'
|
93
|
+
|
94
|
+
|
95
|
+
option '--version', :flag, 'Print version' do
|
96
|
+
puts Bitferry::VERSION
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
option ['--verbose', '-v'], :flag, 'Extensive logging' do
|
102
|
+
Bitferry.verbosity = :verbose
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
option ['--quiet', '-q'], :flag, 'Disable logging' do
|
107
|
+
Bitferry.verbosity = :quiet
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
option ['--dry-run', '-n'], :flag, 'Simulation mode (make no on-disk changes)' do
|
112
|
+
Bitferry.simulate = true
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
subcommand ['show', 'info', 'i'], 'Print state' do
|
117
|
+
def execute
|
118
|
+
Bitferry.restore
|
119
|
+
unless (xs = Bitferry::Volume.intact).empty?
|
120
|
+
puts '# Intact volumes'
|
121
|
+
puts
|
122
|
+
xs.each do |volume|
|
123
|
+
puts " #{volume.tag} #{volume.root}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
unless (xs = Bitferry::Task.intact).empty?
|
127
|
+
puts
|
128
|
+
puts '# Intact tasks'
|
129
|
+
puts
|
130
|
+
xs.each do |task|
|
131
|
+
puts " #{task.tag} #{task.show_status}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
unless (xs = Bitferry::Task.stale).empty?
|
135
|
+
puts
|
136
|
+
puts '# Stale tasks'
|
137
|
+
puts
|
138
|
+
xs.each do |task|
|
139
|
+
puts " #{task.tag} #{task.show_status}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
subcommand ['create', 'c'], 'Create entity' do
|
147
|
+
|
148
|
+
|
149
|
+
subcommand ['volume', 'v'], 'Create volume' do
|
150
|
+
banner %{
|
151
|
+
Create new volume in specified directory. Create directory if it does not exist.
|
152
|
+
Refuse to overwrite existing volume storage unless --force is specified.
|
153
|
+
}
|
154
|
+
option '--force', :flag, 'Overwrite existing volume storage in target directory'
|
155
|
+
parameter 'DIRECTORY', 'Target volume directory'
|
156
|
+
def execute
|
157
|
+
bitferry { Bitferry::Volume.new(directory, overwrite: force?) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
subcommand ['task', 't'], 'Create task' do
|
163
|
+
|
164
|
+
|
165
|
+
subcommand ['copy', 'c'], 'Create copy task' do
|
166
|
+
banner %{
|
167
|
+
Create source --> destination file copy task.
|
168
|
+
|
169
|
+
The task operates recursively on two specified endpoints.
|
170
|
+
This task unconditionally copies all source files overwriting existing files in destination.
|
171
|
+
|
172
|
+
#{Endpoint}
|
173
|
+
|
174
|
+
#{Encryption}
|
175
|
+
|
176
|
+
This task employs the Rclone worker.
|
177
|
+
}
|
178
|
+
setup_rclone_task(self)
|
179
|
+
def execute
|
180
|
+
bitferry { create_rclone_task(Bitferry::Rclone::Copy, source, destination) }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
subcommand ['update', 'u'], 'Create update task' do
|
186
|
+
banner %{
|
187
|
+
Create source --> destination file update (freshen) task.
|
188
|
+
|
189
|
+
The task operates recursively on two specified endpoints.
|
190
|
+
This task copies newer source files while skipping unchanged files in destination.
|
191
|
+
|
192
|
+
#{Endpoint}
|
193
|
+
|
194
|
+
#{Encryption}
|
195
|
+
|
196
|
+
This task employs the Rclone worker.
|
197
|
+
}
|
198
|
+
setup_rclone_task(self)
|
199
|
+
def execute
|
200
|
+
bitferry { create_rclone_task(Bitferry::Rclone::Update, source, destination) }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
subcommand ['synchronize', 'sync', 's'], 'Create one way sync task' do
|
206
|
+
banner %{
|
207
|
+
Create source --> destination one way file synchronization task.
|
208
|
+
|
209
|
+
The task operates recursively on two specified endpoints.
|
210
|
+
This task copies newer source files while skipping unchanged files in destination.
|
211
|
+
Also, it deletes destination files which are non-existent in source.
|
212
|
+
|
213
|
+
#{Endpoint}
|
214
|
+
|
215
|
+
#{Encryption}
|
216
|
+
|
217
|
+
This task employs the Rclone worker.
|
218
|
+
}
|
219
|
+
setup_rclone_task(self)
|
220
|
+
def execute
|
221
|
+
bitferry { create_rclone_task(Bitferry::Rclone::Synchronize, source, destination) }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
subcommand ['equalize', 'bisync', 'e'], 'Create two way sync task' do
|
227
|
+
banner %{
|
228
|
+
Create source <-> destination two way file synchronization task.
|
229
|
+
|
230
|
+
The task operates recursively on two specified endpoints.
|
231
|
+
This task retains only the most recent versions of files on both endpoints.
|
232
|
+
Opon execution both endpoints are left identical.
|
233
|
+
|
234
|
+
#{Endpoint}
|
235
|
+
|
236
|
+
#{Encryption}
|
237
|
+
|
238
|
+
This task employs the Rclone worker.
|
239
|
+
}
|
240
|
+
setup_rclone_task(self)
|
241
|
+
def execute
|
242
|
+
bitferry { create_rclone_task(Bitferry::Rclone::Equalize, source, destination) }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
subcommand ['backup', 'b'], 'Create backup task' do
|
248
|
+
banner %{
|
249
|
+
Create source --> repository incremental backup task.
|
250
|
+
This task employs the Restic worker.
|
251
|
+
}
|
252
|
+
option '--force', :flag, 'Force overwriting existing repository' do $format = true end
|
253
|
+
option ['--attach', '-a'], :flag, 'Attach to existing repository' do $format = false end
|
254
|
+
option '-f', :flag, 'Rig for application of the snapshot retention policy (alias for -F default)', attribute_name: :f do $forget = :default end
|
255
|
+
option '-c', :flag, 'Rig for repository checking (alias for -C default)', attribute_name: :c do $check = :default end
|
256
|
+
option ['--process', '-X'], 'OPTIONS', 'Extra task processing profile/options' do |opts| $process = opts end
|
257
|
+
option ['--forget', '-F'], 'OPTIONS', 'Rig for snapshot retention policy with profile/options' do |opts| $forget = opts end
|
258
|
+
option ['--check', '-C'], 'OPTIONS', 'Rig for repository checking with profile/options' do |opts| $check = opts end
|
259
|
+
parameter 'SOURCE', 'Source endpoint specifier'
|
260
|
+
parameter 'REPOSITORY', 'Destination repository endpoint specifier'
|
261
|
+
def execute
|
262
|
+
bitferry {
|
263
|
+
Bitferry::Restic::Backup.new(
|
264
|
+
source, repository, obtain_password,
|
265
|
+
format: $format,
|
266
|
+
process: $process,
|
267
|
+
check: $check,
|
268
|
+
forget: $forget
|
269
|
+
)
|
270
|
+
}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
subcommand ['restore', 'r'], 'Create restore task' do
|
276
|
+
banner %{
|
277
|
+
Create repository --> destination restore task.
|
278
|
+
This task employs the Restic worker.
|
279
|
+
}
|
280
|
+
option ['--process', '-X'], 'OPTIONS', 'Extra task processing profile/options' do |opts| $process = opts end
|
281
|
+
parameter 'REPOSITORY', 'Source repository endpoint specifier'
|
282
|
+
parameter 'DESTINATION', 'Destination endpoint specifier'
|
283
|
+
def execute
|
284
|
+
bitferry {
|
285
|
+
Bitferry::Restic::Restore.new(
|
286
|
+
destination, repository, obtain_password,
|
287
|
+
process: $process,
|
288
|
+
)
|
289
|
+
}
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
subcommand ['delete', 'd'], 'Delete entity' do
|
301
|
+
|
302
|
+
|
303
|
+
subcommand ['volume', 'v'], 'Delete volume' do
|
304
|
+
banner %{
|
305
|
+
Delete volumes matched by specified (partial) tags.
|
306
|
+
There may be multiple tags but each tag must match at most one volume.
|
307
|
+
This command deletes the volume storage file only with the rest of data left intact.
|
308
|
+
}
|
309
|
+
option '--wipe', :flag, 'Wipe target directory upon deletion'
|
310
|
+
parameter 'TAG ...', 'Volume tags', attribute_name: :tags
|
311
|
+
def execute
|
312
|
+
bitferry { Bitferry::Volume.delete(*tags, wipe: wipe?) }
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
subcommand ['task', 't'], 'Delete task' do
|
318
|
+
banner %{
|
319
|
+
Delete tasks matched by specified (partial) tags.
|
320
|
+
There may be multiple tags but each tag must match at most one task.
|
321
|
+
}
|
322
|
+
parameter 'TAG ...', 'Task tags', attribute_name: :tags
|
323
|
+
def execute
|
324
|
+
bitferry { Bitferry::Task.delete(*tags) }
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
subcommand ['process', 'x'], 'Process tasks' do
|
333
|
+
banner %{
|
334
|
+
Process tasks matched by specified (partial) tags.
|
335
|
+
If no tags are given, process all intact tasks.
|
336
|
+
}
|
337
|
+
parameter '[TAG] ...', 'Task tags', attribute_name: :tags
|
338
|
+
def execute
|
339
|
+
bitferry { Bitferry.process(*tags) }
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
|
344
|
+
end
|