yobi 0.3.1 → 1.1.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +17 -0
  4. data/README.md +83 -44
  5. data/lib/yobi/argv_builder.rb +1 -35
  6. data/lib/yobi/cancellable_proxy.rb +48 -0
  7. data/lib/yobi/cancellation.rb +97 -0
  8. data/lib/yobi/errors.rb +45 -30
  9. data/lib/yobi/fancy_hash.rb +1 -5
  10. data/lib/yobi/io_handle.rb +9 -17
  11. data/lib/yobi/mount_handle.rb +7 -11
  12. data/lib/yobi/repository/backup.rb +59 -90
  13. data/lib/yobi/repository/cat.rb +23 -43
  14. data/lib/yobi/repository/check.rb +21 -34
  15. data/lib/yobi/repository/copy.rb +11 -13
  16. data/lib/yobi/repository/diff.rb +18 -49
  17. data/lib/yobi/repository/dump.rb +14 -15
  18. data/lib/yobi/repository/find.rb +17 -37
  19. data/lib/yobi/repository/forget.rb +35 -39
  20. data/lib/yobi/repository/init.rb +19 -24
  21. data/lib/yobi/repository/key.rb +18 -33
  22. data/lib/yobi/repository/list.rb +5 -6
  23. data/lib/yobi/repository/ls.rb +20 -43
  24. data/lib/yobi/repository/migrate.rb +6 -6
  25. data/lib/yobi/repository/mount.rb +22 -32
  26. data/lib/yobi/repository/prune.rb +11 -9
  27. data/lib/yobi/repository/recover.rb +2 -4
  28. data/lib/yobi/repository/repair.rb +16 -23
  29. data/lib/yobi/repository/restore.rb +31 -54
  30. data/lib/yobi/repository/rewrite.rb +15 -20
  31. data/lib/yobi/repository/snapshots.rb +7 -8
  32. data/lib/yobi/repository/stats.rb +26 -21
  33. data/lib/yobi/repository/tag.rb +23 -33
  34. data/lib/yobi/repository/unlock.rb +2 -4
  35. data/lib/yobi/repository.rb +96 -25
  36. data/lib/yobi/restic.rb +93 -114
  37. data/lib/yobi/restic_output.rb +2 -74
  38. data/lib/yobi/snapshot.rb +15 -27
  39. data/lib/yobi/version.rb +1 -2
  40. data/lib/yobi.rb +2 -0
  41. data/sig/yobi.rbs +83 -6
  42. metadata +5 -2
