imap-backup 4.1.2 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/imap-backup.gemspec +1 -0
- data/lib/email/mboxrd/message.rb +6 -2
- data/lib/imap/backup/account/connection.rb +4 -4
- data/lib/imap/backup/account/folder.rb +8 -0
- data/lib/imap/backup/cli/folders.rb +1 -1
- 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/downloader.rb +23 -9
- data/lib/imap/backup/migrator.rb +51 -0
- data/lib/imap/backup/sanitizer.rb +7 -4
- data/lib/imap/backup/thunderbird/mailbox_exporter.rb +10 -1
- data/lib/imap/backup/version.rb +3 -3
- data/lib/thunderbird/subdirectory.rb +3 -6
- data/spec/features/configuration/minimal_configuration.rb +15 -0
- data/spec/features/configuration/missing_configuration.rb +14 -0
- data/spec/features/folders_spec.rb +36 -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 +77 -36
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"
|
data/lib/email/mboxrd/message.rb
CHANGED
@@ -10,7 +10,7 @@ module Email::Mboxrd
|
|
10
10
|
|
11
11
|
attr_reader :supplied_body
|
12
12
|
|
13
|
-
def self.
|
13
|
+
def self.clean_serialized(serialized)
|
14
14
|
cleaned = serialized.gsub(/^>(>*From)/, "\\1")
|
15
15
|
# Serialized messages in this format *should* start with a line
|
16
16
|
# From xxx yy zz
|
@@ -19,7 +19,11 @@ module Email::Mboxrd
|
|
19
19
|
cleaned = cleaned.sub(/^From .*[\r\n]*/, "")
|
20
20
|
end
|
21
21
|
# rubocop:enable Style/IfUnlessModifier
|
22
|
-
|
22
|
+
cleaned
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_serialized(serialized)
|
26
|
+
new(clean_serialized(serialized))
|
23
27
|
end
|
24
28
|
|
25
29
|
def initialize(supplied_body)
|
@@ -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
|
@@ -13,7 +13,7 @@ module Imap::Backup
|
|
13
13
|
no_commands do
|
14
14
|
def run
|
15
15
|
each_connection(account_names) do |connection|
|
16
|
-
puts connection.username
|
16
|
+
puts connection.account.username
|
17
17
|
# TODO: Make folder_names private once this command
|
18
18
|
# has been removed.
|
19
19
|
folders = connection.folder_names
|
@@ -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
|
@@ -13,31 +13,45 @@ module Imap::Backup
|
|
13
13
|
def run
|
14
14
|
uids = folder.uids - serializer.uids
|
15
15
|
count = uids.count
|
16
|
-
|
16
|
+
debug "#{count} new messages"
|
17
17
|
uids.each_slice(block_size).with_index do |block, i|
|
18
|
-
offset = i * block_size + 1
|
19
18
|
uids_and_bodies = folder.fetch_multi(block)
|
20
19
|
if uids_and_bodies.nil?
|
21
20
|
if block_size > 1
|
22
|
-
|
21
|
+
debug("Multi fetch failed for UIDs #{block.join(", ")}, switching to single fetches")
|
23
22
|
@block_size = 1
|
24
23
|
redo
|
25
24
|
else
|
26
|
-
|
25
|
+
debug("Fetch failed for UID #{block[0]} - skipping")
|
27
26
|
next
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
30
|
+
offset = i * block_size + 1
|
31
31
|
uids_and_bodies.each.with_index do |uid_and_body, j|
|
32
32
|
uid = uid_and_body[:uid]
|
33
33
|
body = uid_and_body[:body]
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
case
|
35
|
+
when !body
|
36
|
+
info("Fetch returned empty body - skipping")
|
37
|
+
when !uid
|
38
|
+
info("Fetch returned empty UID - skipping")
|
39
|
+
else
|
40
|
+
debug("uid: #{uid} (#{offset + j}/#{count}) - #{body.size} bytes")
|
41
|
+
serializer.save(uid, body)
|
42
|
+
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def info(message)
|
50
|
+
Imap::Backup::Logger.logger.info("[#{folder.name}] #{message}")
|
51
|
+
end
|
52
|
+
|
53
|
+
def debug(message)
|
54
|
+
Imap::Backup::Logger.logger.debug("[#{folder.name}] #{message}")
|
55
|
+
end
|
42
56
|
end
|
43
57
|
end
|
@@ -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
|
@@ -40,7 +40,16 @@ module Imap::Backup
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
File.open(local_folder.full_path, "w") do |f|
|
44
|
+
enumerator = Serializer::MboxEnumerator.new(serializer.mbox_pathname)
|
45
|
+
enumerator.each.with_index do |raw, i|
|
46
|
+
clean = Email::Mboxrd::Message.clean_serialized(raw)
|
47
|
+
timestamp = Time.now.strftime("%a %b %d %H:%M:%S %Y")
|
48
|
+
thunderbird_fom_line = "From - #{timestamp}"
|
49
|
+
output = "#{thunderbird_fom_line}\n#{clean}\n"
|
50
|
+
f.write output
|
51
|
+
end
|
52
|
+
end
|
44
53
|
|
45
54
|
true
|
46
55
|
end
|
data/lib/imap/backup/version.rb
CHANGED
@@ -77,17 +77,14 @@ class Thunderbird::Subdirectory
|
|
77
77
|
|
78
78
|
def check
|
79
79
|
case
|
80
|
-
when placeholder.exists? && !exists?
|
81
|
-
Kernel.puts "Can't set up folder '#{folder_path}': '#{placeholder.path}' exists, but '#{full_path}' is missing"
|
82
|
-
false
|
83
80
|
when exists? && !placeholder.exists?
|
84
|
-
Kernel.puts "Can't set up folder '#{
|
81
|
+
Kernel.puts "Can't set up folder '#{full_path}': '#{full_path}' exists, but '#{placeholder.path}' is missing"
|
85
82
|
false
|
86
83
|
when placeholder.exists? && !placeholder.regular?
|
87
|
-
Kernel.puts "Can't set up folder '#{
|
84
|
+
Kernel.puts "Can't set up folder '#{full_path}': '#{placeholder.path}' exists, but it is not a regular file"
|
88
85
|
false
|
89
86
|
when exists? && !directory?
|
90
|
-
Kernel.puts "Can't set up folder '#{
|
87
|
+
Kernel.puts "Can't set up folder '#{full_path}': '#{full_path}' exists, but it is not a directory"
|
91
88
|
false
|
92
89
|
else
|
93
90
|
true
|
@@ -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,36 @@
|
|
1
|
+
require "features/helper"
|
2
|
+
require "imap/backup/cli/folders"
|
3
|
+
|
4
|
+
RSpec.describe "folders", type: :feature, docker: true do
|
5
|
+
include_context "imap-backup connection"
|
6
|
+
|
7
|
+
let(:options) do
|
8
|
+
{accounts: "address@example.org"}
|
9
|
+
end
|
10
|
+
let(:folder) { "my-stuff" }
|
11
|
+
let(:output) { StringIO.new }
|
12
|
+
|
13
|
+
before do
|
14
|
+
allow(Imap::Backup::CLI::Accounts).to receive(:new) { [account] }
|
15
|
+
server_create_folder folder
|
16
|
+
end
|
17
|
+
|
18
|
+
around do |example|
|
19
|
+
stdout = $stdout
|
20
|
+
$stdout = output
|
21
|
+
example.run
|
22
|
+
$stdout = stdout
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
FileUtils.rm_rf local_backup_path
|
27
|
+
server_delete_folder folder
|
28
|
+
connection.disconnect
|
29
|
+
end
|
30
|
+
|
31
|
+
it "lists account folders" do
|
32
|
+
Imap::Backup::CLI::Folders.new(options).run
|
33
|
+
|
34
|
+
expect(output.string).to match(/^\tmy-stuff\n/)
|
35
|
+
end
|
36
|
+
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
|
-
autorequire:
|
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,9 +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
|
251
|
+
- spec/features/folders_spec.rb
|
232
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
|
233
259
|
- spec/features/restore_spec.rb
|
234
260
|
- spec/features/status_spec.rb
|
261
|
+
- spec/features/support/aruba.rb
|
235
262
|
- spec/features/support/backup_directory.rb
|
236
263
|
- spec/features/support/email_server.rb
|
237
264
|
- spec/features/support/shared/connection_context.rb
|
@@ -251,12 +278,14 @@ files:
|
|
251
278
|
- spec/unit/imap/backup/account/connection_spec.rb
|
252
279
|
- spec/unit/imap/backup/account/folder_spec.rb
|
253
280
|
- spec/unit/imap/backup/cli/accounts_spec.rb
|
281
|
+
- spec/unit/imap/backup/cli/helpers_spec.rb
|
254
282
|
- spec/unit/imap/backup/cli/local_spec.rb
|
255
283
|
- spec/unit/imap/backup/cli/utils_spec.rb
|
256
284
|
- spec/unit/imap/backup/client/default_spec.rb
|
257
285
|
- spec/unit/imap/backup/configuration_spec.rb
|
258
286
|
- spec/unit/imap/backup/downloader_spec.rb
|
259
287
|
- spec/unit/imap/backup/logger_spec.rb
|
288
|
+
- spec/unit/imap/backup/migrator_spec.rb
|
260
289
|
- spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb
|
261
290
|
- spec/unit/imap/backup/serializer/mbox_spec.rb
|
262
291
|
- spec/unit/imap/backup/serializer/mbox_store_spec.rb
|
@@ -271,7 +300,7 @@ homepage: https://github.com/joeyates/imap-backup
|
|
271
300
|
licenses:
|
272
301
|
- MIT
|
273
302
|
metadata: {}
|
274
|
-
post_install_message:
|
303
|
+
post_install_message:
|
275
304
|
rdoc_options: []
|
276
305
|
require_paths:
|
277
306
|
- lib
|
@@ -287,46 +316,58 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
287
316
|
version: '0'
|
288
317
|
requirements: []
|
289
318
|
rubygems_version: 3.1.6
|
290
|
-
signing_key:
|
319
|
+
signing_key:
|
291
320
|
specification_version: 4
|
292
321
|
summary: Backup GMail (or other IMAP) accounts to disk
|
293
322
|
test_files:
|
294
|
-
- spec/
|
295
|
-
- spec/
|
296
|
-
- spec/
|
297
|
-
- spec/
|
298
|
-
- spec/
|
299
|
-
- spec/
|
300
|
-
- spec/
|
301
|
-
- spec/features/backup_spec.rb
|
302
|
-
- spec/support/higline_test_helpers.rb
|
303
|
-
- spec/support/fixtures.rb
|
304
|
-
- spec/support/silence_logging.rb
|
305
|
-
- spec/gather_rspec_coverage.rb
|
306
|
-
- spec/unit/email/provider/gmail_spec.rb
|
307
|
-
- spec/unit/email/provider/fastmail_spec.rb
|
308
|
-
- spec/unit/email/provider/base_spec.rb
|
309
|
-
- spec/unit/email/provider/apple_mail_spec.rb
|
310
|
-
- spec/unit/email/mboxrd/message_spec.rb
|
311
|
-
- spec/unit/email/provider_spec.rb
|
312
|
-
- spec/unit/imap/backup/cli/utils_spec.rb
|
313
|
-
- spec/unit/imap/backup/cli/accounts_spec.rb
|
314
|
-
- spec/unit/imap/backup/cli/local_spec.rb
|
323
|
+
- spec/spec_helper.rb
|
324
|
+
- spec/unit/imap/backup/serializer/mbox_spec.rb
|
325
|
+
- spec/unit/imap/backup/serializer/mbox_store_spec.rb
|
326
|
+
- spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb
|
327
|
+
- spec/unit/imap/backup/setup_spec.rb
|
328
|
+
- spec/unit/imap/backup/logger_spec.rb
|
329
|
+
- spec/unit/imap/backup/configuration_spec.rb
|
315
330
|
- spec/unit/imap/backup/setup/account_spec.rb
|
316
331
|
- spec/unit/imap/backup/setup/connection_tester_spec.rb
|
317
|
-
- spec/unit/imap/backup/setup/folder_chooser_spec.rb
|
318
332
|
- spec/unit/imap/backup/setup/asker_spec.rb
|
319
|
-
- spec/unit/imap/backup/
|
320
|
-
- spec/unit/imap/backup/
|
321
|
-
- spec/unit/imap/backup/
|
322
|
-
- spec/unit/imap/backup/
|
323
|
-
- spec/unit/imap/backup/
|
324
|
-
- spec/unit/imap/backup/serializer/mbox_store_spec.rb
|
325
|
-
- spec/unit/imap/backup/serializer/mbox_enumerator_spec.rb
|
326
|
-
- spec/unit/imap/backup/serializer/mbox_spec.rb
|
333
|
+
- spec/unit/imap/backup/setup/folder_chooser_spec.rb
|
334
|
+
- spec/unit/imap/backup/cli/helpers_spec.rb
|
335
|
+
- spec/unit/imap/backup/cli/accounts_spec.rb
|
336
|
+
- spec/unit/imap/backup/cli/utils_spec.rb
|
337
|
+
- spec/unit/imap/backup/cli/local_spec.rb
|
327
338
|
- spec/unit/imap/backup/downloader_spec.rb
|
339
|
+
- spec/unit/imap/backup/migrator_spec.rb
|
340
|
+
- spec/unit/imap/backup/uploader_spec.rb
|
328
341
|
- spec/unit/imap/backup/account/folder_spec.rb
|
329
342
|
- spec/unit/imap/backup/account/connection_spec.rb
|
343
|
+
- spec/unit/imap/backup/utils_spec.rb
|
330
344
|
- spec/unit/imap/backup/client/default_spec.rb
|
331
|
-
- spec/
|
345
|
+
- spec/unit/email/mboxrd/message_spec.rb
|
346
|
+
- spec/unit/email/provider/gmail_spec.rb
|
347
|
+
- spec/unit/email/provider/apple_mail_spec.rb
|
348
|
+
- spec/unit/email/provider/fastmail_spec.rb
|
349
|
+
- spec/unit/email/provider/base_spec.rb
|
350
|
+
- spec/unit/email/provider_spec.rb
|
351
|
+
- spec/features/folders_spec.rb
|
352
|
+
- spec/features/configuration/missing_configuration.rb
|
353
|
+
- spec/features/configuration/minimal_configuration.rb
|
354
|
+
- spec/features/backup_spec.rb
|
355
|
+
- spec/features/helper.rb
|
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
|
361
|
+
- spec/features/status_spec.rb
|
362
|
+
- spec/features/support/email_server.rb
|
363
|
+
- spec/features/support/backup_directory.rb
|
364
|
+
- spec/features/support/aruba.rb
|
365
|
+
- spec/features/support/shared/connection_context.rb
|
366
|
+
- spec/features/support/shared/message_fixtures.rb
|
367
|
+
- spec/features/migrate_spec.rb
|
368
|
+
- spec/features/remote/list_account_folders_spec.rb
|
369
|
+
- spec/support/fixtures.rb
|
370
|
+
- spec/support/silence_logging.rb
|
371
|
+
- spec/support/higline_test_helpers.rb
|
332
372
|
- spec/fixtures/connection.yml
|
373
|
+
- spec/gather_rspec_coverage.rb
|