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.
@@ -6,19 +6,17 @@ require "tempfile"
6
6
 
7
7
  module Yobi
8
8
  class Repository
9
- # `restic key add`: creates a new key (password) for this repository.
9
+ # +restic key add+: creates a new key (password) for this repository.
10
10
  #
11
- # @param host [String, nil] hostname to record on the new key
12
- # @param user [String, nil] username to record on the new key
13
- # @param new_password [String, Array, Symbol, #call] the new key's password,
14
- # accepting the same shapes as {#initialize}'s `password:` minus `[:command, ...]`: a
15
- # literal String; a `[:file, "..."]` tuple, resolved natively by Restic
16
- # itself; `:insecure_no_password`; or anything responding to `#call`. A
17
- # literal String or callable is written to a briefly-lived,
18
- # 0600-permissioned tempfile, since Restic itself only accepts a new
19
- # password by file or interactive prompt, unlike the repository's own
20
- # `password:`
21
- # @return [true]
11
+ # +new_password:+ accepts the same shapes as #initialize's +password:+
12
+ # minus +[:command, ...]+: a literal String; a +[:file, "..."]+ tuple,
13
+ # resolved natively by Restic itself; +:insecure_no_password+; or
14
+ # anything responding to +#call+. A literal String or callable is
15
+ # written to a briefly-lived, 0600-permissioned tempfile, since Restic
16
+ # itself only accepts a new password by file or interactive prompt.
17
+ #
18
+ # +host:+ and +user:+ optionally override the hostname/username
19
+ # recorded on the new key.
22
20
  def key_add(new_password:, host: nil, user: nil)
23
21
  with_new_password_flag(new_password) do |flag_name, flag_value|
24
22
  argv = build_argv("key", "add") do |a|
@@ -32,24 +30,19 @@ module Yobi
32
30
  end
33
31
  alias_method :add_key, :key_add
34
32
 
35
- # `restic key list`: lists every key (password) associated with this repository.
36
- #
37
- # @return [Array<Yobi::Key>]
33
+ # +restic key list+: every Yobi::Key associated with this repository.
38
34
  def key_list
39
35
  execution = run_restic(build_argv("key", "list"))
40
- JSON.parse(execution[:output].to_s).map { |raw| Key.new(raw) }
36
+ parse_json_output(execution).map { |raw| Key.new(raw) }
41
37
  end
42
38
  alias_method :keys, :key_list
43
39
 
44
- # `restic key passwd`: creates a new key for this repository and
40
+ # +restic key passwd+: creates a new key for this repository and
45
41
  # removes the key currently in use. On success, also updates this
46
- # `Repository` instance's own `password:` to `new_password:`, so it
42
+ # Repository instance's own +password:+ to +new_password:+, so it
47
43
  # keeps working against this same repository afterward.
48
44
  #
49
- # @param host [String, nil] hostname to record on the new key
50
- # @param user [String, nil] username to record on the new key
51
- # @param new_password [String, Array, Symbol, #call] see {#key_add}
52
- # @return [true]
45
+ # +new_password:+, +host:+ and +user:+ take the same shapes as #key_add.
53
46
  def key_passwd(new_password:, host: nil, user: nil)
54
47
  with_new_password_flag(new_password) do |flag_name, flag_value|
55
48
  argv = build_argv("key", "passwd") do |a|
@@ -64,12 +57,8 @@ module Yobi
64
57
  end
65
58
  alias_method :change_password, :key_passwd
66
59
 
67
- # `restic key remove`: removes the given key ID from this repository.
68
- # Restic refuses to remove the key currently being used to access the
69
- # repository.
70
- #
71
- # @param id [String]
72
- # @return [true]
60
+ # +restic key remove+: removes the given key +id+ from this repository.
61
+ # Restic refuses to remove the key currently being used to access it.
73
62
  def key_remove(id:)
74
63
  run_restic(build_argv("key", "remove", id))
75
64
  true
@@ -105,29 +94,25 @@ module Yobi
105
94
  end
106
95
  end
107
96
 
108
- # One key (password) associated with the repository, from {Yobi::Repository#key_list}.
97
+ # One key (password) associated with the repository, from Yobi::Repository#key_list.
109
98
  class Key < Yobi::FancyHash
110
- # @return [String]
111
99
  def id
112
100
  self["id"]
113
101
  end
114
102
 
115
- # @return [String]
116
103
  def user_name
117
104
  self["userName"]