@@ -2,52 +2,41 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic cat config`: the repository's own config document.
6
- #
7
- # @return [Hash]
8
- # @raise [Yobi::RepositoryNotFound, Yobi::AuthenticationFailed]
5
+ # +restic cat config+: the repository's own config document, as a Hash.
6
+ # Raises Yobi::RepositoryNotFound or Yobi::AuthenticationFailed.
9
7
  def cat_config
10
8
  execution = run_restic(build_argv("cat", "config"))
11
9
  parse_json_output(execution)
12
10
  end
13
11
  alias_method :config, :cat_config
14
12
 
15
- # `restic cat snapshot ID`: one snapshot's own raw stored record.
16
- #
17
- # @param id [String, Yobi::Snapshot]
18
- # @return [Hash]
13
+ # +restic cat snapshot ID+: one snapshot's own raw stored record, as a
14
+ # Hash. +id+ can be a String or a Yobi::Snapshot.
19
15
  def cat_snapshot(id)
20
16
  id = id.id if id.is_a?(Yobi::Snapshot)
21
17
  execution = run_restic(build_argv("cat", "snapshot", id))
22
18
  parse_json_output(execution)
23
19
  end
24
20
 
25
- # `restic cat index ID`: one index file's own raw contents. IDs come
26
- # from `list(:index)`.
27
- #
28
- # @param id [String]
29
- # @return [Hash]
21
+ # +restic cat index ID+: one index file's own raw contents, as a Hash.
22
+ # IDs come from +list(:index)+.
30
23
  def cat_index(id)
31
24
  execution = run_restic(build_argv("cat", "index", id))
32
25
  parse_json_output(execution)
33
26
  end
34
27
 
35
- # `restic cat key ID`: one key's own raw stored record.
36
- #
37
- # @param id [String, Yobi::Key]
38
- # @return [Hash]
28
+ # +restic cat key ID+: one key's own raw stored record, as a Hash. +id+
29
+ # can be a String or a Yobi::Key.
39
30
  def cat_key(id)
40
31
  id = id.id if id.is_a?(Yobi::Key)
41
32
  execution = run_restic(build_argv("cat", "key", id))
42
33
  parse_json_output(execution)
43
34
  end
44
35
 
45
- # `restic cat tree snapshot:subfolder`: the raw tree object at a
46
- # snapshot's root, or at `subfolder` within it.
47
- #
48
- # @param snapshot_id [String, Yobi::Snapshot] also accepts Restic's own `"snapshotID:subfolder"` form directly
49
- # @param subfolder [String, nil]
50
- # @return [Hash]
36
+ # +restic cat tree snapshot:subfolder+: the raw tree object at a
37
+ # snapshot's root, or at +subfolder+ within it. +snapshot_id+ can be a
38
+ # String, a Yobi::Snapshot, or Restic's own +"snapshotID:subfolder"+
39
+ # form directly.
51
40
  def cat_tree(snapshot_id, subfolder: nil)
52
41
  snapshot_id = snapshot_id.id if snapshot_id.is_a?(Yobi::Snapshot)
53
42
  target = if subfolder.nil?
@@ -59,34 +48,25 @@ module Yobi
59
48
  parse_json_output(execution)
60
49
  end
61
50
 
62
- # `restic cat pack ID`: one pack file's raw, still-encrypted bytes.
63
- # IDs come from `list(:packs)`. Same block/handle shape as {#dump}.
64
- #
65
- # @param id [String]
66
- # @yieldparam io [IO]
67
- # @return [Yobi::IOHandle] if no block is given
51
+ # +restic cat pack ID+: one pack file's raw, still-encrypted bytes. IDs
52
+ # come from +list(:packs)+. Same block/handle shape as #dump: without a
53
+ # block, returns a Yobi::IOHandle.
68
54
  def cat_pack(id, &block)
69
55
  run_restic_dump(build_argv("cat", "pack", id), &block)
70
56
  end
71
57
 
72
- # `restic cat blob ID`: one data blob's raw, decrypted bytes. IDs come
73
- # from {#cat_tree}'s own node `"content"` arrays. Same block/handle
74
- # shape as {#dump}.
75
- #
76
- # @param id [String]
77
- # @yieldparam io [IO]
78
- # @return [Yobi::IOHandle] if no block is given
58
+ # +restic cat blob ID+: one data blob's raw, decrypted bytes. IDs come
59
+ # from #cat_tree's own node +"content"+ arrays. Same block/handle shape
60
+ # as #dump.
79
61
  def cat_blob(id, &block)
80
62
  run_restic_dump(build_argv("cat", "blob", id), &block)
81
63
  end
82
64
 
83
- # `restic cat masterkey`: this repository's own encryption/MAC key
84
- # material. Extremely sensitive: this is the actual key, not a
85
- # redacted reference to it, and there is no operation that rotates it;
86
- # every other key/password management method here only manages
87
- # different ways to unlock this same master key.
88
- #
89
- # @return [Hash]
65
+ # +restic cat masterkey+: this repository's own encryption/MAC key
66
+ # material. Extremely sensitive: this is the actual key, not a redacted
67
+ # reference to it, and there is no operation that rotates it; every
68
+ # other key/password management method here only manages different ways
69
+ # to unlock this same master key.
90
70
  def cat_masterkey_and_game_over_if_this_leaks
91
71
  execution = run_restic(build_argv("cat", "masterkey"))
92
72
  parse_json_output(execution)
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic check`: tests the repository for errors.
5
+ # +restic check+: tests the repository for errors.
6
6
  #
