imap-backup 6.0.0.rc2 → 6.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/imap-backup.gemspec +5 -1
  3. data/lib/cli_coverage.rb +11 -11
  4. data/lib/email/provider/base.rb +2 -0
  5. data/lib/email/provider/unknown.rb +2 -0
  6. data/lib/email/provider.rb +2 -0
  7. data/lib/imap/backup/account/connection/backup_folders.rb +27 -0
  8. data/lib/imap/backup/account/connection/client_factory.rb +54 -0
  9. data/lib/imap/backup/account/connection/folder_names.rb +26 -0
  10. data/lib/imap/backup/account/connection.rb +11 -95
  11. data/lib/imap/backup/account/folder.rb +9 -6
  12. data/lib/imap/backup/account.rb +3 -5
  13. data/lib/imap/backup/cli/backup.rb +1 -3
  14. data/lib/imap/backup/cli/helpers.rb +24 -22
  15. data/lib/imap/backup/cli/local.rb +20 -13
  16. data/lib/imap/backup/cli/migrate.rb +4 -10
  17. data/lib/imap/backup/cli/restore.rb +8 -7
  18. data/lib/imap/backup/cli/setup.rb +10 -8
  19. data/lib/imap/backup/cli/stats.rb +78 -0
  20. data/lib/imap/backup/cli/status.rb +2 -2
  21. data/lib/imap/backup/cli/utils.rb +4 -6
  22. data/lib/imap/backup/cli.rb +24 -3
  23. data/lib/imap/backup/configuration.rb +9 -11
  24. data/lib/imap/backup/downloader.rb +48 -30
  25. data/lib/imap/backup/migrator.rb +5 -5
  26. data/lib/imap/backup/sanitizer.rb +3 -2
  27. data/lib/imap/backup/serializer/appender.rb +49 -0
  28. data/lib/imap/backup/serializer/message_enumerator.rb +29 -0
  29. data/lib/imap/backup/serializer/unused_name_finder.rb +27 -0
  30. data/lib/imap/backup/serializer.rb +24 -78
  31. data/lib/imap/backup/setup/account/header.rb +75 -0
  32. data/lib/imap/backup/setup/account.rb +14 -91
  33. data/lib/imap/backup/setup/asker.rb +4 -15
  34. data/lib/imap/backup/setup/backup_path.rb +41 -0
  35. data/lib/imap/backup/setup/email.rb +45 -0
  36. data/lib/imap/backup/setup/folder_chooser.rb +3 -3
  37. data/lib/imap/backup/setup/helpers.rb +1 -1
  38. data/lib/imap/backup/setup.rb +5 -4
  39. data/lib/imap/backup/thunderbird/mailbox_exporter.rb +39 -20
  40. data/lib/imap/backup/uploader.rb +46 -8
  41. data/lib/imap/backup/utils.rb +1 -1
  42. data/lib/imap/backup/version.rb +1 -1
  43. data/lib/imap/backup.rb +0 -1
  44. metadata +31 -134
  45. data/spec/features/backup_spec.rb +0 -100
  46. data/spec/features/configuration/minimal_configuration.rb +0 -15
  47. data/spec/features/configuration/missing_configuration.rb +0 -14
  48. data/spec/features/folders_spec.rb +0 -36
  49. data/spec/features/helper.rb +0 -2
  50. data/spec/features/local/list_accounts_spec.rb +0 -12
  51. data/spec/features/local/list_emails_spec.rb +0 -21
  52. data/spec/features/local/list_folders_spec.rb +0 -21
  53. data/spec/features/local/show_an_email_spec.rb +0 -34
  54. data/spec/features/migrate_spec.rb +0 -35
  55. data/spec/features/remote/list_account_folders_spec.rb +0 -16
  56. data/spec/features/restore_spec.rb +0 -162
  57. data/spec/features/status_spec.rb +0 -43
  58. data/spec/features/support/aruba.rb +0 -78
  59. data/spec/features/support/backup_directory.rb +0 -43
  60. data/spec/features/support/email_server.rb +0 -110
  61. data/spec/features/support/shared/connection_context.rb +0 -14
  62. data/spec/features/support/shared/message_fixtures.rb +0 -16
  63. data/spec/fixtures/connection.yml +0 -7
  64. data/spec/spec_helper.rb +0 -15
  65. data/spec/support/fixtures.rb +0 -11
  66. data/spec/support/higline_test_helpers.rb +0 -8
  67. data/spec/support/silence_logging.rb +0 -7
  68. data/spec/unit/email/mboxrd/message_spec.rb +0 -177
  69. data/spec/unit/email/provider/apple_mail_spec.rb +0 -7
  70. data/spec/unit/email/provider/base_spec.rb +0 -11
  71. data/spec/unit/email/provider/fastmail_spec.rb +0 -7
  72. data/spec/unit/email/provider/gmail_spec.rb +0 -7
  73. data/spec/unit/email/provider_spec.rb +0 -27
  74. data/spec/unit/imap/backup/account/connection_spec.rb +0 -433
  75. data/spec/unit/imap/backup/account/folder_spec.rb +0 -261
  76. data/spec/unit/imap/backup/account_spec.rb +0 -246
  77. data/spec/unit/imap/backup/cli/accounts_spec.rb +0 -58
  78. data/spec/unit/imap/backup/cli/backup_spec.rb +0 -19
  79. data/spec/unit/imap/backup/cli/folders_spec.rb +0 -39
  80. data/spec/unit/imap/backup/cli/helpers_spec.rb +0 -87
  81. data/spec/unit/imap/backup/cli/local_spec.rb +0 -100
  82. data/spec/unit/imap/backup/cli/migrate_spec.rb +0 -80
  83. data/spec/unit/imap/backup/cli/restore_spec.rb +0 -67
  84. data/spec/unit/imap/backup/cli/setup_spec.rb +0 -17
  85. data/spec/unit/imap/backup/cli/utils_spec.rb +0 -125
  86. data/spec/unit/imap/backup/cli_spec.rb +0 -93
  87. data/spec/unit/imap/backup/client/apple_mail_spec.rb +0 -9
  88. data/spec/unit/imap/backup/client/default_spec.rb +0 -22
  89. data/spec/unit/imap/backup/configuration_spec.rb +0 -238
  90. data/spec/unit/imap/backup/downloader_spec.rb +0 -96
  91. data/spec/unit/imap/backup/logger_spec.rb +0 -48
  92. data/spec/unit/imap/backup/migrator_spec.rb +0 -58
  93. data/spec/unit/imap/backup/sanitizer_spec.rb +0 -42
  94. data/spec/unit/imap/backup/serializer/directory_spec.rb +0 -37
  95. data/spec/unit/imap/backup/serializer/imap_spec.rb +0 -218
  96. data/spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb +0 -45
  97. data/spec/unit/imap/backup/serializer/mbox_spec.rb +0 -101
  98. data/spec/unit/imap/backup/serializer_spec.rb +0 -296
  99. data/spec/unit/imap/backup/setup/account_spec.rb +0 -461
  100. data/spec/unit/imap/backup/setup/asker_spec.rb +0 -137
  101. data/spec/unit/imap/backup/setup/connection_tester_spec.rb +0 -51
  102. data/spec/unit/imap/backup/setup/folder_chooser_spec.rb +0 -146
  103. data/spec/unit/imap/backup/setup/helpers_spec.rb +0 -15
  104. data/spec/unit/imap/backup/setup_spec.rb +0 -301
  105. data/spec/unit/imap/backup/thunderbird/mailbox_exporter_spec.rb +0 -116
  106. data/spec/unit/imap/backup/uploader_spec.rb +0 -54
  107. data/spec/unit/imap/backup/utils_spec.rb +0 -92
  108. data/spec/unit/retry_on_error_spec.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f9cac7966fac9858fdc380d8e9638c8d479035ee4053444a104b8c3eb5a304c
