imap-backup 8.0.2 → 9.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/docs/delimiters-and-prefixes.md +16 -0
- data/docs/restore.md +1 -3
- data/docs/setup.md +1 -1
- data/lib/imap/backup/cli/folder_enumerator.rb +96 -0
- data/lib/imap/backup/cli/migrate.rb +19 -46
- data/lib/imap/backup/cli/mirror.rb +19 -46
- data/lib/imap/backup/cli.rb +24 -1
- data/lib/imap/backup/version.rb +3 -3
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a95742a7ae3b07a12f7cb95d50bcea360530ee351edbca8d9b93e5c4579090a
|
4
|
+
data.tar.gz: 9d7d43ba0f44f13a19272214dfe8ca265c72f7d1173ccf67c4d4a873de007a81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 155eeb475d56b03bc8012fc8b9b2882fbd8bcaad4366ee2119952f710de79d94a6709c81185ccc49b4f20f6d333523272de4cfa3742c1ff05f797830d1cb916e
|
7
|
+
data.tar.gz: dc6c0ce95c22c81512eb71791f6a75ecc8fe35f011e48fd0d68266771fac96f234664f22316fd1e98fbfc93397713f60375555442577dc0977eedcabfc2cf1ea
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Delimiters and Prefixes
|
2
|
+
|
3
|
+
A simple folder name is `Friends`.
|
4
|
+
|
5
|
+
Most email servers allow you to put folders inside other folders.
|
6
|
+
|
7
|
+
On most email servers, the parts of a folder's name are separated with a `/` character.
|
8
|
+
So you might have `People/Friends`.
|
9
|
+
|
10
|
+
On the other hand, some email servers use a `.`, giving `People.Friends`.
|
11
|
+
|
12
|
+
Some email servers keep most email in a parent folder, often `INBOX`, so the above folder
|
13
|
+
would be `INBOX/People/Friends`.
|
14
|
+
|
15
|
+
The `migrate` and `mirror` commands provide options to help "translate" between
|
16
|
+
the behaviour of the source and destination servers.
|
data/docs/restore.md
CHANGED
@@ -25,6 +25,4 @@ is already on the server is skipped.
|
|
25
25
|
|
26
26
|
## How do I restore to a different service?
|
27
27
|
|
28
|
-
|
29
|
-
2. Rename of the existing backup directory to match the new email address,
|
30
|
-
3. Run the restore.
|
28
|
+
It is best to use the `migrate` command in this case.
|
data/docs/setup.md
CHANGED
@@ -0,0 +1,96 @@
|
|
1
|
+
module Imap::Backup
|
2
|
+
class CLI::FolderEnumerator
|
3
|
+
attr_reader :destination
|
4
|
+
attr_reader :destination_delimiter
|
5
|
+
attr_reader :source
|
6
|
+
attr_reader :source_delimiter
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
destination:,
|
10
|
+
source:,
|
11
|
+
destination_delimiter: "/",
|
12
|
+
destination_prefix: "",
|
13
|
+
source_delimiter: "/",
|
14
|
+
source_prefix: ""
|
15
|
+
)
|
16
|
+
@destination = destination
|
17
|
+
@destination_delimiter = destination_delimiter
|
18
|
+
@destination_prefix = destination_prefix
|
19
|
+
@source = source
|
20
|
+
@source_delimiter = source_delimiter
|
21
|
+
@source_prefix = source_prefix
|
22
|
+
end
|
23
|
+
|
24
|
+
def each
|
25
|
+
return enum_for(:each) if !block_given?
|
26
|
+
|
27
|
+
glob = File.join(source_local_path, "**", "*.imap")
|
28
|
+
Pathname.glob(glob) do |path|
|
29
|
+
name = source_folder_name(path)
|
30
|
+
serializer = Serializer.new(source_local_path, name)
|
31
|
+
folder = destination_folder_for(name)
|
32
|
+
yield serializer, folder
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def destination_prefix_clipped
|
39
|
+
@destination_prefix_clipped ||=
|
40
|
+
if @destination_prefix.end_with?(destination_delimiter)
|
41
|
+
@destination_prefix[0..-2]
|
42
|
+
else
|
43
|
+
@destination_prefix
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def source_prefix_clipped
|
48
|
+
@source_prefix_clipped ||=
|
49
|
+
if @source_prefix.end_with?(source_delimiter)
|
50
|
+
@source_prefix[0..-2]
|
51
|
+
else
|
52
|
+
@source_prefix
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def destination_folder_for(name)
|
57
|
+
parts = name.split(source_delimiter)
|
58
|
+
no_source_prefix =
|
59
|
+
if source_prefix_clipped != "" && parts.first == source_prefix_clipped
|
60
|
+
parts[1..]
|
61
|
+
else
|
62
|
+
parts
|
63
|
+
end
|
64
|
+
|
65
|
+
with_destination_prefix =
|
66
|
+
if destination_prefix_clipped && destination_prefix_clipped != ""
|
67
|
+
no_source_prefix.unshift(destination_prefix_clipped)
|
68
|
+
else
|
69
|
+
no_source_prefix
|
70
|
+
end
|
71
|
+
|
72
|
+
destination_name = with_destination_prefix.join(destination_delimiter)
|
73
|
+
|
74
|
+
Account::Folder.new(
|
75
|
+
destination.connection,
|
76
|
+
destination_name
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def source_local_path
|
81
|
+
source.local_path
|
82
|
+
end
|
83
|
+
|
84
|
+
def source_folder_name(imap_pathname)
|
85
|
+
base = Pathname.new(source_local_path)
|
86
|
+
imap_name = imap_pathname.relative_path_from(base).to_s
|
87
|
+
dir = File.dirname(imap_name)
|
88
|
+
stripped = File.basename(imap_name, ".imap")
|
89
|
+
if dir == "."
|
90
|
+
stripped
|
91
|
+
else
|
92
|
+
File.join(dir, stripped)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "imap/backup/cli/folder_enumerator"
|
1
2
|
require "imap/backup/migrator"
|
2
3
|
|
3
4
|
module Imap::Backup
|
@@ -5,10 +6,12 @@ module Imap::Backup
|
|
5
6
|
include Thor::Actions
|
6
7
|
include CLI::Helpers
|
7
8
|
|
9
|
+
attr_reader :destination_delimiter
|
8
10
|
attr_reader :destination_email
|
9
11
|
attr_reader :destination_prefix
|
10
12
|
attr_reader :config_path
|
11
13
|
attr_reader :reset
|
14
|
+
attr_reader :source_delimiter
|
12
15
|
attr_reader :source_email
|
13
16
|
attr_reader :source_prefix
|
14
17
|
|
@@ -16,15 +19,19 @@ module Imap::Backup
|
|
16
19
|
source_email,
|
17
20
|
destination_email,
|
18
21
|
config: nil,
|
22
|
+
destination_delimiter: "/",
|
19
23
|
destination_prefix: "",
|
20
24
|
reset: false,
|
25
|
+
source_delimiter: "/",
|
21
26
|
source_prefix: ""
|
22
27
|
)
|
23
28
|
super([])
|
29
|
+
@destination_delimiter = destination_delimiter
|
24
30
|
@destination_email = destination_email
|
25
31
|
@destination_prefix = destination_prefix
|
26
32
|
@config_path = config
|
27
33
|
@reset = reset
|
34
|
+
@source_delimiter = source_delimiter
|
28
35
|
@source_email = source_email
|
29
36
|
@source_prefix = source_prefix
|
30
37
|
end
|
@@ -51,62 +58,28 @@ module Imap::Backup
|
|
51
58
|
@config ||= load_config(config: config_path)
|
52
59
|
end
|
53
60
|
|
54
|
-
def
|
55
|
-
|
61
|
+
def enumerator_options
|
62
|
+
{
|
63
|
+
destination: destination_account,
|
64
|
+
destination_delimiter: destination_delimiter,
|
65
|
+
destination_prefix: destination_prefix,
|
66
|
+
source: source_account,
|
67
|
+
source_delimiter: source_delimiter,
|
68
|
+
source_prefix: source_prefix
|
69
|
+
}
|
56
70
|
end
|
57
71
|
|
58
72
|
def folders
|
59
|
-
|
60
|
-
|
61
|
-
glob = File.join(source_local_path, "**", "*.imap")
|
62
|
-
Pathname.glob(glob) do |path|
|
63
|
-
name = source_folder_name(path)
|
64
|
-
serializer = Serializer.new(source_local_path, name)
|
65
|
-
folder = folder_for(name)
|
66
|
-
yield serializer, folder
|
67
|
-
end
|
73
|
+
CLI::FolderEnumerator.new(**enumerator_options)
|
68
74
|
end
|
69
75
|
|
70
|
-
def
|
71
|
-
|
72
|
-
if source_prefix != "" && source_folder.start_with?(source_prefix)
|
73
|
-
source_folder.delete_prefix(source_prefix)
|
74
|
-
else
|
75
|
-
source_folder.to_s
|
76
|
-
end
|
77
|
-
|
78
|
-
with_destination_prefix =
|
79
|
-
if destination_prefix && destination_prefix != ""
|
80
|
-
destination_prefix + no_source_prefix
|
81
|
-
else
|
82
|
-
no_source_prefix
|
83
|
-
end
|
84
|
-
|
85
|
-
Account::Folder.new(
|
86
|
-
destination_account.connection,
|
87
|
-
with_destination_prefix
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
def source_local_path
|
92
|
-
source_account.local_path
|
76
|
+
def destination_account
|
77
|
+
config.accounts.find { |a| a.username == destination_email }
|
93
78
|
end
|
94
79
|
|
95
80
|
def source_account
|
96
81
|
config.accounts.find { |a| a.username == source_email }
|
97
82
|
end
|
98
|
-
|
99
|
-
def source_folder_name(imap_pathname)
|
100
|
-
base = Pathname.new(source_local_path)
|
101
|
-
imap_name = imap_pathname.relative_path_from(base).to_s
|
102
|
-
dir = File.dirname(imap_name)
|
103
|
-
stripped = File.basename(imap_name, ".imap")
|
104
|
-
if dir == "."
|
105
|
-
stripped
|
106
|
-
else
|
107
|
-
File.join(dir, stripped)
|
108
|
-
end
|
109
|
-
end
|
110
83
|
end
|
111
84
|
end
|
112
85
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "imap/backup/cli/folder_enumerator"
|
1
2
|
require "imap/backup/mirror"
|
2
3
|
|
3
4
|
module Imap::Backup
|
@@ -5,9 +6,11 @@ module Imap::Backup
|
|
5
6
|
include Thor::Actions
|
6
7
|
include CLI::Helpers
|
7
8
|
|
9
|
+
attr_reader :destination_delimiter
|
8
10
|
attr_reader :destination_email
|
9
11
|
attr_reader :destination_prefix
|
10
12
|
attr_reader :config_path
|
13
|
+
attr_reader :source_delimiter
|
11
14
|
attr_reader :source_email
|
12
15
|
attr_reader :source_prefix
|
13
16
|
|
@@ -15,13 +18,17 @@ module Imap::Backup
|
|
15
18
|
source_email,
|
16
19
|
destination_email,
|
17
20
|
config: nil,
|
21
|
+
destination_delimiter: "/",
|
18
22
|
destination_prefix: "",
|
23
|
+
source_delimiter: "/",
|
19
24
|
source_prefix: ""
|
20
25
|
)
|
21
26
|
super([])
|
27
|
+
@destination_delimiter = destination_delimiter
|
22
28
|
@destination_email = destination_email
|
23
29
|
@destination_prefix = destination_prefix
|
24
30
|
@config_path = config
|
31
|
+
@source_delimiter = source_delimiter
|
25
32
|
@source_email = source_email
|
26
33
|
@source_prefix = source_prefix
|
27
34
|
end
|
@@ -61,62 +68,28 @@ module Imap::Backup
|
|
61
68
|
@config = load_config(config: config_path)
|
62
69
|
end
|
63
70
|
|
64
|
-
def
|
65
|
-
|
71
|
+
def enumerator_options
|
72
|
+
{
|
73
|
+
destination: destination_account,
|
74
|
+
destination_delimiter: destination_delimiter,
|
75
|
+
destination_prefix: destination_prefix,
|
76
|
+
source: source_account,
|
77
|
+
source_delimiter: source_delimiter,
|
78
|
+
source_prefix: source_prefix
|
79
|
+
}
|
66
80
|
end
|
67
81
|
|
68
82
|
def folders
|
69
|
-
|
70
|
-
|
71
|
-
glob = File.join(source_local_path, "**", "*.imap")
|
72
|
-
Pathname.glob(glob) do |path|
|
73
|
-
name = source_folder_name(path)
|
74
|
-
serializer = Serializer.new(source_local_path, name)
|
75
|
-
folder = folder_for(name)
|
76
|
-
yield serializer, folder
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def folder_for(source_folder)
|
81
|
-
no_source_prefix =
|
82
|
-
if source_prefix != "" && source_folder.start_with?(source_prefix)
|
83
|
-
source_folder.delete_prefix(source_prefix)
|
84
|
-
else
|
85
|
-
source_folder.to_s
|
86
|
-
end
|
87
|
-
|
88
|
-
with_destination_prefix =
|
89
|
-
if destination_prefix && destination_prefix != ""
|
90
|
-
destination_prefix + no_source_prefix
|
91
|
-
else
|
92
|
-
no_source_prefix
|
93
|
-
end
|
94
|
-
|
95
|
-
Account::Folder.new(
|
96
|
-
destination_account.connection,
|
97
|
-
with_destination_prefix
|
98
|
-
)
|
83
|
+
CLI::FolderEnumerator.new(**enumerator_options)
|
99
84
|
end
|
100
85
|
|
101
|
-
def
|
102
|
-
|
86
|
+
def destination_account
|
87
|
+
config.accounts.find { |a| a.username == destination_email }
|
103
88
|
end
|
104
89
|
|
105
90
|
def source_account
|
106
91
|
config.accounts.find { |a| a.username == source_email }
|
107
92
|
end
|
108
|
-
|
109
|
-
def source_folder_name(imap_pathname)
|
110
|
-
base = Pathname.new(source_local_path)
|
111
|
-
imap_name = imap_pathname.relative_path_from(base).to_s
|
112
|
-
dir = File.dirname(imap_name)
|
113
|
-
stripped = File.basename(imap_name, ".imap")
|
114
|
-
if dir == "."
|
115
|
-
stripped
|
116
|
-
else
|
117
|
-
File.join(dir, stripped)
|
118
|
-
end
|
119
|
-
end
|
120
93
|
end
|
121
94
|
end
|
122
95
|
end
|
data/lib/imap/backup/cli.rb
CHANGED
@@ -69,9 +69,12 @@ module Imap::Backup
|
|
69
69
|
All emails which have been backed up for the "source account" (SOURCE_EMAIL) are
|
70
70
|
uploaded to the "destination account" (DESTINATION_EMAIL).
|
71
71
|
|
72
|
-
When one or other account has namespaces (i.e. prefixes like "INBOX
|
72
|
+
When one or other account has namespaces (i.e. prefixes like "INBOX"),
|
73
73
|
use the `--source-prefix=` and/or `--destination-prefix=` options.
|
74
74
|
|
75
|
+
When one or other account uses a delimiter other than `/` (i.e. `.`),
|
76
|
+
use the `--source-delimiter=` and/or `--destination-delimiter=` options.
|
77
|
+
|
75
78
|
Usually, you should migrate to an account with empty folders.
|
76
79
|
|
77
80
|
Before migrating each folder, `imap-backup` checks if the destination
|
@@ -86,6 +89,11 @@ module Imap::Backup
|
|
86
89
|
config_option
|
87
90
|
quiet_option
|
88
91
|
verbose_option
|
92
|
+
method_option(
|
93
|
+
"destination-delimiter",
|
94
|
+
type: :string,
|
95
|
+
desc: "the delimiter for destination folder names"
|
96
|
+
)
|
89
97
|
method_option(
|
90
98
|
"destination-prefix",
|
91
99
|
type: :string,
|
@@ -98,6 +106,11 @@ module Imap::Backup
|
|
98
106
|
desc: "DANGER! This option deletes all messages from destination folders before uploading",
|
99
107
|
aliases: ["-r"]
|
100
108
|
)
|
109
|
+
method_option(
|
110
|
+
"source-delimiter",
|
111
|
+
type: :string,
|
112
|
+
desc: "the delimiter for source folder names"
|
113
|
+
)
|
101
114
|
method_option(
|
102
115
|
"source-prefix",
|
103
116
|
type: :string,
|
@@ -132,12 +145,22 @@ module Imap::Backup
|
|
132
145
|
config_option
|
133
146
|
quiet_option
|
134
147
|
verbose_option
|
148
|
+
method_option(
|
149
|
+
"destination-delimiter",
|
150
|
+
type: :string,
|
151
|
+
desc: "the delimiter for destination folder names"
|
152
|
+
)
|
135
153
|
method_option(
|
136
154
|
"destination-prefix",
|
137
155
|
type: :string,
|
138
156
|
desc: "the prefix (namespace) to add to destination folder names",
|
139
157
|
aliases: ["-d"]
|
140
158
|
)
|
159
|
+
method_option(
|
160
|
+
"source-delimiter",
|
161
|
+
type: :string,
|
162
|
+
desc: "the delimiter for source folder names"
|
163
|
+
)
|
141
164
|
method_option(
|
142
165
|
"source-prefix",
|
143
166
|
type: :string,
|
data/lib/imap/backup/version.rb
CHANGED
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: 9.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: 2022-12-
|
11
|
+
date: 2022-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -218,6 +218,7 @@ files:
|
|
218
218
|
- README.md
|
219
219
|
- bin/imap-backup
|
220
220
|
- docs/configuration.md
|
221
|
+
- docs/delimiters-and-prefixes.md
|
221
222
|
- docs/development.md
|
222
223
|
- docs/restore.md
|
223
224
|
- docs/setup.md
|
@@ -240,6 +241,7 @@ files:
|
|
240
241
|
- lib/imap/backup/account/folder.rb
|
241
242
|
- lib/imap/backup/cli.rb
|
242
243
|
- lib/imap/backup/cli/backup.rb
|
244
|
+
- lib/imap/backup/cli/folder_enumerator.rb
|
243
245
|
- lib/imap/backup/cli/helpers.rb
|
244
246
|
- lib/imap/backup/cli/local.rb
|
245
247
|
- lib/imap/backup/cli/migrate.rb
|
@@ -299,9 +301,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
299
301
|
version: '2.6'
|
300
302
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
301
303
|
requirements:
|
302
|
-
- - "
|
304
|
+
- - ">"
|
303
305
|
- !ruby/object:Gem::Version
|
304
|
-
version:
|
306
|
+
version: 1.3.1
|
305
307
|
requirements: []
|
306
308
|
rubygems_version: 3.3.7
|
307
309
|
signing_key:
|