118
105
  end
119
106
 
120
- # @return [String]
121
107
  def host_name
122
108
  self["hostName"]
123
109
  end
124
110
 
125
- # @return [Boolean] whether this is the key currently in use
111
+ # Whether this is the key currently in use.
126
112
  def current?
127
113
  self["current"]
128
114
  end
129
115
 
130
- # @return [Time]
131
116
  def created
132
117
  @created ||= Time.parse(self["created"])
133
118
  end
@@ -2,12 +2,11 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic list`: lists every object ID of the given type in this
6
- # repository. Restic ignores `--json` for this command; each line is a
7
- # bare ID, except for `:blobs`, where each line is `"data <id>"` or `"tree <id>"`.
8
- #
9
- # @param type [Symbol, String] `:blobs`, `:packs`, `:index`, `:snapshots`, `:keys`, or `:locks`
10
- # @return [Array<String>]
5
+ # +restic list+: every object ID of the given +type+ in this repository.
6
+ # +type+ is +:blobs+, +:packs+, +:index+, +:snapshots+, +:keys+, or
7
+ # +:locks+. Restic ignores +--json+ for this command; each line is a
8
+ # bare ID, except for +:blobs+, where each line is +"data <id>"+ or
9
+ # +"tree <id>"+.
11
10
  def list(type)
12
11
  argv = build_argv("list", type)
13
12
  execution = run_restic(argv)
@@ -4,19 +4,18 @@ require "time"
4
4
 
5
5
  module Yobi
6
6
  class Repository
7
- # `restic ls`: lists a snapshot's files/directories.
7
+ # +restic ls+: lists a snapshot's files/directories.
8
8
  #
9
- # @param snapshot_id [String] also accepts `"latest"`
10
- # @param dirs [Array<String>, String] restrict to these directories within the snapshot
11
- # @param hosts [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
12
- # @param human_readable [Boolean] format sizes for humans
13
- # @param long [Boolean] include long listing format
14
- # @param paths [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
15
- # @param recursive [Boolean] recurse into subdirectories
16
- # @param reverse [Boolean] reverse sort order
17
- # @param sort [String, nil] sort key, e.g. `"size"`
18
- # @param tags [Array<String>, String] only relevant when `snapshot_id` is `"latest"`
19
- # @return [Yobi::LsOutcome]
9
+ # +snapshot_id:+ is a snapshot ID, or +"latest"+. +dirs:+ restricts the
10
+ # listing to specific directories within the snapshot.
11
+ #
12
+ # +hosts:+, +paths:+ and +tags:+ each accept a single value or an Array
13
+ # and are only relevant when +snapshot_id+ is +"latest"+.
14
+ #
15
+ # +recursive:+ recurses into subdirectories. +human_readable:+, +long:+,
16
+ # +reverse:+ and +sort:+ (e.g. +"size"+) toggle formatting/sort options.
17
+ #
18
+ # Returns a Yobi::LsOutcome.
20
19
  def ls(snapshot_id:, dirs: [], hosts: [], human_readable: false, long: false, paths: [],
21
20
  recursive: false, reverse: false, sort: nil, tags: [])
22
21
  argv = build_argv("ls", snapshot_id) do |a|
@@ -36,16 +35,7 @@ module Yobi
36
35
  end
37
36
  end
38
37
 
39
- # Classifies a raw ls message Hash by its own message_type, wrapping it
40
- # in the matching typed class. Used both as the {Yobi::ResticOutput}
41
- # `transform:` for {Yobi::Repository#ls} and by {Yobi::LsOutcome}'s own
42
- # post-hoc accessors.
43
- #
44
- # @private
45
- module LsMessageWrapper
46
- # @param raw [Hash]
47
- # @return [Yobi::Snapshot, Yobi::Node, Hash]
48
- # the raw Hash itself for a message_type this version of Yobi doesn't recognize
38
+ module LsMessageWrapper # :nodoc:
49
39
  def self.call(raw)
50
40
  case raw["message_type"]
51
41
  when "snapshot" then Snapshot.new(raw)
@@ -55,28 +45,26 @@ module Yobi
55
45
  end
56
46
  end
57
47
 
58
- # The outcome of one {Yobi::Repository#ls} call.
48
+ # The outcome of one Yobi::Repository#ls call.
59
49
  class LsOutcome
60
- # @return [Yobi::ResticOutput]
50
+ # The Yobi::ResticOutput backing this outcome.
61
51
  attr_reader :output
62
52
 
63
- # @private
64
- def initialize(execution)
53
+ def initialize(execution) # :nodoc:
65
54
  @output = execution[:output]
66
55
  end
67
56
 
68
- # @return [Yobi::Snapshot] the resolved snapshot, useful when `snapshot_id:` was `"latest"`
57
+ # The resolved Yobi::Snapshot, useful when +snapshot_id:+ was +"latest"+.
69
58
  def snapshot
70
59
  @snapshot ||= output.messages("snapshot").first
71
60
  end
72
61
 
73
- # @return [Enumerable<Yobi::Node>]
62
+ # Every Yobi::Node from the run.
74
63
  def nodes
75
64
  @nodes ||= output.messages("node")
76
65
  end
77
66
  alias_method :entries, :nodes
78
67
 
79
- # @return [void]
80
68
  def pretty_print(q)
81
69
  q.object_group(self) do
82
70
  q.breakable
@@ -87,61 +75,50 @@ module Yobi
87
75
  end
88
76
  end
89
77
 
90
- # One file/directory entry from a {Yobi::Repository#ls} call. Restic's
91
- # own term for this is a "node" - the same structure it uses internally
92
- # for every entry in a snapshot's tree, not just ones `ls` happens to show.
78
+ # One file/directory entry from a Yobi::Repository#ls call. Restic's own
79
+ # term for this is a "node" - the same structure it uses internally for
80
+ # every entry in a snapshot's tree, not just ones +ls+ happens to show.
93
81
  class Node < Yobi::FancyHash
94
- # @return [String]
95
82
  def name
96
83
  self["name"]
97
84
  end
98
85
 
99
- # @return [String]
100
86
  def type
101
87
  self["type"]
102
88
  end
103
89
 
104
- # @return [String]
105
90
  def path
106
91
  self["path"]
107
92
  end
108
93
 
109
- # @return [Integer]
110
94
  def size
111
95
  self["size"]
112
96
  end
113
97
 
114
- # @return [String]
115
98
  def permissions
116
99
  self["permissions"]
117
100
  end
118
101
 
119
- # @return [Integer]
120
102
  def uid
121
103
  self["uid"]
122
104
  end
123
105
 
124
- # @return [Integer]
125
106
  def gid
126
107
  self["gid"]
127
108
  end
128
109
 
129
- # @return [Integer]
130
110
  def inode
131
111
  self["inode"]
132
112
  end
133
113
 
134
- # @return [Time]
135
114
  def mtime
136
115
  @mtime ||= Time.parse(self["mtime"])
137
116
  end
138
117
 
139
- # @return [Time]
140
118
  def atime
141
119
  @atime ||= Time.parse(self["atime"])
142
120
  end
143
121
 
144
- # @return [Time]
145
122
  def ctime
146
123
  @ctime ||= Time.parse(self["ctime"])
147
124
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic migrate`: checks which migrations can be applied to this
6
- # repository, or applies the given ones. Restic ignores `--json` for
5
+ # +restic migrate+: checks which migrations can be applied to this
6
+ # repository, or applies the given ones. Restic ignores +--json+ for
7
7
  # this command, so there's no programmatic way to discover which