7
- # @param hosts [Array<String>, String] filter by hostname(s)
8
- # @param paths [Array<String>, String] filter by originally backed-up path(s)
9
- # @param read_data [Boolean] read and verify pack file contents, not just structure
10
- # @param read_data_subset [String, nil] read and verify only a subset of packs, e.g. `"5%"`
11
- # @param tags [Array<String>, String] filter by tag(s)
12
- # @param with_cache [Boolean] use the local cache
13
- # @return [Yobi::CheckOutcome]
7
+ # +hosts:+, +paths:+ and +tags:+ each accept a single value or an Array
8
+ # to filter by.
9
+ #
10
+ # +read_data:+ reads and verifies pack file contents, not just structure.
11
+ # +read_data_subset:+ narrows that to a subset of packs, e.g. +"5%"+.
12
+ # +with_cache:+ uses the local cache.
13
+ #
14
+ # Returns a Yobi::CheckOutcome.
14
15
  def check(hosts: [], paths: [], read_data: false, read_data_subset: nil, tags: [], with_cache: false)
15
16
  argv = build_argv("check") do |a|
16
17
  a.repeat_flag(:host, hosts)
@@ -26,16 +27,7 @@ module Yobi
26
27
  end
27
28
  end
28
29
 
29
- # Classifies a raw check message Hash by its own message_type, wrapping
30
- # it in the matching typed class. Used both as the {Yobi::ResticOutput}
31
- # `transform:` for {Yobi::Repository#check} and by {Yobi::CheckOutcome}'s
32
- # own post-hoc accessors.
33
- #
34
- # @private
35
- module CheckMessageWrapper
36
- # @param raw [Hash]
37
- # @return [Yobi::CheckError, Yobi::CheckSummary, Hash]
38
- # the raw Hash itself for a message_type this version of Yobi doesn't recognize
30
+ module CheckMessageWrapper # :nodoc:
39
31
  def self.call(raw)
40
32
  case raw["message_type"]
41
33
  when "error" then CheckError.new(raw)
@@ -45,28 +37,26 @@ module Yobi
45
37
  end
46
38
  end
47
39
 
48
- # The outcome of one {Yobi::Repository#check} call.
40
+ # The outcome of one Yobi::Repository#check call.
49
41
  class CheckOutcome
50
- # @return [Yobi::ResticOutput]
42
+ # The Yobi::ResticOutput backing this outcome.
51
43
  attr_reader :output
52
44
 
53
- # @private
54
- def initialize(execution)
45
+ def initialize(execution) # :nodoc:
55
46
  @output = execution[:output]
56
47
  end
57
48
 
58
- # @return [Yobi::CheckSummary] Restic's own `"summary"` fields
49
+ # The Yobi::CheckSummary of Restic's own +"summary"+ fields.
59
50
  def summary
60
51
  @summary ||= output.messages("summary").first || CheckSummary.new({})
61
52
  end
62
53
  alias_method :report, :summary
63
54
 
64
- # @return [Enumerable<Yobi::CheckError>]
55
+ # Every Yobi::CheckError from the run.
65
56
  def errors
66
57
  @errors ||= output.messages("error")
67
58
  end
68
59
 
69
- # @return [void]
70
60
  def pretty_print(q)
71
61
  q.object_group(self) do
72
62
  q.breakable
@@ -77,34 +67,31 @@ module Yobi
77
67
  end
78
68
  end
79
69
 
80
- # One `"error"` message from a check run.
81
- # https://restic.readthedocs.io/en/stable/075_scripting.html#error
70
+ # One +"error"+ message from a check run.
82
71
  class CheckError < Yobi::FancyHash
83
- # @return [String]
84
72
  def message
85
73
  self["message"]
86
74
  end
87
75
  end
88
76
 
89
- # The `"summary"` message from a check run, the final result once the
90
- # command finishes. Dispatched to {Yobi::CheckOutcome#summary}.
77
+ # The +"summary"+ message from a check run, the final result once the
78
+ # command finishes. Dispatched to Yobi::CheckOutcome#summary.
91
79
  class CheckSummary < Yobi::FancyHash
92
- # @return [Integer]
93
80
  def num_errors
94
81
  self["num_errors"] || 0
95
82
  end
96
83
 
97
- # @return [Array<String>] pack IDs needing `repair_packs`/`repair_snapshots`
84
+ # Pack IDs needing #repair_packs / #repair_snapshots.
98
85
  def broken_packs
99
86
  self["broken_packs"] || []
100
87
  end
101
88
 
102
- # @return [Boolean] whether to run {Yobi::Repository#repair_index}
89
+ # Whether to run Yobi::Repository#repair_index.
103
90
  def suggest_repair_index?
