imap-backup 8.0.2 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31b3a3ccf051c6496e8b4fde5eb0b062927fc8a0cb0c605dd597bc1289dd77e1
4
- data.tar.gz: f7a7a88cb51f2ebe01e5debd4a25df4df8adf4ee1a5fd2480532c948d51e382b
3
+ metadata.gz: 3daac577a7328b73a4593e677826b2f168f7565487595a04b37504b863dccd46
4
+ data.tar.gz: 3290089c8c67f31d7dc7cfc53ca6c6d2dd20328727447b2164273409408d36d5
5
5
  SHA512:
6
- metadata.gz: 47377d324d8a4f4bf0853ac12f6e972107bbb2d215f4916bd5a6ec301870ef6fad2eb646325dba127dd7bb8ca02f6abe72d2bfeccc139bac87c9df38a55d498a
7
- data.tar.gz: 2a07b644b145263f41394f2f96590a0003381911389238f242f973236828ded448c169ed043ec7453d8bd0acc942ecb3d210e298b46d975c08b015794b7f4445
6
+ metadata.gz: df10381df343a5c4c08d8fa39310a6593b6383608926d360202feb92652bc2ad42bbeffc306789e6f4761bc06405cb2b8d51efe76e65cfc5a9507d397d36e2ae
7
+ data.tar.gz: 05a4d8b9941622fc56f68e952f71b38383a9593fe6abedb64d6c4b1a5670eee0ca2c40a27cc14a7d05d298638e3c242f056b3a8b68288a61dafae8449f51e36b
@@ -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/development.md CHANGED
@@ -4,6 +4,11 @@
4
4
  * Restartable - calculate start point based on already downloaded messages
5
5
  * Standalone - do not rely on an email client or MTA
6
6
 
7
+ # Development
8
+
9
+ A setup for developing under any available Ruby version is
10
+ available in the container directory.
11
+
7
12
  # Testing
8
13
 
9
14
  ## Feature Specs
@@ -56,6 +61,11 @@ uids = imap.uid_search(["ALL"]).sort
56
61
  fetch_data_items = imap.uid_fetch(uids, ["BODY[]"])
57
62
  ```
58
63
 
64
+ # Older Ruby Versions
65
+
66
+ Dockerfiles are available for all the supported Ruby versions,
67
+ see the `docker` directory.
68
+
59
69
  # Contributing
60
70
 
61
71
  1. Fork it
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
- 1. Run setup and add the new server, (but don't run any backups),
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
@@ -2,4 +2,4 @@
2
2
 
3
3
  ## Set the server for a Google Apps account
4
4
 
5
- Use imap.gmail.com
5
+ Use `imap.gmail.com` as the 'server' setting.
@@ -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 destination_account
55
- config.accounts.find { |a| a.username == destination_email }
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
- 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.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 folder_for(source_folder)
71
- no_source_prefix =
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 destination_account
65
- config.accounts.find { |a| a.username == destination_email }
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
- return enum_for(:folders) if !block_given?
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 source_local_path
102
- source_account.local_path
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
@@ -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,
@@ -1,9 +1,9 @@
1
1
  module Imap; end
2
2
 
3
3
  module Imap::Backup
4
- MAJOR = 8
4
+ MAJOR = 9
5
5
  MINOR = 0
6
- REVISION = 2
6
+ REVISION = 0
7
7
  PRE = nil
8
8
  VERSION = [MAJOR, MINOR, REVISION, PRE].compact.map(&:to_s).join(".")
9
9
  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: 8.0.2
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-12 00:00:00.000000000 Z
11
+ date: 2022-12-29 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