imap-backup 4.2.0 → 5.1.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 +2 -0
- 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/restore.rb +20 -4
- data/lib/imap/backup/cli.rb +55 -10
- 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/version.rb +2 -2
- data/spec/features/backup_spec.rb +13 -12
- 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/restore_spec.rb +7 -5
- data/spec/features/support/aruba.rb +73 -0
- data/spec/features/support/backup_directory.rb +0 -4
- data/spec/features/support/email_server.rb +1 -1
- data/spec/spec_helper.rb +2 -3
- 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 +57 -11
- data/lib/thunderbird/install.rb +0 -16
- data/lib/thunderbird/local_folder.rb +0 -65
- data/lib/thunderbird/profile.rb +0 -30
- data/lib/thunderbird/profiles.rb +0 -71
- data/lib/thunderbird/subdirectory.rb +0 -93
- data/lib/thunderbird/subdirectory_placeholder.rb +0 -21
- data/lib/thunderbird.rb +0 -14
- data/spec/gather_rspec_coverage.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59babb556b2f47a07590debff15dcd5456f1e61454c3aba2e504610ce4322647
|
4
|
+
data.tar.gz: 89909077444746e44fe3955070df6b590942da0d44da58c9b08b282e694000d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea00bb55bb853cef73ec12171a4bdde9b0b5ef88a914065bbe307f48712db3329e8c8f1712cfa48b4a49102d20fb38cc465dc463c2d3ea9e0caba000a184766b
|
7
|
+
data.tar.gz: 24d368c209c11db4ae7f05a93b9cf4e0435b65eef0cffd7e58f8c669e634ca735aa3187b6a6506b7b10ba3bec961d3aa9d7387df40d4880f1bed73df7f24bbb9
|
data/imap-backup.gemspec
CHANGED
@@ -27,7 +27,9 @@ Gem::Specification.new do |gem|
|
|
27
27
|
gem.add_runtime_dependency "os"
|
28
28
|
gem.add_runtime_dependency "rake"
|
29
29
|
gem.add_runtime_dependency "thor", "~> 1.1"
|
30
|
+
gem.add_runtime_dependency "thunderbird", ">= 0.0.0"
|
30
31
|
|
32
|
+
gem.add_development_dependency "aruba", ">= 0.0.0"
|
31
33
|
gem.add_development_dependency "codeclimate-test-reporter", "~> 0.4.8"
|
32
34
|
if RUBY_ENGINE == "jruby"
|
33
35
|
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
|
@@ -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
|
@@ -3,16 +3,32 @@ module Imap::Backup
|
|
3
3
|
include Thor::Actions
|
4
4
|
include CLI::Helpers
|
5
5
|
|
6
|
+
attr_reader :email
|
6
7
|
attr_reader :account_names
|
7
8
|
|
8
|
-
def initialize(options)
|
9
|
-
|
10
|
-
@account_names =
|
9
|
+
def initialize(email = nil, options)
|
10
|
+
@email = email
|
11
|
+
@account_names =
|
12
|
+
if options.key?(:accounts)
|
13
|
+
options[:accounts].split(",")
|
14
|
+
end
|
11
15
|
end
|
12
16
|
|
13
17
|
no_commands do
|
14
18
|
def run
|
15
|
-
|
19
|
+
case
|
20
|
+
when email && !account_names
|
21
|
+
connection = connection(email)
|
22
|
+
connection.restore
|
23
|
+
when !email && !account_names
|
24
|
+
Logger.logger.info "Calling restore without an EMAIL parameter is deprecated"
|
25
|
+
each_connection([]) { |connection| connection.restore }
|
26
|
+
when email && account_names.any?
|
27
|
+
raise "Pass either an email or the --accounts option, not both"
|
28
|
+
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 }
|
31
|
+
end
|
16
32
|
end
|
17
33
|
end
|
18
34
|
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,15 +58,62 @@ module Imap::Backup
|
|
57
58
|
Folders.new(symbolized(options)).run
|
58
59
|
end
|
59
60
|
|
60
|
-
desc "
|
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"
|
61
66
|
long_desc <<~DESC
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
+
|
109
|
+
desc "restore EMAIL", "Restores a single account"
|
110
|
+
long_desc <<~DESC
|
111
|
+
Restores all backed-up emails for the supplied account to
|
112
|
+
their original server.
|
65
113
|
DESC
|
66
114
|
accounts_option
|
67
|
-
def restore
|
68
|
-
Restore.new(symbolized(options)).run
|
115
|
+
def restore(email = nil)
|
116
|
+
Restore.new(email, symbolized(options)).run
|
69
117
|
end
|
70
118
|
|
71
119
|
desc "setup", "Configure imap-backup"
|
@@ -86,9 +134,6 @@ module Imap::Backup
|
|
86
134
|
Status.new(symbolized(options)).run
|
87
135
|
end
|
88
136
|
|
89
|
-
desc "local SUBCOMMAND [OPTIONS]", "View local info"
|
90
|
-
subcommand "local", Local
|
91
|
-
|
92
137
|
desc "utils SUBCOMMAND [OPTIONS]", "Various utilities"
|
93
138
|
subcommand "utils", Utils
|
94
139
|
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
|
data/lib/imap/backup/version.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
require "features/helper"
|
2
2
|
|
3
|
-
RSpec.describe "backup", type: :
|
3
|
+
RSpec.describe "backup", type: :aruba, docker: true do
|
4
4
|
include_context "imap-backup connection"
|
5
5
|
include_context "message-fixtures"
|
6
6
|
|
7
|
+
let(:local_backup_path) { File.expand_path("~/backup") }
|
8
|
+
let(:backup_folders) { [{name: folder}] }
|
9
|
+
let(:folder) { "my-stuff" }
|
7
10
|
let(:messages_as_mbox) do
|
8
11
|
message_as_mbox_entry(msg1) + message_as_mbox_entry(msg2)
|
9
12
|
end
|
10
|
-
|
11
|
-
let(:email1) { send_email folder, msg1 }
|
12
|
-
let(:email2) { send_email folder, msg2 }
|
13
|
+
|
13
14
|
let!(:pre) {}
|
14
15
|
let!(:setup) do
|
15
16
|
server_create_folder folder
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
send_email folder, msg1
|
18
|
+
send_email folder, msg2
|
19
|
+
create_config(accounts: [account.to_h])
|
20
|
+
|
21
|
+
run_command_and_stop("imap-backup backup")
|
19
22
|
end
|
20
23
|
|
21
24
|
after do
|
22
|
-
FileUtils.rm_rf local_backup_path
|
23
|
-
delete_emails folder
|
24
25
|
server_delete_folder folder
|
25
|
-
connection.disconnect
|
26
26
|
end
|
27
27
|
|
28
28
|
it "downloads messages" do
|
@@ -51,11 +51,10 @@ RSpec.describe "backup", type: :feature, docker: true do
|
|
51
51
|
|
52
52
|
context "when uid_validity does not match" do
|
53
53
|
let(:new_name) { "NEWNAME" }
|
54
|
-
let(:email3) { send_email folder, msg3 }
|
55
54
|
let(:original_folder_uid_validity) { server_uid_validity(folder) }
|
56
55
|
let!(:pre) do
|
57
56
|
server_create_folder folder
|
58
|
-
|
57
|
+
send_email folder, msg3
|
59
58
|
original_folder_uid_validity
|
60
59
|
connection.run_backup
|
61
60
|
connection.disconnect
|
@@ -78,6 +77,7 @@ RSpec.describe "backup", type: :feature, docker: true do
|
|
78
77
|
context "when a renamed local backup exists" do
|
79
78
|
let!(:pre) do
|
80
79
|
super()
|
80
|
+
create_directory local_backup_path
|
81
81
|
File.write(imap_path(renamed_folder), "existing imap")
|
82
82
|
File.write(mbox_path(renamed_folder), "existing mbox")
|
83
83
|
end
|
@@ -91,6 +91,7 @@ RSpec.describe "backup", type: :feature, docker: true do
|
|
91
91
|
|
92
92
|
context "when an unversioned .imap file is found" do
|
93
93
|
let!(:pre) do
|
94
|
+
create_directory local_backup_path
|
94
95
|
File.open(imap_path(folder), "w") { |f| f.write "old format imap" }
|
95
96
|
File.open(mbox_path(folder), "w") { |f| f.write "old format emails" }
|
96
97
|
end
|
@@ -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
|