8
- # migrations are available. Run `restic migrate` directly for that.
8
+ # migrations are available - run +restic migrate+ directly for that.
9
9
  #
10
- # @param names [Array<String>, String] migration names to apply; only lists available ones if empty
11
- # @param force [Boolean] reapply a migration already marked as applied
12
- # @return [true]
10
+ # +names:+ names the migrations to apply, or only lists available ones
11
+ # if empty. +force: true+ reapplies a migration already marked as
12
+ # applied.
13
13
  def migrate(names: [], force: false)
14
14
  argv = build_argv("migrate", names) do |a|
15
15
  a.flag(:force) if force
@@ -4,27 +4,25 @@ require "open3"
4
4
 
5
5
  module Yobi
6
6
  class Repository
7
- # `restic mount`: serves this repository as a read-only FUSE
8
- # filesystem at `mountpoint`, which must already exist.
7
+ # +restic mount+: serves this repository as a read-only FUSE filesystem
8
+ # at +mountpoint:+, which must already exist.
9
9
  #
10
- # Without a block, returns a {Yobi::MountHandle} once Restic reports
11
- # itself ready; call `#stop` yourself once done. With one, yields the
12
- # `MountHandle` and stops it automatically once the block returns or raises.
10
+ # Without a block, returns a Yobi::MountHandle once Restic reports
11
+ # itself ready; call +#stop+ yourself once done. With one, yields the
12
+ # MountHandle and stops it automatically once the block returns or
13
+ # raises, returning the block's own value.
13
14
  #