4
- data.tar.gz: 5d9785b5e34d90535c8052d216d9b3dbf46ea743672f05129604729662f42f34
3
+ metadata.gz: 00576d7b3a0482f2e2ede92e545a5bbebcdf5ab2a688feb8e0c54281a1d9ba9a
4
+ data.tar.gz: e8bc14ff755f817cb08f4b979b6c689d4ee87c1b9d96acca4d0dc2a8297a40a7
5
5
  SHA512:
6
- metadata.gz: a4595e4316dcdc20123a8ed2bec524d37c1de95da49281a30484349c317a996cf3c6946617a489880a0c41db41698b2ee862d9aee4f9c9b8fa34d67707ba924c
7
- data.tar.gz: ccee268de9cb6225c72fe0cb11a2552fc793f664429d8dfa918e5b4697961c8e5e15e47ed653dac241f377385806443f17683614b8ff76075a8ff2f12e07f98c
6
+ metadata.gz: 155476a2d92177685b58802d1431a15975161fcee512f43ee79cb332078faba8e0247f81020eb4c92c20fdb308ec6bb1650136cf1d92f468e4ece68142717e67
7
+ data.tar.gz: ddd269797169fdbc255ef907bb30a9c66775709ad32bc10f2a3d6ec75da441625269db307ed3bfa8e06dd3f076ff313e6124d47be73654c1f2b2cc8202e1f55a
data/imap-backup.gemspec CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |gem|
18
18
  gem.files += %w[LICENSE README.md]
