s3_uploader 0.0.9 → 0.1.0
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 +8 -8
- data/README.md +2 -0
- data/lib/s3_uploader/s3_uploader.rb +30 -5
- data/lib/s3_uploader/version.rb +1 -1
- data/s3_uploader.gemspec +1 -1
- data/spec/s3uploader_spec.rb +175 -47
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDZiOTVmMWI5NTExMmQ2NzEyMTA1MTliYTVhNGJhMDA1MWJmYjEwZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZDcyZTAwNjAwOGFlNzJjYzk0YjU3MGJmYTBiNTM2MmViZDVkYTkwNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjYxNGVjODAwNjY2Y2E4YzU5NmY4NWEzNDFlNjg2NmI5NmJjYzhkYmNhMTg0
|
10
|
+
NWNjOGM0MzQ2Yzk4NWRiYWY5N2NkYjUyY2M2ZGUzMGZkYTYyMzEyYmFlOGMw
|
11
|
+
ZTI1NmQ1ZjFmYTFkN2MyNDViMWM4ZTFiMzFkNzEwYzAxNTBhZGY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MGQ4NjEyMDA3N2M4OWY0NmIwMTI1MjFhY2UzY2NlY2VlZjNhM2NkNDNlZTQz
|
14
|
+
NmVlNTk0MzNjYjBiOWUzYjBlYTA3ZDBmMzVhZDJiMjlkN2NjYzE5Y2ZjZWFl
|
15
|
+
ZjgxYjA1OGVhZmU0MjFjODc3ZTE2ZDAyMmIxYjU4MzY1ZTIzMTg=
|
data/README.md
CHANGED
@@ -70,6 +70,8 @@ Metadata headers are documented [here](http://docs.aws.amazon.com/AmazonS3/lates
|
|
70
70
|
|
71
71
|
* [Mark Wagner](https://github.com/theSociableme)
|
72
72
|
* [Brandon Hilkert](https://github.com/brandonhilkert)
|
73
|
+
* [Philip Cunningham](https://github.com/unsymbol)
|
74
|
+
* [Ludwig Bratke](https://github.com/bratke)
|
73
75
|
|
74
76
|
## License
|
75
77
|
|
@@ -9,12 +9,19 @@ module S3Uploader
|
|
9
9
|
:public => false,
|
10
10
|
:region => 'us-east-1',
|
11
11
|
:metadata => {},
|
12
|
-
:path_style => false
|
12
|
+
:path_style => false,
|
13
|
+
:regexp => /.*/,
|
14
|
+
:gzip => false,
|
15
|
+
:gzip_working_dir => source,
|
16
|
+
:time_range => Time.at(0)..(Time.now + (60 * 60 * 24))
|
13
17
|
}.merge(options)
|
14
18
|
|
15
19
|
log = options[:logger] || Logger.new(STDOUT)
|
16
20
|
|
17
21
|
raise 'Source must be a directory' unless File.directory?(source)
|
22
|
+
if options[:gzip_working_dir] != source && options[:gzip_working_dir][source]
|
23
|
+
raise 'gzip_working_dir may not be located within source-folder'
|
24
|
+
end
|
18
25
|
|
19
26
|
if options[:connection]
|
20
27
|
connection = options[:connection]
|
@@ -31,15 +38,33 @@ module S3Uploader
|
|
31
38
|
end
|
32
39
|
|
33
40
|
source = source.chop if source.end_with?('/')
|
41
|
+
options[:gzip_working_dir] = options[:gzip_working_dir].chop if options[:gzip_working_dir].end_with?('/')
|
34
42
|
if options[:destination_dir] != '' and !options[:destination_dir].end_with?('/')
|
35
43
|
options[:destination_dir] = "#{options[:destination_dir]}/"
|
36
44
|
end
|
37
45
|
total_size = 0
|
38
46
|
files = Queue.new
|
39
|
-
Dir.glob("#{source}/**/*").select{ |f| !File.directory?(f) }.each do |f|
|
40
|
-
files << f
|
41
|
-
total_size += File.size(f)
|
42
47
|
|
48
|
+
Dir.glob("#{source}/**/*").select { |f| !File.directory?(f) }.each do |f|
|
49
|
+
if File.basename(f).match(options[:regexp]) and options[:time_range].cover?(File.mtime(f))
|
50
|
+
if options[:gzip] && File.extname(f) != '.gz'
|
51
|
+
dir, base = File.split(f)
|
52
|
+
dir = dir.sub(source, options[:gzip_working_dir])
|
53
|
+
gz_file = "#{dir}/#{base}.gz"
|
54
|
+
|
55
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
56
|
+
Zlib::GzipWriter.open(gz_file) do |gz|
|
57
|
+
gz.mtime = File.mtime(f)
|
58
|
+
gz.orig_name = f
|
59
|
+
gz.write IO.binread(f)
|
60
|
+
end
|
61
|
+
files << gz_file
|
62
|
+
total_size += File.size(gz_file)
|
63
|
+
else
|
64
|
+
files << f
|
65
|
+
total_size += File.size(f)
|
66
|
+
end
|
67
|
+
end
|
43
68
|
end
|
44
69
|
|
45
70
|
directory = connection.directories.new(:key => bucket)
|
@@ -60,7 +85,7 @@ module S3Uploader
|
|
60
85
|
end
|
61
86
|
file = files.pop rescue nil
|
62
87
|
if file
|
63
|
-
key = file.gsub(source, '')[1..-1]
|
88
|
+
key = file.gsub(source, '').gsub(options[:gzip_working_dir], '')[1..-1]
|
64
89
|
dest = "#{options[:destination_dir]}#{key}"
|
65
90
|
log.info("[#{Thread.current["file_number"]}/#{total_files}] Uploading #{key} to s3://#{bucket}/#{dest}")
|
66
91
|
|
data/lib/s3_uploader/version.rb
CHANGED
data/s3_uploader.gemspec
CHANGED
data/spec/s3uploader_spec.rb
CHANGED
@@ -1,63 +1,191 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe S3Uploader do
|
4
|
-
|
4
|
+
|
5
|
+
let(:access) do
|
6
|
+
%w(access.log access.log.1 access.log.2.gz subdir/access.log subdir/access.log.1 subdir/access.log.2.gz)
|
7
|
+
end
|
8
|
+
let(:error) do
|
9
|
+
%w(error.log error.log.1 error.log.2.gz subdir/error.log subdir/error.log.1 subdir/error.log.2.gz)
|
10
|
+
end
|
11
|
+
let(:tmp_directory) do
|
12
|
+
File.join(Dir.tmpdir, 'test_s3_uploader')
|
13
|
+
end
|
14
|
+
let(:logger) do
|
15
|
+
Logger.new(STDOUT)
|
16
|
+
end
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
Fog.mock!
|
20
|
+
|
21
|
+
FileUtils.rm_rf(Dir.glob("#{tmp_directory}/*"))
|
22
|
+
|
23
|
+
(access + error).each do |file|
|
24
|
+
directory, basename = File.split("#{tmp_directory}/#{file}")
|
25
|
+
FileUtils.mkdir_p directory
|
26
|
+
Open3.popen3("dd if=/dev/zero of=#{directory}/#{basename} count=1024 bs=1024")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
5
30
|
it 'when called with missing access keys it should raise an exception' do
|
6
31
|
lambda {
|
7
32
|
S3Uploader.upload_directory('/tmp', 'mybucket',
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
})
|
33
|
+
{ destination_dir: 'test1/',
|
34
|
+
s3_key: nil,
|
35
|
+
s3_secret: nil })
|
12
36
|
}.should raise_error('Missing access keys')
|
13
37
|
end
|
14
|
-
|
38
|
+
|
15
39
|
it 'when called with source not directory it should raise an exception' do
|
16
40
|
lambda {
|
17
41
|
S3Uploader.upload_directory('/xzzaz1232', 'mybucket')
|
18
42
|
}.should raise_error('Source must be a directory')
|
19
43
|
end
|
20
|
-
|
21
|
-
|
22
|
-
before :all do
|
23
|
-
Fog.mock!
|
24
|
-
|
25
|
-
@connection = Fog::Storage.new({
|
26
|
-
:provider => 'AWS',
|
27
|
-
:aws_access_key_id => '11111111111',
|
28
|
-
:aws_secret_access_key => 'XXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
29
|
-
})
|
30
|
-
|
31
|
-
@connection.directories.create(
|
32
|
-
:key => 'mybucket',
|
33
|
-
:public => true
|
34
|
-
)
|
35
|
-
|
36
|
-
@tmp_directory = File.join(Dir.tmpdir, 'test_s3_uploader')
|
37
|
-
create_test_files(@tmp_directory, 10)
|
38
|
-
create_test_files(File.join(@tmp_directory, 'subdir1'), 5)
|
39
|
-
@logger = Logger.new(STDOUT)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should upload all files in a directory" do
|
43
|
-
puts @tmp_directory
|
44
|
-
# @logger.should_receive(:info).exactly(15).times.with(/Uploading/)
|
45
|
-
# @logger.should_receive(:info).exactly(1).times.with(/Uploaded/)
|
46
|
-
|
47
|
-
S3Uploader.upload_directory(@tmp_directory, 'mybucket',
|
48
|
-
{ :destination_dir => 'test1/',
|
49
|
-
:logger => @logger,
|
50
|
-
:connection => @connection
|
51
|
-
})
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
44
|
|
57
|
-
|
58
|
-
|
45
|
+
it 'should upload all files in a directory' do
|
46
|
+
connection = double(:connection)
|
47
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
48
|
+
directory.stub(:files).and_return(files = double(:files))
|
49
|
+
|
50
|
+
files.should_receive(:create).exactly(12).times
|
51
|
+
|
52
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
53
|
+
{ destination_dir: 'test1/',
|
54
|
+
logger: logger,
|
55
|
+
connection: connection })
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'regexp' do
|
59
|
+
|
60
|
+
it 'should upload specific files' do
|
61
|
+
connection = double(:connection)
|
62
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
63
|
+
directory.stub(:files).and_return(files = double(:files))
|
64
|
+
|
65
|
+
keys = access.dup
|
66
|
+
files.should_receive(:create).exactly(6).times do |hash|
|
67
|
+
expect(keys).to include(hash[:key])
|
68
|
+
keys.delete(hash[:key])
|
69
|
+
end
|
70
|
+
|
71
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
72
|
+
{ logger: logger,
|
73
|
+
connection: connection,
|
74
|
+
regexp: /access/ })
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'gzip' do
|
80
|
+
|
81
|
+
it 'should upload compressed files' do
|
82
|
+
connection = double(:connection)
|
83
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
84
|
+
directory.stub(:files).and_return(files = double(:files))
|
85
|
+
|
86
|
+
#expect to upload gz-files only
|
87
|
+
keys = error.map { |f| f.sub('.gz', '') }.map { |f| f + '.gz' }
|
88
|
+
files.should_receive(:create).exactly(6).times do |hash|
|
89
|
+
expect(keys).to include(hash[:key])
|
90
|
+
keys.delete(hash[:key])
|
91
|
+
end
|
92
|
+
|
93
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
94
|
+
{ logger: logger,
|
95
|
+
connection: connection,
|
96
|
+
regexp: /error/,
|
97
|
+
gzip: true })
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should use gzip_working_dir correctly' do
|
101
|
+
working_dir = File.join(Dir.tmpdir, 's3uploader_spec/working_dir')
|
102
|
+
FileUtils.mkdir_p working_dir
|
103
|
+
FileUtils.rm_rf(Dir.glob("#{working_dir}/*"))
|
104
|
+
|
105
|
+
connection = double(:connection)
|
106
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
107
|
+
directory.stub(:files).and_return(files = double(:files))
|
108
|
+
|
109
|
+
#expect to upload gz-files only
|
110
|
+
keys = error.map { |f| f.sub('.gz', '') }.map { |f| f + '.gz' }
|
111
|
+
files.should_receive(:create).exactly(6).times do |hash|
|
112
|
+
expect(keys).to include(hash[:key])
|
113
|
+
keys.delete(hash[:key])
|
114
|
+
end
|
115
|
+
|
116
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
117
|
+
{ logger: logger,
|
118
|
+
connection: connection,
|
119
|
+
regexp: /error/,
|
120
|
+
gzip: true,
|
121
|
+
gzip_working_dir: working_dir })
|
122
|
+
|
123
|
+
#only compress files which aren't compressed yet
|
124
|
+
compressed_files = error.select { |f| File.extname(f) != '.gz' }.map { |f| f + '.gz' }
|
125
|
+
working_dir_content = Dir["#{working_dir}/**/*"].map { |f| f.sub(working_dir, '')[1..-1] }
|
126
|
+
|
127
|
+
#expect compressed files within working_directory
|
128
|
+
expect(working_dir_content & compressed_files).to match_array(compressed_files)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'when called with bad gzip_working_dir it should raise an exception' do
|
132
|
+
expect {
|
133
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
134
|
+
{ gzip: true,
|
135
|
+
gzip_working_dir: File.join(Dir.tmpdir, 'test_s3_uploader/working_dir') })
|
136
|
+
}.to raise_error('gzip_working_dir may not be located within source-folder')
|
137
|
+
|
138
|
+
expect {
|
139
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
140
|
+
{ gzip: true,
|
141
|
+
gzip_working_dir: File.join(Dir.tmpdir, 'test_s3_uploader_working_dir') })
|
142
|
+
}.to raise_error('gzip_working_dir may not be located within source-folder')
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'time_range' do
|
148
|
+
|
149
|
+
it 'should not upload any files' do
|
150
|
+
connection = double(:connection)
|
151
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
152
|
+
directory.stub(:files).and_return(files = double(:files))
|
153
|
+
|
154
|
+
file_names = access.map { |f| "#{tmp_directory}/#{f}" }
|
155
|
+
yesterday = Time.now - (60 * 60 * 24)
|
156
|
+
File.utime(yesterday, yesterday, *file_names)
|
157
|
+
|
158
|
+
files.should_not_receive(:create)
|
159
|
+
|
160
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
161
|
+
{ logger: logger,
|
162
|
+
connection: connection,
|
163
|
+
regexp: /access/,
|
164
|
+
time_range: (Time.now - (60 * 60 * 12))..Time.now })
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should upload files' do
|
168
|
+
connection = double(:connection)
|
169
|
+
connection.stub_chain(:directories, :new).and_return(directory = double(:directory))
|
170
|
+
directory.stub(:files).and_return(files = double(:files))
|
171
|
+
|
172
|
+
file_names = access.map { |f| "#{tmp_directory}/#{f}" }
|
173
|
+
yesterday = Time.now - (60 * 60 * 12)
|
174
|
+
File.utime(yesterday, yesterday, *file_names)
|
175
|
+
|
176
|
+
keys = access.dup
|
177
|
+
files.should_receive(:create).exactly(6).times do |hash|
|
178
|
+
expect(keys).to include(hash[:key])
|
179
|
+
keys.delete(hash[:key])
|
180
|
+
end
|
181
|
+
|
182
|
+
S3Uploader.upload_directory(tmp_directory, 'mybucket',
|
183
|
+
{ logger: logger,
|
184
|
+
connection: connection,
|
185
|
+
regexp: /access/,
|
186
|
+
time_range: (Time.now - (60 * 60 * 24))..Time.now })
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
59
190
|
|
60
|
-
number_of_files.times do |i|
|
61
|
-
Open3.popen3("dd if=/dev/zero of=#{directory}/file#{i}.txt count=1024 bs=1024")
|
62
|
-
end
|
63
191
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3_uploader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Hein
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fog
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 2.14.1
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 2.14.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
94
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.2
|
95
|
+
rubygems_version: 2.1.2
|
96
96
|
signing_key:
|
97
97
|
specification_version: 4
|
98
98
|
summary: S3 multithreaded directory uploader
|