imap-backup 4.2.2 → 5.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.
- checksums.yaml +4 -4
- data/imap-backup.gemspec +1 -0
- data/lib/imap/backup/account/connection.rb +4 -4
- data/lib/imap/backup/account/folder.rb +8 -0
- data/lib/imap/backup/cli/helpers.rb +4 -1
- data/lib/imap/backup/cli/local.rb +1 -1
- data/lib/imap/backup/cli/migrate.rb +114 -0
- data/lib/imap/backup/cli/remote.rb +15 -0
- data/lib/imap/backup/cli.rb +50 -4
- data/lib/imap/backup/client/default.rb +2 -2
- data/lib/imap/backup/migrator.rb +51 -0
- data/lib/imap/backup/sanitizer.rb +7 -4
- data/lib/imap/backup/version.rb +3 -3
- data/spec/features/configuration/minimal_configuration.rb +15 -0
- data/spec/features/configuration/missing_configuration.rb +14 -0
- data/spec/features/local/list_accounts_spec.rb +12 -0
- data/spec/features/local/list_emails_spec.rb +21 -0
- data/spec/features/local/list_folders_spec.rb +21 -0
- data/spec/features/local/show_an_email_spec.rb +34 -0
- data/spec/features/migrate_spec.rb +35 -0
- data/spec/features/remote/list_account_folders_spec.rb +16 -0
- data/spec/features/support/aruba.rb +69 -0
- data/spec/features/support/email_server.rb +1 -0
- data/spec/unit/imap/backup/account/connection_spec.rb +6 -8
- data/spec/unit/imap/backup/account/folder_spec.rb +26 -5
- data/spec/unit/imap/backup/cli/helpers_spec.rb +87 -0
- data/spec/unit/imap/backup/migrator_spec.rb +58 -0
- metadata +41 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 16911b1cea1983b844c3bbf7f74c03ff7436990fb5aa4d5b49fa18f03ae2e229
|
|
4
|
+
data.tar.gz: 265f63995e70ba3f68b98ec72d3a12b3e95100f7e6b320026b18bcc156888a92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a541a7830ddab458f2366bdad4924f3e6cbc3ba858651839e6dcd1a530acbbeb01e2c59a44331af73a2d77f606f2d6b39eacd2b5a705d78ec20e93d2c2f2527
|
|
7
|
+
data.tar.gz: 7b60170e3d29e9882f3bcbf13b04daa162434944d59311a5a03a4b1c1022a7a9501b292c3eb929d6e07039c47cc433316a338e062ced4e8a6b7ea424e6c0678b
|
data/imap-backup.gemspec
CHANGED
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |gem|
|
|
|
28
28
|
gem.add_runtime_dependency "rake"
|
|
29
29
|
gem.add_runtime_dependency "thor", "~> 1.1"
|
|
30
30
|
|
|
31
|
+
gem.add_development_dependency "aruba", ">= 0.0.0"
|
|
31
32
|
gem.add_development_dependency "codeclimate-test-reporter", "~> 0.4.8"
|
|
32
33
|
if RUBY_ENGINE == "jruby"
|
|
33
34
|
gem.add_development_dependency "pry-debugger-jruby"
|
|
@@ -16,11 +16,8 @@ module Imap::Backup
|
|
|
16
16
|
def initialize(account)
|
|
17
17
|
@account = account
|
|
18
18
|
reset
|
|
19
|
-
create_account_folder
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
# TODO: Make this private once the 'folders' command
|
|
23
|
-
# has been removed.
|
|
24
21
|
def folder_names
|
|
25
22
|
@folder_names ||=
|
|
26
23
|
begin
|
|
@@ -53,6 +50,7 @@ module Imap::Backup
|
|
|
53
50
|
end
|
|
54
51
|
|
|
55
52
|
def status
|
|
53
|
+
ensure_account_folder
|
|
56
54
|
backup_folders.map do |folder|
|
|
57
55
|
s = Serializer::Mbox.new(account.local_path, folder.name)
|
|
58
56
|
{name: folder.name, local: s.uids, remote: folder.uids}
|
|
@@ -63,6 +61,7 @@ module Imap::Backup
|
|
|
63
61
|
Imap::Backup::Logger.logger.debug "Running backup of account: #{account.username}"
|
|
64
62
|
# start the connection so we get logging messages in the right order
|
|
65
63
|
client
|
|
64
|
+
ensure_account_folder
|
|
66
65
|
each_folder do |folder, serializer|
|
|
67
66
|
next if !folder.exist?
|
|
68
67
|
|
|
@@ -82,6 +81,7 @@ module Imap::Backup
|
|
|
82
81
|
def local_folders
|
|
83
82
|
return enum_for(:local_folders) if !block_given?
|
|
84
83
|
|
|
84
|
+
ensure_account_folder
|
|
85
85
|
glob = File.join(account.local_path, "**", "*.imap")
|
|
86
86
|
base = Pathname.new(account.local_path)
|
|
87
87
|
Pathname.glob(glob) do |path|
|
|
@@ -176,7 +176,7 @@ module Imap::Backup
|
|
|
176
176
|
end
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
-
def
|
|
179
|
+
def ensure_account_folder
|
|
180
180
|
Utils.make_folder(
|
|
181
181
|
File.dirname(account.local_path),
|
|
182
182
|
File.basename(account.local_path),
|
|
@@ -111,6 +111,14 @@ module Imap::Backup
|
|
|
111
111
|
extract_uid(response)
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
def clear
|
|
115
|
+
existing = uids
|
|
116
|
+
# Use read-write access, via `select`
|
|
117
|
+
client.select(utf7_encoded_name)
|
|
118
|
+
client.uid_store(existing, "+FLAGS", [:Deleted])
|
|
119
|
+
client.expunge
|
|
120
|
+
end
|
|
121
|
+
|
|
114
122
|
private
|
|
115
123
|
|
|
116
124
|
def examine
|
|
@@ -3,7 +3,10 @@ require "imap/backup/cli/accounts"
|
|
|
3
3
|
|
|
4
4
|
module Imap::Backup::CLI::Helpers
|
|
5
5
|
def symbolized(options)
|
|
6
|
-
options.each.with_object({})
|
|
6
|
+
options.each.with_object({}) do |(k, v), acc|
|
|
7
|
+
key = k.gsub("-", "_").intern
|
|
8
|
+
acc[key] = v
|
|
9
|
+
end
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
def account(email)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require "imap/backup/migrator"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup
|
|
4
|
+
class CLI::Migrate < Thor
|
|
5
|
+
include Thor::Actions
|
|
6
|
+
|
|
7
|
+
attr_reader :destination_email
|
|
8
|
+
attr_reader :destination_prefix
|
|
9
|
+
attr_reader :reset
|
|
10
|
+
attr_reader :source_email
|
|
11
|
+
attr_reader :source_prefix
|
|
12
|
+
|
|
13
|
+
def initialize(
|
|
14
|
+
source_email,
|
|
15
|
+
destination_email,
|
|
16
|
+
destination_prefix: "",
|
|
17
|
+
reset: false,
|
|
18
|
+
source_prefix: ""
|
|
19
|
+
)
|
|
20
|
+
super([])
|
|
21
|
+
@destination_email = destination_email
|
|
22
|
+
@destination_prefix = destination_prefix
|
|
23
|
+
@reset = reset
|
|
24
|
+
@source_email = source_email
|
|
25
|
+
@source_prefix = source_prefix
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
no_commands do
|
|
29
|
+
def run
|
|
30
|
+
check_accounts!
|
|
31
|
+
folders.each do |serializer, folder|
|
|
32
|
+
Migrator.new(serializer, folder, reset: reset).run
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def check_accounts!
|
|
37
|
+
if destination_email == source_email
|
|
38
|
+
raise "Source and destination accounts cannot be the same!"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if !destination_account
|
|
42
|
+
raise "Account #{destination_email} does not exist"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if !source_account
|
|
46
|
+
raise "Account #{source_email} does not exist"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def config
|
|
51
|
+
Configuration.new
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def destination_account
|
|
55
|
+
config.accounts.find { |a| a.username == destination_email }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def folders
|
|
59
|
+
return enum_for(:folders) if !block_given?
|
|
60
|
+
|
|
61
|
+
glob = File.join(source_local_path, "**", "*.imap")
|
|
62
|
+
Pathname.glob(glob) do |path|
|
|
63
|
+
name = source_folder_name(path)
|
|
64
|
+
serializer = Serializer::Mbox.new(source_local_path, name)
|
|
65
|
+
folder = folder_for(name)
|
|
66
|
+
yield serializer, folder
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def folder_for(source_folder)
|
|
71
|
+
no_source_prefix =
|
|
72
|
+
if source_prefix != "" &&
|
|
73
|
+
source_folder.start_with?(source_prefix)
|
|
74
|
+
source_folder.delete_prefix(source_prefix)
|
|
75
|
+
else
|
|
76
|
+
source_folder.to_s
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
with_destination_prefix =
|
|
80
|
+
if destination_prefix &&
|
|
81
|
+
destination_prefix != ""
|
|
82
|
+
destination_prefix + no_source_prefix
|
|
83
|
+
else
|
|
84
|
+
no_source_prefix
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
Account::Folder.new(
|
|
88
|
+
destination_account.connection,
|
|
89
|
+
with_destination_prefix
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def source_local_path
|
|
94
|
+
source_account.local_path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def source_account
|
|
98
|
+
config.accounts.find { |a| a.username == source_email }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def source_folder_name(imap_pathname)
|
|
102
|
+
base = Pathname.new(source_local_path)
|
|
103
|
+
imap_name = imap_pathname.relative_path_from(base).to_s
|
|
104
|
+
dir = File.dirname(imap_name)
|
|
105
|
+
stripped = File.basename(imap_name, ".imap")
|
|
106
|
+
if dir == "."
|
|
107
|
+
stripped
|
|
108
|
+
else
|
|
109
|
+
File.join(dir, stripped)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Remote < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
desc "folders EMAIL", "List account folders"
|
|
7
|
+
def folders(email)
|
|
8
|
+
connection = connection(email)
|
|
9
|
+
|
|
10
|
+
connection.folder_names.each do |name|
|
|
11
|
+
Kernel.puts %("#{name}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/imap/backup/cli.rb
CHANGED
|
@@ -9,6 +9,7 @@ module Imap::Backup
|
|
|
9
9
|
autoload :Backup, "imap/backup/cli/backup"
|
|
10
10
|
autoload :Folders, "imap/backup/cli/folders"
|
|
11
11
|
autoload :Local, "imap/backup/cli/local"
|
|
12
|
+
autoload :Migrate, "imap/backup/cli/migrate"
|
|
12
13
|
autoload :Remote, "imap/backup/cli/remote"
|
|
13
14
|
autoload :Restore, "imap/backup/cli/restore"
|
|
14
15
|
autoload :Setup, "imap/backup/cli/setup"
|
|
@@ -27,7 +28,7 @@ module Imap::Backup
|
|
|
27
28
|
method_option(
|
|
28
29
|
"accounts",
|
|
29
30
|
type: :string,
|
|
30
|
-
|
|
31
|
+
desc: "a comma-separated list of accounts (defaults to all configured accounts)",
|
|
31
32
|
aliases: ["-a"]
|
|
32
33
|
)
|
|
33
34
|
end
|
|
@@ -57,6 +58,54 @@ module Imap::Backup
|
|
|
57
58
|
Folders.new(symbolized(options)).run
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
desc "local SUBCOMMAND [OPTIONS]", "View local info"
|
|
62
|
+
subcommand "local", Local
|
|
63
|
+
|
|
64
|
+
desc "migrate SOURCE_EMAIL DESTINATION_EMAIL [OPTIONS]",
|
|
65
|
+
"[Experimental] Uploads backed-up emails from account SOURCE_EMAIL to account DESTINATION_EMAIL"
|
|
66
|
+
long_desc <<~DESC
|
|
67
|
+
All emails which have been backed up for the "source account" (SOURCE_EMAIL) are
|
|
68
|
+
uploaded to the "destination account" (DESTINATION_EMAIL).
|
|
69
|
+
|
|
70
|
+
When one or other account has namespaces (i.e. prefixes like "INBOX."),
|
|
71
|
+
use the `--source-prefix=` and/or `--destination-prefix=` options.
|
|
72
|
+
|
|
73
|
+
Usually, you should migrate to an account with empty folders.
|
|
74
|
+
|
|
75
|
+
Before migrating each folder, `imap-backup` checks if the destination
|
|
76
|
+
folder is empty.
|
|
77
|
+
|
|
78
|
+
If it finds a non-empty destination folder, it halts with an error.
|
|
79
|
+
|
|
80
|
+
If you are sure that these destination emails can be deleted,
|
|
81
|
+
use the `--reset` option. In this case, all existing emails are
|
|
82
|
+
deleted before uploading the migrated emails.
|
|
83
|
+
DESC
|
|
84
|
+
method_option(
|
|
85
|
+
"destination-prefix",
|
|
86
|
+
type: :string,
|
|
87
|
+
desc: "the prefix (namespace) to add to destination folder names",
|
|
88
|
+
aliases: ["-d"]
|
|
89
|
+
)
|
|
90
|
+
method_option(
|
|
91
|
+
"reset",
|
|
92
|
+
type: :boolean,
|
|
93
|
+
desc: "DANGER! This option deletes all messages from destination folders before uploading",
|
|
94
|
+
aliases: ["-r"]
|
|
95
|
+
)
|
|
96
|
+
method_option(
|
|
97
|
+
"source-prefix",
|
|
98
|
+
type: :string,
|
|
99
|
+
desc: "the prefix (namespace) to strip from source folder names",
|
|
100
|
+
aliases: ["-s"]
|
|
101
|
+
)
|
|
102
|
+
def migrate(source_email, destination_email)
|
|
103
|
+
Migrate.new(source_email, destination_email, symbolized(options)).run
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
desc "remote SUBCOMMAND [OPTIONS]", "View info about online accounts"
|
|
107
|
+
subcommand "remote", Remote
|
|
108
|
+
|
|
60
109
|
desc "restore [OPTIONS]", "This command is deprecated, use `imap-backup restore ACCOUNT`"
|
|
61
110
|
long_desc <<~DESC
|
|
62
111
|
By default, restores all local emails to their respective servers.
|
|
@@ -86,9 +135,6 @@ module Imap::Backup
|
|
|
86
135
|
Status.new(symbolized(options)).run
|
|
87
136
|
end
|
|
88
137
|
|
|
89
|
-
desc "local SUBCOMMAND [OPTIONS]", "View local info"
|
|
90
|
-
subcommand "local", Local
|
|
91
|
-
|
|
92
138
|
desc "utils SUBCOMMAND [OPTIONS]", "Various utilities"
|
|
93
139
|
subcommand "utils", Utils
|
|
94
140
|
end
|
|
@@ -7,8 +7,8 @@ module Imap::Backup
|
|
|
7
7
|
class Client::Default
|
|
8
8
|
extend Forwardable
|
|
9
9
|
def_delegators :imap, *%i(
|
|
10
|
-
append authenticate create disconnect examine
|
|
11
|
-
login responses uid_fetch uid_search
|
|
10
|
+
append authenticate create disconnect examine expunge
|
|
11
|
+
login responses select uid_fetch uid_search uid_store
|
|
12
12
|
)
|
|
13
13
|
|
|
14
14
|
attr_reader :args
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class Migrator
|
|
3
|
+
attr_reader :folder
|
|
4
|
+
attr_reader :reset
|
|
5
|
+
attr_reader :serializer
|
|
6
|
+
|
|
7
|
+
def initialize(serializer, folder, reset: false)
|
|
8
|
+
@folder = folder
|
|
9
|
+
@reset = reset
|
|
10
|
+
@serializer = serializer
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
count = serializer.uids.count
|
|
15
|
+
folder.create
|
|
16
|
+
ensure_destination_empty!
|
|
17
|
+
|
|
18
|
+
Imap::Backup::Logger.logger.debug "[#{folder.name}] #{count} to migrate"
|
|
19
|
+
serializer.each_message(serializer.uids).with_index do |(uid, message), i|
|
|
20
|
+
next if message.nil?
|
|
21
|
+
|
|
22
|
+
log_prefix = "[#{folder.name}] uid: #{uid} (#{i + 1}/#{count}) -"
|
|
23
|
+
Imap::Backup::Logger.logger.debug(
|
|
24
|
+
"#{log_prefix} #{message.supplied_body.size} bytes"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
folder.append(message)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def ensure_destination_empty!
|
|
34
|
+
if reset
|
|
35
|
+
folder.clear
|
|
36
|
+
else
|
|
37
|
+
fail_if_destination_not_empty!
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def fail_if_destination_not_empty!
|
|
42
|
+
return if folder.uids.empty?
|
|
43
|
+
|
|
44
|
+
raise <<~ERROR
|
|
45
|
+
The destination folder '#{folder.name}' is not empty.
|
|
46
|
+
Pass the --reset flag if you want to clear existing emails from destination
|
|
47
|
+
folders before uploading.
|
|
48
|
+
ERROR
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
|
|
1
3
|
module Imap::Backup
|
|
2
4
|
class Sanitizer
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
3
7
|
attr_reader :output
|
|
4
8
|
|
|
9
|
+
delegate puts: :output
|
|
10
|
+
delegate write: :output
|
|
11
|
+
|
|
5
12
|
def initialize(output)
|
|
6
13
|
@output = output
|
|
7
14
|
@current = ""
|
|
8
15
|
end
|
|
9
16
|
|
|
10
|
-
def write(*args)
|
|
11
|
-
output.write(*args)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
17
|
def print(*args)
|
|
15
18
|
@current << args.join
|
|
16
19
|
loop do
|
data/lib/imap/backup/version.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Running commands", type: :aruba do
|
|
4
|
+
before do
|
|
5
|
+
create_config(accounts: [])
|
|
6
|
+
run_command("imap-backup local accounts")
|
|
7
|
+
last_command_started.stop
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
context "when no accounts are configured" do
|
|
11
|
+
it "succeeds" do
|
|
12
|
+
expect(last_command_started).to have_exit_status(0)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Running commands", type: :aruba do
|
|
4
|
+
before do
|
|
5
|
+
run_command("imap-backup")
|
|
6
|
+
last_command_started.stop
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
context "when the configuration file is missing" do
|
|
10
|
+
it "fails" do
|
|
11
|
+
expect(last_command_started).not_to have_exit_status(0)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Listing accounts", type: :aruba do
|
|
4
|
+
before do
|
|
5
|
+
create_config(accounts: [{"username": "me@example.com"}])
|
|
6
|
+
run_command_and_stop("imap-backup local accounts")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "lists accounts" do
|
|
10
|
+
expect(last_command_started).to have_output("me@example.com")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Listing emails", type: :aruba do
|
|
4
|
+
let(:email) { "me@example.com" }
|
|
5
|
+
let(:account) do
|
|
6
|
+
{
|
|
7
|
+
username: email,
|
|
8
|
+
local_path: File.join(config_path, email.gsub("@", "_"))
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
create_config(accounts: [account])
|
|
14
|
+
store_email(email: email, folder: "my_folder", subject: "Ciao")
|
|
15
|
+
run_command_and_stop("imap-backup local list #{email} my_folder")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "lists emails" do
|
|
19
|
+
expect(last_command_started).to have_output(/1: Ciao/)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Listing account folders", type: :aruba do
|
|
4
|
+
let(:email) { "me@example.com" }
|
|
5
|
+
let(:account) do
|
|
6
|
+
{
|
|
7
|
+
username: email,
|
|
8
|
+
local_path: File.join(config_path, email.gsub("@", "_"))
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
create_config(accounts: [account])
|
|
14
|
+
store_email(email: email, folder: "my_folder", body: "Hi")
|
|
15
|
+
run_command_and_stop("imap-backup local folders #{email}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "lists folders that have been backed up" do
|
|
19
|
+
expect(last_command_started).to have_output(%q("my_folder"))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Show an email", type: :aruba do
|
|
4
|
+
let(:email) { "me@example.com" }
|
|
5
|
+
let(:account) do
|
|
6
|
+
{
|
|
7
|
+
username: email,
|
|
8
|
+
local_path: File.join(config_path, email.gsub("@", "_"))
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
create_config(accounts: [account])
|
|
14
|
+
store_email(
|
|
15
|
+
email: email,
|
|
16
|
+
folder: "my_folder",
|
|
17
|
+
uid: 99,
|
|
18
|
+
from: "me@example.com",
|
|
19
|
+
subject: "Hello",
|
|
20
|
+
body: "How're things?"
|
|
21
|
+
)
|
|
22
|
+
run_command_and_stop("imap-backup local show #{email} my_folder 99")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "shows the email" do
|
|
26
|
+
expected = <<~BODY
|
|
27
|
+
From: me@example.com
|
|
28
|
+
Subject: Hello
|
|
29
|
+
|
|
30
|
+
How're things?
|
|
31
|
+
BODY
|
|
32
|
+
expect(last_command_started).to have_output(expected)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "Migration", type: :aruba, docker: true do
|
|
4
|
+
let(:email) { "me@example.com" }
|
|
5
|
+
let(:folder) { "my_folder" }
|
|
6
|
+
let(:source_account) do
|
|
7
|
+
{
|
|
8
|
+
username: email,
|
|
9
|
+
local_path: File.join(config_path, email.gsub("@", "_"))
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
let(:destination_account) { fixture("connection") }
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
create_config(accounts: [source_account, destination_account])
|
|
16
|
+
store_email(email: email, folder: folder, subject: "Ciao")
|
|
17
|
+
run_command_and_stop("imap-backup migrate #{email} #{destination_account[:username]}")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
after do
|
|
21
|
+
delete_emails(folder)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "copies email to the destination account" do
|
|
25
|
+
messages = server_messages(folder)
|
|
26
|
+
expected = <<~MESSAGE.gsub("\n", "\r\n")
|
|
27
|
+
From: sender@example.com
|
|
28
|
+
Subject: Ciao
|
|
29
|
+
|
|
30
|
+
body
|
|
31
|
+
|
|
32
|
+
MESSAGE
|
|
33
|
+
expect(messages[0]["BODY[]"]).to eq(expected)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "features/helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "List account folders", type: :aruba do
|
|
4
|
+
let(:account) do
|
|
5
|
+
fixture("connection")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
create_config(accounts: [account])
|
|
10
|
+
run_command_and_stop("imap-backup remote folders #{account[:username]}")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "lists folders" do
|
|
14
|
+
expect(last_command_started).to have_output(/"INBOX"/)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require "aruba/rspec"
|
|
2
|
+
|
|
3
|
+
Aruba.configure do |config|
|
|
4
|
+
config.home_directory = File.expand_path("./tmp/home")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ConfigurationHelpers
|
|
8
|
+
def config_path
|
|
9
|
+
File.expand_path("~/.imap-backup")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create_config(accounts:, debug: false)
|
|
13
|
+
pathname = File.join(config_path, "config.json")
|
|
14
|
+
save_data = {
|
|
15
|
+
version: Imap::Backup::Configuration::VERSION,
|
|
16
|
+
accounts: accounts,
|
|
17
|
+
debug: debug
|
|
18
|
+
}
|
|
19
|
+
FileUtils.mkdir_p config_path
|
|
20
|
+
File.open(pathname, "w") { |f| f.write(JSON.pretty_generate(save_data)) }
|
|
21
|
+
FileUtils.chmod(0o600, pathname)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module StoreHelpers
|
|
26
|
+
def store_email(
|
|
27
|
+
email:, folder:,
|
|
28
|
+
uid: 1,
|
|
29
|
+
from: "sender@example.com",
|
|
30
|
+
subject: "The Subject",
|
|
31
|
+
body: "body"
|
|
32
|
+
)
|
|
33
|
+
account = config.accounts.find { |a| a.username == email }
|
|
34
|
+
raise "Account not found" if !account
|
|
35
|
+
FileUtils.mkdir_p account.local_path
|
|
36
|
+
store = Imap::Backup::Serializer::MboxStore.new(account.local_path, folder)
|
|
37
|
+
store.uid_validity = "42" if !store.uid_validity
|
|
38
|
+
serialized = to_serialized(from: from, subject: subject, body: body)
|
|
39
|
+
store.add(uid, serialized)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_serialized(from:, subject:, body:)
|
|
43
|
+
body_and_headers = <<~BODY
|
|
44
|
+
From: #{from}
|
|
45
|
+
Subject: #{subject}
|
|
46
|
+
|
|
47
|
+
#{body}
|
|
48
|
+
BODY
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def config
|
|
52
|
+
Imap::Backup::Configuration.new(
|
|
53
|
+
File.expand_path("~/.imap-backup/config.json")
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
RSpec.configure do |config|
|
|
59
|
+
config.include ConfigurationHelpers, type: :aruba
|
|
60
|
+
config.include StoreHelpers, type: :aruba
|
|
61
|
+
|
|
62
|
+
config.before(:suite) do
|
|
63
|
+
FileUtils.rm_rf "./tmp/home"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
config.after do
|
|
67
|
+
FileUtils.rm_rf "./tmp/home"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -61,14 +61,6 @@ describe Imap::Backup::Account::Connection do
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
describe "#initialize" do
|
|
65
|
-
it "creates the path" do
|
|
66
|
-
expect(Imap::Backup::Utils).to receive(:make_folder)
|
|
67
|
-
|
|
68
|
-
subject
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
64
|
describe "#client" do
|
|
73
65
|
let(:result) { subject.client }
|
|
74
66
|
|
|
@@ -127,6 +119,12 @@ describe Imap::Backup::Account::Connection do
|
|
|
127
119
|
allow(Imap::Backup::Serializer::Mbox).to receive(:new) { serializer }
|
|
128
120
|
end
|
|
129
121
|
|
|
122
|
+
it "creates the path" do
|
|
123
|
+
expect(Imap::Backup::Utils).to receive(:make_folder)
|
|
124
|
+
|
|
125
|
+
subject.status
|
|
126
|
+
end
|
|
127
|
+
|
|
130
128
|
it "returns the names of folders" do
|
|
131
129
|
expect(subject.status[0][:name]).to eq(IMAP_FOLDER)
|
|
132
130
|
end
|
|
@@ -12,7 +12,10 @@ describe Imap::Backup::Account::Folder do
|
|
|
12
12
|
append: append_response,
|
|
13
13
|
create: nil,
|
|
14
14
|
examine: nil,
|
|
15
|
-
|
|
15
|
+
expunge: nil,
|
|
16
|
+
responses: responses,
|
|
17
|
+
select: nil,
|
|
18
|
+
uid_store: nil
|
|
16
19
|
)
|
|
17
20
|
end
|
|
18
21
|
let(:connection) do
|
|
@@ -27,12 +30,11 @@ describe Imap::Backup::Account::Folder do
|
|
|
27
30
|
end
|
|
28
31
|
let(:responses) { [] }
|
|
29
32
|
let(:append_response) { nil }
|
|
33
|
+
let(:uids) { [5678, 123] }
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
let(:uids) { [5678, 123] }
|
|
33
|
-
|
|
34
|
-
before { allow(client).to receive(:uid_search) { uids } }
|
|
35
|
+
before { allow(client).to receive(:uid_search) { uids } }
|
|
35
36
|
|
|
37
|
+
describe "#uids" do
|
|
36
38
|
it "lists available messages" do
|
|
37
39
|
expect(subject.uids).to eq(uids.reverse)
|
|
38
40
|
end
|
|
@@ -233,6 +235,25 @@ describe Imap::Backup::Account::Folder do
|
|
|
233
235
|
expect(subject.uid_validity).to eq(1)
|
|
234
236
|
end
|
|
235
237
|
end
|
|
238
|
+
|
|
239
|
+
describe "#clear" do
|
|
240
|
+
before do
|
|
241
|
+
subject.clear
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "uses select to have read-write access" do
|
|
245
|
+
expect(client).to have_received(:select)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "marks all emails as deleted" do
|
|
249
|
+
expect(client).
|
|
250
|
+
to have_received(:uid_store).with(uids.sort, "+FLAGS", [:Deleted])
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "deletes marked emails" do
|
|
254
|
+
expect(client).to have_received(:expunge)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
236
257
|
end
|
|
237
258
|
|
|
238
259
|
# rubocop:enable RSpec/PredicateMatcher
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require "imap/backup/cli/helpers"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup
|
|
4
|
+
class WithHelpers
|
|
5
|
+
include CLI::Helpers
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
RSpec.describe CLI::Helpers do
|
|
9
|
+
subject { WithHelpers.new }
|
|
10
|
+
|
|
11
|
+
let(:accounts) { instance_double(CLI::Accounts) }
|
|
12
|
+
let(:email) { "email@example.com" }
|
|
13
|
+
let(:account1) { instance_double(Account, username: email, connection: "c1") }
|
|
14
|
+
let(:account2) { instance_double(Account, username: "foo", connection: "c2") }
|
|
15
|
+
let(:items) { [account1, account2] }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
allow(CLI::Accounts).to receive(:new) { accounts }
|
|
19
|
+
allow(accounts).to receive(:each).
|
|
20
|
+
and_yield(account1).
|
|
21
|
+
and_yield(account2)
|
|
22
|
+
allow(accounts).to receive(:find) do |&block|
|
|
23
|
+
items.find { |a| block.call(a) }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe ".symbolized" do
|
|
28
|
+
let(:arguments) { {"foo" => 1, "bar" => 2} }
|
|
29
|
+
let(:result) { subject.symbolized(arguments) }
|
|
30
|
+
|
|
31
|
+
it "converts string keys to symbols" do
|
|
32
|
+
expect(result.keys).to eq([:foo, :bar])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "when keys have hyphens" do
|
|
36
|
+
let(:arguments) { {"some-option"=> 3} }
|
|
37
|
+
|
|
38
|
+
it "replaces them with underscores" do
|
|
39
|
+
expect(result.keys).to eq([:some_option])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe ".account" do
|
|
45
|
+
it "returns any account with a matching username" do
|
|
46
|
+
expect(subject.account(email)).to eq(account1)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "when no match is found" do
|
|
50
|
+
let(:items) { [account2] }
|
|
51
|
+
it "fails" do
|
|
52
|
+
expect do
|
|
53
|
+
subject.account(email)
|
|
54
|
+
end.to raise_error(RuntimeError, /not a configured account/)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe ".connection" do
|
|
60
|
+
it "returns the connection for any account with a matching username" do
|
|
61
|
+
result = subject.connection(email)
|
|
62
|
+
expect(result).to be_a(Account::Connection)
|
|
63
|
+
expect(result.account).to eq(account1)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe ".each_connection" do
|
|
68
|
+
it "yields each connection" do
|
|
69
|
+
expect { |b| subject.each_connection([email, "foo"], &b) }.
|
|
70
|
+
to yield_successive_args("c1", "c2")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when there is no configuration" do
|
|
74
|
+
before do
|
|
75
|
+
allow(accounts).to receive(:each).
|
|
76
|
+
and_raise(Imap::Backup::ConfigurationNotFound)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "fails" do
|
|
80
|
+
expect do
|
|
81
|
+
subject.each_connection([email])
|
|
82
|
+
end.to raise_error(RuntimeError, /not configured/)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require "imap/backup/migrator"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup
|
|
4
|
+
RSpec.describe Migrator do
|
|
5
|
+
subject { described_class.new(serializer, folder, reset: reset) }
|
|
6
|
+
|
|
7
|
+
let(:serializer) { instance_double(Serializer::MboxStore, uids: [1]) }
|
|
8
|
+
let(:folder) do
|
|
9
|
+
instance_double(
|
|
10
|
+
Account::Folder,
|
|
11
|
+
append: nil, clear: nil, create: nil, name: "name", uids: folder_uids
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
let(:folder_uids) { [] }
|
|
15
|
+
let(:reset) { false }
|
|
16
|
+
let(:messages) { [[1, message]] }
|
|
17
|
+
let(:message) { instance_double(Email::Mboxrd::Message, supplied_body: body) }
|
|
18
|
+
let(:body) { "body" }
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
allow(serializer).to receive(:each_message) do
|
|
22
|
+
messages.enum_for(:each)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "creates the folder" do
|
|
27
|
+
subject.run
|
|
28
|
+
|
|
29
|
+
expect(folder).to have_received(:create)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "uploads messages" do
|
|
33
|
+
subject.run
|
|
34
|
+
|
|
35
|
+
expect(folder).to have_received(:append).with(message)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when the folder is not empty" do
|
|
39
|
+
let(:folder_uids) { [99] }
|
|
40
|
+
|
|
41
|
+
it "fails" do
|
|
42
|
+
expect do
|
|
43
|
+
subject.run
|
|
44
|
+
end.to raise_error(RuntimeError, /The destination folder 'name' is not empty/)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "when `reset` is true" do
|
|
48
|
+
let(:reset) { true }
|
|
49
|
+
|
|
50
|
+
it "clears the folder" do
|
|
51
|
+
subject.run
|
|
52
|
+
|
|
53
|
+
expect(folder).to have_received(:clear)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: imap-backup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joe Yates
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-02-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: highline
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '1.1'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: aruba
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 0.0.0
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 0.0.0
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
98
|
name: codeclimate-test-reporter
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -196,6 +210,8 @@ files:
|
|
|
196
210
|
- lib/imap/backup/cli/folders.rb
|
|
197
211
|
- lib/imap/backup/cli/helpers.rb
|
|
198
212
|
- lib/imap/backup/cli/local.rb
|
|
213
|
+
- lib/imap/backup/cli/migrate.rb
|
|
214
|
+
- lib/imap/backup/cli/remote.rb
|
|
199
215
|
- lib/imap/backup/cli/restore.rb
|
|
200
216
|
- lib/imap/backup/cli/setup.rb
|
|
201
217
|
- lib/imap/backup/cli/status.rb
|
|
@@ -205,6 +221,7 @@ files:
|
|
|
205
221
|
- lib/imap/backup/configuration.rb
|
|
206
222
|
- lib/imap/backup/downloader.rb
|
|
207
223
|
- lib/imap/backup/logger.rb
|
|
224
|
+
- lib/imap/backup/migrator.rb
|
|
208
225
|
- lib/imap/backup/sanitizer.rb
|
|
209
226
|
- lib/imap/backup/serializer.rb
|
|
210
227
|
- lib/imap/backup/serializer/mbox.rb
|
|
@@ -229,10 +246,19 @@ files:
|
|
|
229
246
|
- lib/thunderbird/subdirectory.rb
|
|
230
247
|
- lib/thunderbird/subdirectory_placeholder.rb
|
|
231
248
|
- spec/features/backup_spec.rb
|
|
249
|
+
- spec/features/configuration/minimal_configuration.rb
|
|
250
|
+
- spec/features/configuration/missing_configuration.rb
|
|
232
251
|
- spec/features/folders_spec.rb
|
|
233
252
|
- spec/features/helper.rb
|
|
253
|
+
- spec/features/local/list_accounts_spec.rb
|
|
254
|
+
- spec/features/local/list_emails_spec.rb
|
|
255
|
+
- spec/features/local/list_folders_spec.rb
|
|
256
|
+
- spec/features/local/show_an_email_spec.rb
|
|
257
|
+
- spec/features/migrate_spec.rb
|
|
258
|
+
- spec/features/remote/list_account_folders_spec.rb
|
|
234
259
|
- spec/features/restore_spec.rb
|
|
235
260
|
- spec/features/status_spec.rb
|
|
261
|
+
- spec/features/support/aruba.rb
|
|
236
262
|
- spec/features/support/backup_directory.rb
|
|
237
263
|
- spec/features/support/email_server.rb
|
|
238
264
|
- spec/features/support/shared/connection_context.rb
|
|
@@ -252,12 +278,14 @@ files:
|
|
|
252
278
|
- spec/unit/imap/backup/account/connection_spec.rb
|
|
253
279
|
- spec/unit/imap/backup/account/folder_spec.rb
|
|
254
280
|
- spec/unit/imap/backup/cli/accounts_spec.rb
|
|
281
|
+
- spec/unit/imap/backup/cli/helpers_spec.rb
|
|
255
282
|
- spec/unit/imap/backup/cli/local_spec.rb
|
|
256
283
|
- spec/unit/imap/backup/cli/utils_spec.rb
|
|
257
284
|
- spec/unit/imap/backup/client/default_spec.rb
|
|
258
285
|
- spec/unit/imap/backup/configuration_spec.rb
|
|
259
286
|
- spec/unit/imap/backup/downloader_spec.rb
|
|
260
287
|
- spec/unit/imap/backup/logger_spec.rb
|
|
288
|
+
- spec/unit/imap/backup/migrator_spec.rb
|
|
261
289
|
- spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb
|
|
262
290
|
- spec/unit/imap/backup/serializer/mbox_spec.rb
|
|
263
291
|
- spec/unit/imap/backup/serializer/mbox_store_spec.rb
|
|
@@ -303,10 +331,12 @@ test_files:
|
|
|
303
331
|
- spec/unit/imap/backup/setup/connection_tester_spec.rb
|
|
304
332
|
- spec/unit/imap/backup/setup/asker_spec.rb
|
|
305
333
|
- spec/unit/imap/backup/setup/folder_chooser_spec.rb
|
|
334
|
+
- spec/unit/imap/backup/cli/helpers_spec.rb
|
|
306
335
|
- spec/unit/imap/backup/cli/accounts_spec.rb
|
|
307
336
|
- spec/unit/imap/backup/cli/utils_spec.rb
|
|
308
337
|
- spec/unit/imap/backup/cli/local_spec.rb
|
|
309
338
|
- spec/unit/imap/backup/downloader_spec.rb
|
|
339
|
+
- spec/unit/imap/backup/migrator_spec.rb
|
|
310
340
|
- spec/unit/imap/backup/uploader_spec.rb
|
|
311
341
|
- spec/unit/imap/backup/account/folder_spec.rb
|
|
312
342
|
- spec/unit/imap/backup/account/connection_spec.rb
|
|
@@ -319,14 +349,23 @@ test_files:
|
|
|
319
349
|
- spec/unit/email/provider/base_spec.rb
|
|
320
350
|
- spec/unit/email/provider_spec.rb
|
|
321
351
|
- spec/features/folders_spec.rb
|
|
352
|
+
- spec/features/configuration/missing_configuration.rb
|
|
353
|
+
- spec/features/configuration/minimal_configuration.rb
|
|
322
354
|
- spec/features/backup_spec.rb
|
|
323
355
|
- spec/features/helper.rb
|
|
324
356
|
- spec/features/restore_spec.rb
|
|
357
|
+
- spec/features/local/list_emails_spec.rb
|
|
358
|
+
- spec/features/local/list_accounts_spec.rb
|
|
359
|
+
- spec/features/local/show_an_email_spec.rb
|
|
360
|
+
- spec/features/local/list_folders_spec.rb
|
|
325
361
|
- spec/features/status_spec.rb
|
|
326
362
|
- spec/features/support/email_server.rb
|
|
327
363
|
- spec/features/support/backup_directory.rb
|
|
364
|
+
- spec/features/support/aruba.rb
|
|
328
365
|
- spec/features/support/shared/connection_context.rb
|
|
329
366
|
- spec/features/support/shared/message_fixtures.rb
|
|
367
|
+
- spec/features/migrate_spec.rb
|
|
368
|
+
- spec/features/remote/list_account_folders_spec.rb
|
|
330
369
|
- spec/support/fixtures.rb
|
|
331
370
|
- spec/support/silence_logging.rb
|
|
332
371
|
- spec/support/higline_test_helpers.rb
|