104
91
  self["suggest_repair_index"]
105
92
  end
106
93
 
107
- # @return [Boolean] whether to run {Yobi::Repository#prune}
94
+ # Whether to run Yobi::Repository#prune.
108
95
  def suggest_prune?
109
96
  self["suggest_prune"]
110
97
  end
@@ -2,20 +2,18 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic copy`: replicates snapshots from another repository into
6
- # this one. Already-copied snapshots are skipped automatically.
5
+ # +restic copy+: replicates snapshots from another repository into this
6
+ # one. Already-copied snapshots are skipped automatically.
7
7
  #
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
11
- # @param from_password [String, Array, Symbol, #call, nil] the source
12
- # repository's password, same shape as {#initialize}'s `password:`
13
- # @param snapshot_ids [Array<String>, String] snapshots to copy; all of them if empty
14
- # @param from_key_hint [String, nil]
15
- # @param hosts [Array<String>, String] filter by hostname(s)
16
- # @param paths [Array<String>, String] filter by originally backed-up path(s)
17
- # @param tags [Array<String>, String] filter by tag(s)
18
- # @return [true]
8
+ # +from_repo:+ is the source repository's URL, a Yobi::Repository (its
9
+ # own #url/#password are used automatically), or a +[:file, "..."]+
10
+ # tuple reading the URL from a file. +from_password:+ takes the same
11
+ # shape as #initialize's +password:+, and defaults to the source
12
+ # Repository's own password when +from_repo:+ is one.
13
+ #
14
+ # +snapshot_ids:+ names the snapshots to copy; all of them if empty.
15
+ # +hosts:+, +paths:+, and +tags:+ each accept a single value or an
16
+ # Array to filter by.
19
17
  def copy(from_repo:, from_password: nil, snapshot_ids: [], from_key_hint: nil, hosts: [], paths: [], tags: [])
20
18
  from_repo_flag, from_repo_value = resolved_from_repo_flag(from_repo)
21
19
  from_password = from_repo_password(from_repo) if from_password.nil?
@@ -2,12 +2,9 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic diff`: compares two snapshots.
6
- #
7
- # @param from [String] snapshot ID
8
- # @param to [String] snapshot ID
9
- # @param metadata [Boolean] also report metadata-only changes (access mode, timestamps, ...)
10
- # @return [Yobi::DiffOutcome]
5
+ # +restic diff+: compares two snapshots, +from:+ and +to:+ (both
6
+ # snapshot IDs). +metadata: true+ also reports metadata-only changes
7
+ # (access mode, timestamps, ...). Returns a Yobi::DiffOutcome.
11
8
  def diff(from:, to:, metadata: false)
12
9
  argv = build_argv("diff", from, to) do |a|
13
10
  a.flag(:metadata) if metadata
@@ -18,16 +15,7 @@ module Yobi
18
15
  end
19
16
  end
20
17
 
21
- # Classifies a raw diff message Hash by its own message_type, wrapping
22
- # it in the matching typed class. Used both as the {Yobi::ResticOutput}
23
- # `transform:` for {Yobi::Repository#diff} and by {Yobi::DiffOutcome}'s
24
- # own post-hoc accessors.
25
- #
26
- # @private
27
- module DiffMessageWrapper
28
- # @param raw [Hash]
29
- # @return [Yobi::DiffChange, Yobi::DiffStatistics, Hash]
30
- # the raw Hash itself for a message_type this version of Yobi doesn't recognize
18
+ module DiffMessageWrapper # :nodoc:
31
19
  def self.call(raw)
32
20
  case raw["message_type"]
33
21
  when "change" then DiffChange.new(raw)
@@ -37,28 +25,26 @@ module Yobi
37
25
  end
38
26
  end
39
27
 
40
- # The outcome of one {Yobi::Repository#diff} call.
28
+ # The outcome of one Yobi::Repository#diff call.
41
29
  class DiffOutcome
42
- # @return [Yobi::ResticOutput]
30
+ # The Yobi::ResticOutput backing this outcome.
43
31
  attr_reader :output
44
32
 
45
- # @private
46
- def initialize(execution)
33
+ def initialize(execution) # :nodoc:
47
34
  @output = execution[:output]