19
19
 
20
20
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
21
- gem.test_files = Dir.glob("spec/**/*{.rb,.yml}")
22
21
  gem.require_paths = ["lib"]
23
22
  gem.required_ruby_version = ">= 2.5"
24
23
 
@@ -34,4 +33,9 @@ Gem::Specification.new do |gem|
34
33
  gem.add_development_dependency "rspec", ">= 3.0.0"
35
34
  gem.add_development_dependency "rubocop-rspec"
36
35
  gem.add_development_dependency "simplecov"
36
+ gem.add_development_dependency "yard"
37
+
38
+ gem.metadata = {
39
+ "rubygems_mfa_required" => "true"
40
+ }
37
41
  end
data/lib/cli_coverage.rb CHANGED
@@ -1,18 +1,18 @@
1
1
  class CliCoverage
2
2
  def self.conditionally_activate
3
- if ENV["COVERAGE"]
4
- require "simplecov"
3
+ return if !ENV["COVERAGE"]
5
4
 
6
- # Collect coverage separately
7
- SimpleCov.command_name "#{ENV['COVERAGE']} #{ARGV.join(' ')} coverage"
5
+ require "simplecov"
8
6
 
9
- # Silence output
10
- SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter
11
- SimpleCov.print_error_status = false
7
+ # Collect coverage separately
8
+ SimpleCov.command_name "#{ENV['COVERAGE']} #{ARGV.join(' ')} coverage"
12
9
 
13
- # Ensure SimpleCov doesn't filter out all out code
14
- project_root = File.expand_path("..", __dir__)
15
- SimpleCov.root project_root
16
- end
10
+ # Silence output
11
+ SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter
12
+ SimpleCov.print_error_status = false
13
+
14
+ # Ensure SimpleCov doesn't filter out all out code
15
+ project_root = File.expand_path("..", __dir__)
16
+ SimpleCov.root project_root
17
17
  end
18
18
  end
@@ -3,6 +3,8 @@ class Email::Provider; end
3
3
 
4
4
  class Email::Provider::Base
5
5
  def options
6
+ # rubocop:disable Naming/VariableNumber
6
7
  {port: 993, ssl: {ssl_version: :TLSv1_2}}
8
+ # rubocop:enable Naming/VariableNumber
7
9
  end
8
10
  end
@@ -6,6 +6,8 @@ class Email::Provider::Unknown < Email::Provider::Base
6
6
  end
7
7
 
8
8
  def options
9
+ # rubocop:disable Naming/VariableNumber
9
10
  {port: 993, ssl: {ssl_version: :TLSv1_2}}
11
+ # rubocop:enable Naming/VariableNumber
10
12
  end
11
13
  end
@@ -7,6 +7,7 @@ module Email; end
7
7
 
8
8
  class Email::Provider
9
9
  def self.for_address(address)