14
- # @param mountpoint [String] must already exist
15
- # @param hosts [Array<String>, String] restrict which snapshots appear under `snapshots/`
16
- # @param paths [Array<String>, String] restrict which snapshots appear under `snapshots/`
17
- # @param tags [Array<String>, String] restrict which snapshots appear under `snapshots/`
18
- # @param allow_other [Boolean] allow other users to access the mount
19
- # @param no_default_permissions [Boolean] don't check file permissions
20
- # @param owner_root [Boolean] mount files as owned by root
21
- # @param path_templates [Array<String>, String] directory naming scheme(s) under `snapshots/`
22
- # @param time_template [String, nil] directory naming scheme for time-based paths
23
- # @param ready_timeout [Numeric] seconds to wait for Restic's readiness message before raising
24
- # @yieldparam mount [Yobi::MountHandle]
25
- # @return [Yobi::MountHandle] if no block is given
26
- # @return [Object] the block's own return value, otherwise
27
- # @raise [Yobi::MountTimeout]
15
+ # +hosts:+, +paths:+, and +tags:+ each accept a single value or an
16
+ # Array to restrict which snapshots appear under +snapshots/+.
17
+ #
18
+ # +allow_other:+ allows other users to access the mount.
19
+ # +no_default_permissions:+ skips file permission checks.
20
+ # +owner_root:+ mounts files as owned by root. +path_templates:+ and
21
+ # +time_template:+ control the directory naming schemes under
22
+ # +snapshots/+.
23
+ #
24
+ # +ready_timeout:+ is the number of seconds to wait for Restic's
25
+ # readiness message before raising Yobi::MountTimeout.
28
26
  def mount(mountpoint:, hosts: [], paths: [], tags: [], allow_other: false,
29
27
  no_default_permissions: false, owner_root: false, path_templates: [], time_template: nil,
30
28
  ready_timeout: 10)
@@ -58,20 +56,12 @@ module Yobi
58
56
  end
59
57
 
60
58
  class Restic
61
- # @private
62
- READY_LINE = "Now serving the repository at"
59
+ READY_LINE = "Now serving the repository at" # :nodoc:
63
60
 
64
- # For {Yobi::Repository#mount}. Spawns Restic and waits for its
65
- # readiness line (or `ready_timeout:` seconds, or Restic exiting on
66
- # its own) before returning.
67
- #
68
- # @param argv [Array<String>]
69
- # @param mountpoint [String]
70
- # @param extra_env [Hash{String => String}]
71
- # @param ready_timeout [Numeric]
72
- # @return [Yobi::MountHandle]
73
- # @raise [Yobi::MountTimeout]
74
- def run_mount(argv, mountpoint:, extra_env: {}, ready_timeout: 10)
61
+ # For Yobi::Repository#mount. Spawns Restic and waits for its readiness
62
+ # line (or +ready_timeout:+ seconds, or Restic exiting on its own)
63
+ # before returning a Yobi::MountHandle. Raises Yobi::MountTimeout.
64
+ def run_mount(argv, mountpoint:, extra_env: {}, ready_timeout: 10) # :nodoc:
75
65
  ensure_minimum_version!
76
66
  output = Yobi::ResticOutput.new
77
67
 
