imap-backup 14.4.1 → 14.4.4

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/bin/imap-backup +5 -2
  3. data/docs/api.md +20 -0
  4. data/docs/development.md +18 -7
  5. data/lib/imap/backup/account/backup.rb +6 -3
  6. data/lib/imap/backup/account/backup_folders.rb +6 -3
  7. data/lib/imap/backup/account/client_factory.rb +3 -2
  8. data/lib/imap/backup/account/folder.rb +10 -9
  9. data/lib/imap/backup/account/folder_backup.rb +5 -4
  10. data/lib/imap/backup/account/folder_ensurer.rb +5 -2
  11. data/lib/imap/backup/account/local_only_folder_deleter.rb +7 -3
  12. data/lib/imap/backup/account/restore.rb +5 -2
  13. data/lib/imap/backup/account/serialized_folders.rb +3 -2
  14. data/lib/imap/backup/account.rb +85 -0
  15. data/lib/imap/backup/cli/backup.rb +14 -12
  16. data/lib/imap/backup/cli/folder_enumerator.rb +5 -5
  17. data/lib/imap/backup/cli/local/check.rb +4 -2
  18. data/lib/imap/backup/cli/local.rb +50 -49
  19. data/lib/imap/backup/cli/remote.rb +46 -46
  20. data/lib/imap/backup/cli/restore.rb +5 -3
  21. data/lib/imap/backup/cli/setup.rb +4 -2
  22. data/lib/imap/backup/cli/single/backup.rb +3 -3
  23. data/lib/imap/backup/cli/stats.rb +54 -52
  24. data/lib/imap/backup/cli/transfer.rb +93 -93
  25. data/lib/imap/backup/cli/utils.rb +28 -28
  26. data/lib/imap/backup/cli.rb +12 -0
  27. data/lib/imap/backup/client/default.rb +5 -5
  28. data/lib/imap/backup/configuration.rb +5 -4
  29. data/lib/imap/backup/downloader.rb +6 -14
  30. data/lib/imap/backup/email/mboxrd/message.rb +2 -3
  31. data/lib/imap/backup/file_mode.rb +4 -2
  32. data/lib/imap/backup/flag_refresher.rb +3 -3
  33. data/lib/imap/backup/local_only_message_deleter.rb +5 -3
  34. data/lib/imap/backup/migrator.rb +6 -4
  35. data/lib/imap/backup/mirror/map.rb +3 -3
  36. data/lib/imap/backup/mirror.rb +5 -5
  37. data/lib/imap/backup/serializer/appender.rb +7 -4
  38. data/lib/imap/backup/serializer/delayed_metadata_serializer.rb +15 -2
  39. data/lib/imap/backup/serializer/directory.rb +12 -3
  40. data/lib/imap/backup/serializer/folder_maker.rb +12 -4
  41. data/lib/imap/backup/serializer/imap.rb +5 -1
  42. data/lib/imap/backup/serializer/integrity_checker.rb +10 -3
  43. data/lib/imap/backup/serializer/mbox.rb +2 -1
  44. data/lib/imap/backup/serializer/message.rb +10 -18
  45. data/lib/imap/backup/serializer/permission_checker.rb +5 -3
  46. data/lib/imap/backup/serializer/transaction.rb +4 -1
  47. data/lib/imap/backup/serializer/unused_name_finder.rb +4 -2
  48. data/lib/imap/backup/serializer/version2_migrator.rb +2 -2
  49. data/lib/imap/backup/serializer.rb +5 -0
  50. data/lib/imap/backup/setup/account/header.rb +3 -3
  51. data/lib/imap/backup/setup/account.rb +6 -6
  52. data/lib/imap/backup/setup/asker.rb +6 -4
  53. data/lib/imap/backup/setup/backup_path.rb +3 -4
  54. data/lib/imap/backup/setup/connection_tester.rb +4 -2
  55. data/lib/imap/backup/setup/{email.rb → email_changer.rb} +4 -4
  56. data/lib/imap/backup/setup/folder_chooser.rb +2 -2
  57. data/lib/imap/backup/setup/global_options/download_strategy_chooser.rb +2 -2
  58. data/lib/imap/backup/setup/global_options.rb +2 -2
  59. data/lib/imap/backup/setup.rb +2 -2
  60. data/lib/imap/backup/text/sanitizer.rb +2 -2
  61. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +10 -8
  62. data/lib/imap/backup/uploader.rb +3 -3
  63. data/lib/imap/backup/version.rb +1 -1
  64. metadata +4 -4
  65. data/lib/imap/backup/cli_coverage.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f83228485fa483834d66fa4fb2fd8dcfba3523100608136e8d82eb3c90765f40
