imap-backup 6.0.0.rc2 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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