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 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