s5 0.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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +37 -0
- data/Rakefile +9 -0
- data/bin/s5 +15 -0
- data/lib/s5.rb +8 -0
- data/lib/s5/cli.rb +18 -0
- data/lib/s5/daemon.rb +52 -0
- data/lib/s5/sync.rb +104 -0
- data/lib/s5/version.rb +3 -0
- data/s5.gemspec +28 -0
- data/test/s5/bootstrap_test.rb +49 -0
- data/test/s5/cli_test.rb +10 -0
- data/test/s5/daemon_test.rb +78 -0
- data/test/s5/sync_test.rb +98 -0
- data/test/test_helper.rb +17 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc684faafc38e71b4030a868526c0023c98420b7
|
4
|
+
data.tar.gz: 2ec967791830fd872100f6ad6cdf5ed876355760
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 34d07d8a1643313dcf809bdd2b2f25e94b45a5437edba07744f3b3fdb7de02723d0ff86055eb54d127e7f9de9fcec56d4b3b9dfb267fc582ca4b87f35f3b4fa5
|
7
|
+
data.tar.gz: 2639fbe2eef0226e4de69f156b11587d4f70003fe7133e64050099cb7aace5599553f36f5b386a6d8aea47d38369350643f8979b7221aafe577c39758aa9fcf1
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 yalab
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# S5
|
2
|
+
|
3
|
+
Secure Sync to Amazon S3(Simple Storage Service).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 's5'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install s5
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
For exapme. ~/project directory sync to 'yalab-project' S3 bucket.
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ s5 observe ~/project --backet="YOUR_BUCKET_NAME"
|
25
|
+
```
|
26
|
+
|
27
|
+
Files under ~/project directory will client side encryption and put to S3 bucekt.
|
28
|
+
|
29
|
+
You *must backup* the encryption key. It is to create on **~/.s5.key**.
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/s5
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path('../../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require "s5/cli"
|
7
|
+
wait = 120
|
8
|
+
begin
|
9
|
+
S5::Cli.start
|
10
|
+
rescue SocketError => e
|
11
|
+
STDERR.puts e
|
12
|
+
STDERR.puts "restart after #{wait} sec."
|
13
|
+
sleep wait
|
14
|
+
retry
|
15
|
+
end
|
data/lib/s5.rb
ADDED
data/lib/s5/cli.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 's5'
|
3
|
+
|
4
|
+
class S5::Cli < Thor
|
5
|
+
class_option :help, type: :boolean, aliases: '-h', desc: 'Print help message.'
|
6
|
+
|
7
|
+
desc "observe DIRECTORIES", "Observe the DIRECTORIES to sync S3"
|
8
|
+
method_option :bucket, type: :string, default: nil, aliases: '-b', desc: 'Set bucket name.'
|
9
|
+
def observe(directory)
|
10
|
+
if options[:help]
|
11
|
+
S5::Cli.command_help(shell, 'observe')
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
daemon = S5::Daemon.new(directory, bucket_name: options[:bucket])
|
15
|
+
daemon.start
|
16
|
+
daemon
|
17
|
+
end
|
18
|
+
end
|
data/lib/s5/daemon.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fssm'
|
2
|
+
|
3
|
+
class S5::Daemon
|
4
|
+
attr_reader :pid
|
5
|
+
def initialize(*paths, bucket_name: nil)
|
6
|
+
@syncs = paths.map{|path|
|
7
|
+
sync = S5::Sync.new(local_path: path, remote_bucket: bucket_name)
|
8
|
+
sync.encrypt!
|
9
|
+
[path, sync]
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
@pid = fork do
|
15
|
+
observe
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
Process.kill :QUIT, @pid
|
21
|
+
end
|
22
|
+
|
23
|
+
def observe
|
24
|
+
observers = @syncs.map!{|path, sync|
|
25
|
+
sync.sync!
|
26
|
+
[path, create_or_update(sync), delete(sync)]
|
27
|
+
}
|
28
|
+
FSSM.monitor do
|
29
|
+
observers.each do |_, create_or_update, delete_proc|
|
30
|
+
path _ do
|
31
|
+
glob '**/*'
|
32
|
+
create &create_or_update
|
33
|
+
update &create_or_update
|
34
|
+
delete &delete_proc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def create_or_update(sync)
|
42
|
+
->(base, relative){
|
43
|
+
sync.put(relative)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(sync)
|
48
|
+
->(base, relative){
|
49
|
+
sync.delete(relative)
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
data/lib/s5/sync.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
class S5::Sync
|
2
|
+
attr_reader :remote_bucket
|
3
|
+
|
4
|
+
def self.encrypt_key_path
|
5
|
+
ENV['HOME'] + '/.s5.key'
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(local_path: nil, remote_bucket: nil)
|
9
|
+
raise "You must set local_path argument." unless local_path
|
10
|
+
@local_path = local_path.to_s
|
11
|
+
@remote_bucket = remote_bucket || AWS.iam.users.first.name + '-s5sync'
|
12
|
+
@options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(key)
|
16
|
+
(path, s3_key) = generate_path_and_key(key)
|
17
|
+
s3_object(s3_key).tap{|o| o.delete }
|
18
|
+
end
|
19
|
+
|
20
|
+
def encrypt!
|
21
|
+
key_path = self.class.encrypt_key_path
|
22
|
+
unless File.exists?(key_path)
|
23
|
+
File.open(key_path, 'w:BINARY', 0600) do |f|
|
24
|
+
f.write OpenSSL::Cipher::AES256.new(:CBC).random_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@options[:server_side_encryption] = :aes256
|
28
|
+
@options[:encryption_key] = File.binread(key_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(key)
|
32
|
+
(path, s3_key) = generate_path_and_key(key)
|
33
|
+
FileUtils.mkdir_p(File.dirname(path))
|
34
|
+
File.open(path, 'wb') do |f|
|
35
|
+
f.write s3_object(s3_key).read(@options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def local_list
|
40
|
+
raise unless @local_path
|
41
|
+
offset = @local_path.to_s.length + 1
|
42
|
+
Hash[Dir.glob(@local_path + '/**/*').to_a.map{|f|
|
43
|
+
next unless File.file?(f)
|
44
|
+
[f[offset..-1], File.mtime(f)]
|
45
|
+
}.compact]
|
46
|
+
end
|
47
|
+
|
48
|
+
def put(key)
|
49
|
+
(path, s3_key) = generate_path_and_key(key)
|
50
|
+
s3_object(s3_key).write(File.binread(path), @options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def remote_list
|
54
|
+
Hash[s3_objects.to_a.map do |object|
|
55
|
+
[object.key, object.last_modified]
|
56
|
+
end.sort_by{|o| o.first }]
|
57
|
+
end
|
58
|
+
|
59
|
+
def sync!
|
60
|
+
local_list = self.local_list
|
61
|
+
remote_list = self.remote_list
|
62
|
+
need_put = local_list.select do |name, mtime|
|
63
|
+
if remote_list[name] && mtime <= remote_list[name]
|
64
|
+
remote_list.delete(name)
|
65
|
+
false
|
66
|
+
else
|
67
|
+
true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
need_put.each do |name, mtime|
|
71
|
+
self.put name
|
72
|
+
end
|
73
|
+
remote_list.each do |key, last_modified|
|
74
|
+
self.get key
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def s3_bucket
|
80
|
+
s3 = AWS.s3
|
81
|
+
_bucket = s3.buckets[@remote_bucket]
|
82
|
+
if _bucket.exists?
|
83
|
+
_bucket
|
84
|
+
else
|
85
|
+
s3.buckets.create(@remote_bucket)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def s3_object(key)
|
90
|
+
s3_objects[key]
|
91
|
+
end
|
92
|
+
|
93
|
+
def s3_objects
|
94
|
+
s3_bucket.objects
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_path_and_key(path)
|
98
|
+
if Pathname.new(path).absolute?
|
99
|
+
[path, File.basename(path)]
|
100
|
+
else
|
101
|
+
[File.join(@local_path, path), path]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/s5/version.rb
ADDED
data/s5.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 's5/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "s5"
|
8
|
+
spec.version = S5::VERSION
|
9
|
+
spec.authors = ["yalab"]
|
10
|
+
spec.email = ["rudeboyjet@gmail.com"]
|
11
|
+
spec.description = %q{Secure Sync to Amazon S3. }
|
12
|
+
spec.summary = %q{This gem provides Amazon S3 sync with client side encryption.}
|
13
|
+
spec.homepage = "https://github.com/yalab/s5"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "aws-sdk"
|
22
|
+
spec.add_dependency "fssm"
|
23
|
+
spec.add_dependency "thor"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "minitest"
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class S5::BootstrapTest < S5::Test
|
4
|
+
def setup
|
5
|
+
bucket_name = "#{ENV['USER']}-s5-test-bootstrap"
|
6
|
+
s3 = AWS.s3
|
7
|
+
@bucket = s3.buckets.create(bucket_name)
|
8
|
+
@local_dir = File.expand_path('../../bootstrap_test', __FILE__)
|
9
|
+
setup_local
|
10
|
+
setup_remote
|
11
|
+
@sync = S5::Sync.new(local_path: @local_dir, remote_bucket: bucket_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
@bucket.delete!
|
16
|
+
FileUtils.rm_rf(@local_dir)
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup_remote
|
20
|
+
@remote_object_name = 'remote'
|
21
|
+
object = @bucket.objects[@remote_object_name].write("remotetest")
|
22
|
+
@last_modified = object.last_modified
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_local
|
26
|
+
@local_file_name = 'local.txt'
|
27
|
+
FileUtils.mkdir_p(@local_dir)
|
28
|
+
File.open(@local_dir + "/#{@local_file_name}", 'w') do |f|
|
29
|
+
f.write("localtest")
|
30
|
+
@mtime = f.mtime
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_remote_list
|
35
|
+
expect = {@remote_object_name => @last_modified}
|
36
|
+
assert_equal expect, @sync.remote_list
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_local_list
|
40
|
+
FileUtils.mkdir_p(@local_dir + '/dir')
|
41
|
+
expect = {@local_file_name => @mtime}
|
42
|
+
assert_equal expect, @sync.local_list
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_sync!
|
46
|
+
@sync.sync!
|
47
|
+
assert_equal @sync.remote_list.keys.sort, @sync.local_list.keys.sort
|
48
|
+
end
|
49
|
+
end
|
data/test/s5/cli_test.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class S5::DaemonTest < S5::Test
|
4
|
+
class DaemonFiber < S5::Daemon
|
5
|
+
attr_accessor :fiber
|
6
|
+
def observe
|
7
|
+
@fiber = Fiber.new do
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
%w(create_or_update delete).each do |name|
|
13
|
+
module_eval <<-METHOD, __FILE__, __LINE__
|
14
|
+
def #{name}(*args)
|
15
|
+
proc = super
|
16
|
+
->(base, relative){
|
17
|
+
proc.call(base, relative).tap{
|
18
|
+
Fiber.yield
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
METHOD
|
23
|
+
end
|
24
|
+
|
25
|
+
def resume
|
26
|
+
@fiber.resume
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
super
|
32
|
+
@bucket_name = "#{ENV["USER"]}-s5-daemon-test"
|
33
|
+
@daemon = DaemonFiber.new(@fixtures_path, bucket_name: @bucket_name)
|
34
|
+
@path = @fixtures_path.join(Time.now.to_f.to_s)
|
35
|
+
FileUtils.rm_rf @path
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
super
|
40
|
+
bucket.delete! if bucket.exists? && bucket.versioned?
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_sync_when_initialize
|
44
|
+
sync = S5::Sync.new(local_path: @fixtures_path,
|
45
|
+
remote_bucket: @bucket_name)
|
46
|
+
assert_equal sync.remote_list.keys.sort, sync.local_list.keys.sort
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_touch_new_file_and_delete
|
50
|
+
@daemon.observe
|
51
|
+
user_context{ FileUtils.touch @path }
|
52
|
+
@daemon.resume
|
53
|
+
key = File.basename(@path)
|
54
|
+
assert true, s3_object(key).exists?
|
55
|
+
|
56
|
+
user_context{ FileUtils.rm_rf(@path) }
|
57
|
+
@daemon.resume
|
58
|
+
assert_raises AWS::S3::Errors::NoSuchKey do
|
59
|
+
s3_object(key).read
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def user_context
|
65
|
+
fork do
|
66
|
+
sleep 0.5
|
67
|
+
yield
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def s3_object(key)
|
72
|
+
bucket.objects[key]
|
73
|
+
end
|
74
|
+
|
75
|
+
def bucket
|
76
|
+
AWS.s3.buckets[@bucket_name]
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class S5::SyncTest < S5::Test
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
@encrypt_key_path = S5::Sync.encrypt_key_path
|
7
|
+
@encrypt_key_path_backup = @encrypt_key_path + '.s5_test'
|
8
|
+
if File.exists?(@encrypt_key_path)
|
9
|
+
FileUtils.mv @encrypt_key_path, @encrypt_key_path_backup
|
10
|
+
end
|
11
|
+
@remote_bucket = "#{ENV['USER']}-s5-test"
|
12
|
+
@sync = S5::Sync.new(local_path: @fixtures_path, remote_bucket: @remote_bucket)
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
super
|
17
|
+
if File.exists?(@encrypt_key_path_backup)
|
18
|
+
FileUtils.mv @encrypt_key_path_backup, @encrypt_key_path
|
19
|
+
end
|
20
|
+
bucket = @sync.send(:s3_bucket)
|
21
|
+
bucket.delete! if bucket.exists? && bucket.versioned?
|
22
|
+
end
|
23
|
+
|
24
|
+
class DefaultValues < self
|
25
|
+
def test_encrypt_key_path
|
26
|
+
assert_equal ENV['HOME'] + '/.s5.key', S5::Sync.encrypt_key_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module SyncPutGetTest
|
31
|
+
def test_sync_put_get
|
32
|
+
s3_object = @sync.put(@path)
|
33
|
+
assert_equal @plain, s3_object.read
|
34
|
+
FileUtils.rm_rf(File.dirname(@path))
|
35
|
+
@sync.get(@path)
|
36
|
+
assert_equal @plain, File.read(@path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_sync_put_with_encrypt
|
40
|
+
@sync.encrypt!
|
41
|
+
assert File.exists?(S5::Sync.encrypt_key_path)
|
42
|
+
s3_object = @sync.put(@path)
|
43
|
+
refute_equal @plain, s3_object.read
|
44
|
+
assert_equal @plain, s3_object.read(encryption_key: File.binread(@encrypt_key_path))
|
45
|
+
FileUtils.rm_rf(File.dirname(@path))
|
46
|
+
@sync.get(@path)
|
47
|
+
assert_equal @plain, File.binread(@path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class SinglePathTest < self
|
52
|
+
include SyncPutGetTest
|
53
|
+
def setup
|
54
|
+
super
|
55
|
+
@plain = Digest::SHA2.hexdigest(Time.now.to_f.to_s) + 'test'
|
56
|
+
@path = @fixtures_path.join('test.txt')
|
57
|
+
File.open(@path, 'w') do |f|
|
58
|
+
f.write @plain
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_default_remote_bucket
|
63
|
+
assert_match '-s5sync', S5::Sync.new(local_path: @fixtures_path).remote_bucket
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class RelativePathTest < self
|
68
|
+
include SyncPutGetTest
|
69
|
+
def setup
|
70
|
+
super
|
71
|
+
@plain = Digest::SHA2.hexdigest(Time.now.to_f.to_s) + 'test'
|
72
|
+
@key = 'fixtures/test.txt'
|
73
|
+
basedir = File.expand_path('../../', __FILE__)
|
74
|
+
@sync = S5::Sync.new(local_path: basedir, remote_bucket: @remote_bucket)
|
75
|
+
@path = basedir + '/' + @key
|
76
|
+
FileUtils.mkdir_p File.dirname(@path)
|
77
|
+
File.open(@path, 'w') do |f|
|
78
|
+
f.write @plain
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_object_path
|
83
|
+
s3_object = @sync.put(@key)
|
84
|
+
assert_equal @key, s3_object.key
|
85
|
+
FileUtils.rm_rf(File.dirname(@path))
|
86
|
+
@sync.get(@key)
|
87
|
+
assert_equal @plain, File.binread(@path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_delete
|
91
|
+
@sync.put(@key)
|
92
|
+
s3_object = @sync.delete(@key)
|
93
|
+
assert_raises AWS::S3::Errors::NoSuchKey do
|
94
|
+
s3_object.read
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/pride'
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'fileutils'
|
5
|
+
require 's5'
|
6
|
+
|
7
|
+
class S5::Test < MiniTest::Test
|
8
|
+
def setup
|
9
|
+
@fixtures_path ||= Pathname.new(File.expand_path('../fixtures', __FILE__)).tap{|path|
|
10
|
+
FileUtils.mkdir_p path.to_s
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
FileUtils.rm_rf(@fixtures_path)
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- yalab
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: fssm
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: 'Secure Sync to Amazon S3. '
|
98
|
+
email:
|
99
|
+
- rudeboyjet@gmail.com
|
100
|
+
executables:
|
101
|
+
- s5
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- bin/s5
|
111
|
+
- lib/s5.rb
|
112
|
+
- lib/s5/cli.rb
|
113
|
+
- lib/s5/daemon.rb
|
114
|
+
- lib/s5/sync.rb
|
115
|
+
- lib/s5/version.rb
|
116
|
+
- s5.gemspec
|
117
|
+
- test/s5/bootstrap_test.rb
|
118
|
+
- test/s5/cli_test.rb
|
119
|
+
- test/s5/daemon_test.rb
|
120
|
+
- test/s5/sync_test.rb
|
121
|
+
- test/test_helper.rb
|
122
|
+
homepage: https://github.com/yalab/s5
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.0.3
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: This gem provides Amazon S3 sync with client side encryption.
|
146
|
+
test_files:
|
147
|
+
- test/s5/bootstrap_test.rb
|
148
|
+
- test/s5/cli_test.rb
|
149
|
+
- test/s5/daemon_test.rb
|
150
|
+
- test/s5/sync_test.rb
|
151
|
+
- test/test_helper.rb
|