imap-backup 3.3.0 → 4.0.0.rc1
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/.circleci/config.yml +2 -2
- data/.rubocop_todo.yml +103 -16
- data/CHANGELOG.md +11 -0
- data/README.md +11 -3
- data/bin/imap-backup +3 -93
- data/docs/{setting-up-gmail.md → setting-up-gmail-with-oauth2.md} +0 -0
- data/imap-backup +9 -0
- data/imap-backup.gemspec +2 -1
- data/lib/email/mboxrd/message.rb +2 -2
- data/lib/imap/backup/account/connection.rb +25 -16
- data/lib/imap/backup/cli/backup.rb +21 -0
- data/lib/imap/backup/cli/folders.rb +27 -0
- data/lib/imap/backup/cli/helpers.rb +20 -0
- data/lib/imap/backup/cli/local.rb +70 -0
- data/lib/imap/backup/cli/restore.rb +19 -0
- data/lib/imap/backup/cli/setup.rb +13 -0
- data/lib/imap/backup/cli/status.rb +26 -0
- data/lib/imap/backup/cli.rb +87 -0
- data/lib/imap/backup/configuration/account.rb +6 -1
- data/lib/imap/backup/configuration/gmail_oauth2.rb +1 -1
- data/lib/imap/backup/configuration/list.rb +13 -12
- data/lib/imap/backup/version.rb +3 -3
- data/spec/fixtures/connection.yml +1 -1
- data/spec/unit/imap/backup/account/connection_spec.rb +58 -7
- data/spec/unit/imap/backup/configuration/account_spec.rb +37 -8
- data/spec/unit/imap/backup/configuration/list_spec.rb +1 -0
- data/spec/unit/imap/backup/configuration/setup_spec.rb +1 -1
- data/spec/unit/imap/backup/utils_spec.rb +0 -2
- metadata +31 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ba3f202308a586f7ec54b28d66ea2f9422cf30f706c118ab02f362346351f268
|
|
4
|
+
data.tar.gz: 585bd29f2d2f836aad27c6ac58855649b7621eff770d5e2b40bfdd3f6aa774f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6270660f55ab52e3a3d8242bdfbb2d044ce7428ccc75daabf25b6753a7c91f9c3f4d8b2be4db517f44fb887663a40e946f128c2bf06f4d1006cd02182d9f477e
|
|
7
|
+
data.tar.gz: f94af41fee60be97e15e0d2aa3da5a0696b9d8bab5cb03cb42c805881b13e8a38fc5be42ee30efd26576d5cadb10d2f53b0c46c00fc94ca72cf23f94e05d602b
|
data/.circleci/config.yml
CHANGED
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
type: string
|
|
28
28
|
environment:
|
|
29
29
|
BUNDLE_PATH: ./vendor/bundle
|
|
30
|
-
|
|
30
|
+
DOCKER_IMAP_SERVER: 993
|
|
31
31
|
docker:
|
|
32
32
|
- image: "cimg/ruby:<< parameters.ruby_version >>"
|
|
33
33
|
- image: antespi/docker-imap-devel:latest
|
|
@@ -48,4 +48,4 @@ workflows:
|
|
|
48
48
|
- test:
|
|
49
49
|
matrix:
|
|
50
50
|
parameters:
|
|
51
|
-
ruby_version: ["2.
|
|
51
|
+
ruby_version: ["2.5", "2.6", "2.7"]
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,42 +1,129 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2021-
|
|
3
|
+
# on 2021-09-21 15:30:34 UTC using RuboCop version 1.21.0.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count:
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Cop supports --auto-correct.
|
|
11
|
+
Layout/ElseAlignment:
|
|
12
|
+
Exclude:
|
|
13
|
+
- 'lib/imap/backup/configuration/gmail_oauth2.rb'
|
|
13
14
|
|
|
14
15
|
# Offense count: 2
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
# Cop supports --auto-correct.
|
|
17
|
+
# Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
|
|
18
|
+
Layout/EmptyLineBetweenDefs:
|
|
19
|
+
Exclude:
|
|
20
|
+
- 'lib/google/auth/stores/in_memory_token_store.rb'
|
|
21
|
+
|
|
22
|
+
# Offense count: 1
|
|
23
|
+
# Cop supports --auto-correct.
|
|
24
|
+
# Configuration parameters: EnforcedStyleAlignWith, Severity.
|
|
25
|
+
# SupportedStylesAlignWith: keyword, variable, start_of_line
|
|
26
|
+
Layout/EndAlignment:
|
|
27
|
+
Exclude:
|
|
28
|
+
- 'lib/imap/backup/configuration/gmail_oauth2.rb'
|
|
29
|
+
|
|
30
|
+
# Offense count: 1
|
|
31
|
+
# Cop supports --auto-correct.
|
|
32
|
+
# Configuration parameters: Width, IgnoredPatterns.
|
|
33
|
+
Layout/IndentationWidth:
|
|
34
|
+
Exclude:
|
|
35
|
+
- 'lib/imap/backup/configuration/gmail_oauth2.rb'
|
|
36
|
+
|
|
37
|
+
# Offense count: 34
|
|
38
|
+
# Configuration parameters: AllowedMethods.
|
|
39
|
+
# AllowedMethods: enums
|
|
40
|
+
Lint/ConstantDefinitionInBlock:
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'lib/imap/backup/configuration/asker.rb'
|
|
43
|
+
- 'spec/unit/gmail/authenticator_spec.rb'
|
|
44
|
+
- 'spec/unit/google/auth/stores/in_memory_token_store_spec.rb'
|
|
45
|
+
- 'spec/unit/imap/backup/account/connection_spec.rb'
|
|
46
|
+
- 'spec/unit/imap/backup/account/folder_spec.rb'
|
|
47
|
+
- 'spec/unit/imap/backup/configuration/account_spec.rb'
|
|
48
|
+
- 'spec/unit/imap/backup/configuration/gmail_oauth2_spec.rb'
|
|
19
49
|
|
|
20
50
|
# Offense count: 2
|
|
51
|
+
# Cop supports --auto-correct.
|
|
52
|
+
# Configuration parameters: AllowComments.
|
|
53
|
+
Lint/UselessMethodDefinition:
|
|
54
|
+
Exclude:
|
|
55
|
+
- 'lib/imap/backup/configuration/account.rb'
|
|
56
|
+
- 'lib/imap/backup/configuration/asker.rb'
|
|
57
|
+
|
|
58
|
+
# Offense count: 11
|
|
59
|
+
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
|
60
|
+
Metrics/AbcSize:
|
|
61
|
+
Max: 33
|
|
62
|
+
|
|
63
|
+
# Offense count: 3
|
|
21
64
|
# Configuration parameters: CountComments, CountAsOne.
|
|
22
65
|
Metrics/ClassLength:
|
|
23
|
-
Max:
|
|
66
|
+
Max: 172
|
|
24
67
|
|
|
25
|
-
# Offense count:
|
|
26
|
-
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
|
|
68
|
+
# Offense count: 19
|
|
69
|
+
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
|
27
70
|
Metrics/MethodLength:
|
|
28
|
-
Max:
|
|
71
|
+
Max: 26
|
|
29
72
|
|
|
30
73
|
# Offense count: 2
|
|
31
74
|
# Configuration parameters: CountComments, CountAsOne.
|
|
32
75
|
Metrics/ModuleLength:
|
|
33
|
-
Max:
|
|
76
|
+
Max: 145
|
|
77
|
+
|
|
78
|
+
# Offense count: 2
|
|
79
|
+
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers.
|
|
80
|
+
# SupportedStyles: snake_case, normalcase, non_integer
|
|
81
|
+
# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339
|
|
82
|
+
Naming/VariableNumber:
|
|
83
|
+
Exclude:
|
|
84
|
+
- 'lib/email/provider.rb'
|
|
85
|
+
- 'spec/unit/email/provider_spec.rb'
|
|
34
86
|
|
|
35
|
-
# Offense count:
|
|
87
|
+
# Offense count: 209
|
|
36
88
|
# Configuration parameters: AllowSubject.
|
|
37
89
|
RSpec/MultipleMemoizedHelpers:
|
|
38
90
|
Max: 16
|
|
39
91
|
|
|
40
|
-
# Offense count:
|
|
92
|
+
# Offense count: 49
|
|
41
93
|
RSpec/NestedGroups:
|
|
42
94
|
Max: 6
|
|
95
|
+
|
|
96
|
+
# Offense count: 8
|
|
97
|
+
# Cop supports --auto-correct.
|
|
98
|
+
# Configuration parameters: EnforcedStyle.
|
|
99
|
+
# SupportedStyles: nested, compact
|
|
100
|
+
Style/ClassAndModuleChildren:
|
|
101
|
+
Exclude:
|
|
102
|
+
- 'lib/email/mboxrd/message.rb'
|
|
103
|
+
- 'lib/imap/backup/downloader.rb'
|
|
104
|
+
- 'lib/imap/backup/serializer.rb'
|
|
105
|
+
- 'lib/imap/backup/serializer/mbox.rb'
|
|
106
|
+
- 'lib/imap/backup/serializer/mbox_enumerator.rb'
|
|
107
|
+
- 'lib/imap/backup/serializer/mbox_store.rb'
|
|
108
|
+
- 'lib/imap/backup/uploader.rb'
|
|
109
|
+
- 'lib/imap/backup/utils.rb'
|
|
110
|
+
|
|
111
|
+
# Offense count: 1
|
|
112
|
+
# Cop supports --auto-correct.
|
|
113
|
+
Style/RedundantBegin:
|
|
114
|
+
Exclude:
|
|
115
|
+
- 'lib/imap/backup/account/connection.rb'
|
|
116
|
+
|
|
117
|
+
# Offense count: 1
|
|
118
|
+
# Cop supports --auto-correct.
|
|
119
|
+
# Configuration parameters: MinSize, WordRegex.
|
|
120
|
+
# SupportedStyles: percent, brackets
|
|
121
|
+
Style/WordArray:
|
|
122
|
+
EnforcedStyle: percent
|
|
123
|
+
|
|
124
|
+
# Offense count: 1
|
|
125
|
+
# Cop supports --auto-correct.
|
|
126
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
127
|
+
# URISchemes: http, https
|
|
128
|
+
Layout/LineLength:
|
|
129
|
+
Max: 133
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [4.0.0.rc1] - 2021-11-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
* `local` commands to list accounts, folders and emails and to view single
|
|
11
|
+
emails.
|
data/README.md
CHANGED
|
@@ -16,11 +16,19 @@
|
|
|
16
16
|
[Rubygem]: http://rubygems.org/gems/imap-backup "Ruby gem at rubygems.org"
|
|
17
17
|
[Continuous Integration]: https://circleci.com/gh/joeyates/imap-backup "Build status by CirceCI"
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
# GMail
|
|
20
20
|
|
|
21
|
-
GMail
|
|
21
|
+
To use imap-backup with GMail, you will need to enable 'App passwords' on your account.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
## GMail OAuth2
|
|
24
|
+
|
|
25
|
+
GMail OAuth2 authentication is supported, but as GMail's policy requires
|
|
26
|
+
users to set up an application specific to their account, the feature
|
|
27
|
+
is disabled by default.
|
|
28
|
+
|
|
29
|
+
You will need to set the environment variable IMAP_BACKUP_ENABLE_GMAIL_OAUTH2.
|
|
30
|
+
|
|
31
|
+
To set it up, [follow the HOWTO](docs/setting-up-gmail-with-oauth2.md).
|
|
24
32
|
|
|
25
33
|
# Installation
|
|
26
34
|
|
data/bin/imap-backup
CHANGED
|
@@ -1,98 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
require "optparse"
|
|
3
2
|
|
|
4
3
|
$LOAD_PATH.unshift(File.expand_path("../lib/", __dir__))
|
|
5
|
-
require "imap/backup"
|
|
4
|
+
require "imap/backup/cli"
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
{name: "setup", help: "Create/edit the configuration file"},
|
|
9
|
-
{name: "backup", help: "Do the backup (default)"},
|
|
10
|
-
{name: "folders", help: "List folders for all (or selected) accounts"},
|
|
11
|
-
{name: "restore", help: "Restore emails to server"},
|
|
12
|
-
{name: "status", help: "List count of non backed-up emails per folder"},
|
|
13
|
-
{name: "help", help: "Show usage"}
|
|
14
|
-
].freeze
|
|
6
|
+
Imap::Backup::Configuration::List.new.setup_logging
|
|
15
7
|
|
|
16
|
-
|
|
17
|
-
parser = OptionParser.new do |opts|
|
|
18
|
-
opts.banner = "Usage: #{$PROGRAM_NAME} [options] COMMAND"
|
|
19
|
-
|
|
20
|
-
opts.separator ""
|
|
21
|
-
opts.separator "Commands:"
|
|
22
|
-
KNOWN_COMMANDS.each do |command|
|
|
23
|
-
opts.separator format("\t%- 20<name>s %<help>s", command)
|
|
24
|
-
end
|
|
25
|
-
opts.separator ""
|
|
26
|
-
opts.separator "Common options:"
|
|
27
|
-
|
|
28
|
-
opts.on(
|
|
29
|
-
"-a",
|
|
30
|
-
"--accounts ACCOUNT1[,ACCOUNT2,...]",
|
|
31
|
-
Array,
|
|
32
|
-
"only these accounts"
|
|
33
|
-
) do |account|
|
|
34
|
-
options[:accounts] = account
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
opts.on_tail("-h", "--help", "Show usage") do
|
|
38
|
-
puts opts
|
|
39
|
-
exit
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
opts.on_tail("--version", "Show version") do
|
|
43
|
-
puts Imap::Backup::VERSION
|
|
44
|
-
exit
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
parser.parse!
|
|
48
|
-
|
|
49
|
-
options[:command] = ARGV.shift if !ARGV.empty?
|
|
50
|
-
|
|
51
|
-
# rubocop:disable Style/IfUnlessModifier
|
|
52
|
-
if KNOWN_COMMANDS.find { |c| c[:name] == options[:command] }.nil?
|
|
53
|
-
raise "Unknown command '#{options[:command]}'"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# rubocop:enable Style/IfUnlessModifier
|
|
57
|
-
|
|
58
|
-
if options[:command] == "help"
|
|
59
|
-
puts parser
|
|
60
|
-
exit
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
begin
|
|
64
|
-
configuration = Imap::Backup::Configuration::List.new(options[:accounts])
|
|
65
|
-
rescue Imap::Backup::ConfigurationNotFound
|
|
66
|
-
Imap::Backup::Configuration::Setup.new.run
|
|
67
|
-
exit
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
configuration.setup_logging
|
|
71
|
-
|
|
72
|
-
case options[:command]
|
|
73
|
-
when "setup"
|
|
74
|
-
Imap::Backup::Configuration::Setup.new.run
|
|
75
|
-
when "backup"
|
|
76
|
-
configuration.each_connection(&:run_backup)
|
|
77
|
-
when "folders"
|
|
78
|
-
configuration.each_connection do |connection|
|
|
79
|
-
puts connection.username
|
|
80
|
-
folders = connection.folders
|
|
81
|
-
if folders.nil?
|
|
82
|
-
warn "Unable to list account folders"
|
|
83
|
-
exit 1
|
|
84
|
-
end
|
|
85
|
-
folders.each { |f| puts "\t#{f}" }
|
|
86
|
-
end
|
|
87
|
-
when "restore"
|
|
88
|
-
configuration.each_connection(&:restore)
|
|
89
|
-
when "status"
|
|
90
|
-
configuration.each_connection do |connection|
|
|
91
|
-
puts connection.username
|
|
92
|
-
folders = connection.status
|
|
93
|
-
folders.each do |f|
|
|
94
|
-
missing_locally = f[:remote] - f[:local]
|
|
95
|
-
puts "#{f[:name]}: #{missing_locally.size}"
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
8
|
+
Imap::Backup::CLI.start(ARGV)
|
|
File without changes
|
data/imap-backup
ADDED
data/imap-backup.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
|
|
|
13
13
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
14
14
|
gem.test_files = gem.files.grep(%r{^spec/})
|
|
15
15
|
gem.require_paths = ["lib"]
|
|
16
|
-
gem.required_ruby_version =
|
|
16
|
+
gem.required_ruby_version = ">= 2.5"
|
|
17
17
|
gem.version = Imap::Backup::VERSION
|
|
18
18
|
|
|
19
19
|
gem.add_runtime_dependency "gmail_xoauth"
|
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
|
|
|
21
21
|
gem.add_runtime_dependency "highline"
|
|
22
22
|
gem.add_runtime_dependency "mail"
|
|
23
23
|
gem.add_runtime_dependency "rake"
|
|
24
|
+
gem.add_runtime_dependency "thor", "~> 1.1"
|
|
24
25
|
|
|
25
26
|
gem.add_development_dependency "codeclimate-test-reporter", "~> 0.4.8"
|
|
26
27
|
if RUBY_ENGINE == "jruby"
|
data/lib/email/mboxrd/message.rb
CHANGED
|
@@ -64,7 +64,25 @@ module Imap::Backup
|
|
|
64
64
|
|
|
65
65
|
Imap::Backup.logger.debug "[#{folder.name}] running backup"
|
|
66
66
|
serializer.apply_uid_validity(folder.uid_validity)
|
|
67
|
-
|
|
67
|
+
begin
|
|
68
|
+
Downloader.new(folder, serializer).run
|
|
69
|
+
rescue Net::IMAP::ByeResponseError
|
|
70
|
+
reconnect
|
|
71
|
+
retry
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def local_folders
|
|
77
|
+
return enum_for(:local_folders) if !block_given?
|
|
78
|
+
|
|
79
|
+
glob = File.join(local_path, "**", "*.imap")
|
|
80
|
+
base = Pathname.new(local_path)
|
|
81
|
+
Pathname.glob(glob) do |path|
|
|
82
|
+
name = path.relative_path_from(base).to_s[0..-6]
|
|
83
|
+
serializer = Serializer::Mbox.new(local_path, name)
|
|
84
|
+
folder = Account::Folder.new(self, name)
|
|
85
|
+
yield serializer, folder
|
|
68
86
|
end
|
|
69
87
|
end
|
|
70
88
|
|
|
@@ -75,7 +93,7 @@ module Imap::Backup
|
|
|
75
93
|
end
|
|
76
94
|
|
|
77
95
|
def disconnect
|
|
78
|
-
imap.disconnect
|
|
96
|
+
imap.disconnect if @imap
|
|
79
97
|
end
|
|
80
98
|
|
|
81
99
|
def reconnect
|
|
@@ -91,7 +109,7 @@ module Imap::Backup
|
|
|
91
109
|
"Creating IMAP instance: #{server}, options: #{options.inspect}"
|
|
92
110
|
)
|
|
93
111
|
imap = Net::IMAP.new(server, options)
|
|
94
|
-
if
|
|
112
|
+
if use_gmail_oauth2? && Gmail::Authenticator.refresh_token?(password)
|
|
95
113
|
authenticator = Gmail::Authenticator.new(email: username, token: password)
|
|
96
114
|
credentials = authenticator.credentials
|
|
97
115
|
raise InvalidGmailOauth2RefreshToken if !credentials
|
|
@@ -163,19 +181,10 @@ module Imap::Backup
|
|
|
163
181
|
password.gsub(/./, "x")
|
|
164
182
|
end
|
|
165
183
|
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
def local_folders
|
|
171
|
-
glob = File.join(local_path, "**", "*.imap")
|
|
172
|
-
base = Pathname.new(local_path)
|
|
173
|
-
Pathname.glob(glob) do |path|
|
|
174
|
-
name = path.relative_path_from(base).to_s[0..-6]
|
|
175
|
-
serializer = Serializer::Mbox.new(local_path, name)
|
|
176
|
-
folder = Account::Folder.new(self, name)
|
|
177
|
-
yield serializer, folder
|
|
178
|
-
end
|
|
184
|
+
def use_gmail_oauth2?
|
|
185
|
+
# TODO: test use of ENV
|
|
186
|
+
server == Email::Provider::GMAIL_IMAP_SERVER &&
|
|
187
|
+
ENV["IMAP_BACKUP_ENABLE_GMAIL_OAUTH2"]
|
|
179
188
|
end
|
|
180
189
|
|
|
181
190
|
def backup_folders
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Backup < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
attr_reader :account_names
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
super([])
|
|
10
|
+
@account_names = (options[:accounts] || "").split(",")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
no_commands do
|
|
14
|
+
def run
|
|
15
|
+
each_connection(account_names) do |connection|
|
|
16
|
+
connection.run_backup
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Folders < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
attr_reader :account_names
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
super([])
|
|
10
|
+
@account_names = (options[:accounts] || "").split(",")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
no_commands do
|
|
14
|
+
def run
|
|
15
|
+
each_connection(account_names) do |connection|
|
|
16
|
+
puts connection.username
|
|
17
|
+
folders = connection.folders
|
|
18
|
+
if folders.nil?
|
|
19
|
+
warn "Unable to list account folders"
|
|
20
|
+
return false
|
|
21
|
+
end
|
|
22
|
+
folders.each { |f| puts "\t#{f}" }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "imap/backup"
|
|
2
|
+
|
|
3
|
+
module Imap::Backup::CLI::Helpers
|
|
4
|
+
def symbolized(options)
|
|
5
|
+
options.each.with_object({}) { |(k, v), acc| acc[k.intern] = v }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def each_connection(names)
|
|
9
|
+
begin
|
|
10
|
+
connections = Imap::Backup::Configuration::List.new(names)
|
|
11
|
+
rescue Imap::Backup::ConfigurationNotFound
|
|
12
|
+
raise "imap-backup is not configured. Run `imap-backup setup`"
|
|
13
|
+
return
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
connections.each_connection do |connection|
|
|
17
|
+
yield connection
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Local < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
desc "accounts", "list locally backed-up accounts"
|
|
7
|
+
def accounts
|
|
8
|
+
connections = Imap::Backup::Configuration::List.new
|
|
9
|
+
connections.accounts.each { |a| puts a[:username] }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc "folders EMAIL", "list account folders"
|
|
13
|
+
def folders(email)
|
|
14
|
+
connections = Imap::Backup::Configuration::List.new
|
|
15
|
+
account = connections.accounts.find { |a| a[:username] == email }
|
|
16
|
+
raise "#{email} is not a configured account" if !account
|
|
17
|
+
|
|
18
|
+
account_connection = Imap::Backup::Account::Connection.new(account)
|
|
19
|
+
account_connection.local_folders.each do |_s, f|
|
|
20
|
+
puts %("#{f.name}")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "emails EMAIL FOLDER", "list emails in a folder"
|
|
25
|
+
def emails(email, folder_name)
|
|
26
|
+
connections = Imap::Backup::Configuration::List.new
|
|
27
|
+
account = connections.accounts.find { |a| a[:username] == email }
|
|
28
|
+
raise "#{email} is not a configured account" if !account
|
|
29
|
+
|
|
30
|
+
account_connection = Imap::Backup::Account::Connection.new(account)
|
|
31
|
+
folder_serializer, folder = account_connection.local_folders.find do |(_s, f)|
|
|
32
|
+
f.name == folder_name
|
|
33
|
+
end
|
|
34
|
+
raise "Folder '#{folder_name}' not found" if !folder_serializer
|
|
35
|
+
|
|
36
|
+
max_subject = 60
|
|
37
|
+
puts format("%-10<uid>s %-#{max_subject}<subject>s - %<date>s", {uid: "UID", subject: "Subject", date: "Date"})
|
|
38
|
+
puts "-" * (12 + max_subject + 28)
|
|
39
|
+
|
|
40
|
+
uids = folder_serializer.uids
|
|
41
|
+
|
|
42
|
+
folder_serializer.each_message(uids).map do |uid, message|
|
|
43
|
+
m = {uid: uid, date: message.parsed.date.to_s, subject: message.parsed.subject}
|
|
44
|
+
if m[:subject].length > max_subject
|
|
45
|
+
puts format("% 10<uid>u: %.#{max_subject - 3}<subject>s... - %<date>s", m)
|
|
46
|
+
else
|
|
47
|
+
puts format("% 10<uid>u: %-#{max_subject}<subject>s - %<date>s", m)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc "email EMAIL FOLDER UID", "show an email"
|
|
53
|
+
def email(email, folder_name, uid)
|
|
54
|
+
connections = Imap::Backup::Configuration::List.new
|
|
55
|
+
account = connections.accounts.find { |a| a[:username] == email }
|
|
56
|
+
raise "#{email} is not a configured account" if !account
|
|
57
|
+
|
|
58
|
+
account_connection = Imap::Backup::Account::Connection.new(account)
|
|
59
|
+
folder_serializer, _folder = account_connection.local_folders.find do |(_s, f)|
|
|
60
|
+
f.name == folder_name
|
|
61
|
+
end
|
|
62
|
+
raise "Folder '#{folder_name}' not found" if !folder_serializer
|
|
63
|
+
|
|
64
|
+
loaded_message = folder_serializer.load(uid)
|
|
65
|
+
raise "Message #{uid} not found in folder '#{folder_name}'" if !loaded_message
|
|
66
|
+
|
|
67
|
+
puts loaded_message.supplied_body
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Restore < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
attr_reader :account_names
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
super([])
|
|
10
|
+
@account_names = (options[:accounts] || "").split(",")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
no_commands do
|
|
14
|
+
def run
|
|
15
|
+
each_connection(account_names) { |connection| connection.restore }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Imap::Backup
|
|
2
|
+
class CLI::Status < Thor
|
|
3
|
+
include Thor::Actions
|
|
4
|
+
include CLI::Helpers
|
|
5
|
+
|
|
6
|
+
attr_reader :account_names
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
super([])
|
|
10
|
+
@account_names = (options[:accounts] || "").split(",")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
no_commands do
|
|
14
|
+
def run
|
|
15
|
+
each_connection(account_names) do |connection|
|
|
16
|
+
puts connection.username
|
|
17
|
+
folders = connection.status
|
|
18
|
+
folders.each do |f|
|
|
19
|
+
missing_locally = f[:remote] - f[:local]
|
|
20
|
+
puts "#{f[:name]}: #{missing_locally.size}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
|
|
3
|
+
class Imap::Backup::CLI < Thor
|
|
4
|
+
require "imap/backup/cli/helpers"
|
|
5
|
+
|
|
6
|
+
autoload :Backup, "imap/backup/cli/backup"
|
|
7
|
+
autoload :Folders, "imap/backup/cli/folders"
|
|
8
|
+
autoload :Local, "imap/backup/cli/local"
|
|
9
|
+
autoload :Remote, "imap/backup/cli/remote"
|
|
10
|
+
autoload :Restore, "imap/backup/cli/restore"
|
|
11
|
+
autoload :Setup, "imap/backup/cli/setup"
|
|
12
|
+
autoload :Status, "imap/backup/cli/status"
|
|
13
|
+
|
|
14
|
+
include Helpers
|
|
15
|
+
|
|
16
|
+
default_task :backup
|
|
17
|
+
|
|
18
|
+
def self.exit_on_failure?
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.accounts_option
|
|
23
|
+
method_option(
|
|
24
|
+
"accounts",
|
|
25
|
+
type: :string,
|
|
26
|
+
banner: "a comma-separated list of accounts (defaults to all configured accounts)",
|
|
27
|
+
aliases: ["-a"]
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
desc "backup [OPTIONS]", "Run the backup"
|
|
32
|
+
long_desc <<~DESC
|
|
33
|
+
Downloads any emails not yet present locally.
|
|
34
|
+
Runs the backup for each configured account,
|
|
35
|
+
or for those requested via the --accounts option.
|
|
36
|
+
By default all folders, are backed up.
|
|
37
|
+
The setup tool can be used to choose a specific list of folders to back up.
|
|
38
|
+
DESC
|
|
39
|
+
accounts_option
|
|
40
|
+
def backup
|
|
41
|
+
Backup.new(symbolized(options)).run
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "folders [OPTIONS]", "This command is deprecated, use `imap-backup remote folders ACCOUNT`"
|
|
45
|
+
long_desc <<~DESC
|
|
46
|
+
Lists all folders of all configured accounts.
|
|
47
|
+
This command is deprecated.
|
|
48
|
+
Instead, use a combination of `imap-backup local accounts` to get the list of accounts,
|
|
49
|
+
and `imap-backup remote folders ACCOUNT` to get the folder list.
|
|
50
|
+
DESC
|
|
51
|
+
accounts_option
|
|
52
|
+
def folders
|
|
53
|
+
Folders.new(symbolized(options)).run
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
desc "restore [OPTIONS]", "This command is deprecated, use `imap-backup restore ACCOUNT`"
|
|
57
|
+
long_desc <<~DESC
|
|
58
|
+
By default, restores all local emails to their respective servers.
|
|
59
|
+
This command is deprecated.
|
|
60
|
+
Instead, use `imap-backup restore ACCOUNT` to restore a single account.
|
|
61
|
+
DESC
|
|
62
|
+
accounts_option
|
|
63
|
+
def restore
|
|
64
|
+
Restore.new(symbolized(options)).run
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
desc "setup", "Configure imap-backup"
|
|
68
|
+
long_desc <<~DESC
|
|
69
|
+
A menu-driven command-line application used to configure imap-backup.
|
|
70
|
+
Configure email accounts to back up.
|
|
71
|
+
DESC
|
|
72
|
+
def setup
|
|
73
|
+
Setup.new().run
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
desc "status", "Show backup status"
|
|
77
|
+
long_desc <<~DESC
|
|
78
|
+
For each configured account and folder, lists the number of emails yet to be downloaded.
|
|
79
|
+
DESC
|
|
80
|
+
accounts_option
|
|
81
|
+
def status
|
|
82
|
+
Status.new(symbolized(options)).run
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc "local subcommand ...ARGS", "View local info"
|
|
86
|
+
subcommand "local", Local
|
|
87
|
+
end
|
|
@@ -69,7 +69,7 @@ module Imap::Backup
|
|
|
69
69
|
def modify_password(menu)
|
|
70
70
|
menu.choice("modify password") do
|
|
71
71
|
password =
|
|
72
|
-
if account
|
|
72
|
+
if use_gmail_oauth2?(account)
|
|
73
73
|
Configuration::GmailOauth2.new(account).run
|
|
74
74
|
else
|
|
75
75
|
Configuration::Asker.password
|
|
@@ -82,6 +82,11 @@ module Imap::Backup
|
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
def use_gmail_oauth2?(account)
|
|
86
|
+
account[:server] == Email::Provider::GMAIL_IMAP_SERVER &&
|
|
87
|
+
ENV["IMAP_BACKUP_ENABLE_GMAIL_OAUTH2"]
|
|
88
|
+
end
|
|
89
|
+
|
|
85
90
|
def modify_server(menu)
|
|
86
91
|
menu.choice("modify server") do
|
|
87
92
|
server = highline.ask("server: ")
|
|
@@ -8,7 +8,7 @@ module Imap::Backup
|
|
|
8
8
|
You need to authorize imap_backup to get access to your email.
|
|
9
9
|
To do so, please follow the instructions here:
|
|
10
10
|
|
|
11
|
-
https://github.com/joeyates/imap-backup/blob/main/docs/setting-up-gmail.md
|
|
11
|
+
https://github.com/joeyates/imap-backup/blob/main/docs/setting-up-gmail-with-oauth2.md
|
|
12
12
|
|
|
13
13
|
BANNER
|
|
14
14
|
|
|
@@ -4,7 +4,7 @@ module Imap::Backup
|
|
|
4
4
|
class Configuration::List
|
|
5
5
|
attr_reader :required_accounts
|
|
6
6
|
|
|
7
|
-
def initialize(required_accounts =
|
|
7
|
+
def initialize(required_accounts = [])
|
|
8
8
|
@required_accounts = required_accounts
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -12,6 +12,7 @@ module Imap::Backup
|
|
|
12
12
|
return if !config_exists?
|
|
13
13
|
|
|
14
14
|
Imap::Backup.setup_logging config
|
|
15
|
+
Net::IMAP.debug = config.debug?
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def each_connection
|
|
@@ -22,6 +23,17 @@ module Imap::Backup
|
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
def accounts
|
|
27
|
+
@accounts ||=
|
|
28
|
+
if required_accounts.empty?
|
|
29
|
+
config.accounts
|
|
30
|
+
else
|
|
31
|
+
config.accounts.select do |account|
|
|
32
|
+
required_accounts.include?(account[:username])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
25
37
|
private
|
|
26
38
|
|
|
27
39
|
def config
|
|
@@ -37,16 +49,5 @@ module Imap::Backup
|
|
|
37
49
|
def config_exists?
|
|
38
50
|
Configuration::Store.exist?
|
|
39
51
|
end
|
|
40
|
-
|
|
41
|
-
def accounts
|
|
42
|
-
@accounts ||=
|
|
43
|
-
if required_accounts.nil?
|
|
44
|
-
config.accounts
|
|
45
|
-
else
|
|
46
|
-
config.accounts.select do |account|
|
|
47
|
-
required_accounts.include?(account[:username])
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
52
|
end
|
|
52
53
|
end
|
data/lib/imap/backup/version.rb
CHANGED
|
@@ -111,7 +111,15 @@ describe Imap::Backup::Account::Connection do
|
|
|
111
111
|
with(email: USERNAME, token: PASSWORD) { authenticator }
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
context "when the password is our copy of a GMail refresh token" do
|
|
114
|
+
context "when the password is our copy of a GMail refresh token and the environment IMAP_BACKUP_ENABLE_GMAIL_OAUTH2 is set" do
|
|
115
|
+
before do
|
|
116
|
+
ENV["IMAP_BACKUP_ENABLE_GMAIL_OAUTH2"] = "1"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
after do
|
|
120
|
+
ENV.delete("IMAP_BACKUP_ENABLE_GMAIL_OAUTH2")
|
|
121
|
+
end
|
|
122
|
+
|
|
115
123
|
it "uses the OAuth2 access_token to authenticate" do
|
|
116
124
|
subject.imap
|
|
117
125
|
|
|
@@ -288,6 +296,24 @@ describe Imap::Backup::Account::Connection do
|
|
|
288
296
|
end
|
|
289
297
|
end
|
|
290
298
|
|
|
299
|
+
context "when the IMAP session expires" do
|
|
300
|
+
before do
|
|
301
|
+
data = OpenStruct.new(data: "Session expired")
|
|
302
|
+
response = OpenStruct.new(data: data)
|
|
303
|
+
outcomes = [
|
|
304
|
+
-> { raise Net::IMAP::ByeResponseError, response },
|
|
305
|
+
-> { nil }
|
|
306
|
+
]
|
|
307
|
+
allow(downloader).to receive(:run) { outcomes.shift.call }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it "reconnects" do
|
|
311
|
+
expect(downloader).to receive(:run).exactly(:twice)
|
|
312
|
+
|
|
313
|
+
subject.run_backup
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
291
317
|
context "when run" do
|
|
292
318
|
before { subject.run_backup }
|
|
293
319
|
|
|
@@ -407,24 +433,49 @@ describe Imap::Backup::Account::Connection do
|
|
|
407
433
|
end
|
|
408
434
|
|
|
409
435
|
describe "#reconnect" do
|
|
410
|
-
|
|
411
|
-
|
|
436
|
+
context "when the IMAP connection has been used" do
|
|
437
|
+
before { subject.imap }
|
|
412
438
|
|
|
413
|
-
|
|
439
|
+
it "disconnects from the server" do
|
|
440
|
+
expect(imap).to receive(:disconnect)
|
|
441
|
+
|
|
442
|
+
subject.reconnect
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
context "when the IMAP connection has not been used" do
|
|
447
|
+
it "does not disconnect from the server" do
|
|
448
|
+
expect(imap).to_not receive(:disconnect)
|
|
449
|
+
|
|
450
|
+
subject.reconnect
|
|
451
|
+
end
|
|
414
452
|
end
|
|
415
453
|
|
|
416
454
|
it "causes reconnection on future access" do
|
|
417
455
|
expect(Net::IMAP).to receive(:new)
|
|
418
456
|
|
|
419
457
|
subject.reconnect
|
|
458
|
+
subject.imap
|
|
420
459
|
end
|
|
421
460
|
end
|
|
422
461
|
|
|
423
462
|
describe "#disconnect" do
|
|
424
|
-
|
|
425
|
-
|
|
463
|
+
context "when the IMAP connection has been used" do
|
|
464
|
+
it "disconnects from the server" do
|
|
465
|
+
subject.imap
|
|
426
466
|
|
|
427
|
-
|
|
467
|
+
expect(imap).to receive(:disconnect)
|
|
468
|
+
|
|
469
|
+
subject.disconnect
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
context "when the IMAP connection has not been used" do
|
|
474
|
+
it "does not disconnect from the server" do
|
|
475
|
+
expect(imap).to_not receive(:disconnect)
|
|
476
|
+
|
|
477
|
+
subject.disconnect
|
|
478
|
+
end
|
|
428
479
|
end
|
|
429
480
|
end
|
|
430
481
|
end
|
|
@@ -214,16 +214,10 @@ describe Imap::Backup::Configuration::Account do
|
|
|
214
214
|
|
|
215
215
|
describe "choosing 'modify password'" do
|
|
216
216
|
let(:new_password) { "new_password" }
|
|
217
|
-
let(:gmail_oauth2) do
|
|
218
|
-
instance_double(Imap::Backup::Configuration::GmailOauth2, run: nil)
|
|
219
|
-
end
|
|
220
217
|
|
|
221
218
|
before do
|
|
222
219
|
allow(Imap::Backup::Configuration::Asker).
|
|
223
220
|
to receive(:password) { new_password }
|
|
224
|
-
allow(Imap::Backup::Configuration::GmailOauth2).
|
|
225
|
-
to receive(:new).
|
|
226
|
-
with(account) { gmail_oauth2 }
|
|
227
221
|
subject.run
|
|
228
222
|
menu.choices["modify password"].call
|
|
229
223
|
end
|
|
@@ -245,14 +239,49 @@ describe Imap::Backup::Configuration::Account do
|
|
|
245
239
|
|
|
246
240
|
include_examples "it doesn't flag the account as modified"
|
|
247
241
|
end
|
|
242
|
+
end
|
|
248
243
|
|
|
249
|
-
|
|
250
|
-
|
|
244
|
+
describe "choosing 'modify password' when the server is for GMail" do
|
|
245
|
+
let(:new_password) { "new_password" }
|
|
246
|
+
let(:current_server) { GMAIL_IMAP_SERVER }
|
|
247
|
+
let(:gmail_oauth2) do
|
|
248
|
+
instance_double(Imap::Backup::Configuration::GmailOauth2, run: nil)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
before do
|
|
252
|
+
allow(Imap::Backup::Configuration::Asker).
|
|
253
|
+
to receive(:password) { new_password }
|
|
254
|
+
allow(Imap::Backup::Configuration::GmailOauth2).
|
|
255
|
+
to receive(:new).
|
|
256
|
+
with(account) { gmail_oauth2 }
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
context "when the environment IMAP_BACKUP_ENABLE_GMAIL_OAUTH2 is set" do
|
|
260
|
+
before do
|
|
261
|
+
ENV["IMAP_BACKUP_ENABLE_GMAIL_OAUTH2"] = "1"
|
|
262
|
+
subject.run
|
|
263
|
+
menu.choices["modify password"].call
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
after do
|
|
267
|
+
ENV.delete("IMAP_BACKUP_ENABLE_GMAIL_OAUTH2")
|
|
268
|
+
end
|
|
251
269
|
|
|
252
270
|
it "sets up GMail OAuth2" do
|
|
253
271
|
expect(gmail_oauth2).to have_received(:run)
|
|
254
272
|
end
|
|
255
273
|
end
|
|
274
|
+
|
|
275
|
+
context "when the environment IMAP_BACKUP_ENABLE_GMAIL_OAUTH2 is not set" do
|
|
276
|
+
before do
|
|
277
|
+
subject.run
|
|
278
|
+
menu.choices["modify password"].call
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "sets up GMail OAuth2" do
|
|
282
|
+
expect(gmail_oauth2).to_not have_received(:run)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
256
285
|
end
|
|
257
286
|
|
|
258
287
|
describe "choosing 'modify server'" do
|
|
@@ -35,6 +35,7 @@ describe Imap::Backup::Configuration::List do
|
|
|
35
35
|
allow(Imap::Backup::Configuration::Store).
|
|
36
36
|
to receive(:exist?) { config_exists }
|
|
37
37
|
allow(Imap::Backup).to receive(:setup_logging)
|
|
38
|
+
allow(store).to receive(:debug?)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
it "sets global logging level" do
|
|
@@ -43,7 +43,7 @@ describe Imap::Backup::Configuration::Setup do
|
|
|
43
43
|
describe "main menu" do
|
|
44
44
|
before { subject.run }
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
["add account", "save and exit", "exit without saving"].each do |choice|
|
|
47
47
|
it "includes #{choice}" do
|
|
48
48
|
expect(output.string).to include(choice)
|
|
49
49
|
end
|
|
@@ -12,7 +12,6 @@ describe Imap::Backup::Utils do
|
|
|
12
12
|
describe ".check_permissions" do
|
|
13
13
|
let(:requested) { 0o345 }
|
|
14
14
|
|
|
15
|
-
# rubocop:disable RSpec/EmptyExampleGroup
|
|
16
15
|
context "with existing files" do
|
|
17
16
|
[
|
|
18
17
|
[0o100, "less than the limit", true],
|
|
@@ -37,7 +36,6 @@ describe Imap::Backup::Utils do
|
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
|
-
# rubocop:enable RSpec/EmptyExampleGroup
|
|
41
39
|
|
|
42
40
|
context "with non-existent files" do
|
|
43
41
|
let(:exists) { false }
|
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: 4.0.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joe Yates
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-11-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: gmail_xoauth
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: thor
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.1'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.1'
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
98
|
name: codeclimate-test-reporter
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,6 +192,7 @@ files:
|
|
|
178
192
|
- ".rspec-all"
|
|
179
193
|
- ".rubocop.yml"
|
|
180
194
|
- ".rubocop_todo.yml"
|
|
195
|
+
- CHANGELOG.md
|
|
181
196
|
- Gemfile
|
|
182
197
|
- LICENSE
|
|
183
198
|
- README.md
|
|
@@ -210,7 +225,8 @@ files:
|
|
|
210
225
|
- docs/26-type-code-into-imap-backup.png
|
|
211
226
|
- docs/27-success.png
|
|
212
227
|
- docs/docker-imap.md
|
|
213
|
-
- docs/setting-up-gmail.md
|
|
228
|
+
- docs/setting-up-gmail-with-oauth2.md
|
|
229
|
+
- imap-backup
|
|
214
230
|
- imap-backup.gemspec
|
|
215
231
|
- lib/email/mboxrd/message.rb
|
|
216
232
|
- lib/email/provider.rb
|
|
@@ -219,6 +235,14 @@ files:
|
|
|
219
235
|
- lib/imap/backup.rb
|
|
220
236
|
- lib/imap/backup/account/connection.rb
|
|
221
237
|
- lib/imap/backup/account/folder.rb
|
|
238
|
+
- lib/imap/backup/cli.rb
|
|
239
|
+
- lib/imap/backup/cli/backup.rb
|
|
240
|
+
- lib/imap/backup/cli/folders.rb
|
|
241
|
+
- lib/imap/backup/cli/helpers.rb
|
|
242
|
+
- lib/imap/backup/cli/local.rb
|
|
243
|
+
- lib/imap/backup/cli/restore.rb
|
|
244
|
+
- lib/imap/backup/cli/setup.rb
|
|
245
|
+
- lib/imap/backup/cli/status.rb
|
|
222
246
|
- lib/imap/backup/configuration/account.rb
|
|
223
247
|
- lib/imap/backup/configuration/asker.rb
|
|
224
248
|
- lib/imap/backup/configuration/connection_tester.rb
|
|
@@ -283,14 +307,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
283
307
|
requirements:
|
|
284
308
|
- - ">="
|
|
285
309
|
- !ruby/object:Gem::Version
|
|
286
|
-
version: 2.
|
|
310
|
+
version: '2.5'
|
|
287
311
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
288
312
|
requirements:
|
|
289
|
-
- - "
|
|
313
|
+
- - ">"
|
|
290
314
|
- !ruby/object:Gem::Version
|
|
291
|
-
version:
|
|
315
|
+
version: 1.3.1
|
|
292
316
|
requirements: []
|
|
293
|
-
rubygems_version: 3.
|
|
317
|
+
rubygems_version: 3.1.4
|
|
294
318
|
signing_key:
|
|
295
319
|
specification_version: 4
|
|
296
320
|
summary: Backup GMail (or other IMAP) accounts to disk
|