48
35
  end
49
36
 
50
- # @return [Yobi::DiffStatistics] Restic's own `"statistics"` fields
37
+ # The Yobi::DiffStatistics of Restic's own +"statistics"+ fields.
51
38
  def statistics
52
39
  @statistics ||= output.messages("statistics").first || DiffStatistics.new({})
53
40
  end
54
41
  alias_method :report, :statistics
55
42
 
56
- # @return [Enumerable<Yobi::DiffChange>]
43
+ # Every Yobi::DiffChange from the run.
57
44
  def changes
58
45
  @changes ||= output.messages("change")
59
46
  end
60
47
 
61
- # @return [void]
62
48
  def pretty_print(q)
63
49
  q.object_group(self) do
64
50
  q.breakable
@@ -67,109 +53,92 @@ module Yobi
67
53
  end
68
54
  end
69
55
 
70
- # One `"change"` message from a diff run. `modifier` is Restic's own
71
- # concatenation of single-character codes: `"+"` added, `"-"` removed,
72
- # `"U"` metadata updated, `"M"` content modified, `"T"` type changed,
73
- # `"?"` bitrot detected.
56
+ # One +"change"+ message from a diff run. #modifier is Restic's own
57
+ # concatenation of single-character codes: +"+"+ added, +"-"+ removed,
58
+ # +"U"+ metadata updated, +"M"+ content modified, +"T"+ type changed,
59
+ # +"?"+ bitrot detected.
74
60
  class DiffChange < Yobi::FancyHash
75
- # @return [String]
76
61
  def path
77
62
  self["path"]
78
63
  end
79
64
 
80
- # @return [String]
81
65
  def modifier
82
66
  self["modifier"]
83
67
  end
84
68
 
85
- # @return [Boolean]
86
69
  def added?
87
70
  modifier.include?("+")
88
71
  end
89
72
 
90
- # @return [Boolean]
91
73
  def removed?
92
74
  modifier.include?("-")
93
75
  end
94
76
 
95
- # @return [Boolean]
96
77
  def type_changed?
97
78
  modifier.include?("T")
98
79
  end
99
80
 
100
- # @return [Boolean]
101
81
  def modified?
102
82
  modifier.include?("M")
103
83
  end
104
84
 
105
- # @return [Boolean]
106
85
  def metadata_updated?
107
86
  modifier.include?("U")
108
87
  end
109
88
 
110
- # @return [Boolean]
111
89
  def bitrot?
112
90
  modifier.include?("?")
113
91
  end
114
92
  end
115
93
 
116
- # The `"statistics"` message from a diff run, the final result once the
117
- # command finishes. Dispatched to {Yobi::DiffOutcome#statistics}.
94
+ # The +"statistics"+ message from a diff run, the final result once the
95
+ # command finishes. Dispatched to Yobi::DiffOutcome#statistics.
118
96
  class DiffStatistics < Yobi::FancyHash
119
- # @return [String, nil]
120
97
  def source_snapshot
121
98
  self["source_snapshot"]
122
99
  end
123
100
 
124
- # @return [String, nil]
125
101
  def target_snapshot
126
102
  self["target_snapshot"]
127
103
  end
128
104
 
129
- # @return [Integer]
130
105
  def changed_files
131
106
  self["changed_files"] || 0
132
107
  end
133
108
 
134
- # @return [Yobi::DiffStat]
109
+ # A Yobi::DiffStat of what was added.
135
110
  def added
136
111
  @added ||= DiffStat.new(self["added"] || {})
137
112
  end
138
113
 
139
- # @return [Yobi::DiffStat]
114
+ # A Yobi::DiffStat of what was removed.
140
115
  def removed
141
116
  @removed ||= DiffStat.new(self["removed"] || {})
142
117
  end
143
118
  end
144
119
 
145
- # The `"added"`/`"removed"` sub-object of a {Yobi::DiffStatistics} message.
120
+ # The +"added"+ / +"removed"+ sub-object of a Yobi::DiffStatistics message.
146
121
  class DiffStat < Yobi::FancyHash
147
- # @return [Integer]
148
122
  def files
149
123
  self["files"] || 0
150
124
  end
151
125
 