4
- data.tar.gz: d1c52e0743c7b2922e0c5e65c388446ef344f32a42887f0069f2070b5e0903bc
3
+ metadata.gz: fc28eee3a2ef71157ebe6e50490488ce92b101bb3c4e02a46964b398ddc85d83
4
+ data.tar.gz: e6ee9d519463a25bf391fb71bf426d59aeaf27072afdf6306bbe631703a82dfb
5
5
  SHA512:
6
- metadata.gz: 4a95165223801af4c9e72b7aa66b054caaad51300f229d105d6ca6d0636f8f3a500598eb184b7230c48e0c27492d1f14121660c96db1c515d89bf21a73fcaa89
7
- data.tar.gz: 9c3b7fe3b38ab2819285406503d61651f3df175e3ce6702e2e274183d99a361a6e986e2afb75859ea74a788688fda05856ad869b62a736b2c996a1b2593a23f3
6
+ metadata.gz: 0004c4453debba185805fdce233f450570b6bf5a11ae6976641abf91b3adbbc33f62c8da195bcc3eccf99119203cf270bd1506c6620564a81f0c64197814c738
7
+ data.tar.gz: 378acbd1e668f87b76ebd2db0649344e2904f8992ee4c60aff2f5cf539a145b411fc39bdca962fc4c60e81ed444919b84bf3c305a0199b09fbbd1eb1c87d5d72
data/bin/imap-backup CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  $LOAD_PATH.unshift(File.expand_path("../lib/", __dir__))
4
4
 
5
- require "imap/backup/cli_coverage"
5
+ spec_path = File.expand_path("../spec", __dir__)
6
+ if File.directory?(spec_path)
7
+ require_relative "../spec/support/cli_coverage"
6
8
 
7
- Imap::Backup::CliCoverage.conditionally_activate
9
+ CliCoverage.conditionally_activate
10
+ end
8
11
 
9
12
  require "imap/backup/cli"
10
13
  require "imap/backup/logger"
