yobi 0.3.0 → 1.0.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.
data/lib/yobi/restic.rb CHANGED
@@ -7,87 +7,68 @@ module Yobi
7
7
  # A specific Restic binary, plus its process-level settings that apply
8
8
  # regardless of which repository is being operated on.
9
9
  # Repository-specific identity (url, credentials) lives on
10
- # {Yobi::Repository} instead.
10
+ # Yobi::Repository instead.
11
11
  class Restic
12
- # The oldest Restic version {#run}/{#run_dump}/{#run_mount} verify the
12
+ # The oldest Restic version #run/#run_dump/#run_mount verify the
13
13
  # installed binary meets before executing a real command. See
14
- # {Yobi::UnsupportedResticVersion}.
15
- MINIMUM_VERSION = Gem::Version.new("0.17.1")
14
+ # Yobi::UnsupportedResticVersion.
15
+ MINIMUM_VERSION = Gem::Version.new("0.18.0") # :nodoc:
16
16
 
17
- # Env vars {#inspect} shows in the clear; anything else is redacted.
18
- ALLOWED_ENV_VARS = %w[
17
+ # Env vars #inspect shows in the clear; anything else is redacted.
18
+ ALLOWED_ENV_VARS = %w[ # :nodoc:
19
19
  RESTIC_REPOSITORY RESTIC_CACHE_DIR RESTIC_COMPRESSION RESTIC_PACK_SIZE
20
20
  RESTIC_READ_CONCURRENCY RESTIC_HOST RESTIC_PROGRESS_FPS RESTIC_CACERT
21
21
  RESTIC_TLS_CLIENT_CERT RESTIC_KEY_HINT TMPDIR TMP AWS_DEFAULT_REGION
22
22
  AWS_SHARED_CREDENTIALS_FILE AZURE_ENDPOINT_SUFFIX AZURE_FORCE_CLI_CREDENTIAL
23
- RCLONE_BWLIMIT
24
- ].to_set.freeze
23
+ RCLONE_BWLIMIT].to_set.freeze
25
24
 
26
- # @return [String] path to the Restic binary
27
- attr_reader :restic_path
28
- # @return [String, nil] `$RESTIC_CACHE_DIR`
25
+ # Path to the Restic binary.
26
+ attr_accessor :restic_path
27
+ # +$RESTIC_CACHE_DIR+
29
28
  attr_accessor :cache_dir
30
- # @return [String, nil] `$RESTIC_COMPRESSION`
29
+ # +$RESTIC_COMPRESSION+
31
30
  attr_accessor :compression
32
- # @return [Integer, nil] `$RESTIC_PACK_SIZE`
31
+ # +$RESTIC_PACK_SIZE+
33
32
  attr_accessor :pack_size
34
- # @return [Integer, nil] `$RESTIC_READ_CONCURRENCY`
33
+ # +$RESTIC_READ_CONCURRENCY+
35
34
  attr_accessor :read_concurrency
36
- # @return [String, nil] `$RESTIC_HOST`
35
+ # +$RESTIC_HOST+
37
36
  attr_accessor :host
38
- # @return [Integer, nil] `$RESTIC_PROGRESS_FPS`
37
+ # +$RESTIC_PROGRESS_FPS+
39
38
  attr_accessor :progress_fps
40
- # @return [String, nil] `$RESTIC_CACERT`
39
+ # +$RESTIC_CACERT+
41
40
  attr_accessor :cacert
42
- # @return [String, nil] `$RESTIC_TLS_CLIENT_CERT`
41
+ # +$RESTIC_TLS_CLIENT_CERT+
43
42
  attr_accessor :tls_client_cert
44
- # @return [String, nil] `$RESTIC_KEY_HINT`
43
+ # +$RESTIC_KEY_HINT+
45
44
  attr_accessor :key_hint
46
- # @return [String, nil] `--limit-download`
45
+ # +--limit-download+
47
46
  attr_accessor :limit_download
48
- # @return [String, nil] `--limit-upload`
47
+ # +--limit-upload+
49
48
  attr_accessor :limit_upload
50
- # @return [String, nil] `--retry-lock`
49
+ # +--retry-lock+
51
50
  attr_accessor :retry_lock
52
- # @return [Boolean] `--no-lock`
51
+ # +--no-lock+
53
52
  attr_accessor :no_lock
54
- # @return [Boolean] `--no-cache`
53
+ # +--no-cache+
55
54
  attr_accessor :no_cache