10
+ # rubocop:disable Lint/DuplicateBranch
10
11
  case
11
12
  when address.end_with?("@fastmail.com")
12
13
  Email::Provider::Fastmail.new
@@ -23,5 +24,6 @@ class Email::Provider
23
24
  else
24
25
  Email::Provider::Unknown.new
25
26
  end
27
+ # rubocop:enable Lint/DuplicateBranch
26
28
  end
27
29
  end
@@ -0,0 +1,27 @@
1
+ module Imap::Backup
2
+ class Account; end
3
+ class Account::Connection; end
4
+
5
+ class Account::Connection::BackupFolders
6
+ attr_reader :account
7
+ attr_reader :client
8
+
9
+ def initialize(client:, account:)
10
+ @client = client
11
+ @account = account
12
+ end
13
+
14
+ def run
15
+ names =
16
+ if account.folders&.any?
17
+ account.folders.map { |af| af[:name] }
18
+ else
19
+ Account::Connection::FolderNames.new(client: client, account: account).run
20
+ end
21
+
22
+ names.map do |name|
23
+ Account::Folder.new(account.connection, name)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ require "retry_on_error"
2
+
3
+ module Imap::Backup
4
+ class Account::Connection::ClientFactory
5
+ include RetryOnError
6
+
7
+ LOGIN_RETRY_CLASSES = [EOFError, Errno::ECONNRESET, SocketError].freeze
8
+
9
+ attr_reader :account
10
+
11
+ def initialize(account:)
12
+ @account = account
13
+ @provider = nil
14
+ @server = nil
15
+ end
16
+
17
+ def run
18
+ retry_on_error(errors: LOGIN_RETRY_CLASSES) do
19
+ options = provider_options
20
+ Logger.logger.debug(
21
+ "Creating IMAP instance: #{server}, options: #{options.inspect}"
22
+ )
23
+ client =
24
+ if provider.is_a?(Email::Provider::AppleMail)
25
+ Client::AppleMail.new(server, options)
26
+ else
27
+ Client::Default.new(server, options)
28
+ end
29
+ Logger.logger.debug "Logging in: #{account.username}/#{masked_password}"
30
+ client.login(account.username, account.password)
31
+ Logger.logger.debug "Login complete"
32
+ client
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def masked_password
39
+ account.password.gsub(/./, "x")
40
+ end
41
+
42
+ def provider
43
+ @provider ||= Email::Provider.for_address(account.username)
44
+ end
45
+
46
+ def provider_options
47
+ provider.options.merge(account.connection_options || {})
48
+ end
49
+
50
+ def server
51
+ @server ||= account.server || provider.host
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,26 @@
1
+ module Imap::Backup
2
+ class Account; end
3
+ class Account::Connection; end
4
+
5
+ class Account::Connection::FolderNames
6
+ attr_reader :account
7
+ attr_reader :client
8
+
9
+ def initialize(client:, account:)
10
+ @client = client
11
+ @account = account
12
+ end
13
+
14
+ def run
15
+ folder_names = client.list
16
+
17
+ if folder_names.empty?
18
+ message = "Unable to get folder list for account #{account.username}"
19
+ Logger.logger.info message
20
+ raise message
21
+ end
22
+
23
+ folder_names
24
+ end
25
+ end
26
+ end
@@ -1,17 +1,15 @@
1
+ require "email/provider"
1
2
  require "imap/backup/client/apple_mail"
2
3
  require "imap/backup/client/default"
4
+ require "imap/backup/account/connection/backup_folders"
5
+ require "imap/backup/account/connection/client_factory"
6
+ require "imap/backup/account/connection/folder_names"
3
7
  require "imap/backup/serializer/directory"
4
8
 
5
- require "retry_on_error"
6
-
7
9
  module Imap::Backup
8
10
  class Account; end
9
11
 
10
12
  class Account::Connection
11
- include RetryOnError
12
-
13
- LOGIN_RETRY_CLASSES = [EOFError, Errno::ECONNRESET, SocketError].freeze
14
-
15
13
  attr_reader :account
16
14
 
17
15
  def initialize(account)
