bitferry 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|