152
- # @return [Integer]
153
126
  def dirs
154
127
  self["dirs"] || 0
155
128
  end
156
129
 
157
- # @return [Integer]
158
130
  def others
159
131
  self["others"] || 0
160
132
  end
161
133
 
162
- # @return [Integer]
163
134
  def data_blobs
164
135
  self["data_blobs"] || 0
165
136
  end
166
137
 
167
- # @return [Integer]
168
138
  def tree_blobs
169
139
  self["tree_blobs"] || 0
170
140
  end
171
141
 
172
- # @return [Integer]
173
142
  def bytes
174
143
  self["bytes"] || 0
175
144
  end
@@ -4,24 +4,23 @@ require "tempfile"
4
4
 
5
5
  module Yobi
6
6
  class Repository
7
- # @private
8
- ARCHIVE_TYPES = Set.new(%w[tar zip].flat_map { [_1, _1.to_sym] }).freeze
7
+ ARCHIVE_TYPES = Set.new(%w[tar zip].flat_map { [_1, _1.to_sym] }).freeze # :nodoc:
9
8
 
10
- # `restic dump`: extracts a file/folder from a snapshot. A single file's
9
+ # +restic dump+: extracts a file/folder from a snapshot. A single file's
11
10
  # raw bytes are written as-is; a folder is written as a tar/zip archive.
12
- # Give at most one of `target:` or a block.
11
+ # Give at most one of +target:+ or a block.
13
12
  #
14
- # @param snapshot_id [String] also accepts Restic's own `"snapshotID:subfolder"` form directly
15
- # @param file [String] path within the snapshot to extract; `"/"` dumps the whole snapshot
16
- # @param target [String, nil] write straight to this file path instead of yielding a block
17
- # @param archive [String, Symbol, nil] `"tar"` (default) or `"zip"`, when `file` is a folder
18
- # @param hosts [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
19
- # @param paths [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
20
- # @param tags [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
21
- # @yieldparam io [IO]
22
- # @return [true] if `target:` was given
23
- # @return [Yobi::IOHandle] if no block is given
24
- # @raise [ArgumentError] if given both `target:` and a block
13
+ # +snapshot_id:+ is a snapshot ID, or Restic's own
14
+ # +"snapshotID:subfolder"+ form. +file:+ is the path within the snapshot
15
+ # to extract; +"/"+ dumps the whole snapshot. +archive:+ is +"tar"+
16
+ # (default) or +"zip"+, and only applies when +file+ is a folder.
17
+ #
18
+ # +hosts:+, +paths:+ and +tags:+ are only relevant when +snapshot_id+
19
+ # is +"latest"+.
20
+ #
21
+ # With +target:+, writes straight to that file path and returns +true+.
22
+ # Without a block, returns a Yobi::IOHandle. Raises ArgumentError if
23
+ # given both +target:+ and a block.
25
24
  def dump(snapshot_id:, file:, target: nil, archive: nil, hosts: [], paths: [], tags: [], &block)
26
25
  raise ArgumentError, "give at most one of target: or a block, not both" if target && block
27
26
 
@@ -4,25 +4,20 @@ require "time"
4
4
 
5
5
  module Yobi
6
6
  class Repository
7
- # `restic find`: searches for files/directories across snapshots by
7
+ # +restic find+: searches for files/directories across snapshots by
8
8
  # name pattern.
9
9
  #