@@ -20,34 +18,12 @@ module Imap::Backup
20
18
  end
21
19
 
22
20
  def folder_names
23
- @folder_names ||=
24
- begin
25
- folder_names = client.list
26
-
27
- if folder_names.empty?
28
- message = "Unable to get folder list for account #{account.username}"
29
- Imap::Backup::Logger.logger.info message
30
- raise message
31
- end
32
-
33
- folder_names
34
- end
21
+ @folder_names ||= Account::Connection::FolderNames.new(client: client, account: account).run
35
22
  end
36
23
 
37
24
  def backup_folders
38
25
  @backup_folders ||=
39
- begin
40
- names =
41
- if account.folders&.any?
42
- account.folders.map { |af| af[:name] }
43
- else
44
- folder_names
45
- end
46
-
47
- names.map do |name|
48
- Account::Folder.new(self, name)
49
- end
50
- end
26
+ Account::Connection::BackupFolders.new(client: client, account: account).run
51
27
  end
52
28
 
53
29
  def status
@@ -59,14 +35,14 @@ module Imap::Backup
59
35
  end
60
36
 
61
37
  def run_backup
62
- Imap::Backup::Logger.logger.debug "Running backup of account: #{account.username}"
38
+ Logger.logger.debug "Running backup of account: #{account.username}"
63
39
  # start the connection so we get logging messages in the right order
64
40
  client
65
41
  ensure_account_folder
66
42
  each_folder do |folder, serializer|
67
43
  next if !folder.exist?
68
44
 
69
- Imap::Backup::Logger.logger.debug "[#{folder.name}] running backup"
45
+ Logger.logger.debug "[#{folder.name}] running backup"
70
46
  serializer.apply_uid_validity(folder.uid_validity)
71
47
  begin