data/docs/api.md ADDED
@@ -0,0 +1,20 @@
1
+ # @title Index
2
+ # imap-backup API Documentation
3
+
4
+ ![Version](https://img.shields.io/gem/v/imap-backup?label=Version&logo=rubygems)
5
+ [![Build Status](https://github.com/joeyates/imap-backup/actions/workflows/main.yml/badge.svg)][CI Status]
6
+ ![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/joeyates/b54fe758bfb405c04bef72dad293d707/raw/coverage.json)
7
+ ![License](https://img.shields.io/github/license/joeyates/imap-backup?color=brightgreen&label=License)
8
+ [![Stars](https://img.shields.io/github/stars/joeyates/imap-backup?style=social)][GitHub Stars]
9
+
10
+ [CI Status]: https://github.com/joeyates/imap-backup/actions/workflows/main.yml
11
+ [GitHub Stars]: https://github.com/joeyates/imap-backup/stargazers "GitHub Stars"
12
+
13
+ This is the developer documentation for imap-backup's **code**.
14
+
15
+ Usage documentation is on [GitHub](https://github.com/joeyates/imap-backup).
16
+
17
+ You can get an overview of the program's structure from the
18
+ {file:ARCHITECTURE.md ARCHITECTURE} file.
19
+
20
+ The {file:CHANGELOG.md CHANGELOG} has a history of the changes to the program.
data/docs/development.md CHANGED
@@ -17,8 +17,9 @@ git config --local blame.ignoreRevsFile .git-blame-ignore-revs
17
17
 
18
18
  ## Feature Specs
19
19
 
20
- Specs under `specs/features` are integration specs run against
21
- two local IMAP servers controlled by Podman (or Docker) Compose.
20
+ Specs under `specs/features` are integration specs.
21
+ Some of these specs run against two local IMAP servers
22
+ controlled by Podman (or Docker) Compose.
22
23
 
23
24
  Start them before running the test suite
24
25
 
@@ -32,20 +33,30 @@ or, with Podman
32
33
  $ podman-compose -f dev/compose.yml up -d
33
34
  ```
34
35
 
36
+ Then, run all specs
37
+
35
38
  ```sh
36
- $ rake
39
+ $ rspec
37
40
  ```
38
41
 
39
- To exclude container-based tests:
42
+ To exclude container-based tests
40
43
 
41
44
  ```sh
42
- rake no-docker
45
+ $ rspec --tag ~docker
43
46
  ```
44
47
 
45
- or
48
+ To run **just** the feature specs
46
49
 
47
50
  ```sh
48
- $ rspec --tag ~docker
51
+ rspec spec/features/**/*_spec.rb
52
+ ```
53
+
54
+ ## Full Test Run
55
+
56
+ The full test run includes RSpec specs **and** Runbocop checks
57
+
58
+ ```sh
59
+ rake
49
60
  ```
50
61
 
51
62
  # Older Rubies
@@ -8,10 +8,8 @@ module Imap; end
8
8
  module Imap::Backup
9
9
  class Account; end
10
10
 
11
+ # Carries out the backup of the configured folders of the account
11
12
  class Account::Backup
12
- attr_reader :account
13
- attr_reader :refresh
14
-
15
13
  def initialize(account:, refresh: false)
16
14
  @account = account
17
15
  @refresh = refresh
@@ -35,5 +33,10 @@ module Imap::Backup
35
33
  Account::FolderBackup.new(account: account, folder: folder, refresh: refresh).run
36
34
  end
37
35
  end
36
+
37
+ private
38
+
39
+ attr_reader :account
40
+ attr_reader :refresh
38
41
  end
39
42
  end
@@ -5,12 +5,10 @@ module Imap; end
5
5
  module Imap::Backup
6
6
  class Account; end
7
7
 
8
+ # Iterates over the account folders that are to be backed up
8
9
  class Account::BackupFolders
9
10
  include Enumerable
10
11
 
11
- attr_reader :account
12
- attr_reader :client
13
-
14
12
  def initialize(client:, account:)
15
13
  @client = client
16
14
  @account = account
@@ -46,5 +44,10 @@ module Imap::Backup
46
44
  block.call(folder)
47
45
  end
48
46
  end
47
+
48
+ private
49
+
50
+ attr_reader :account
51
+ attr_reader :client
49
52
  end
50
53
  end
@@ -10,9 +10,8 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class Account; end
12
12
 
13
+ # Returns an IMAP client set up for the supplied account
13
14
  class Account::ClientFactory
14
- attr_reader :account
15
-
16
15
  def initialize(account:)
17
16
  @account = account
18
17
  @provider = nil
@@ -35,6 +34,8 @@ module Imap::Backup
35
34
 
36
35
  private
37
36
 
37
+ attr_reader :account
38
+
38
39
  def provider
39
40
  @provider ||= Email::Provider.for_address(account.username)
40
41
  end
@@ -10,19 +10,13 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class Account; end
12
12
 
13
- class FolderNotFound < StandardError; end
14
-
13
+ # Handles access to a folder on an IMAP server
15
14
  class Account::Folder
15
+ class FolderNotFound < StandardError; end
16
+
16
17
  extend Forwardable
17
18
  include RetryOnError
18
19
 
19
- BODY_ATTRIBUTE = "BODY[]".freeze
20
- UID_FETCH_RETRY_CLASSES = [::EOFError, ::Errno::ECONNRESET, ::IOError].freeze
21
- APPEND_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
22
- CREATE_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
23
- EXAMINE_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
24
- PERMITTED_FLAGS = %i(Answered Draft Flagged Seen).freeze
25
-
26
20
  attr_reader :client
27
21
  attr_reader :name
28
22
 
@@ -156,6 +150,13 @@ module Imap::Backup
156
150
 
157
151
  private
158
152
 
153
+ BODY_ATTRIBUTE = "BODY[]".freeze
154
+ UID_FETCH_RETRY_CLASSES = [::EOFError, ::Errno::ECONNRESET, ::IOError].freeze
155
+ APPEND_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
156
+ CREATE_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
157
+ EXAMINE_RETRY_CLASSES = [::Net::IMAP::BadResponseError].freeze
158
+ PERMITTED_FLAGS = %i(Answered Draft Flagged Seen).freeze
159
+
159
160
  def examine
160
161
  client.examine(utf7_encoded_name)
161
162
  rescue Net::IMAP::NoResponseError
@@ -10,11 +10,8 @@ module Imap; end
10
10
  module Imap::Backup
11
11
  class Account; end
12
12
 
13
+ # Runs a backup for a single account folder
13
14
  class Account::FolderBackup
14
- attr_reader :account
15
- attr_reader :folder
16
- attr_reader :refresh
17
-
18
15
  def initialize(account:, folder:, refresh: false)
19
16
  @account = account
20
17
  @folder = folder
@@ -38,6 +35,10 @@ module Imap::Backup
38
35
 
39
36
  private
40
37
 
38
+ attr_reader :account
39
+ attr_reader :folder
40
+ attr_reader :refresh
41
+
41
42
  def folder_ok?
42
43
  begin
43
44
  return false if !folder.exist?
@@ -6,9 +6,8 @@ module Imap; end
6
6
  module Imap::Backup
7
7
  class Account; end
8
8
 
9
+ # Handles creation of directories for backup storage
9
10
  class Account::FolderEnsurer
10
- attr_reader :account
11
-
12
11
  def initialize(account:)
13
12
  @account = account
14
13
  end
@@ -22,5 +21,9 @@ module Imap::Backup
22
21
  permissions: Serializer::Directory::DIRECTORY_PERMISSIONS
23
22
  ).run
24
23
  end
24
+
25
+ private
26
+
27
+ attr_reader :account
25
28
  end
26
29
  end
@@ -6,10 +6,10 @@ module Imap; end
6
6
  module Imap::Backup
7
7
  class Account; end
8
8
 
9
- # Deletes serialized folders that are not configured to be backed up
9
+ # Deletes serialized folders that are not configured to be backed up.
10
+ # This is used in mirror mode, where local copies are only kept as long as they
11
+ # exist on the server.
10
12
  class Account::LocalOnlyFolderDeleter
11
- attr_reader :account
12
-
13
13
  def initialize(account:)
14
14
  @account = account
15
15
  end
@@ -24,5 +24,9 @@ module Imap::Backup
24
24
  serializer.delete if !wanted.include?(serializer.folder)
25
25
  end
26
26
  end
27
+
28
+ private
29
+
30
+ attr_reader :account
27
31
  end
28
32
  end
@@ -6,9 +6,8 @@ module Imap; end
6
6
  module Imap::Backup
7
7
  class Account; end
8
8
 
9
+ # Restores all backed up folders to the server
9
10
  class Account::Restore
10
- attr_reader :account
11
-
12
11
  def initialize(account:)
13
12
  @account = account
14
13
  end
@@ -19,5 +18,9 @@ module Imap::Backup
19
18
  Uploader.new(folder, serializer).run
20
19
  end
21
20
  end
21
+
22
+ private
23
+
24
+ attr_reader :account
22
25
  end
23
26
  end
@@ -9,11 +9,10 @@ module Imap; end
9
9
  module Imap::Backup
10
10
  class Account; end
11
11
 
12
+ # Enumerates over the folders that are backed up to an account
12
13
  class Account::SerializedFolders
13
14
  include Enumerable
14
15
 
15
- attr_reader :account
16
-
17
16
  def initialize(account:)
18
17
  @account = account
19
18
  end
@@ -31,6 +30,8 @@ module Imap::Backup
31
30
 
32
31
  private
33
32
 
33
+ attr_reader :account
34
+
34
35
  def base
35
36
  @base ||= Pathname.new(account.local_path)
36
37
  end
@@ -6,19 +6,62 @@ require "imap/backup/account/restore"
6
6
  module Imap; end
7
7
 
8
8
  module Imap::Backup
9
+ # Contains the attributes relating to an email account.
9
10
  class Account
11
+ # By default, the backup process fetches one email at a time
10
12
  DEFAULT_MULTI_FETCH_SIZE = 1
11
13
 
14
+ # The username of the account (usually the same as the email address)
15
+ # @return [String]
12
16
  attr_reader :username
17
+ # The password of the Account
13
18
  attr_reader :password
19
+ # The path where backups will be saved
20
+ # @return [String]
14
21
  attr_reader :local_path
22
+ # @overload folders
23
+ # The list of folders that have been configured for the Account
24
+ # @see #folder_blacklist how this list is interpreted.
25
+ # @return [Array<String>, void]
26
+ # @overload folders=(value)
27
+ # Sets the folders attribute and marks it as modified, storing the original value
28
+ # @param value [Array<String>] a list of folders
29
+ # @return [void]
15
30
  attr_reader :folders
31
+ # Indicates whether the configured folders are a whitelist or a blacklist.
32
+ # When true, any folders attribute will be taken as a list of folders to
33
+ # skip when running backups.
34
+ # When false, the folders attribute is used as the list of folders to backup.
35
+ # If no folders are configured, all folders on the server are backed up
36
+ # irrespective of the folder_blacklist setting
37
+ # @return [Boolean]
16
38
  attr_reader :folder_blacklist
39
+ # Should all emails be backed up progressively, or should emails
40
+ # which are deleted from the server be deleted locally?
17
41
  attr_reader :mirror_mode
42
+ # The address of the IMAP server
43
+ # @return [String]
18
44
  attr_reader :server
45
+ # Extra options to be passed to the IMAP server when connecting
46
+ # @return [Hash, void]
19
47
  attr_reader :connection_options
48
+ # The name of the download strategy to adopt during backups
49
+ # @return [String]
20
50
  attr_accessor :download_strategy
51
+ # Should 'Seen' flags be cached before fetchiong emails and
52
+ # rewritten to the server afterwards?
53
+ #
54
+ # Some IMAP providers, notably Apple Mail, set the '\Seen' flag
55
+ # on emails when they are fetched. By setting `:reset_seen_flags_after_fetch`,
56
+ # a workaround is activated which checks which emails are 'unseen' before
57
+ # and after the fetch, and removes the '\Seen' flag from those which have changed.
58
+ # As this check is susceptible to 'race conditions', i.e. when a different
59
+ # client sets the '\Seen' flag while imap-backup is fetching, it is best
60
+ # to only use it when required (i.e. for IMAP providers which always
61
+ # mark messages as '\Seen' when accessed).
62
+ # @return [Boolean]
21
63
  attr_reader :reset_seen_flags_after_fetch
64
+ # Tracks changes to the Account's attributes
22
65
  attr_reader :changes
23
66
 
24
67
  def initialize(options)
@@ -38,23 +81,39 @@ module Imap::Backup
38
81
  @marked_for_deletion = false
39
82
  end
40
83
 
84
+ # Initializes a client for the account's IMAP server
85
+ #
86
+ # @return [Account::Client::Default] the client
41
87
  def client
42
88
  @client ||= Account::ClientFactory.new(account: self).run
43
89
  end
44
90
 
91
+ # Returns the namespaces configured for the account on the IMAP server
92
+ #
93
+ # @return [Array<String>] the namespaces
45
94
  def namespaces
46
95
  client.namespace
47
96
  end
48
97
 
98
+ # Returns the capabilites of the IMAP server
99
+ #
100
+ # @return [Array<String>] the capabilities
49
101
  def capabilities
50
102
  client.capability
51
103
  end
52
104
 
105
+ # Restore the local backup to the server
106
+ #
107
+ # @return [void]
53
108
  def restore
54
109
  restore = Account::Restore.new(account: self)
55
110
  restore.run
56
111
  end
57
112
 
113
+ # Indicates whether the account has been configured, and is ready
114
+ # to be used
115
+ #
116
+ # @return [Boolean]
58
117
  def valid?
59
118
  username && password ? true : false
60
119
  end
@@ -63,18 +122,28 @@ module Imap::Backup
63
122
  changes.any?
64
123
  end
65
124
 
125
+ # Resets the store of changes, indicating that the current state is the saved state
66
126
  def clear_changes
67
127
  @changes = {}
68
128
  end
69
129
 
130
+ # Sets a flag indicating the Account should be excluded from the next save operation
131
+ #
132
+ # @return [void]
70
133
  def mark_for_deletion
71
134
  @marked_for_deletion = true
72
135
  end
73
136
 
137
+ # Indicates whether the account has been flagged for deletion during setup
138
+ #
139
+ # @return [Boolean]
74
140
  def marked_for_deletion?
75
141
  @marked_for_deletion
76
142
  end
77
143
 
144
+ # Returns all Account data for serialization
145
+ #
146
+ # @return [Hash]
78
147
  def to_h
79
148
  h = {username: @username, password: @password}
80
149
  h[:local_path] = @local_path if @local_path
@@ -90,14 +159,23 @@ module Imap::Backup
90
159
  h
91
160
  end
92
161
 
162
+ # Sets the username attribute and marks it as modified, storing the original value
163
+ #
164
+ # @return [void]
93
165
  def username=(value)
94
166
  update(:username, value)
95
167
  end
96
168
 
169
+ # Sets the password attribute and marks it as modified, storing the original value
170
+ #
171
+ # @return [void]
97
172
  def password=(value)
98
173
  update(:password, value)
99
174
  end
100
175
 
176
+ # Sets the local_path attribute and marks it as modified, storing the original value
177
+ #
178
+ # @return [void]
101
179
  def local_path=(value)
102
180
  update(:local_path, value)
103
181
  end
@@ -130,6 +208,9 @@ module Imap::Backup
130
208
  update(:connection_options, parsed)
131
209
  end
132
210
 
211
+ # The number of emails to fetch from the IMAP server at a time
212
+ #
213
+ # @return [Integer]
133
214
  def multi_fetch_size
134
215
  @multi_fetch_size ||= begin
135
216
  int = @multi_fetch_size_orignal.to_i
@@ -141,6 +222,10 @@ module Imap::Backup
141
222
  end
142
223
  end
143
224
 
225
+ # Sets the multi_fetch_size attribute and marks it as modified, storing the original value.
226
+ # If the supplied value is not a positive integer, uses {DEFAULT_MULTI_FETCH_SIZE}
227
+ #
228
+ # @return [void]
144
229
  def multi_fetch_size=(value)
145
230
  parsed = value.to_i
146
231
  parsed = DEFAULT_MULTI_FETCH_SIZE if !parsed.positive?
@@ -14,8 +14,6 @@ module Imap::Backup
14
14
  include Thor::Actions
15
15
  include CLI::Helpers
16
16
 
17
- attr_reader :options
18
-
19
17
  def initialize(options)
20
18
  super([])
21
19
  @options = options
@@ -44,18 +42,22 @@ module Imap::Backup
44
42
  end
45
43
  exit(exit_code) if exit_code
46
44
  end
45
+ end
47
46
 
48
- def refresh
49
- options.key?(:refresh) ? !!options[:refresh] : false
50
- end
47
+ private
51
48
 
52
- def choose_exit_code(exception)
53
- case exception
54
- when Net::IMAP::NoResponseError, Errno::ECONNREFUSED
55
- 111
56
- else
57
- 1
58
- end
49
+ attr_reader :options
50
+
51
+ def refresh
52
+ options.key?(:refresh) ? !!options[:refresh] : false
53
+ end
54
+
55
+ def choose_exit_code(exception)
56
+ case exception
57
+ when Net::IMAP::NoResponseError, Errno::ECONNREFUSED
58
+ 111
59
+ else
60
+ 1
59
61
  end
60
62
  end
61
63
  end
@@ -10,11 +10,6 @@ module Imap::Backup
10
10
  class CLI < Thor; end
11
11
 
12
12
  class CLI::FolderEnumerator
13
- attr_reader :destination
14
- attr_reader :destination_delimiter
15
- attr_reader :source
16
- attr_reader :source_delimiter
17
-
18
13
  def initialize(
19
14
  destination:,
20
15
  source:,
@@ -45,6 +40,11 @@ module Imap::Backup
45
40
 
46
41
  private
47
42
 
43
+ attr_reader :destination
44
+ attr_reader :destination_delimiter
45
+ attr_reader :source
46
+ attr_reader :source_delimiter
47
+
48
48
  def destination_prefix_clipped
49
49
  @destination_prefix_clipped ||=
50
50
  if @destination_prefix.end_with?(destination_delimiter)
@@ -13,8 +13,6 @@ module Imap::Backup
13
13
  class CLI::Local::Check
14
14
  include CLI::Helpers
15
15
 
16
- attr_reader :options
17
-
18
16
  def initialize(options)
19
17
  @options = options
20
18
  end
@@ -48,6 +46,10 @@ module Imap::Backup
48
46
  end
49
47
  end
50
48
 
49
+ private
50
+
51
+ attr_reader :options
52
+
51
53
  def print_check_results_as_json(results)
52
54
  Kernel.puts results.to_json
53
55
  end