10
- # @param patterns [Array<String>, String] glob patterns to match
11
- # @param blob [Boolean] match blob IDs instead of file names
12
- # @param pack [Boolean] match pack IDs instead of file names
13
- # @param tree [Boolean] match tree IDs instead of file names
14
- # @param hosts [Array<String>, String] filter by hostname(s)
15
- # @param human_readable [Boolean] format sizes for humans
16
- # @param ignore_case [Boolean] case-insensitive matching
17
- # @param long [Boolean] include long listing format
18
- # @param newest [String, nil] only consider snapshots at or before this time
19
- # @param oldest [String, nil] only consider snapshots at or after this time
20
- # @param paths [Array<String>, String] filter by originally backed-up path(s)
21
- # @param reverse [Boolean] reverse sort order
22
- # @param show_pack_id [Boolean] include the pack ID each match is stored in
23
- # @param snapshot_ids [Array<String>, String] restrict to these snapshot ID(s)
24
- # @param tags [Array<String>, String] filter by tag(s)
25
- # @return [Array<Yobi::MatchesPerSnapshot>]
10
+ # +patterns:+ accepts a single glob or an Array. +blob:+, +pack:+ and
11
+ # +tree:+ match blob/pack/tree IDs instead of file names.
12
+ #
13
+ # +hosts:+, +paths:+, +snapshot_ids:+, and +tags:+ each accept a single
14
+ # value or an Array to filter by. +newest:+ / +oldest:+ restrict the
15
+ # snapshot window.
16
+ #
17
+ # +ignore_case:+, +long:+, +human_readable:+, +reverse:+ and
18
+ # +show_pack_id:+ toggle formatting/matching options.
19
+ #
20
+ # Returns an Array of Yobi::MatchesPerSnapshot.
26
21
  def find(patterns:, blob: false, pack: false, tree: false, hosts: [], human_readable: false,
27
22
  ignore_case: false, long: false, newest: nil, oldest: nil, paths: [], reverse: false,
28
23
  show_pack_id: false, snapshot_ids: [], tags: [])
@@ -48,88 +43,73 @@ module Yobi
48
43
  end
49
44
  end
50
45
 
51
- # One matched file/directory from a {Yobi::Repository#find} call.
46
+ # One matched file/directory from a Yobi::Repository#find call.
52
47
  class FindMatch < Yobi::FancyHash
53
- # @return [String]
54
48
  def path
55
49
  self["path"]
56
50
  end
57
51
 
58
- # @return [String]
59
52
  def type
60
53
  self["type"]
61
54
  end
62
55
 
63
- # @return [Integer]
64
56
  def size
65
57
  self["size"]
66
58
  end
67
59
 
68
- # @return [String]
69
60
  def permissions
70
61
  self["permissions"]
71
62
  end
72
63
 
73
- # @return [Integer]
74
64
  def uid
75
65
  self["uid"]
76
66
  end
77
67
 
78
- # @return [Integer]
79
68
  def gid
80
69
  self["gid"]
81
70
  end
82
71
 
83
- # @return [String]
84
72
  def user
85
73
  self["user"]
86
74
  end
87
75
 
88
- # @return [String]
89
76
  def group
90
77
  self["group"]
91
78
  end
92
79
 
93
- # @return [Integer]
94
80
  def inode
95
81
  self["inode"]
96
82
  end
97
83
 
98
- # @return [Time]
99
84
  def mtime
100
85
  @mtime ||= Time.parse(self["mtime"])
101
86
  end
102
87
 
103
- # @return [Time]
104
88
  def atime
105
89
  @atime ||= Time.parse(self["atime"])
106
90
  end
107
91
 
108
- # @return [Time]
109
92
  def ctime
110
93
  @ctime ||= Time.parse(self["ctime"])
111
94
  end
112
95
  end
113
96
 
114
- # One snapshot's worth of matches from a {Yobi::Repository#find} call.
97
+ # One snapshot's worth of matches from a Yobi::Repository#find call.
115
98
  class MatchesPerSnapshot < Yobi::FancyHash
116
- # Restic's own `find --json` output only gives the snapshot's ID here,
99
+ # Restic's own +find --json+ output only gives the snapshot's ID here,
117
100
  # not a full record - unlike every other place in this API where
118
- # "snapshot" means a {Yobi::Snapshot}. Call {Yobi::Repository#snapshots}
101
+ # "snapshot" means a Yobi::Snapshot. Call Yobi::Repository#snapshots
119
102
  # yourself if you need the full record.
120
- #
121
- # @return [String]
122
103
  def snapshot
123
104
  self["snapshot"]
124
105
  end
125
106
  alias_method :snapshot_id, :snapshot
126
107
 
127
- # @return [Integer]
128
108
  def hits
129
109
  self["hits"]
130
110
  end
131
111
 
132
- # @return [Array<Yobi::FindMatch>]
112
+ # An Array of Yobi::FindMatch objects for this snapshot.
133
113
  def matches
134
114
  @matches ||= (self["matches"] || []).map { |raw| Yobi::FindMatch.new(raw) }
135
115
  end