imapcli 2.0.0 → 2.0.1
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/CHANGELOG.md +7 -0
- data/Dockerfile +4 -3
- data/Gemfile.lock +2 -2
- data/README.md +5 -13
- data/imapcli.gemspec +1 -1
- data/lib/imapcli/command.rb +24 -22
- data/lib/imapcli/version.rb +1 -1
- data/spec/lib/imapcli/command_spec.rb +35 -23
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee39530d31868e3c8f3c90a1ad9957552ee91f51e7ed05c57fb9a3724a297ef7
|
4
|
+
data.tar.gz: 3d6484ebcce956fc9425447786daaf6d7bce486e0b787d5be9e817cba4517dab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e6fab7ebd5c9e58b432323e7ee974c8880785ccf969139966ac2bc9bc7f1034db51678e95c35d7fb53a7df434790340c03aedd40bf2d1bfb6308b2d6b6d4614
|
7
|
+
data.tar.gz: 44801f7d7aa3311683b7e2370b39b9738d4de629e080f32f034b6ae6ac65bda0882dfc15d3731af3929421757a350217f8e4a74ec2127f35d543215cf8aef84e
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [Version 2.0.1 (2025-03-11)][v2.0.1]
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
|
12
|
+
- Do not crash with empty IMAP mailboxes.
|
13
|
+
|
8
14
|
## [Version 2.0.0 (2025-03-10)][v2.0.0]
|
9
15
|
|
10
16
|
### Added
|
@@ -66,6 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
66
72
|
- Fix: Docker image.
|
67
73
|
- Fix: Options error message.
|
68
74
|
|
75
|
+
[v2.0.1]: https://github.com/bovender/imapcli/releases/tag/v2.0.1
|
69
76
|
[v2.0.0]: https://github.com/bovender/imapcli/releases/tag/v2.0.0
|
70
77
|
[v1.0.7]: https://github.com/bovender/imapcli/releases/tag/v1.0.7
|
71
78
|
[v1.0.5]: https://github.com/bovender/imapcli/releases/tag/v1.0.5
|
data/Dockerfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
FROM ruby:alpine
|
1
|
+
FROM ruby:3.4-alpine
|
2
2
|
LABEL maintainer="bovender@bovender.de"
|
3
3
|
LABEL description="Command-line tool to query IMAP servers, collect stats etc."
|
4
4
|
|
@@ -7,11 +7,12 @@ ADD . /imapcli
|
|
7
7
|
RUN apk add --no-cache git build-base && \
|
8
8
|
gem update --system && \
|
9
9
|
cd imapcli && \
|
10
|
-
|
10
|
+
bundle config set --local without development test && \
|
11
|
+
bundle config set --local deployment true && \
|
11
12
|
bundle install && \
|
12
13
|
apk del build-base && \
|
13
14
|
rm -rf /var/cache/apk/*
|
14
15
|
|
15
16
|
WORKDIR /imapcli
|
16
|
-
ENTRYPOINT ["exe/imapcli"]
|
17
|
+
ENTRYPOINT ["bundle", "exec", "exe/imapcli"]
|
17
18
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -15,7 +15,6 @@ IMAP mailbox sizes.
|
|
15
15
|
- [Terminology](#terminology)
|
16
16
|
- [Usage](#usage)
|
17
17
|
- [Alternative resources](#alternative-resources)
|
18
|
-
- [State of the project](#state-of-the-project)
|
19
18
|
- [Credits](#credits)
|
20
19
|
- [License](#license)
|
21
20
|
|
@@ -292,20 +291,13 @@ following:
|
|
292
291
|
|
293
292
|
Pull down e-mails from an IMAP server to your local disk
|
294
293
|
|
295
|
-
## State of the project
|
296
|
-
|
297
|
-
I have not been able to work on this project for quite some time. It still
|
298
|
-
serves me well when I occasionally need it. Pull requests are of course welcome.
|
299
|
-
|
300
|
-
This project is [semantically versioned](https://semver.org).
|
301
|
-
|
302
294
|
### To do
|
303
295
|
|
304
|
-
[x] More human-friendly number formatting (e.g., MiB/GiB as appropriate)
|
305
|
-
[ ] Output to file
|
306
|
-
[ ] Deal with server-specific mailbox separator characters (e.g. '.' vs. '/')
|
307
|
-
[ ] Man page
|
308
|
-
[ ] More commands?
|
296
|
+
- [x] More human-friendly number formatting (e.g., MiB/GiB as appropriate)
|
297
|
+
- [ ] Output to file
|
298
|
+
- [ ] Deal with server-specific mailbox separator characters (e.g. '.' vs. '/')
|
299
|
+
- [ ] Man page
|
300
|
+
- [ ] More commands?
|
309
301
|
|
310
302
|
## Credits
|
311
303
|
|
data/imapcli.gemspec
CHANGED
@@ -22,10 +22,10 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.bindir = 'exe'
|
23
23
|
s.executables = ['imapcli']
|
24
24
|
|
25
|
+
s.add_dependency('activesupport', '~> 8.0')
|
25
26
|
s.add_dependency('csv')
|
26
27
|
s.add_dependency('descriptive_statistics', '~> 2.5')
|
27
28
|
s.add_dependency('dotenv', '~> 3.1')
|
28
|
-
s.add_dependency('activesupport', '~> 8.0')
|
29
29
|
s.add_dependency('gli', '~> 2.22')
|
30
30
|
s.add_dependency('net-imap')
|
31
31
|
s.add_dependency('tty-progressbar', '~> 0.18')
|
data/lib/imapcli/command.rb
CHANGED
@@ -138,28 +138,30 @@ module Imapcli
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
-
def sorted_list(list, options
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
141
|
+
def sorted_list(list, options)
|
142
|
+
return list if options.nil? || options[:sort].nil?
|
143
|
+
sort_property = options[:sort]&.to_sym
|
144
|
+
if %i[count total_size min_size q1 median_size q3 max_size].include? sort_property
|
145
|
+
sorted = sort_mailboxes(list, sort_property, options[:reverse])
|
146
|
+
else
|
147
|
+
raise "invalid sort option: #{options[:sort]}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
# Sorts a list of mailboxes according to a given property
|
154
|
+
# such as total count of e-mails, total size of all e-mails etc.
|
155
|
+
# Some mailboxes may not have this property, e.g., an empty
|
156
|
+
# mailbox will have `nil` values for median_size etc.
|
157
|
+
# We always sort mailboxes with `nil` values to the bottom.
|
158
|
+
def sort_mailboxes(mailboxes, property, reverse)
|
159
|
+
# Devide ary into two parts, one part where the property has a value
|
160
|
+
# and the other where the property is nil.
|
161
|
+
partitions = mailboxes.partition { |mailbox| mailbox.stats.send(property) }
|
162
|
+
sorted = partitions[0].sort_by { |mailbox| mailbox.stats.send(property) }
|
163
|
+
sorted = sorted.reverse if reverse
|
164
|
+
sorted + partitions[1]
|
163
165
|
end
|
164
166
|
|
165
167
|
end
|
data/lib/imapcli/version.rb
CHANGED
@@ -22,9 +22,11 @@ RSpec.describe Imapcli::Command do
|
|
22
22
|
Net::IMAP::MailboxList.new(nil, '/', 'Inbox'),
|
23
23
|
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Foo'),
|
24
24
|
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Foo/Sub'),
|
25
|
+
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Many/Messages'),
|
25
26
|
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Bar'),
|
26
|
-
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/
|
27
|
-
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/
|
27
|
+
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Largest/Messages'),
|
28
|
+
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Smallest/Messages'),
|
29
|
+
Net::IMAP::MailboxList.new(nil, '/', 'Inbox/Empty'),
|
28
30
|
])
|
29
31
|
end
|
30
32
|
|
@@ -57,17 +59,19 @@ RSpec.describe Imapcli::Command do
|
|
57
59
|
allow(client).to receive(:message_sizes) do |mailbox|
|
58
60
|
case mailbox
|
59
61
|
when 'Inbox'
|
60
|
-
|
62
|
+
[200, 300, 400, 500]
|
61
63
|
when 'Inbox/Foo'
|
62
|
-
|
63
|
-
when 'Inbox/
|
64
|
-
Array.new(10,
|
64
|
+
[355, 360, 380, 200]
|
65
|
+
when 'Inbox/Many/Messages'
|
66
|
+
Array.new(10, 100)
|
65
67
|
when 'Inbox/Bar'
|
66
|
-
|
67
|
-
when 'Inbox/
|
68
|
-
[
|
69
|
-
when 'Inbox/
|
70
|
-
|
68
|
+
[2_000, 3_000, 4_000]
|
69
|
+
when 'Inbox/Largest/Messages'
|
70
|
+
[2_500_000, 100_000, 200_000]
|
71
|
+
when 'Inbox/Smallest/Messages'
|
72
|
+
[10, 20, 30]
|
73
|
+
when 'Inbox/Empty'
|
74
|
+
[]
|
71
75
|
else
|
72
76
|
[1024, 2048, 4096, 8192]
|
73
77
|
end
|
@@ -77,8 +81,8 @@ RSpec.describe Imapcli::Command do
|
|
77
81
|
it 'for all folders' do
|
78
82
|
output = command.stats
|
79
83
|
expect(output).to be_a Array
|
80
|
-
expect(output.length).to eq
|
81
|
-
expect(output[0][0]).to eq 'Inbox'
|
84
|
+
expect(output.length).to eq 9
|
85
|
+
expect(output[0][0]).to eq 'Inbox' # sorted before 'Inbox'
|
82
86
|
expect(output[0][1]).to eq 4
|
83
87
|
end
|
84
88
|
|
@@ -87,7 +91,15 @@ RSpec.describe Imapcli::Command do
|
|
87
91
|
expect(output).to be_a Array
|
88
92
|
expect(output.length).to eq 1
|
89
93
|
expect(output[0][0]).to eq 'Inbox/Foo'
|
90
|
-
expect(output[0][1]).to eq
|
94
|
+
expect(output[0][1]).to eq 4 # depends on message_sizes stub (see above)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'for an empty folder' do
|
98
|
+
output = command.stats('Inbox/Empty')
|
99
|
+
expect(output).to be_a Array
|
100
|
+
expect(output.length).to eq 1
|
101
|
+
expect(output[0][0]).to eq 'Inbox/Empty'
|
102
|
+
expect(output[0][1]).to eq 0
|
91
103
|
end
|
92
104
|
|
93
105
|
it 'for a given folder and subfolders' do
|
@@ -100,26 +112,26 @@ RSpec.describe Imapcli::Command do
|
|
100
112
|
it 'sorts by number of messages' do
|
101
113
|
output = command.stats('Inbox', depth: -1, sort: :count, reverse: true)
|
102
114
|
expect(output).to be_a Array
|
103
|
-
expect(output[0][0]).to eq 'Inbox/
|
115
|
+
expect(output[0][0]).to eq 'Inbox/Many/Messages'
|
104
116
|
end
|
105
117
|
|
106
118
|
it 'sorts by total message size' do
|
107
|
-
output = command.stats('Inbox', depth: -1, sort: :total_size, reverse:
|
119
|
+
output = command.stats('Inbox', depth: -1, sort: :total_size, reverse: false)
|
108
120
|
expect(output).to be_a Array
|
109
|
-
expect(output[
|
121
|
+
expect(output[-2][0]).to eq 'Inbox/Largest/Messages'
|
110
122
|
end
|
111
123
|
|
112
|
-
it 'sorts
|
124
|
+
it 'reverse-sorts largest message first' do
|
113
125
|
output = command.stats('Inbox', depth: -1, sort: :max_size, reverse: true)
|
114
126
|
expect(output).to be_a Array
|
115
|
-
expect(output[0][0]).to eq 'Inbox/
|
127
|
+
expect(output[0][0]).to eq 'Inbox/Largest/Messages'
|
128
|
+
expect(output[-2][0]).to eq 'Inbox/Empty'
|
116
129
|
end
|
117
130
|
|
118
|
-
it 'sorts
|
119
|
-
output = command.stats('Inbox', depth: -1, sort: :min_size, reverse:
|
131
|
+
it 'sorts smallest message first' do
|
132
|
+
output = command.stats('Inbox', depth: -1, sort: :min_size, reverse: false)
|
120
133
|
expect(output).to be_a Array
|
121
|
-
|
122
|
-
expect(output[0][0]).to eq 'Inbox/Foo'
|
134
|
+
expect(output[0][0]).to eq 'Inbox/Smallest/Messages'
|
123
135
|
end
|
124
136
|
end
|
125
137
|
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imapcli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Kraus (bovender)
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '8.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '8.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: csv
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,20 +66,6 @@ dependencies:
|
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '3.1'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: activesupport
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '8.0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '8.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: gli
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|