imap-backup 0.0.3 → 0.0.4
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.
- data/bin/imap-backup +18 -7
- data/imap-backup.gemspec +1 -0
- data/lib/imap/backup.rb +13 -1
- data/lib/imap/backup/configuration/account.rb +85 -0
- data/lib/imap/backup/configuration/asker.rb +42 -0
- data/lib/imap/backup/configuration/connection_tester.rb +19 -0
- data/lib/imap/backup/configuration/folder_chooser.rb +56 -0
- data/lib/imap/backup/configuration/list.rb +32 -0
- data/lib/imap/backup/configuration/setup.rb +68 -0
- data/lib/imap/backup/configuration/store.rb +64 -0
- data/lib/imap/backup/downloader.rb +2 -0
- data/lib/imap/backup/serializer/directory.rb +2 -4
- data/lib/imap/backup/utils.rb +11 -5
- data/lib/imap/backup/version.rb +1 -1
- data/spec/spec_helper.rb +26 -0
- data/spec/unit/configuration/account_spec.rb +224 -0
- data/spec/unit/configuration/asker_spec.rb +122 -0
- data/spec/unit/configuration/connection_tester_spec.rb +47 -0
- data/spec/unit/configuration/folder_chooser_spec.rb +131 -0
- data/spec/unit/configuration/list_spec.rb +73 -0
- data/spec/unit/configuration/setup_spec.rb +115 -0
- data/spec/unit/configuration/store_spec.rb +173 -0
- data/spec/unit/serializer/directory_spec.rb +2 -0
- data/spec/unit/utils_spec.rb +11 -9
- metadata +129 -113
- data/lib/imap/backup/settings.rb +0 -35
- data/spec/unit/settings_spec.rb +0 -109
@@ -6,13 +6,11 @@ module Imap
|
|
6
6
|
module Serializer
|
7
7
|
class Directory
|
8
8
|
|
9
|
-
include Imap::Backup::Utils
|
10
|
-
|
11
9
|
def initialize(path, folder)
|
12
10
|
@path, @folder = path, folder
|
13
11
|
permissions = 0700
|
14
|
-
check_permissions(@path, permissions)
|
15
|
-
make_folder(@path, @folder, permissions)
|
12
|
+
Imap::Backup::Utils.check_permissions(@path, permissions)
|
13
|
+
Imap::Backup::Utils.make_folder(@path, @folder, permissions)
|
16
14
|
end
|
17
15
|
|
18
16
|
def uids
|
data/lib/imap/backup/utils.rb
CHANGED
@@ -5,16 +5,22 @@ module Imap
|
|
5
5
|
module Backup
|
6
6
|
module Utils
|
7
7
|
|
8
|
-
def check_permissions(filename, limit)
|
9
|
-
|
10
|
-
actual = stat.mode & 0777
|
8
|
+
def self.check_permissions(filename, limit)
|
9
|
+
actual = stat(filename)
|
11
10
|
mask = ~limit & 0777
|
12
11
|
if actual & mask != 0
|
13
12
|
raise "Permissions on '#{filename}' should be #{oct(limit)}, not #{oct(actual)}"
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
|
-
def
|
16
|
+
def self.stat(filename)
|
17
|
+
return nil unless File.exist?(filename)
|
18
|
+
|
19
|
+
stat = File.stat(filename)
|
20
|
+
stat.mode & 0777
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.make_folder(base_path, path, permissions)
|
18
24
|
parts = path.split('/')
|
19
25
|
return if parts.size == 0
|
20
26
|
full_path = File.join(base_path, path)
|
@@ -25,7 +31,7 @@ module Imap
|
|
25
31
|
|
26
32
|
private
|
27
33
|
|
28
|
-
def oct(permissions)
|
34
|
+
def self.oct(permissions)
|
29
35
|
"0%o" % permissions
|
30
36
|
end
|
31
37
|
|
data/lib/imap/backup/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -14,3 +14,29 @@ end
|
|
14
14
|
|
15
15
|
require File.expand_path( File.dirname(__FILE__) + '/../lib/imap/backup' )
|
16
16
|
|
17
|
+
module HighLineTestHelpers
|
18
|
+
|
19
|
+
def prepare_highline
|
20
|
+
@input = stub('stdin', :eof? => false)
|
21
|
+
# default gets stub
|
22
|
+
@input.stub!(:gets).with().and_return("q\n")
|
23
|
+
@output = StringIO.new
|
24
|
+
Imap::Backup::Configuration::Setup.highline = HighLine.new(@input, @output)
|
25
|
+
[@input, @output]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
module InputOutputTestHelpers
|
31
|
+
|
32
|
+
def capturing_output
|
33
|
+
output = StringIO.new
|
34
|
+
$stdout = output
|
35
|
+
yield
|
36
|
+
output.string
|
37
|
+
ensure
|
38
|
+
$stdout = STDOUT
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
load File.expand_path( '../../spec_helper.rb', File.dirname(__FILE__) )
|
3
|
+
|
4
|
+
describe Imap::Backup::Configuration::Account do
|
5
|
+
|
6
|
+
include HighLineTestHelpers
|
7
|
+
include InputOutputTestHelpers
|
8
|
+
|
9
|
+
def choose_menu_item(item)
|
10
|
+
@state = :initial
|
11
|
+
@input.should_receive(:gets) do
|
12
|
+
case @state
|
13
|
+
when :initial
|
14
|
+
@state = :done
|
15
|
+
"#{item}\n"
|
16
|
+
when :done
|
17
|
+
"quit\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context '#run' do
|
23
|
+
|
24
|
+
before :each do
|
25
|
+
@account1_path = '/backup/path'
|
26
|
+
@account1 = {
|
27
|
+
:username => 'user@example.com',
|
28
|
+
:password => 'secret',
|
29
|
+
:local_path => @account1_path,
|
30
|
+
:folders => [ { :name => 'my_folder' }, { :name => 'another_folder' } ]
|
31
|
+
}
|
32
|
+
@other_account_path = '/existing/path'
|
33
|
+
@other_account = {
|
34
|
+
:username => 'existing@example.com',
|
35
|
+
:password => 'secret',
|
36
|
+
:local_path => @other_account_path,
|
37
|
+
:folders => []
|
38
|
+
}
|
39
|
+
@data = {:accounts => [@account1, @other_account]}
|
40
|
+
@store = stub('Imap::Backup::Configuration::Store')
|
41
|
+
@store.stub!(:data => @data)
|
42
|
+
@input, @output = prepare_highline
|
43
|
+
end
|
44
|
+
|
45
|
+
subject { Imap::Backup::Configuration::Account.new(@store, @account1) }
|
46
|
+
|
47
|
+
context 'menu' do
|
48
|
+
|
49
|
+
it 'should show a menu' do
|
50
|
+
subject.run
|
51
|
+
|
52
|
+
@output.string.should =~ /modify email/
|
53
|
+
@output.string.should =~ /modify password/
|
54
|
+
@output.string.should =~ /modify backup path/
|
55
|
+
@output.string.should =~ /choose backup folders/
|
56
|
+
@output.string.should =~ /test authentication/
|
57
|
+
@output.string.should =~ /delete/
|
58
|
+
@output.string.should =~ /return to main/
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should show account details in the menu' do
|
62
|
+
subject.run
|
63
|
+
|
64
|
+
@output.string.should =~ /email:\s+user@example.com/
|
65
|
+
@output.string.should =~ /password:\s+x+/
|
66
|
+
@output.string.should =~ %r{path:\s+/backup/path}
|
67
|
+
@output.string.should =~ /folders:\s+my_folder, another_folder/
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should indicate that a password is not set' do
|
71
|
+
@account1[:password] = ''
|
72
|
+
|
73
|
+
subject.run
|
74
|
+
|
75
|
+
@output.string.should =~ /password:\s+\(unset\)/
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'email' do
|
81
|
+
|
82
|
+
it 'should modify the email address' do
|
83
|
+
Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('new@example.com')
|
84
|
+
|
85
|
+
choose_menu_item 'modify email'
|
86
|
+
|
87
|
+
subject.run
|
88
|
+
|
89
|
+
@output.string.should =~ /email:\s+new@example.com/
|
90
|
+
@account1[:username].should == 'new@example.com'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should do nothing if it creates a duplicate' do
|
94
|
+
Imap::Backup::Configuration::Asker.should_receive(:email).once.and_return('existing@example.com')
|
95
|
+
|
96
|
+
choose_menu_item 'modify email'
|
97
|
+
|
98
|
+
capturing_output do
|
99
|
+
subject.run
|
100
|
+
end.should =~ /there is already an account set up with that email address/i
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'password' do
|
106
|
+
|
107
|
+
it 'should update the password' do
|
108
|
+
Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return('new_pwd')
|
109
|
+
|
110
|
+
choose_menu_item 'modify password'
|
111
|
+
|
112
|
+
subject.run
|
113
|
+
|
114
|
+
@account1[:password].should == 'new_pwd'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should do nothing if the user cancels' do
|
118
|
+
Imap::Backup::Configuration::Asker.should_receive(:password).once.and_return(nil)
|
119
|
+
|
120
|
+
choose_menu_item 'modify password'
|
121
|
+
|
122
|
+
subject.run
|
123
|
+
|
124
|
+
@account1[:password].should == 'secret'
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'backup_path' do
|
130
|
+
|
131
|
+
it 'should update the path' do
|
132
|
+
Imap::Backup::Configuration::Asker.should_receive(:backup_path).once do |default, validator|
|
133
|
+
validator.call('new/path')
|
134
|
+
'/new/path'
|
135
|
+
end
|
136
|
+
|
137
|
+
choose_menu_item 'modify backup path'
|
138
|
+
|
139
|
+
subject.run
|
140
|
+
|
141
|
+
@account1[:local_path].should == '/new/path'
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should validate that the path is not used by other backups' do
|
145
|
+
Imap::Backup::Configuration::Asker.should_receive(:backup_path) do |default, validator|
|
146
|
+
validator.call(@other_account_path)
|
147
|
+
'/path'
|
148
|
+
end
|
149
|
+
|
150
|
+
choose_menu_item 'modify backup path'
|
151
|
+
|
152
|
+
capturing_output do
|
153
|
+
subject.run
|
154
|
+
end.should =~ %r{The path '/existing/path' is used to backup the account 'existing@example.com'}
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should add/remove folders' do
|
160
|
+
@chooser = stub('Imap::Backup::Configuration::FolderChooser')
|
161
|
+
Imap::Backup::Configuration::FolderChooser.should_receive(:new).with(@account1).and_return(@chooser)
|
162
|
+
@chooser.should_receive(:run).with().once
|
163
|
+
|
164
|
+
choose_menu_item 'choose backup folders'
|
165
|
+
|
166
|
+
subject.run
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should allow testing the connection' do
|
170
|
+
Imap::Backup::Configuration::ConnectionTester.should_receive(:test).with(@account1).and_return('All fine')
|
171
|
+
|
172
|
+
choose_menu_item 'test authentication'
|
173
|
+
|
174
|
+
capturing_output do
|
175
|
+
subject.run
|
176
|
+
end.should == "All fine\n"
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'deletion' do
|
180
|
+
|
181
|
+
it 'should confirm deletion' do
|
182
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:agree).with("Are you sure? (y/n) ").and_return(true)
|
183
|
+
|
184
|
+
choose_menu_item 'delete'
|
185
|
+
|
186
|
+
subject.run
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should delete the account' do
|
190
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(true)
|
191
|
+
|
192
|
+
choose_menu_item 'delete'
|
193
|
+
|
194
|
+
subject.run
|
195
|
+
|
196
|
+
@data[:accounts].should_not include(@account1)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should not delete if confirmation is not given' do
|
200
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:agree).with("Are you sure? (y/n) ").and_return(false)
|
201
|
+
|
202
|
+
choose_menu_item 'delete'
|
203
|
+
|
204
|
+
subject.run
|
205
|
+
|
206
|
+
@data[:accounts].should include(@account1)
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'return to main menu' do
|
212
|
+
|
213
|
+
it 'should return' do
|
214
|
+
@input.stub!(:gets).with().and_return("return\n")
|
215
|
+
|
216
|
+
subject.run.should be_nil
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
load File.expand_path( '../../spec_helper.rb', File.dirname(__FILE__) )
|
3
|
+
|
4
|
+
describe Imap::Backup::Configuration::Asker do
|
5
|
+
|
6
|
+
context '.email' do
|
7
|
+
|
8
|
+
it 'should ask for an email' do
|
9
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/email/)
|
10
|
+
|
11
|
+
Imap::Backup::Configuration::Asker.email
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should validate the address' do
|
15
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/email/) do |&block|
|
16
|
+
q = stub('HighLine::Question', :default= => nil,
|
17
|
+
:readline= => nil,
|
18
|
+
:responses => {})
|
19
|
+
q.should_receive(:validate=).with(instance_of(Regexp))
|
20
|
+
|
21
|
+
block.call q
|
22
|
+
end
|
23
|
+
|
24
|
+
Imap::Backup::Configuration::Asker.email
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return the address' do
|
28
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/email/).and_return('new@example.com')
|
29
|
+
|
30
|
+
Imap::Backup::Configuration::Asker.email.should == 'new@example.com'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
context '.password' do
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/^password/).and_return('secret')
|
39
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:ask).with(/^repeat password/).and_return('secret')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should ask for a password and confirmation' do
|
43
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/^password/).and_return('secret')
|
44
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/^repeat password/).and_return('secret')
|
45
|
+
|
46
|
+
Imap::Backup::Configuration::Asker.password
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return the password' do
|
50
|
+
Imap::Backup::Configuration::Asker.password.should == 'secret'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should ask again if the passwords don't match" do
|
54
|
+
state = :password1
|
55
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:ask) do
|
56
|
+
case state
|
57
|
+
when :password1
|
58
|
+
state = :confirmation1
|
59
|
+
'secret'
|
60
|
+
when :confirmation1
|
61
|
+
state = :retry?
|
62
|
+
'wrong!!!'
|
63
|
+
when :retry?
|
64
|
+
state = :password2
|
65
|
+
'y'
|
66
|
+
when :password2
|
67
|
+
state = :confirmation2
|
68
|
+
'secret'
|
69
|
+
when :confirmation2
|
70
|
+
'secret'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Imap::Backup::Configuration::Asker.password
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should return nil if the user cancels' do
|
78
|
+
state = :password1
|
79
|
+
Imap::Backup::Configuration::Setup.highline.stub!(:ask) do
|
80
|
+
case state
|
81
|
+
when :password1
|
82
|
+
state = :confirmation1
|
83
|
+
'secret'
|
84
|
+
when :confirmation1
|
85
|
+
state = :retry?
|
86
|
+
'wrong!!!'
|
87
|
+
when :retry?
|
88
|
+
state = :password2
|
89
|
+
'n'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
Imap::Backup::Configuration::Asker.password.should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
context '.backup_path' do
|
99
|
+
|
100
|
+
it 'should ask for a directory' do
|
101
|
+
validator = /validator/
|
102
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/directory/) do |&block|
|
103
|
+
q = stub('HighLine::Question', :responses => {}, :readline= => nil)
|
104
|
+
q.should_receive(:default=).with('default path')
|
105
|
+
q.should_receive(:validate=).with(validator)
|
106
|
+
|
107
|
+
block.call q
|
108
|
+
end
|
109
|
+
|
110
|
+
Imap::Backup::Configuration::Asker.backup_path('default path', validator)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should return the choice' do
|
114
|
+
Imap::Backup::Configuration::Setup.highline.should_receive(:ask).with(/directory/).and_return('/path')
|
115
|
+
|
116
|
+
Imap::Backup::Configuration::Asker.backup_path('default path', //).should == '/path'
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|