yobi 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/yobi/repository/backup.rb +4 -0
- data/lib/yobi/repository/cat.rb +6 -8
- data/lib/yobi/repository/copy.rb +9 -11
- data/lib/yobi/repository/find.rb +1 -2
- data/lib/yobi/repository/forget.rb +1 -3
- data/lib/yobi/repository/init.rb +13 -14
- data/lib/yobi/repository/key.rb +5 -3
- data/lib/yobi/repository/mount.rb +1 -1
- data/lib/yobi/repository/snapshots.rb +1 -1
- data/lib/yobi/repository/stats.rb +1 -3
- data/lib/yobi/repository.rb +66 -2
- data/lib/yobi/restic.rb +3 -3
- data/lib/yobi/version.rb +1 -1
- data/sig/yobi.rbs +4 -3
- 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: 56739c72c75a1d5c856bbd619b781dd3986cf1b3c1447d4864edd19b9543d8d9
|
|
4
|
+
data.tar.gz: a5321fe628cab2f74011ce257a4eee380ed1fcb804456f8afa5482ac84c96b6f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b2253d54dd64aa88658c7ddd53734a2edbcaf2623bb98258bc14d71d0d4a82bb3bcb447e6434bfb28505d2bfcd329988841d8f491ce7c3d1b13865b4a50b0f7
|
|
7
|
+
data.tar.gz: 7cd169b509d216a99b258180381c9caa9cd92837b822467781b01c3788cc37af4252d825b4de50a511b71a521a4e8d9bff8317a7f9c0da11b82847c6b65c2b8c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [0.3.1] - 2026-08-10
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- `#forget`/`#init`/`#stats`/`#find`/`#snapshots`/`#key_list`/the `#cat_*` methods no longer raise a bare, uninformative `JSON::ParserError` when Restic exits with code 3 ("succeeded with warnings" - e.g. `#forget` failing to remove one or more snapshots) and mixes a plain-text diagnostic line into otherwise-JSON output. Raises `Yobi::ResticCommandFailed` instead, with the diagnostic still available in the error message.
|
|
6
|
+
|
|
7
|
+
## [0.3.0] - 2026-08-03
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Breaking:** `#init`/`#copy`'s `from_repository_file:` kwarg removed - `from_repo:` is now polymorphic, additionally accepting a `[:file, "..."]` tuple to read the source repository's URL from a file, alongside the existing plain URL String/`Repository` instance shapes.
|
|
12
|
+
- Invalid shapes for `password:`, `backend_credentials:`, `restic:`, `source:`/a `stdin_from_command` command, `new_password:`, `from_repo:`, and `from_password:` now raise `ArgumentError` with a message like `"invalid password shape"`, instead of a raw `NoMatchingPatternError`/`NoMatchingPatternKeyError`.
|
|
13
|
+
- `Repository#initialize`'s `password:`/`backend_credentials:` shapes are now validated eagerly at construction (and `from_password:`/`from_repo:` eagerly in `#init`/`#copy`), instead of lazily on the first `#env`/`#inspect`/argv-building call.
|
|
14
|
+
|
|
1
15
|
## [0.2.0] - 2026-08-03
|
|
2
16
|
|
|
3
17
|
### Added
|
data/README.md
CHANGED
|
@@ -521,7 +521,7 @@ A shortcut for setting up a `#copy` destination: constructs a new `Repository` a
|
|
|
521
521
|
mirror_repo.copy(from_repo: primary_repo, tags: "nightly")
|
|
522
522
|
```
|
|
523
523
|
|
|
524
|
-
Replicates snapshots from another repository into this one. `from_repo:` accepts a plain URL String or a `Repository` instance. Given the latter, its own `#url`/`#password` are used automatically unless `from_password:` is given explicitly. Already-copied snapshots are skipped automatically on a repeat run. See the [YARD docs](https://rubydoc.info/gems/yobi/Yobi/Repository#copy-instance_method) for the full list of options. Returns `true`.
|
|
524
|
+
Replicates snapshots from another repository into this one. `from_repo:` accepts a plain URL String, a `[:file, "..."]` tuple reading the URL from a file, or a `Repository` instance. Given the latter, its own `#url`/`#password` are used automatically unless `from_password:` is given explicitly. Already-copied snapshots are skipped automatically on a repeat run. See the [YARD docs](https://rubydoc.info/gems/yobi/Yobi/Repository#copy-instance_method) for the full list of options. Returns `true`.
|
|
525
525
|
|
|
526
526
|
## Mounting
|
|
527
527
|
|
|
@@ -83,6 +83,8 @@ module Yobi
|
|
|
83
83
|
a.flag(:stdin_from_command)
|
|
84
84
|
a.flag(:stdin_filename, filename)
|
|
85
85
|
a.end_of_options.append(tokenize(command))
|
|
86
|
+
else
|
|
87
|
+
raise ArgumentError, "invalid source shape"
|
|
86
88
|
end
|
|
87
89
|
end
|
|
88
90
|
|
|
@@ -99,6 +101,8 @@ module Yobi
|
|
|
99
101
|
Shellwords.split(value)
|
|
100
102
|
in Array => values
|
|
101
103
|
values.map(&:to_s)
|
|
104
|
+
else
|
|
105
|
+
raise ArgumentError, "invalid stdin_from_command command shape"
|
|
102
106
|
end
|
|
103
107
|
end
|
|
104
108
|
end
|
data/lib/yobi/repository/cat.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
3
|
module Yobi
|
|
6
4
|
class Repository
|
|
7
5
|
# `restic cat config`: the repository's own config document.
|
|
@@ -10,7 +8,7 @@ module Yobi
|
|
|
10
8
|
# @raise [Yobi::RepositoryNotFound, Yobi::AuthenticationFailed]
|
|
11
9
|
def cat_config
|
|
12
10
|
execution = run_restic(build_argv("cat", "config"))
|
|
13
|
-
|
|
11
|
+
parse_json_output(execution)
|
|
14
12
|
end
|
|
15
13
|
alias_method :config, :cat_config
|
|
16
14
|
|
|
@@ -21,7 +19,7 @@ module Yobi
|
|
|
21
19
|
def cat_snapshot(id)
|
|
22
20
|
id = id.id if id.is_a?(Yobi::Snapshot)
|
|
23
21
|
execution = run_restic(build_argv("cat", "snapshot", id))
|
|
24
|
-
|
|
22
|
+
parse_json_output(execution)
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
# `restic cat index ID`: one index file's own raw contents. IDs come
|
|
@@ -31,7 +29,7 @@ module Yobi
|
|
|
31
29
|
# @return [Hash]
|
|
32
30
|
def cat_index(id)
|
|
33
31
|
execution = run_restic(build_argv("cat", "index", id))
|
|
34
|
-
|
|
32
|
+
parse_json_output(execution)
|
|
35
33
|
end
|
|
36
34
|
|
|
37
35
|
# `restic cat key ID`: one key's own raw stored record.
|
|
@@ -41,7 +39,7 @@ module Yobi
|
|
|
41
39
|
def cat_key(id)
|
|
42
40
|
id = id.id if id.is_a?(Yobi::Key)
|
|
43
41
|
execution = run_restic(build_argv("cat", "key", id))
|
|
44
|
-
|
|
42
|
+
parse_json_output(execution)
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
# `restic cat tree snapshot:subfolder`: the raw tree object at a
|
|
@@ -58,7 +56,7 @@ module Yobi
|
|
|
58
56
|
"#{snapshot_id}:#{subfolder}"
|
|
59
57
|
end
|
|
60
58
|
execution = run_restic(build_argv("cat", "tree", target))
|
|
61
|
-
|
|
59
|
+
parse_json_output(execution)
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
# `restic cat pack ID`: one pack file's raw, still-encrypted bytes.
|
|
@@ -91,7 +89,7 @@ module Yobi
|
|
|
91
89
|
# @return [Hash]
|
|
92
90
|
def cat_masterkey_and_game_over_if_this_leaks
|
|
93
91
|
execution = run_restic(build_argv("cat", "masterkey"))
|
|
94
|
-
|
|
92
|
+
parse_json_output(execution)
|
|
95
93
|
end
|
|
96
94
|
end
|
|
97
95
|
end
|
data/lib/yobi/repository/copy.rb
CHANGED
|
@@ -5,33 +5,31 @@ module Yobi
|
|
|
5
5
|
# `restic copy`: replicates snapshots from another repository into
|
|
6
6
|
# this one. Already-copied snapshots are skipped automatically.
|
|
7
7
|
#
|
|
8
|
-
# @param from_repo [String, Yobi::Repository] the source repository
|
|
9
|
-
#
|
|
8
|
+
# @param from_repo [String, Yobi::Repository, Array] the source repository's
|
|
9
|
+
# URL; a `Repository` instance (its own `#url`/`#password` are used
|
|
10
|
+
# automatically); or a `[:file, "..."]` tuple reading the URL from a file
|
|
10
11
|
# @param from_password [String, Array, Symbol, #call, nil] the source
|
|
11
12
|
# repository's password, same shape as {#initialize}'s `password:`
|
|
12
13
|
# @param snapshot_ids [Array<String>, String] snapshots to copy; all of them if empty
|
|
13
14
|
# @param from_key_hint [String, nil]
|
|
14
|
-
# @param from_repository_file [String, nil] read the source repository's URL from a file
|
|
15
15
|
# @param hosts [Array<String>, String] filter by hostname(s)
|
|
16
16
|
# @param paths [Array<String>, String] filter by originally backed-up path(s)
|
|
17
17
|
# @param tags [Array<String>, String] filter by tag(s)
|
|
18
18
|
# @return [true]
|
|
19
|
-
def copy(from_repo:, from_password: nil, snapshot_ids: [], from_key_hint: nil,
|
|
20
|
-
|
|
21
|
-
if
|
|
22
|
-
|
|
23
|
-
from_repo = from_repo.url
|
|
24
|
-
end
|
|
19
|
+
def copy(from_repo:, from_password: nil, snapshot_ids: [], from_key_hint: nil, hosts: [], paths: [], tags: [])
|
|
20
|
+
from_repo_flag, from_repo_value = resolved_from_repo_flag(from_repo)
|
|
21
|
+
from_password = from_repo_password(from_repo) if from_password.nil?
|
|
22
|
+
validate_from_password_shape!(from_password)
|
|
25
23
|
|
|
26
24
|
argv = build_argv("copy", snapshot_ids) do |a|
|
|
27
|
-
a.flag(
|
|
25
|
+
a.flag(from_repo_flag, from_repo_value)
|
|
28
26
|
a.flag(:from_insecure_no_password) if from_password == :insecure_no_password
|
|
29
27
|
a.flag(:from_key_hint, from_key_hint) unless from_key_hint.nil?
|
|
30
|
-
a.flag(:from_repository_file, from_repository_file) unless from_repository_file.nil?
|
|
31
28
|
a.repeat_flag(:host, hosts)
|
|
32
29
|
a.repeat_flag(:path, paths)
|
|
33
30
|
a.repeat_flag(:tag, tags)
|
|
34
31
|
end
|
|
32
|
+
|
|
35
33
|
run_restic(argv, extra_env: password_env(from_password, "RESTIC_FROM_PASSWORD"))
|
|
36
34
|
true
|
|
37
35
|
end
|
data/lib/yobi/repository/find.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
3
|
require "time"
|
|
5
4
|
|
|
6
5
|
module Yobi
|
|
@@ -45,7 +44,7 @@ module Yobi
|
|
|
45
44
|
a.end_of_options.append(patterns)
|
|
46
45
|
end
|
|
47
46
|
execution = run_restic(argv)
|
|
48
|
-
|
|
47
|
+
parse_json_output(execution).map { |raw| MatchesPerSnapshot.new(raw) }
|
|
49
48
|
end
|
|
50
49
|
end
|
|
51
50
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
3
|
module Yobi
|
|
6
4
|
class Repository
|
|
7
5
|
# `restic forget`: applies a retention policy, removing snapshots
|
|
@@ -69,7 +67,7 @@ module Yobi
|
|
|
69
67
|
a.flag(:repack_smaller_than, repack_smaller_than) unless repack_smaller_than.nil?
|
|
70
68
|
end
|
|
71
69
|
execution = run_restic(argv)
|
|
72
|
-
|
|
70
|
+
parse_json_output(execution).map { |raw| ForgetGroup.new(raw) }
|
|
73
71
|
end
|
|
74
72
|
end
|
|
75
73
|
|
data/lib/yobi/repository/init.rb
CHANGED
|
@@ -1,38 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
3
|
module Yobi
|
|
6
4
|
class Repository
|
|
7
5
|
# `restic init`: creates the repository at {#url}.
|
|
8
6
|
#
|
|
9
|
-
# @param copy_chunker_params [Boolean] copy chunker parameters from `from_repo
|
|
7
|
+
# @param copy_chunker_params [Boolean] copy chunker parameters from `from_repo:`
|
|
10
8
|
# @param from_key_hint [String, nil]
|
|
11
9
|
# @param from_password [String, Array, Symbol, #call, nil] the source
|
|
12
10
|
# repository's password (when copying chunker params from one), same
|
|
13
11
|
# shape as {#initialize}'s `password:`
|
|
14
|
-
# @param from_repo [String, Yobi::Repository, nil] the source repository
|
|
15
|
-
#
|
|
16
|
-
#
|
|
12
|
+
# @param from_repo [String, Yobi::Repository, Array, nil] the source repository's
|
|
13
|
+
# URL; a `Repository` instance (its own `#url`/`#password` are used
|
|
14
|
+
# automatically); or a `[:file, "..."]` tuple reading the URL from a file
|
|
17
15
|
# @param repository_version [String, nil]
|
|
18
16
|
# @return [Yobi::Initialized]
|
|
19
|
-
def init(copy_chunker_params: false, from_key_hint: nil, from_password: nil, from_repo: nil,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
def init(copy_chunker_params: false, from_key_hint: nil, from_password: nil, from_repo: nil, repository_version: nil)
|
|
18
|
+
from_repo_flag, from_repo_value = resolved_from_repo_flag(from_repo) unless from_repo.nil?
|
|
19
|
+
|
|
20
|
+
if from_repo_value
|
|
21
|
+
from_password = from_repo_password(from_repo) if from_password.nil?
|
|
22
|
+
validate_from_password_shape!(from_password)
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
argv = build_argv("init") do |a|
|
|
27
26
|
a.flag(:copy_chunker_params) if copy_chunker_params
|
|
28
27
|
a.flag(:from_insecure_no_password) if from_password == :insecure_no_password
|
|
29
28
|
a.flag(:from_key_hint, from_key_hint) unless from_key_hint.nil?
|
|
30
|
-
a.flag(
|
|
31
|
-
a.flag(:from_repository_file, from_repository_file) unless from_repository_file.nil?
|
|
29
|
+
a.flag(from_repo_flag, from_repo_value) if from_repo_flag
|
|
32
30
|
a.flag(:repository_version, repository_version) unless repository_version.nil?
|
|
33
31
|
end
|
|
32
|
+
|
|
34
33
|
execution = run_restic(argv, extra_env: password_env(from_password, "RESTIC_FROM_PASSWORD"))
|
|
35
|
-
Initialized.new(
|
|
34
|
+
Initialized.new(parse_json_output(execution))
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
# Constructs a new {Yobi::Repository} at `url`, already initialized with
|
data/lib/yobi/repository/key.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Yobi
|
|
|
24
24
|
argv = build_argv("key", "add") do |a|
|
|
25
25
|
a.flag(:host, host) unless host.nil?
|
|
26
26
|
a.flag(:user, user) unless user.nil?
|
|
27
|
-
a.flag(flag_name, flag_value)
|
|
27
|
+
a.flag(flag_name, flag_value)
|
|
28
28
|
end
|
|
29
29
|
run_restic(argv)
|
|
30
30
|
end
|
|
@@ -37,7 +37,7 @@ module Yobi
|
|
|
37
37
|
# @return [Array<Yobi::Key>]
|
|
38
38
|
def key_list
|
|
39
39
|
execution = run_restic(build_argv("key", "list"))
|
|
40
|
-
|
|
40
|
+
parse_json_output(execution).map { |raw| Key.new(raw) }
|
|
41
41
|
end
|
|
42
42
|
alias_method :keys, :key_list
|
|
43
43
|
|
|
@@ -55,7 +55,7 @@ module Yobi
|
|
|
55
55
|
argv = build_argv("key", "passwd") do |a|
|
|
56
56
|
a.flag(:host, host) unless host.nil?
|
|
57
57
|
a.flag(:user, user) unless user.nil?
|
|
58
|
-
a.flag(flag_name, flag_value)
|
|
58
|
+
a.flag(flag_name, flag_value)
|
|
59
59
|
end
|
|
60
60
|
run_restic(argv)
|
|
61
61
|
end
|
|
@@ -88,6 +88,8 @@ module Yobi
|
|
|
88
88
|
with_temp_password_file(literal) { |path| yield :new_password_file, path }
|
|
89
89
|
in callable if callable.respond_to?(:call)
|
|
90
90
|
with_temp_password_file(callable.call.to_s) { |path| yield :new_password_file, path }
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError, "invalid new_password shape"
|
|
91
93
|
end
|
|
92
94
|
end
|
|
93
95
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
3
|
module Yobi
|
|
6
4
|
class Repository
|
|
7
5
|
# @private
|
|
@@ -29,7 +27,7 @@ module Yobi
|
|
|
29
27
|
a.repeat_flag(:tag, tags)
|
|
30
28
|
end
|
|
31
29
|
execution = run_restic(argv)
|
|
32
|
-
RepositoryStats.new(
|
|
30
|
+
RepositoryStats.new(parse_json_output(execution))
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
33
|
|
data/lib/yobi/repository.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "json"
|
|
3
4
|
require "uri"
|
|
4
5
|
|
|
5
6
|
module Yobi
|
|
@@ -23,9 +24,10 @@ module Yobi
|
|
|
23
24
|
# responding to `#call` returning such a Hash
|
|
24
25
|
# @param restic [Yobi::Restic, String, nil] a `Restic` instance to share,
|
|
25
26
|
# a bare Restic binary path, or `nil` to create a default one
|
|
26
|
-
# @raise [ArgumentError] if `password:` is `nil`
|
|
27
|
+
# @raise [ArgumentError] if `password:` is `nil`, or if `password:`/`backend_credentials:`/`restic:` is an invalid shape
|
|
27
28
|
def initialize(url:, password:, backend_credentials: {}, restic: nil)
|
|
28
|
-
|
|
29
|
+
validate_password_shape!(password)
|
|
30
|
+
validate_backend_credentials_shape!(backend_credentials)
|
|
29
31
|
|
|
30
32
|
@url, @extracted_rest_credentials = extract_rest_credentials(url)
|
|
31
33
|
@password = password
|
|
@@ -61,6 +63,21 @@ module Yobi
|
|
|
61
63
|
builder.to_a
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
# Parses a command's captured output as JSON. If parsing fails, raises
|
|
67
|
+
# {Yobi::ResticCommandFailed} when `execution[:exit_code]` is `3`
|
|
68
|
+
# (Restic reported a problem alongside otherwise-JSON output), or
|
|
69
|
+
# re-raises the original +JSON::ParserError+ when it's `0`.
|
|
70
|
+
#
|
|
71
|
+
# @param execution [Hash] `{exit_code:, output:, argv:}`
|
|
72
|
+
# @return [Object] the parsed JSON
|
|
73
|
+
# @raise [Yobi::ResticCommandFailed] if parsing fails and `exit_code` is `3`
|
|
74
|
+
def parse_json_output(execution)
|
|
75
|
+
JSON.parse(execution[:output].to_s)
|
|
76
|
+
rescue JSON::ParserError
|
|
77
|
+
raise if execution[:exit_code].zero?
|
|
78
|
+
raise Yobi::ResticCommandFailed, execution
|
|
79
|
+
end
|
|
80
|
+
|
|
64
81
|
def resolved_password
|
|
65
82
|
password_env(password)
|
|
66
83
|
end
|
|
@@ -119,6 +136,51 @@ module Yobi
|
|
|
119
136
|
end
|
|
120
137
|
end
|
|
121
138
|
|
|
139
|
+
def from_repo_password(from_repo)
|
|
140
|
+
from_repo.password if from_repo.is_a?(Repository)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def resolved_from_repo_flag(from_repo)
|
|
144
|
+
case from_repo
|
|
145
|
+
in Repository
|
|
146
|
+
[:from_repo, from_repo.url]
|
|
147
|
+
in String
|
|
148
|
+
[:from_repo, from_repo]
|
|
149
|
+
in [:file, String => path]
|
|
150
|
+
[:from_repository_file, path]
|
|
151
|
+
else
|
|
152
|
+
raise ArgumentError, "invalid from_repo shape"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def validate_password_shape!(value, name: "password")
|
|
157
|
+
case value
|
|
158
|
+
in nil
|
|
159
|
+
raise ArgumentError, "#{name}: is required (use :insecure_no_password if there truly is none)"
|
|
160
|
+
in :insecure_no_password | String | [:command, String] | [:file, String]
|
|
161
|
+
true
|
|
162
|
+
in callable if callable.respond_to?(:call)
|
|
163
|
+
true
|
|
164
|
+
else
|
|
165
|
+
raise ArgumentError, "invalid #{name} shape"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def validate_from_password_shape!(value)
|
|
170
|
+
validate_password_shape!(value, name: "from_password")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def validate_backend_credentials_shape!(value)
|
|
174
|
+
case value
|
|
175
|
+
in Hash
|
|
176
|
+
true
|
|
177
|
+
in callable if callable.respond_to?(:call)
|
|
178
|
+
true
|
|
179
|
+
else
|
|
180
|
+
raise ArgumentError, "invalid backend_credentials shape"
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
122
184
|
def extract_rest_credentials(url)
|
|
123
185
|
return [url, {}] unless url.start_with?("rest:")
|
|
124
186
|
|
|
@@ -139,6 +201,8 @@ module Yobi
|
|
|
139
201
|
restic_or_restic_path
|
|
140
202
|
in String | nil
|
|
141
203
|
Yobi::Restic.new(restic_or_restic_path)
|
|
204
|
+
else
|
|
205
|
+
raise ArgumentError, "invalid restic shape"
|
|
142
206
|
end
|
|
143
207
|
end
|
|
144
208
|
end
|
data/lib/yobi/restic.rb
CHANGED
|
@@ -262,7 +262,7 @@ module Yobi
|
|
|
262
262
|
self.class.dispatch(exit_code: status.exitstatus, output: output, argv: argv)
|
|
263
263
|
result
|
|
264
264
|
rescue Errno::ENOENT
|
|
265
|
-
output
|
|
265
|
+
output.file.close
|
|
266
266
|
raise Yobi::ResticNotFound.new(restic_path: restic_path, argv: argv)
|
|
267
267
|
end
|
|
268
268
|
|
|
@@ -324,7 +324,7 @@ module Yobi
|
|
|
324
324
|
_, status = Process.wait2(pid)
|
|
325
325
|
{exit_code: status.exitstatus, output: output, argv: argv}
|
|
326
326
|
rescue Errno::ENOENT
|
|
327
|
-
output
|
|
327
|
+
output.file.close
|
|
328
328
|
raise Yobi::ResticNotFound.new(restic_path: restic_path, argv: argv)
|
|
329
329
|
end
|
|
330
330
|
|
|
@@ -352,7 +352,7 @@ module Yobi
|
|
|
352
352
|
{exit_code: wait_thr.value.exitstatus, output: output, argv: argv}
|
|
353
353
|
end
|
|
354
354
|
rescue Errno::ENOENT
|
|
355
|
-
output
|
|
355
|
+
output.file.close
|
|
356
356
|
raise Yobi::ResticNotFound.new(restic_path: restic_path, argv: argv)
|
|
357
357
|
end
|
|
358
358
|
end
|
data/lib/yobi/version.rb
CHANGED
data/sig/yobi.rbs
CHANGED
|
@@ -221,6 +221,7 @@ module Yobi
|
|
|
221
221
|
type new_password = String | [:file, String] | :insecure_no_password | (^() -> String)
|
|
222
222
|
type backend_credentials = Hash[String, String] | (^() -> Hash[String, String])
|
|
223
223
|
type restic_or_path = Restic | String | nil
|
|
224
|
+
type from_repo = String | Repository | [:file, String]
|
|
224
225
|
|
|
225
226
|
class Restic
|
|
226
227
|
MINIMUM_VERSION: Gem::Version
|
|
@@ -295,7 +296,7 @@ module Yobi
|
|
|
295
296
|
def env: () -> Hash[String, String]
|
|
296
297
|
|
|
297
298
|
def init: (?copy_chunker_params: bool, ?from_key_hint: String?, ?from_password: from_password,
|
|
298
|
-
?from_repo:
|
|
299
|
+
?from_repo: from_repo?, ?repository_version: String?) -> Initialized
|
|
299
300
|
|
|
300
301
|
def init_mirror: (url: String, password: password, ?backend_credentials: backend_credentials,
|
|
301
302
|
?restic: restic_or_path, ?repository_version: String?) -> Repository
|
|
@@ -335,8 +336,8 @@ module Yobi
|
|
|
335
336
|
def check: (?hosts: Array[String] | String, ?paths: Array[String] | String, ?read_data: bool,
|
|
336
337
|
?read_data_subset: String?, ?tags: Array[String] | String, ?with_cache: bool) -> CheckOutcome
|
|
337
338
|
|
|
338
|
-
def copy: (from_repo:
|
|
339
|
-
?from_key_hint: String?, ?
|
|
339
|
+
def copy: (from_repo: from_repo, ?from_password: from_password, ?snapshot_ids: Array[String] | String,
|
|
340
|
+
?from_key_hint: String?, ?hosts: Array[String] | String,
|
|
340
341
|
?paths: Array[String] | String, ?tags: Array[String] | String) -> true
|
|
341
342
|
|
|
342
343
|
def diff: (from: String, to: String, ?metadata: bool) -> DiffOutcome
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yobi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zia Perdana
|
|
@@ -61,7 +61,7 @@ metadata:
|
|
|
61
61
|
homepage_uri: https://codeberg.org/ukazap/yobi
|
|
62
62
|
source_code_uri: https://codeberg.org/ukazap/yobi
|
|
63
63
|
changelog_uri: https://codeberg.org/ukazap/yobi/src/branch/main/CHANGELOG.md
|
|
64
|
-
documentation_uri: https://rubydoc.info/gems/yobi
|
|
64
|
+
documentation_uri: https://rubydoc.info/gems/yobi/0.3.1
|
|
65
65
|
rdoc_options: []
|
|
66
66
|
require_paths:
|
|
67
67
|
- lib
|