72
48
  Downloader.new(
@@ -95,7 +71,7 @@ module Imap::Backup
95
71
 
96
72
  def restore
97
73
  local_folders do |serializer, folder|
98
- restore_folder serializer, folder
74
+ Uploader.new(folder, serializer).run
99
75
  end
100
76
  end
101
77
 
@@ -112,32 +88,11 @@ module Imap::Backup
112
88
  @backup_folders = nil
113
89
  @client = nil
114
90
  @folder_names = nil
115
- @provider = nil
116
- @server = nil
117
91
  end
118
92
 
93
+ # TODO: make this private
119
94
  def client
120
- @client ||=
121
- retry_on_error(errors: LOGIN_RETRY_CLASSES) do
122
- options = provider_options
123
- Imap::Backup::Logger.logger.debug(
124
- "Creating IMAP instance: #{server}, options: #{options.inspect}"
125
- )
126
- client =
127
- if provider.is_a?(Email::Provider::AppleMail)
128
- Client::AppleMail.new(server, options)
129
- else
130
- Client::Default.new(server, options)
131
- end
132
- Imap::Backup::Logger.logger.debug "Logging in: #{account.username}/#{masked_password}"
133
- client.login(account.username, account.password)
134
- Imap::Backup::Logger.logger.debug "Login complete"
135
- client
136
- end
137
- end
138
-
139
- def server
140
- @server ||= account.server || provider.host
95
+ @client ||= Account::Connection::ClientFactory.new(account: account).run
141
96
  end
142
97
 
143
98
  private
@@ -149,33 +104,6 @@ module Imap::Backup
149
104
  end
150
105
  end
151
106
 
152
- def restore_folder(serializer, folder)
153
- existing_uids = folder.uids
154
- if existing_uids.any?
155
- Imap::Backup::Logger.logger.debug(
156
- "There's already a '#{folder.name}' folder with emails"
157
- )
158
- new_name = serializer.apply_uid_validity(folder.uid_validity)
159
- old_name = serializer.folder
160
- if new_name
161
- Imap::Backup::Logger.logger.debug(
162
- "Backup '#{old_name}' renamed and restored to '#{new_name}'"
163
- )
164
- new_serializer = Serializer.new(account.local_path, new_name)
165
- new_folder = Account::Folder.new(self, new_name)
166
- new_folder.create
167
- new_serializer.force_uid_validity(new_folder.uid_validity)
168
- Uploader.new(new_folder, new_serializer).run
169
- else
170
- Uploader.new(folder, serializer).run
171
- end
172
- else
173
- folder.create
174
- serializer.force_uid_validity(folder.uid_validity)
175
- Uploader.new(folder, serializer).run
176
- end
177
- end
178
-
179
107
  def ensure_account_folder
180
108
  Utils.make_folder(
181
109
  File.dirname(account.local_path),
@@ -183,17 +111,5 @@ module Imap::Backup
183
111
  Serializer::Directory::DIRECTORY_PERMISSIONS
184
112
  )
185
113
  end
186
-
187
- def masked_password
188
- account.password.gsub(/./, "x")
189
- end
190
-
191
- def provider
192
- @provider ||= Email::Provider.for_address(account.username)
193
- end
194
-
195
- def provider_options
196
- provider.options.merge(account.connection_options || {})
197
- end
198
114
  end
199
115
  end
@@ -12,7 +12,8 @@ module Imap::Backup
12
12
  include RetryOnError
13
13
 
14
14
  BODY_ATTRIBUTE = "BODY[]".freeze
15
- UID_FETCH_RETRY_CLASSES = [EOFError].freeze
15
+ UID_FETCH_RETRY_CLASSES = [EOFError, Errno::ECONNRESET, IOError].freeze
16
+ APPEND_RETRY_CLASSES = [Net::IMAP::BadResponseError].freeze
16
17
 
17
18
  attr_reader :connection
18
19
  attr_reader :name
@@ -64,7 +65,7 @@ module Imap::Backup
64
65
  in `search_internal` in stdlib net/imap.rb.
65
66
  This is caused by `@responses["SEARCH"] being unset/undefined
66
67
  MESSAGE
67
- Imap::Backup::Logger.logger.warn message
68
+ Logger.logger.warn message
68
69
  []
69
70
  end
70
71
 
@@ -91,8 +92,10 @@ module Imap::Backup
91
92
  def append(message)
92
93
  body = message.imap_body
93
94
  date = message.date&.to_time
94
- response = client.append(utf7_encoded_name, body, nil, date)
95
- extract_uid(response)
95
+ retry_on_error(errors: APPEND_RETRY_CLASSES, limit: 3) do
96
+ response = client.append(utf7_encoded_name, body, nil, date)
97
+ extract_uid(response)
98
+ end
96
99
  end
97
100
 
98
101
  def clear
@@ -108,12 +111,12 @@ module Imap::Backup
108
111
  def examine
109
112
  client.examine(utf7_encoded_name)
110
113
  rescue Net::IMAP::NoResponseError
111
- Imap::Backup::Logger.logger.warn "Folder '#{name}' does not exist on server"
114
+ Logger.logger.warn "Folder '#{name}' does not exist on server"
112
115
  raise FolderNotFound, "Folder '#{name}' does not exist on server"
113
116
  end
114
117
 
115
118
  def extract_uid(response)
116
- @uid_validity, uid = response.data.code.data.split(" ").map(&:to_i)
119
+ @uid_validity, uid = response.data.code.data.split.map(&:to_i)
117
120
  uid
118
121
  end
119
122
 
@@ -47,10 +47,7 @@ module Imap::Backup
47
47
  end
48
48
 
49
49
  def to_h
50
- h = {
51
- username: @username,
52
- password: @password,
53
- }
50
+ h = {username: @username, password: @password}
54
51
  h[:local_path] = @local_path if @local_path
55
52
  h[:folders] = @folders if @folders
56
53
  h[:server] = @server if @server
@@ -73,6 +70,7 @@ module Imap::Backup
73
70
 
74
71
  def folders=(value)
75
72
  raise "folders must be an Array" if !value.is_a?(Array)
73
+
76
74
  update(:folders, value)
77
75
  end
78
76
 
@@ -113,7 +111,7 @@ module Imap::Backup
113
111
  end
114
112
  else
115
113
  current = instance_variable_get(key)
116
- changes[field] = {from: current, to: value}
114
+ changes[field] = {from: current, to: value} if value != current
117
115
  end
118
116
 
119
117
  instance_variable_set(key, value)
@@ -12,9 +12,7 @@ module Imap::Backup
12
12
 
13
13
  no_commands do
14
14
  def run
15
- each_connection(account_names) do |connection|
16
- connection.run_backup
17
- end
15
+ each_connection(account_names, &:run_backup)
18
16
  end
19
17
  end
20
18
  end
@@ -1,35 +1,37 @@
1
1
  require "imap/backup"
2
2
  require "imap/backup/cli/accounts"
3
3
 
4
- module Imap::Backup::CLI::Helpers
5
- def symbolized(options)
6
- options.each.with_object({}) do |(k, v), acc|
7
- key = k.gsub("-", "_").intern
8
- acc[key] = v
4
+ module Imap::Backup
5
+ module CLI::Helpers
6
+ def symbolized(options)
7
+ options.each.with_object({}) do |(k, v), acc|
8
+ key = k.gsub("-", "_").intern
9
+ acc[key] = v
10
+ end
9
11
  end
10
- end
11
12
 
12
- def account(email)
13
- accounts = Imap::Backup::CLI::Accounts.new
14
- account = accounts.find { |a| a.username == email }
15
- raise "#{email} is not a configured account" if !account
13
+ def account(email)
14
+ accounts = CLI::Accounts.new
15
+ account = accounts.find { |a| a.username == email }
16
+ raise "#{email} is not a configured account" if !account
16
17
 
17
- account
18
- end
18
+ account
19
+ end
19
20
 
20
- def connection(email)
21
- account = account(email)
21
+ def connection(email)
22
+ account = account(email)
22
23
 
23
- Imap::Backup::Account::Connection.new(account)
24
- end
24
+ Account::Connection.new(account)
25
+ end
25
26
 
26
- def each_connection(names)
27
- accounts = Imap::Backup::CLI::Accounts.new(names)
27
+ def each_connection(names)
28
+ accounts = CLI::Accounts.new(names)
28
29
 
29
- accounts.each do |account|
30
- yield account.connection
30
+ accounts.each do |account|
31
+ yield account.connection
32
+ end
33
+ rescue ConfigurationNotFound
34
+ raise "imap-backup is not configured. Run `imap-backup setup`"
31
35
  end
32
- rescue Imap::Backup::ConfigurationNotFound
33
- raise "imap-backup is not configured. Run `imap-backup setup`"
34
36
  end
35
37
  end
@@ -5,6 +5,8 @@ module Imap::Backup
5
5
  include Thor::Actions
6
6
  include CLI::Helpers
7
7
 
8
+ MAX_SUBJECT = 60
9
+
8
10
  desc "accounts", "List locally backed-up accounts"
9
11
  def accounts
10
12
  accounts = CLI::Accounts.new
@@ -29,26 +31,16 @@ module Imap::Backup
29
31
  end
30
32
  raise "Folder '#{folder_name}' not found" if !folder_serializer
31
33
 
32
- max_subject = 60
33
34
  Kernel.puts format(
34
- "%-10<uid>s %-#{max_subject}<subject>s - %<date>s",
35
+ "%-10<uid>s %-#{MAX_SUBJECT}<subject>s - %<date>s",
35
36
  {uid: "UID", subject: "Subject", date: "Date"}
36
37
  )
37
- Kernel.puts "-" * (12 + max_subject + 28)
38
+ Kernel.puts "-" * (12 + MAX_SUBJECT + 28)
38
39
 
39
40
  uids = folder_serializer.uids
40
41
 
41
42
  folder_serializer.each_message(uids).map do |uid, message|
42
- m = {
43
- uid: uid,
44
- date: message.date.to_s,
45
- subject: message.subject || ""
46
- }
47
- if m[:subject].length > max_subject
48
- Kernel.puts format("% 10<uid>u: %.#{max_subject - 3}<subject>s... - %<date>s", m)
49
- else
50
- Kernel.puts format("% 10<uid>u: %-#{max_subject}<subject>s - %<date>s", m)
51
- end
43
+ list_message uid, message
52
44
  end
53
45
  end
54
46
 
@@ -78,5 +70,20 @@ module Imap::Backup
78
70
  Kernel.puts message.supplied_body
79
71
  end
80
72
  end
73
+
74
+ no_commands do
75
+ def list_message(uid, message)
76
+ m = {
77
+ uid: uid,
78
+ date: message.date.to_s,
79
+ subject: message.subject || ""
80
+ }
81
+ if m[:subject].length > MAX_SUBJECT
82
+ Kernel.puts format("% 10<uid>u: %.#{MAX_SUBJECT - 3}<subject>s... - %<date>s", m)
83
+ else
84
+ Kernel.puts format("% 10<uid>u: %-#{MAX_SUBJECT}<subject>s - %<date>s", m)
85
+ end
86
+ end
87
+ end
81
88
  end
82
89
  end
@@ -38,13 +38,9 @@ module Imap::Backup
38
38
  raise "Source and destination accounts cannot be the same!"
39
39
  end
40
40
 
41
- if !destination_account
42
- raise "Account '#{destination_email}' does not exist"
43
- end
41
+ raise "Account '#{destination_email}' does not exist" if !destination_account
44
42
 
45
- if !source_account
46
- raise "Account '#{source_email}' does not exist"
47
- end
43
+ raise "Account '#{source_email}' does not exist" if !source_account
48
44
  end
49
45
 
50
46
  def config
@@ -69,16 +65,14 @@ module Imap::Backup
69
65
 
70
66
  def folder_for(source_folder)
71
67
  no_source_prefix =
72
- if source_prefix != "" &&
73
- source_folder.start_with?(source_prefix)
68
+ if source_prefix != "" && source_folder.start_with?(source_prefix)
74
69
  source_folder.delete_prefix(source_prefix)
75
70
  else
76
71
  source_folder.to_s
77
72
  end
78
73
 
79
74
  with_destination_prefix =
80
- if destination_prefix &&
81
- destination_prefix != ""
75
+ if destination_prefix && destination_prefix != ""
82
76
  destination_prefix + no_source_prefix
83
77
  else
84
78
  no_source_prefix
@@ -7,11 +7,9 @@ module Imap::Backup
7
7
  attr_reader :account_names
8
8
 
9
9
  def initialize(email = nil, options)
10
+ super([])
10
11
  @email = email
11
- @account_names =
12
- if options.key?(:accounts)
13
- options[:accounts].split(",")
14
- end
12
+ @account_names = options[:accounts].split(",") if options.key?(:accounts)
15
13
  end
16
14
 
17
15
  no_commands do
@@ -22,12 +20,15 @@ module Imap::Backup
22
20
  connection.restore
23
21
  when !email && !account_names
24
22
  Logger.logger.info "Calling restore without an EMAIL parameter is deprecated"
25
- each_connection([]) { |connection| connection.restore }
23
+ each_connection([], &:restore)
26
24
  when email && account_names.any?
27
25
  raise "Pass either an email or the --accounts option, not both"
28
26
  when account_names.any?
29
- Logger.logger.info "Calling restore with the --account option is deprected, please pass a single EMAIL argument"
30
- each_connection(account_names) { |connection| connection.restore }
27
+ Logger.logger.info(
28
+ "Calling restore with the --account option is deprected, " \
29
+ "please pass a single EMAIL argument"
30
+ )
31
+ each_connection(account_names, &:restore)
31
32
  end
32
33
  end
33
34
  end
@@ -1,13 +1,15 @@
1
- class Imap::Backup::CLI::Setup < Thor
2
- include Thor::Actions
1
+ module Imap::Backup
2
+ class CLI::Setup < Thor
3
+ include Thor::Actions
3
4
 
4
- def initialize
5
- super([])
6
- end
5
+ def initialize
6
+ super([])
7
+ end
7
8
 
8
- no_commands do
9
- def run
10
- Imap::Backup::Setup.new.run
9
+ no_commands do
10
+ def run
11
+ Setup.new.run
12
+ end
11
13
  end
12
14
  end
13
15
  end