@@ -2,16 +2,18 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic prune`: removes data no longer referenced by any snapshot.
5
+ # +restic prune+: removes data no longer referenced by any snapshot.
6
6
  #
7
- # @param dry_run [Boolean] report what would happen without doing it
8
- # @param max_repack_size [String, nil] limit the amount of data repacked in this run
9
- # @param max_unused [String, nil] target maximum unused space after pruning, e.g. `"10%"`
10
- # @param repack_cacheable_only [Boolean] only repack packs that are cached locally
11
- # @param repack_smaller_than [String, nil] also repack packs smaller than this size
12
- # @param repack_uncompressed [Boolean] repack packs not yet using compression
13
- # @param unsafe_recover_no_free_space [String, nil] proceed even without enough free space, at the given risk acknowledgement
14
- # @return [true]
7
+ # +dry_run:+ reports what would happen without doing it. +max_unused:+
8
+ # targets a maximum unused space after pruning (e.g. +"10%"+).
9
+ # +max_repack_size:+ caps the amount of data repacked in one run.
10
+ #
11
+ # +repack_cacheable_only:+ only repacks packs cached locally.
12
+ # +repack_smaller_than:+ also repacks packs smaller than a given size.
13
+ # +repack_uncompressed:+ repacks packs not yet using compression.
14
+ #
15
+ # +unsafe_recover_no_free_space:+ proceeds even without enough free
16
+ # space, at the given risk acknowledgement string.
15
17
  def prune(dry_run: false, max_repack_size: nil, max_unused: nil, repack_cacheable_only: false,
16
18
  repack_smaller_than: nil, repack_uncompressed: false, unsafe_recover_no_free_space: nil)
17
19
  argv = build_argv("prune") do |a|
@@ -2,12 +2,10 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic recover`: builds a new snapshot from any data found in this
5
+ # +restic recover+: builds a new snapshot from any data found in this
6
6
  # repository that isn't referenced by an existing snapshot (e.g. after
7
- # an accidental {#forget}). Call {#snapshots} afterward to find the
7
+ # an accidental #forget). Call #snapshots afterward to find the
8
8
  # recovered snapshot, if any was created.
9
- #
10
- # @return [true]
11
9
  def recover
12
10
  run_restic(build_argv("recover"))
13
11
  true