56
- # @return [Boolean] `--cleanup-cache`
55
+ # +--cleanup-cache+
57
56
  attr_accessor :cleanup_cache
58
- # @return [Boolean] `--no-extra-verify`
57
+ # +--no-extra-verify+
59
58
  attr_accessor :no_extra_verify
60
- # @return [String, nil] `--stuck-request-timeout`
59
+ # +--stuck-request-timeout+
61
60
  attr_accessor :stuck_request_timeout
62
- # @return [Array<String>] `--option`, one per element
61
+ # +--option+, one per element.
63
62
  attr_accessor :options
64
- # @return [String, nil] `--http-user-agent`
63
+ # +--http-user-agent+
65
64
  attr_accessor :http_user_agent
66
- # @return [Boolean] `--quiet`
65
+ # +--quiet+
67
66
  attr_accessor :quiet
68
67
 
69
- # @param restic_path [String, nil] defaults to `$RESTIC_PATH`, then `"restic"`
70
- # @param env [Hash{String => String}] extra env vars, merged over the named settings below
71
- # @param cache_dir [String, nil]
72
- # @param compression [String, nil]
73
- # @param pack_size [Integer, nil]
74
- # @param read_concurrency [Integer, nil]
75
- # @param host [String, nil]
76
- # @param progress_fps [Integer, nil]
77
- # @param cacert [String, nil]
78
- # @param tls_client_cert [String, nil]
79
- # @param key_hint [String, nil]
80
- # @param limit_download [String, nil]
81
- # @param limit_upload [String, nil]
82
- # @param retry_lock [String, nil]
83
- # @param no_lock [Boolean]
84
- # @param no_cache [Boolean]
85
- # @param cleanup_cache [Boolean]
86
- # @param no_extra_verify [Boolean]
87
- # @param stuck_request_timeout [String, nil]
88
- # @param options [Array<String>]
89
- # @param http_user_agent [String, nil]
90
- # @param quiet [Boolean]
68
+ # Builds a Restic executor. +restic_path+ defaults to +$RESTIC_PATH+,
69
+ # then +"restic"+. +env:+ is extra env vars merged over the named
70
+ # settings below (env-var-backed accessors like +cache_dir:+,
71
+ # +compression:+, etc.).
91
72
  def initialize(restic_path = nil, env: {}, cache_dir: nil, compression: nil, pack_size: nil,
92
73
  read_concurrency: nil, host: nil, progress_fps: nil, cacert: nil, tls_client_cert: nil,
93
74
  key_hint: nil, limit_download: nil, limit_upload: nil, retry_lock: nil, no_lock: false,
@@ -118,10 +99,8 @@ module Yobi
118
99
  end
119
100
 
120
101
  # The env-var-backed settings above, computed fresh from their current
121
- # accessor values on every call. `env:` given at construction wins over
102
+ # accessor values on every call. +env:+ given at construction wins over
122
103
  # any of these on key collision.
123
- #
124
- # @return [Hash{String => String}]
125
104
  def env
126
105
  {
127
106
  "RESTIC_CACHE_DIR" => cache_dir,
@@ -137,12 +116,9 @@ module Yobi
137
116
  end
138
117
 
139
118
  # Appends the CLI-only global flags (the ones above with no env var
140
- # equivalent) to a builder. Called from both {#build_argv} and
141
- # `Repository#build_argv`.
142
- #
143
- # @param a [Yobi::ArgvBuilder]
144
- # @return [void]
145
- def append_global_flags(a)
119
+ # equivalent) to a builder. Called from both #build_argv and
120
+ # Repository#build_argv.
121
+ def append_global_flags(a) # :nodoc:
146
122
  a.flag(:limit_download, limit_download) unless limit_download.nil?
147
123
  a.flag(:limit_upload, limit_upload) unless limit_upload.nil?
148
124
  a.flag(:retry_lock, retry_lock) unless retry_lock.nil?
@@ -156,26 +132,22 @@ module Yobi
156
132
  a.flag(:quiet) if quiet
157
133
  end
158
134
 
159
- # @return [String]
135
+ # Redacts sensitive env values so a stray +pp+/+puts+/log call never
136
+ # prints a credential in plaintext.
160
137
  def inspect
161
138
  "#<#{self.class} restic_path=#{restic_path.inspect} env=#{redacted_env.inspect}>"
162
139
  end
163
140
 
164
- # `restic version`: the installed binary's own version info.
165
- #
166
- # @return [Yobi::ResticVersion]
141
+ # +restic version+: the installed binary's own version info. Returns a
142
+ # Yobi::ResticVersion.
167
143
  def version
168
144
  execution = run(build_argv("version"), skip_version_check: true)
169
145
  Yobi::ResticVersion.new(parse_version_output(execution[:output].to_s))
170
146
  end
171
147
 
172
- # `restic cache`: lists and optionally cleans local cache directories.
173
- # Not repository-scoped.
174
- #
175
- # @param cleanup [Boolean] `--cleanup`
176
- # @param max_age [String, nil] `--max-age`
177
- # @param no_size [Boolean] `--no-size`
178
- # @return [true]
148
+ # +restic cache+: lists and optionally cleans local cache directories.
149
+ # Not repository-scoped. +cleanup:+ triggers +--cleanup+, +max_age:+
150
+ # sets +--max-age+, +no_size:+ triggers +--no-size+. Returns +true+.
179
151
  def cache(cleanup: false, max_age: nil, no_size: false)
180
152
  argv = build_argv("cache") do |a|
181
153
  a.flag(:cleanup) if cleanup
@@ -186,19 +158,19 @@ module Yobi
186
158
  true
187
159
  end
188
160
 
189
- # Runs argv against this Restic binary, merging extra_env with this
190
- # instance's own global env.
161
+ # Runs +argv+ against this Restic binary, merging +extra_env:+ with
162
+ # this instance's own global env. +output:+ takes a caller-configured
163
+ # Yobi::ResticOutput (e.g. with its own +transform:+); passing one forces
164
+ # streaming even without a block. When a block is given, each parsed
165
+ # message is yielded live as the command runs.
191
166
  #
192
- # @param argv [Array<String>]
193
- # @param extra_env [Hash{String => String}]
194
- # @param skip_version_check [Boolean] used internally by {#version} to avoid recursing into {#ensure_minimum_version!}
195
- # @param output [Yobi::ResticOutput, nil] a caller-configured one (e.g. with its own `transform:`),
196
- # used instead of a plain one this creates itself; forces streaming even without a block
197
- # @yieldparam message [Object] each message, live, as the command runs - transformed via
198
- # `output`'s own `transform:` if it has one, the raw parsed Hash otherwise
199
- # @return [Hash] `{exit_code:, output:, argv:}` on exit code 0/3
200
- # @raise [Yobi::RepositoryNotFound, Yobi::RepositoryLocked, Yobi::AuthenticationFailed, Yobi::ResticCommandFailed]
201
- def run(argv, extra_env: {}, skip_version_check: false, output: nil, &block)
167
+ # +skip_version_check:+ is used internally by #version to avoid recursing
168
+ # into #ensure_minimum_version!
169
+ #
170
+ # Returns +{exit_code:, output:, argv:}+ on exit code 0 or 3.
171
+ # Raises Yobi::RepositoryNotFound, Yobi::RepositoryLocked,
172
+ # Yobi::AuthenticationFailed, or Yobi::ResticCommandFailed otherwise.
173
+ def run(argv, extra_env: {}, skip_version_check: false, output: nil, &block) # :nodoc:
202
174
  ensure_minimum_version! unless skip_version_check
203
175
  execution = if output || block
204
176
  execute_with_streaming(argv, extra_env, output: output, &block)
@@ -208,10 +180,9 @@ module Yobi
208
180
  self.class.dispatch(execution)
209
181
  end
210
182
 
211
- # @param execution [Hash] `{exit_code:, output:, argv:}`
212
- # @return [Hash] `execution`, unchanged, on exit code 0/3
213
- # @raise [Yobi::RepositoryNotFound, Yobi::RepositoryLocked, Yobi::AuthenticationFailed, Yobi::ResticCommandFailed]
214
- def self.dispatch(execution)
183
+ # Maps Restic's exit codes to Yobi's typed errors. Returns +execution+
184
+ # unchanged on 0/3.
185
+ def self.dispatch(execution) # :nodoc:
215
186
  case execution[:exit_code]
216
187
  when 0, 3
217
188
  execution
@@ -227,21 +198,15 @@ module Yobi
227
198
  end
228
199
 
229
200
  # For commands whose success output is raw bytes with no JSON message
230
- # framing (currently only `Repository#dump`). Spawns Restic with
231
- # stdout wired to a pipe.
201
+ # framing (currently only Repository#dump). Spawns Restic with stdout
202
+ # wired to a pipe.
232
203
  #
233
- # Without a block, returns a {Yobi::IOHandle} immediately; closing,
204
+ # Without a block, returns a Yobi::IOHandle immediately; closing,
234
205
  # reaping, and exit-code dispatch are the caller's own responsibility.
235
206
  # With one, yields the pipe's read end; it's always closed and the
236
207
  # process always reaped once the block returns or raises, before any
237
208
  # exit-code dispatch runs.
238
- #
239
- # @param argv [Array<String>]
240
- # @param extra_env [Hash{String => String}]
241
- # @yieldparam io [IO]
242
- # @return [Yobi::IOHandle] if no block is given
243
- # @return [Object] the block's own return value, otherwise
244
- def run_dump(argv, extra_env: {})
209
+ def run_dump(argv, extra_env: {}) # :nodoc:
245
210
  ensure_minimum_version!
246
211
  output = Yobi::ResticOutput.new
247
212
  read_end, write_end = IO.pipe
@@ -266,13 +231,11 @@ module Yobi
266
231
  raise Yobi::ResticNotFound.new(restic_path: restic_path, argv: argv)
267
232
  end
268
233
 
269
- # Verifies the installed Restic binary meets {MINIMUM_VERSION}, once
270
- # per instance (memoized). {#run}/{#run_dump}/{#run_mount} call this
234
+ # Verifies the installed Restic binary meets MINIMUM_VERSION, once per
235
+ # instance (memoized). #run/#run_dump/#run_mount call this
271
236
  # automatically before executing a real command; public so a caller
272
- # can also call it explicitly to fail fast.
273
- #
274
- # @return [void]
275
- # @raise [Yobi::UnsupportedResticVersion]
237
+ # can also call it explicitly to fail fast. Raises
238
+ # Yobi::UnsupportedResticVersion when too old.
276
239
  def ensure_minimum_version!
277
240
  return if defined?(@version_checked)
278
241
  @version_checked = true
@@ -288,7 +251,7 @@ module Yobi
288
251
  # An old enough Restic ignores --json for `version` entirely and
289
252
  # prints plain text instead (e.g. "restic 0.9.6 compiled with
290
253
  # go1.13.4 on linux/amd64"), which JSON.parse can't handle.
291
- VERSION_LINE_PATTERN = /restic\s+(\d+\.\d+\.\d+\S*)/
254
+ VERSION_LINE_PATTERN = /restic\s+(\d+\.\d+\.\d+\S*)/ # :nodoc:
292
255
 
293
256
  def parse_version_output(raw)
294
257
  JSON.parse(raw)
@@ -357,24 +320,24 @@ module Yobi
357
320
  end
358
321
  end
359
322
 
360
- # The result of one {Yobi::Restic#version} call.
323
+ # The result of one Yobi::Restic#version call.
361
324
  class ResticVersion < Yobi::FancyHash
362
- # @return [String]
325
+ # The Restic version string, e.g. +"0.19.1"+.
363
326
  def version
364
327
  self["version"]
365
328
  end
366
329
 
367
- # @return [String, nil]
330
+ # The Go compiler version Restic was built with, if reported.
368
331
  def go_version
369
332
  self["go_version"]
370
333
  end
371
334
 
372
- # @return [String, nil]
335
+ # The OS Restic was built for, if reported.
373
336
  def go_os
374
337
  self["go_os"]
375
338
  end
376
339
 
377
- # @return [String, nil]
340
+ # The CPU architecture Restic was built for, if reported.
378
341
  def go_arch
379
342
  self["go_arch"]
380
343
  end
@@ -4,21 +4,11 @@ require "json"
4
4
  require "tempfile"
5
5
 
6
6
  module Yobi
7
- # Wraps the tempfile a repository operation's stdout+stderr are both
8
- # written to, with random access so a caller asking only for the last
9
- # line (see {#last_line}) doesn't have to read the entire output.
10
- #
11
- # @private
12
- class ResticOutput
13
- # Default read window size, in bytes, for {#last_line}.
7
+ class ResticOutput # :nodoc:
14
8
  DEFAULT_TAIL_CHUNK_SIZE = 4096
15
9
 
16
- # @return [File] a fresh, already-unlinked tempfile of its own
17
10
  attr_reader :file
18
11
 
19
- # @param tail_chunk_size [Integer] read window size for {#last_line}
20
- # @param transform [Proc, nil] used by {#write_and_parse} during a streaming run to transform
21
- # each message, and as {#messages}' default transform afterward, when no explicit one is given
22
12
  def initialize(tail_chunk_size: DEFAULT_TAIL_CHUNK_SIZE, transform: nil)
23
13
  @file = Tempfile.new("yobi-restic-output")
24
14
  @file.unlink
@@ -28,25 +18,15 @@ module Yobi
28
18
  @stderr_offsets = []
29
19
  end
30
20
 
31
- # Byte offsets of every line, grouped by message_type. Built once and
32
- # memoized.
33
- #
34
- # @return [Hash{String => Array<Integer>}]
35
21
  def index
36
22
  @index ||= build_index
37
23
  end
38
24
 
39
- # @param offset [Integer] a byte offset, as recorded by {#index}
40
- # @return [String] the line starting at that offset
41
25
  def read_line_at(offset)
42
26
  @file.seek(offset)
43
27
  @file.gets
44
28
  end
45
29
 
46
- # The last non-blank line, found by seeking backward from the end of
47
- # the file.
48
- #
49
- # @return [String, nil]
50
30
  def last_line
51
31
  size = @file.size
52
32
  return nil if size.zero?
@@ -66,8 +46,6 @@ module Yobi
66
46
  end
67
47
  end
68
48
 
69
- # @yieldparam line [String]
70
- # @return [Enumerator] if no block is given
71
49
  def each_line(&block)
72
50
  return enum_for(:each_line) unless block_given?
73
51
 
@@ -75,17 +53,6 @@ module Yobi
75
53
  @file.each_line(&block)
76
54
  end
77
55
 
78
- # Every message recorded in {#index}, restricted to one +message_type+
79
- # if given, in file order. Without an explicit transform block, uses
80
- # the +transform:+ given to {#initialize} (if any); with neither, just
81
- # yields/returns the raw parsed Hash. Whenever a transform (explicit
82
- # or the stored one) applies, wraps the result in a {LazyList}
83
- # instead of yielding.
84
- #
85
- # @param message_type [String, nil] every message, if omitted
86
- # @yieldparam message [Hash] the raw parsed message, to transform
87
- # @return [Yobi::ResticOutput::LazyList] if a transform block (or a stored transform) applies
88
- # @return [Enumerator] of raw Hashes, otherwise
89
56
  def messages(message_type = nil, &transform)
90
57
  transform ||= @transform
91
58
  return raw_messages(message_type) unless transform
@@ -94,27 +61,12 @@ module Yobi
94
61
  LazyList.new(self, offsets, transform)
95
62
  end
96
63
 
97
- # Every line known to have arrived on stderr rather than stdout during
98
- # a streaming run (see {#write_and_parse}), in file order.
99
- #
100
- # @yieldparam line [String]
101
- # @return [Enumerator] if no block is given
102
64
  def stderr_lines
103
65
  return enum_for(:stderr_lines) unless block_given?
104
66
 
105
67
  @stderr_offsets.each { |offset| yield read_line_at(offset) }
106
68
  end
107
69
 
108
- # Called once per line read from a live streaming run's stdout/stderr.
109
- # Writes it to the file, parses it, and - if it's a JSON message -
110
- # indexes it by message_type and returns it transformed via the
111
- # +transform:+ given to {#initialize} (or the raw parsed Hash, if none
112
- # was given). A non-JSON line's offset is recorded in {#stderr_lines}
113
- # instead, if +origin+ is +:stderr+; either way, returns nil.
114
- #
115
- # @param line [String]
116
- # @param origin [:stdout, :stderr]
117
- # @return [Object, nil]
118
70
  def write_and_parse(line, origin)
119
71
  offset = @file.pos
120
72
  @file.write(line)
@@ -134,13 +86,11 @@ module Yobi
134
86
  end
135
87
  end
136
88
 
137
- # @return [String] the full captured output
138
89
  def to_s
139
90
  @file.rewind
140
91
  @file.read
141
92
  end
142
93
 
143
- # @return [String]
144
94
  def inspect
145
95
  "#<#{self.class} #{@file.size} bytes>"
146
96
  end
@@ -179,32 +129,17 @@ module Yobi
179
129
  index
180
130
  end
181
131
 
182
- # A lazily-transformed view over a set of {#index} offsets, printing
183
- # like a plain Array (bounded to a preview, unlike one). Returned by
184
- # {ResticOutput#messages} when given a transform block.
185
- # #inspect/#pretty_print's preview is memoized, and #each reuses it
186
- # rather than re-reading/re-transforming those same offsets again
187
- # when the caller iterates the whole thing.
188
- #
189
- # @private
190
- class LazyList
132
+ class LazyList # :nodoc:
191
133
  include Enumerable
192
134
 
193
- # Items #inspect/#pretty_print show before truncating with "...".
194
- # One louder than ActiveRecord::Relation#inspect's own preview size.
195
135
  INSPECT_PREVIEW_SIZE = 11
196
136
 
197
- # @param output [Yobi::ResticOutput]
198
- # @param offsets [Array<Integer>]
199
- # @param transform [Proc] applied to each offset's raw parsed Hash
200
137
  def initialize(output, offsets, transform)
201
138
  @output = output
202
139
  @offsets = offsets
203
140
  @transform = transform
204
141
  end
205
142
 
206
- # @yieldparam item [Object]
207
- # @return [Enumerator] if no block is given
208
143
  def each
209
144
  return enum_for(:each) unless block_given?
210
145
 
@@ -212,23 +147,17 @@ module Yobi
212
147
  @offsets[preview.size..].each { |offset| yield transform_at(offset) }
213
148
  end
214
149
 
215
- # The number of messages, known upfront from {#index} - unlike
216
- # +Enumerable#count+, doesn't read/transform a single one to answer.
217
- #
218
- # @return [Integer]
219
150
  def size
220
151
  @offsets.size
221
152
  end
222
153
  alias_method :length, :size
223
154
 
224
- # @return [String]
225
155
  def inspect
226
156
  shown = preview.first(INSPECT_PREVIEW_SIZE).map(&:inspect).join(", ")
227
157
  shown += ", ..." if preview.size > INSPECT_PREVIEW_SIZE
228
158
  "[#{shown}]"
229
159
  end
230
160
 
231
- # @return [void]
232
161
  def pretty_print(q)
233
162
  q.group(1, "[", "]") do
234
163
  q.seplist(preview.first(INSPECT_PREVIEW_SIZE)) { |item| q.pp item }
@@ -238,7 +167,6 @@ module Yobi
238
167
 
239
168
  private
240
169
 
241
- # @return [Array<Object>]
242
170
  def preview
243
171
  @preview ||= @offsets.first(INSPECT_PREVIEW_SIZE + 1).map { |offset| transform_at(offset) }
244
172
  end
data/lib/yobi/snapshot.rb CHANGED
@@ -3,120 +3,108 @@
3
3
  require "time"
4
4
 
5
5
  module Yobi
6
- # One snapshot, as Restic reports it. Shared across {Yobi::Repository#snapshots},
7
- # {Yobi::Repository#ls}, and {Yobi::Repository#forget}'s keep/remove entries.
6
+ # One snapshot, as Restic reports it. Shared across Yobi::Repository#snapshots,
7
+ # Yobi::Repository#ls, and Yobi::Repository#forget's keep/remove entries.
8
8
  class Snapshot < Yobi::FancyHash
9
- # @return [String]
9
+ # Full snapshot ID (64-char hex).
10
10
  def id
11
11
  self["id"]
12
12
  end
13
13
 
14
- # @return [String]
14
+ # First 8 chars of #id.
15
15
  def short_id
16
16
  self["short_id"]
17
17
  end
18
18
 
19
- # @return [Time]
19
+ # When the snapshot was created.
20
20
  def time
21
21
  @time ||= Time.parse(self["time"])
22
22
  end
23
23
 
24
- # @return [String]
24
+ # Hostname recorded on the snapshot.
25
25
  def host
26
26
  self["hostname"]
27
27
  end
28
28
 
29
- # @return [Array<String>]
29
+ # Tags recorded on the snapshot.
30
30
  def tags
31
31
  @tags ||= self["tags"] || []
32
32
  end
33
33
 
34
- # @return [Array<String>]
34
+ # Paths backed up in the snapshot.
35
35
  def paths
36
36
  self["paths"]
37
37
  end
38
38
 
39
- # @return [String, nil]
39
+ # Parent snapshot's #id, if any.
40
40
  def parent_id
41
41
  self["parent"]
42
42
  end
43
43
 
44
- # @return [Yobi::SnapshotSummary]
44
+ # A Yobi::SnapshotSummary of the snapshot's stats at creation time.
45
45
  def summary
46
46
  @summary ||= SnapshotSummary.new(self["summary"] || {})
47
47
  end
48
48
  end
49
49
 
50
- # The `"summary"` field of a {Yobi::Snapshot}, the stats recorded when it
51
- # was created.
52
- # https://restic.readthedocs.io/en/stable/075_scripting.html#snapshotsummary-object
50
+ # The +"summary"+ field of a Yobi::Snapshot, the stats recorded when it
51
+ # was created. See
52
+ # https://restic.readthedocs.io/en/stable/075_scripting.html#snapshotsummary-object.
53
53
  class SnapshotSummary < Yobi::FancyHash
54
- # @return [Time, nil]
54
+ # When the backup started.
55
55
  def backup_start
56
56
  @backup_start ||= Time.parse(self["backup_start"]) if self["backup_start"]
57
57
  end
58
58
 
59
- # @return [Time, nil]
59
+ # When the backup finished.
60
60
  def backup_end
61
61
  @backup_end ||= Time.parse(self["backup_end"]) if self["backup_end"]
62
62
  end
63
63
 
64
- # @return [Integer]
65
64
  def files_new
66
65
  self["files_new"] || 0
67
66
  end
68
67
 
69
- # @return [Integer]
70
68
  def files_changed
71
69
  self["files_changed"] || 0
72
70
  end
73
71
 
74
- # @return [Integer]
75
72
  def files_unmodified
76
73
  self["files_unmodified"] || 0
77
74
  end
78
75
 
79
- # @return [Integer]
80
76
  def dirs_new
81
77
  self["dirs_new"] || 0
82
78
  end
83
79
 
84
- # @return [Integer]
85
80
  def dirs_changed
86
81
  self["dirs_changed"] || 0
87
82
  end
88
83
 
89
- # @return [Integer]
90
84
  def dirs_unmodified
91
85
  self["dirs_unmodified"] || 0
92
86
  end
93
87
 
94
- # @return [Integer]
95
88
  def data_blobs
96
89
  self["data_blobs"] || 0
97
90
  end
98
91
 
99
- # @return [Integer]
100
92
  def tree_blobs
101
93
  self["tree_blobs"] || 0
102
94
  end
103
95
 
104
- # @return [Integer]
105
96
  def data_added
106
97
  self["data_added"] || 0
107
98
  end
108
99
 
109
- # @return [Integer]
110
100
  def data_added_packed
111
101
  self["data_added_packed"] || 0
112
102
  end
113
103
 
114
- # @return [Integer]
115
104
  def total_files_processed
116
105
  self["total_files_processed"] || 0
117
106
  end
118
107
 
119
- # @return [Integer]
120
108
  def total_bytes_processed
121
109
  self["total_bytes_processed"] || 0
122
110
  end
data/lib/yobi/version.rb CHANGED
@@ -3,6 +3,5 @@
3
3
  # A Ruby library for the Restic backup program, wrapping the `restic` CLI in
4
4
  # plain Ruby objects instead of shelling out to flags and raw JSON by hand.
5
5
  module Yobi
6
- # @return [String]
7
- VERSION = "0.3.0"
6
+ VERSION = "1.0.0"
8
7
  end
data/sig/yobi.rbs CHANGED
@@ -227,7 +227,7 @@ module Yobi
227
227
  MINIMUM_VERSION: Gem::Version
228
228
  ALLOWED_ENV_VARS: Set[String]
229
229
 
230
- attr_reader restic_path: String
230
+ attr_accessor restic_path: String
231
231
  attr_accessor cache_dir: String?
232
232
  attr_accessor compression: String?
233
233
  attr_accessor pack_size: Integer?
@@ -287,9 +287,9 @@ module Yobi
287
287
  end
288
288
 
289
289
  class Repository
290
- attr_reader url: String
291
- attr_reader password: password
292
- attr_reader backend_credentials: backend_credentials
290
+ attr_accessor url: String
291
+ attr_accessor password: password
292
+ attr_accessor backend_credentials: backend_credentials
293
293
 
294
294
  def initialize: (url: String, password: password, ?backend_credentials: backend_credentials, ?restic: restic_or_path) -> void
295
295