s3_uploader 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- N2JiYmFhYzUzMjEwZmUzN2RlYzM2YTQ2MGZiNWRjNDcyN2ZlYjFiOA==
4
+ MDZiOTVmMWI5NTExMmQ2NzEyMTA1MTliYTVhNGJhMDA1MWJmYjEwZA==
5
5
  data.tar.gz: !binary |-
6
- ZDU4ZjExZWI0MjJkNDM3MzBhNTExYzExOWJiYjE3NWJmOTg3YzkzNQ==
6
+ ZDcyZTAwNjAwOGFlNzJjYzk0YjU3MGJmYTBiNTM2MmViZDVkYTkwNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MDMyNjE0ZjJlNzdjOWQ3NmI5MzYwYWM5ZDliYzAwOTQzZWE1MTY2YjU5OGY3
10
- MjQ0ZDMzOGQ1N2Q5NDYzNGViYTZlMmQxNDExN2Q3ZmE3N2E2NjkzZDJhNGVh
11
- Y2YxMTNlNzQ0OTNjYTEwNWFjODlkN2Y1MDRhMDM0MjcxMjE4ZDA=
9
+ YjYxNGVjODAwNjY2Y2E4YzU5NmY4NWEzNDFlNjg2NmI5NmJjYzhkYmNhMTg0
10
+ NWNjOGM0MzQ2Yzk4NWRiYWY5N2NkYjUyY2M2ZGUzMGZkYTYyMzEyYmFlOGMw
11
+ ZTI1NmQ1ZjFmYTFkN2MyNDViMWM4ZTFiMzFkNzEwYzAxNTBhZGY=
12
12
  data.tar.gz: !binary |-
13
- ZjRhY2RhZTA1NDBmZTcxYTg4MGRmYTE3MTQ3Njk4NjZiMjVjZmMyMTY2ZDk4
14
- N2I0YjJlNjMwYjZjMDNhZTIwYjFiNDFmZGRkNDYwOGI0OWFkNTdiM2RlYmE2
15
- MTllYTgyMTM2MTAxYzg5MDYyZTQyNzU5ZWQ0OGFmZTA0YzgyNDM=
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
 
@@ -1,3 +1,3 @@
1
1
  module S3Uploader
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
data/s3_uploader.gemspec CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |gem|
18
18
 
19
19
  gem.add_dependency 'fog'
20
20
 
21
- gem.add_development_dependency 'rspec'
21
+ gem.add_development_dependency 'rspec', '~>2.14.1'
22
22
  gem.add_development_dependency 'rake'
23
23
  end
@@ -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
- { :destination_dir => 'test1/',
9
- :s3_key => nil,
10
- :s3_secret => nil
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
- def create_test_files(directory, number_of_files)
58
- FileUtils.mkdir_p directory
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.9
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-01-29 00:00:00.000000000 Z
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: '0'
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: '0'
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.1
95
+ rubygems_version: 2.1.2
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: S3 multithreaded directory uploader