@@ -2,12 +2,10 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic repair index`: creates a new index based on the pack files
5
+ # +restic repair index+: creates a new index based on the pack files
6
6
  # present in this repository. Successor to the deprecated
7
- # `rebuild-index` command.
8
- #
9
- # @param read_all_packs [Boolean] read every pack file fully instead of just headers
10
- # @return [true]
7
+ # +rebuild-index+ command. +read_all_packs: true+ reads every pack file
8
+ # fully instead of just headers.
11
9
  def repair_index(read_all_packs: false)
12
10
  argv = build_argv("repair", "index") do |a|
13
11
  a.flag(:read_all_packs) if read_all_packs
@@ -16,34 +14,29 @@ module Yobi
16
14
  true
17
15
  end
18
16
 
19
- # `restic repair packs`: extracts intact blobs from the given pack
20
- # files, rebuilds the index to drop the damaged packs, and removes
17
+ # +restic repair packs+: extracts intact blobs from the given pack
18
+ # +ids:+, rebuilds the index to drop the damaged packs, and removes
21
19
  # them from the repository. Restic also writes a backup copy of each
22
- # given pack file (named `pack-<id>`) into the calling process's
20
+ # given pack file (named +pack-<id>+) into the calling process's
23
21
  # current working directory before removing it. There's no flag to
24
22
  # disable this.
25
- #
26
- # @param ids [Array<String>, String] pack IDs
27
- # @return [true]
28
23
  def repair_packs(ids:)
29
24
  argv = build_argv("repair", "packs", ids)
30
25
  run_restic(argv)
31
26
  true
32
27
  end
33
28
 
34
- # `restic repair snapshots`: scans the given snapshots and generates
35
- # new ones with damaged directories/file contents removed. This
36
- # causes data loss for the content actually removed; prefer a fresh
37
- # {Yobi::Repository#backup} where the source data is still available.
38
- # Depends on a correct index. Call {#repair_index} first.
29
+ # +restic repair snapshots+: scans the given snapshots and generates
30
+ # new ones with damaged directories/file contents removed. This causes
31
+ # data loss for the content actually removed; prefer a fresh
32
+ # Yobi::Repository#backup where the source data is still available.
33
+ # Depends on a correct index - call #repair_index first.
39
34
  #
40
- # @param snapshot_ids [Array<String>, String] snapshots to repair; all of them if empty
41
- # @param dry_run [Boolean] report what would happen without doing it
42
- # @param forget [Boolean] remove the original damaged snapshots after repairing
43
- # @param hosts [Array<String>, String] filter by hostname(s)
44
- # @param paths [Array<String>, String] filter by originally backed-up path(s)
45
- # @param tags [Array<String>, String] filter by tag(s)
46
- # @return [true]
35
+ # +snapshot_ids:+ names the snapshots to repair, or all of them if
36
+ # empty. +dry_run:+ reports what would happen without doing it.
37
+ # +forget:+ removes the original damaged snapshots after repairing.
38
+ # +hosts:+, +paths:+, and +tags:+ each accept a single value or an
39
+ # Array to filter by.
47
40
  def repair_snapshots(snapshot_ids: [], dry_run: false, forget: false, hosts: [], paths: [], tags: [])
48
41
  argv = build_argv("repair", "snapshots", snapshot_ids) do |a|
49
42
  a.flag(:dry_run) if dry_run
@@ -2,32 +2,28 @@
2
2
 
3
3
  module Yobi
4
4
  class Repository
5
- # `restic restore`: extracts a snapshot's contents to a target directory.
5
+ # +restic restore+: extracts a snapshot's contents to a target directory.
6
6
  #
7
- # @param snapshot_id [String] also accepts `"latest"`
8
- # @param target [String] directory to restore into
9
- # @param excludes [Array<String>, String] exclude files matching these glob patterns
10
- # @param exclude_files [Array<String>, String] path(s) to file(s) listing exclude patterns
11
- # @param exclude_xattrs [Array<String>, String] exclude extended attributes matching these pattern(s)
12
- # @param hosts [Array<String>, String] only relevant when `snapshot_id:` is `"latest"`
13
- # @param iexcludes [Array<String>, String] like `excludes`, case-insensitive
14
- # @param iexclude_files [Array<String>, String] like `exclude_files`, case-insensitive
15
- # @param iincludes [Array<String>, String] like `includes`, case-insensitive
16
- # @param iinclude_files [Array<String>, String] like `include_files`, case-insensitive
17
- # @param includes [Array<String>, String] only restore files matching these glob patterns
18
- # @param include_files [Array<String>, String] path(s) to file(s) listing include patterns
19
- # @param include_xattrs [Array<String>, String] only restore extended attributes matching these pattern(s)
20
- # @param paths [Array<String>, String] only relevant when `snapshot_id:` is `"latest"`
21
- # @param tags [Array<String>, String] only relevant when `snapshot_id:` is `"latest"`
22
- # @param delete [Boolean] delete files in `target:` not present in the snapshot
23
- # @param dry_run [Boolean] report what would happen without doing it
24
- # @param overwrite [String, Symbol, nil] `"always"`, `"if-changed"`, or `"if-newer"`
25
- # @param ownership_by_name [Boolean] map ownership by user/group name instead of numeric ID
26
- # @param sparse [Boolean] write sparse files
27
- # @param verbose [Boolean] stream a {Yobi::RestoreVerboseStatus} per file to the block
28
- # @param verify [Boolean] verify restored file content against the repository
29
- # @yieldparam message [Yobi::RestoreStatus, Yobi::RestoreVerboseStatus]
30
- # @return [Yobi::RestoreOutcome]
7
+ # +snapshot_id:+ is a snapshot ID or +"latest"+. +target:+ is the
8
+ # directory to restore into.
9
+ #
10
+ # +excludes:+, +exclude_files:+, +exclude_xattrs:+, +includes:+,
11
+ # +include_files:+, +include_xattrs:+ and their +i+-prefixed
12
+ # (case-insensitive) variants each accept a single value or an Array.
13
+ #
14
+ # +hosts:+, +paths:+ and +tags:+ each accept a single value or an
15
+ # Array and are only relevant when +snapshot_id+ is +"latest"+.
16
+ #
17
+ # +delete:+ deletes files in +target+ not present in the snapshot.
18
+ # +dry_run:+ reports what would happen without doing it.
19
+ # +overwrite:+ is +"always"+, +"if-changed"+, or +"if-newer"+.
20
+ # +ownership_by_name:+ maps ownership by user/group name instead of
21
+ # numeric ID. +sparse:+ writes sparse files. +verify:+ verifies restored
22
+ # file content against the repository.
23
+ #
24
+ # When +verbose: true+, a Yobi::RestoreVerboseStatus is streamed to the
25
+ # block per file. The block also receives Yobi::RestoreStatus messages
26
+ # as they arrive. Returns a Yobi::RestoreOutcome.
31
27
  def restore(snapshot_id:, target:, excludes: [], exclude_files: [], exclude_xattrs: [], hosts: [],
32
28
  iexcludes: [], iexclude_files: [], iincludes: [], iinclude_files: [], includes: [], include_files: [],
33
29
  include_xattrs: [], paths: [], tags: [], delete: false, dry_run: false, overwrite: nil,
@@ -58,7 +54,7 @@ module Yobi
58
54
 
59
55
  output = Yobi::ResticOutput.new(transform: Yobi::RestoreMessageWrapper)
60
56
  # Restic's own restore summary isn't meant for the live block - only
61
- # {RestoreOutcome#summary}'s post-hoc access sees it - but it shares
57
+ # RestoreOutcome#summary's post-hoc access sees it - but it shares
62
58
  # the same @transform (needed there since it isn't a status/verbose_status
63
59
  # message), so it has to be filtered back out here instead.
64
60
  live_block = block && proc { |message| block.call(message) if message.is_a?(RestoreStatus) || message.is_a?(RestoreVerboseStatus) }
@@ -67,16 +63,7 @@ module Yobi
67
63
  end
68
64
  end
69
65
 
70
- # Classifies a raw restore message Hash by its own message_type, wrapping
71
- # it in the matching typed class. Used both by {Yobi::Repository#restore}
72
- # (as the {Yobi::ResticOutput} `transform:` for a live streaming run) and
73
- # by {Yobi::RestoreOutcome}'s own post-hoc accessors.
74
- #
75
- # @private
76
- module RestoreMessageWrapper
77
- # @param raw [Hash]
78
- # @return [Yobi::RestoreStatus, Yobi::RestoreVerboseStatus, Hash]
79
- # the raw Hash itself for a message_type this version of Yobi doesn't recognize
66
+ module RestoreMessageWrapper # :nodoc:
80
67
  def self.call(raw)
81
68
  case raw["message_type"]
82
69
  when "status" then RestoreStatus.new(raw)
@@ -86,23 +73,21 @@ module Yobi
86
73
  end
87
74
  end
88
75
 
89
- # The outcome of one {Yobi::Repository#restore} call.
76
+ # The outcome of one Yobi::Repository#restore call.
90
77
  class RestoreOutcome
91
- # @return [Yobi::ResticOutput]
78
+ # The Yobi::ResticOutput backing this outcome.
92
79
  attr_reader :output
93
80
 
94
- # @private
95
- def initialize(execution)
81
+ def initialize(execution) # :nodoc:
96
82
  @output = execution[:output]
97
83
  end
98
84
 
99
- # @return [Hash] Restic's own `"summary"` fields (`"total_files"`, `"files_restored"`, ...)
85
+ # Restic's own +"summary"+ fields (+"total_files"+, +"files_restored"+, ...).
100
86
  def summary
101
87
  @summary ||= output.messages("summary").first || {}
102
88
  end
103
89
  alias_method :report, :summary
104
90
 
105
- # @return [void]
106
91
  def pretty_print(q)
107
92
  q.object_group(self) do
108
93
  q.breakable
@@ -111,49 +96,41 @@ module Yobi
111
96
  end
112
97
  end
113
98
 
114
- # One `"status"` message from a live restore run.
115
- # https://restic.readthedocs.io/en/stable/075_scripting.html#restore
99
+ # One +"status"+ message from a live restore run. See
100
+ # https://restic.readthedocs.io/en/stable/075_scripting.html#restore.
116
101
  class RestoreStatus < Yobi::FancyHash
117
- # @return [Float, nil]
118
102
  def percent_done
119
103
  self["percent_done"]
120
104
  end
121
105
 
122
- # @return [Integer, nil]
123
106
  def total_files
124
107
  self["total_files"]
125
108
  end
126
109
 
127
- # @return [Integer, nil]
128
110
  def files_restored
129
111
  self["files_restored"]
130
112
  end
131
113
 
132
- # @return [Integer, nil]
133
114
  def total_bytes
134
115
  self["total_bytes"]
135
116
  end
136
117
 
137
- # @return [Integer, nil]
138
118
  def bytes_restored
139
119
  self["bytes_restored"]
140
120
  end
141
121
  end
142
122
 
143
- # One `"verbose_status"` message from a restore run, one per file. Only
144
- # emitted when `verbose: true` is passed to {Yobi::Repository#restore}.
123
+ # One +"verbose_status"+ message from a restore run, one per file. Only
124
+ # emitted when +verbose: true+ is passed to Yobi::Repository#restore.
145
125
  class RestoreVerboseStatus < Yobi::FancyHash
146
- # @return [String]
147
126
  def action
148
127
  self["action"]
149
128
  end
150
129
 
151
- # @return [String]
152
130
  def item
153
131
  self["item"]
154
132
  end
155
133
 
156
- # @return [Integer]
157
134
  def size
158
135
  self["size"]
159
136
  end