shuck 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ tmp
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shuck (0.0.1)
4
+ shuck (0.0.2)
5
5
  builder
6
6
  thor
7
7
 
@@ -9,10 +9,15 @@ GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
11
  archive-tar-minitar (0.5.2)
12
+ aws-s3 (0.6.2)
13
+ builder
14
+ mime-types
15
+ xml-simple
12
16
  builder (2.1.2)
13
17
  columnize (0.3.2)
14
18
  linecache19 (0.5.11)
15
19
  ruby_core_source (>= 0.1.4)
20
+ mime-types (1.16)
16
21
  ruby-debug-base19 (0.11.24)
17
22
  columnize (>= 0.3.1)
18
23
  linecache19 (>= 0.5.11)
@@ -24,11 +29,13 @@ GEM
24
29
  ruby_core_source (0.1.4)
25
30
  archive-tar-minitar (>= 0.5.2)
26
31
  thor (0.14.4)
32
+ xml-simple (1.0.12)
27
33
 
28
34
  PLATFORMS
29
35
  ruby
30
36
 
31
37
  DEPENDENCIES
38
+ aws-s3
32
39
  builder
33
40
  bundler (>= 1.0.0)
34
41
  ruby-debug19
data/Rakefile CHANGED
@@ -1,2 +1,10 @@
1
1
  require 'bundler'
2
+ require 'rake/testtask'
2
3
  Bundler::GemHelper.install_tasks
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.test_files = FileList['test/*_test.rb']
7
+ t.ruby_opts = ['-rubygems'] if defined? Gem
8
+ t.ruby_opts << '-I.'
9
+ end
10
+
data/bin/shuck CHANGED
@@ -1,5 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'ruby-debug'
4
2
  require 'shuck/cli'
5
3
  Shuck::CLI.start
@@ -0,0 +1,18 @@
1
+ require 'builder'
2
+ require 'shuck/s3_object'
3
+
4
+ module Shuck
5
+ class Bucket
6
+ attr_accessor :name,:creation_date,:objects
7
+
8
+ def initialize(name,creation_date,objects)
9
+ @name = name
10
+ @creation_date = creation_date
11
+ @objects = []
12
+ objects.each do |obj|
13
+ @objects << obj
14
+ end
15
+ end
16
+
17
+ end
18
+ end
data/lib/shuck/cli.rb CHANGED
@@ -6,12 +6,20 @@ module Shuck
6
6
  default_task("server")
7
7
 
8
8
  desc "server", "Run a server"
9
- method_option :root, :type => :string, :aliases => '-r',:required => true
9
+ method_option :root, :type => :string, :aliases => '-r'
10
10
  method_option :port, :type => :numeric, :aliases => '-p', :required => true
11
11
  def server
12
12
  root = File.expand_path(options[:root])
13
13
  puts "Loading Shuck with #{root} on port #{options[:port]}"
14
- server = Shuck::Server.new(options[:port],options[:root])
14
+ store = nil
15
+ if options[:root]
16
+ store = FileStore.new(options[:root])
17
+ end
18
+ if store.nil?
19
+ puts "You must specify a root to use a file store (the current default)"
20
+ exit(-1)
21
+ end
22
+ server = Shuck::Server.new(options[:port],store)
15
23
  server.serve
16
24
  end
17
25
  end
@@ -0,0 +1,56 @@
1
+ require 'fileutils'
2
+ require 'time'
3
+ require 'shuck/bucket'
4
+
5
+ module Shuck
6
+ class FileStore
7
+ def initialize(root)
8
+ @root = root
9
+ @buckets = []
10
+ @bucket_hash = {}
11
+ Dir[File.join(root,"*")].each do |bucket|
12
+ bucket_name = File.basename(bucket)
13
+ bucket_obj = Bucket.new(bucket_name,Time.now,[])
14
+ @buckets << bucket_obj
15
+ @bucket_hash[bucket_name] = bucket_obj
16
+ end
17
+ end
18
+
19
+ def buckets
20
+ @buckets
21
+ end
22
+
23
+ def get_bucket(bucket)
24
+ @bucket_hash[bucket]
25
+ end
26
+
27
+ def create_bucket(bucket)
28
+ FileUtils.mkdir_p(File.join(@root,bucket))
29
+ bucket_obj = Bucket.new(bucket,Time.now,[])
30
+ @buckets << bucket_obj
31
+ @bucket_hash[bucket] = bucket_obj
32
+ end
33
+
34
+ def get_object(bucket,object)
35
+ begin
36
+ io = File.open(File.join(@root,bucket,object),'rb')
37
+ return io
38
+ rescue
39
+ puts $!
40
+ return nil
41
+ end
42
+ end
43
+
44
+ def store_object(bucket,object,request)
45
+ begin
46
+ File.open(File.join(@root,bucket,object),'w') do |f|
47
+ request.body do |chunk|
48
+ f << chunk
49
+ end
50
+ end
51
+ rescue
52
+ puts $!
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module Shuck
2
+ class S3Object
3
+ attr_accessor :name,:size,:creation_date
4
+ end
5
+ end
data/lib/shuck/server.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'webrick'
2
- require 'shuck/store'
2
+ require 'shuck/file_store'
3
+ require 'shuck/xml_adapter'
3
4
 
4
5
  module Shuck
5
6
  class Servlet < WEBrick::HTTPServlet::AbstractServlet
6
- def initialize(server,root)
7
+ def initialize(server,store)
7
8
  super(server)
8
- @store = Store.new(root)
9
+ @store = store
9
10
  end
10
11
 
11
12
  def do_GET(request, response)
@@ -15,15 +16,22 @@ module Shuck
15
16
  if path == "/"
16
17
  response.status = 200
17
18
  response['Content-Type'] = 'text/xml'
18
- response.body = @store.buckets
19
+ buckets = @store.buckets
20
+ response.body = XmlAdapter.buckets(buckets)
19
21
  else
20
22
  elems = path[1,path_len].split("/")
21
23
  bucket = elems[0]
22
24
  if elems.size == 1
23
- bucket_list = @store.get_bucket(bucket)
24
- response.status = 200
25
- response.body = bucket_list
26
- response['Content-Type'] = "text/xml"
25
+ bucket_obj = @store.get_bucket(bucket)
26
+ if bucket_obj
27
+ response.status = 200
28
+ response.body = XmlAdapter.bucket(bucket_obj)
29
+ response['Content-Type'] = "application/xml"
30
+ else
31
+ response.status = 404
32
+ response.body = XmlAdapter.error_no_such_bucket(bucket)
33
+ response['Content-Type'] = "application/xml"
34
+ end
27
35
  else
28
36
  object = elems[1,elems.size].join('/')
29
37
  io = @store.get_object(bucket,object)
@@ -72,16 +80,20 @@ module Shuck
72
80
  end
73
81
 
74
82
  class Server
75
- def initialize(port,root)
83
+ def initialize(port,store)
76
84
  @port = port
77
- @root = root
85
+ @store = store
78
86
  end
79
87
 
80
88
  def serve
81
89
  @server = WEBrick::HTTPServer.new(:Port => @port)
82
- @server.mount "/", Servlet, @root
90
+ @server.mount "/", Servlet, @store
83
91
  trap "INT" do @server.shutdown end
84
92
  @server.start
85
93
  end
94
+
95
+ def shutdown
96
+ @server.shutdown
97
+ end
86
98
  end
87
99
  end
data/lib/shuck/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Shuck
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,62 @@
1
+ require 'builder'
2
+ require 'time'
3
+
4
+ module Shuck
5
+ class XmlAdapter
6
+ def self.buckets(buckets)
7
+ output = ""
8
+ xml = Builder::XmlMarkup.new(:target => output)
9
+ xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
10
+ xml.ListAllMyBucketsResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lam|
11
+ lam.Owner { |owner|
12
+ owner.ID("123")
13
+ owner.DisplayName("Shuck")
14
+ }
15
+ lam.Buckets { |buckets|
16
+ @buckets.each do |bucket|
17
+ buckets.Bucket do |b|
18
+ b.Name(bucket.name)
19
+ b.CreationDate(bucket.creation_date.xmlschema)
20
+ end
21
+ end
22
+ }
23
+ }
24
+ output
25
+ end
26
+
27
+ # <?xml version="1.0" encoding="UTF-8"?>
28
+ #<Error>
29
+ # <Code>NoSuchKey</Code>
30
+ # <Message>The resource you requested does not exist</Message>
31
+ # <Resource>/mybucket/myfoto.jpg</Resource>
32
+ # <RequestId>4442587FB7D0A2F9</RequestId>
33
+ #</Error>
34
+ def self.error_no_such_bucket(name)
35
+ output = ""
36
+ xml = Builder::XmlMarkup.new(:target => output)
37
+ xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
38
+ xml.Error { |err|
39
+ err.Code("NoSuchBucket")
40
+ err.Message("The resource you requested does not exist")
41
+ err.Resource(name)
42
+ err.RequestId(1)
43
+ }
44
+ output
45
+ end
46
+
47
+ def self.bucket(bucket)
48
+ output = ""
49
+ xml = Builder::XmlMarkup.new(:target => output)
50
+ xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
51
+ xml.ListBucketResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lbr|
52
+ lbr.Name(bucket.name)
53
+ lbr.Prefix
54
+ lbr.Marker
55
+ lbr.MaxKeys("1000")
56
+ lbr.IsTruncated("false")
57
+ }
58
+ output
59
+ end
60
+
61
+ end
62
+ end
data/lib/shuck.rb CHANGED
@@ -1,5 +1,3 @@
1
1
  require 'shuck/version'
2
+ require 'shuck/file_store'
2
3
  require 'shuck/server'
3
- module Shuck
4
- # Your code goes here...
5
- end
data/shuck.gemspec CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.add_development_dependency "bundler", ">= 1.0.0"
18
18
  s.add_development_dependency "ruby-debug19"
19
+ s.add_development_dependency "aws-s3"
19
20
  s.add_dependency "thor"
20
21
  s.add_dependency "builder"
21
22
 
@@ -0,0 +1,58 @@
1
+ require 'test/test_helper'
2
+ require 'fileutils'
3
+ require 'shuck/server'
4
+ require 'aws/s3'
5
+
6
+ class S3CommandsTest < Test::Unit::TestCase
7
+ include AWS::S3
8
+
9
+ def setup
10
+ AWS::S3::Base.establish_connection!(:access_key_id => "123", :secret_access_key => "abc", :server => "localhost", :port => "10453" )
11
+ end
12
+
13
+ def teardown
14
+ AWS::S3::Base.disconnect!
15
+ end
16
+
17
+ def test_create_bucket
18
+ bucket = Bucket.create("mybucket")
19
+ assert_not_nil bucket
20
+ end
21
+
22
+ def test_store
23
+ bucket = Bucket.create("mybucket")
24
+ S3Object.store("hello","world","mybucket")
25
+
26
+ output = ""
27
+ obj = S3Object.stream("hello","mybucket") do |chunk|
28
+ output << chunk
29
+ end
30
+ assert_equal "world", output
31
+ end
32
+
33
+ def test_large_store
34
+ bucket = Bucket.create("mybucket")
35
+ buffer = ""
36
+ 500000.times do
37
+ buffer << "#{(rand * 100).to_i}"
38
+ end
39
+
40
+ buf_len = buffer.length
41
+ S3Object.store("big",buffer,"mybucket")
42
+
43
+ output = ""
44
+ S3Object.stream("big","mybucket") do |chunk|
45
+ output << chunk
46
+ end
47
+ assert_equal buf_len,output.size
48
+ end
49
+
50
+ def test_find_nil_bucket
51
+ begin
52
+ bucket = Bucket.find("unknown")
53
+ assert_fail "Bucket.find didn't throw an exception"
54
+ rescue
55
+ assert_equal AWS::S3::NoSuchBucket,$!.class
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'bundler/setup'
3
+
4
+ testdir = File.dirname(__FILE__)
5
+ $LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
6
+
7
+ libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
8
+ $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Curtis Spencer
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-19 00:00:00 -08:00
17
+ date: 2010-11-23 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -46,7 +46,7 @@ dependencies:
46
46
  type: :development
47
47
  version_requirements: *id002
48
48
  - !ruby/object:Gem::Dependency
49
- name: thor
49
+ name: aws-s3
50
50
  prerelease: false
51
51
  requirement: &id003 !ruby/object:Gem::Requirement
52
52
  none: false
@@ -56,10 +56,10 @@ dependencies:
56
56
  segments:
57
57
  - 0
58
58
  version: "0"
59
- type: :runtime
59
+ type: :development
60
60
  version_requirements: *id003
61
61
  - !ruby/object:Gem::Dependency
62
- name: builder
62
+ name: thor
63
63
  prerelease: false
64
64
  requirement: &id004 !ruby/object:Gem::Requirement
65
65
  none: false
@@ -71,6 +71,19 @@ dependencies:
71
71
  version: "0"
72
72
  type: :runtime
73
73
  version_requirements: *id004
74
+ - !ruby/object:Gem::Dependency
75
+ name: builder
76
+ prerelease: false
77
+ requirement: &id005 !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ type: :runtime
86
+ version_requirements: *id005
74
87
  description: Use Shuck to test basic S3 functionality without actually connecting to S3
75
88
  email:
76
89
  - curtis@sevenforge.com
@@ -87,11 +100,16 @@ files:
87
100
  - Rakefile
88
101
  - bin/shuck
89
102
  - lib/shuck.rb
103
+ - lib/shuck/bucket.rb
90
104
  - lib/shuck/cli.rb
105
+ - lib/shuck/file_store.rb
106
+ - lib/shuck/s3_object.rb
91
107
  - lib/shuck/server.rb
92
- - lib/shuck/store.rb
93
108
  - lib/shuck/version.rb
109
+ - lib/shuck/xml_adapter.rb
94
110
  - shuck.gemspec
111
+ - test/s3_commands_test.rb
112
+ - test/test_helper.rb
95
113
  has_rdoc: true
96
114
  homepage: ""
97
115
  licenses: []
@@ -124,5 +142,6 @@ rubygems_version: 1.3.7
124
142
  signing_key:
125
143
  specification_version: 3
126
144
  summary: Shuck is a phony S3 engine with minimal dependencies
127
- test_files: []
128
-
145
+ test_files:
146
+ - test/s3_commands_test.rb
147
+ - test/test_helper.rb
data/lib/shuck/store.rb DELETED
@@ -1,76 +0,0 @@
1
- require 'builder'
2
- require 'fileutils'
3
- require 'time'
4
-
5
- module Shuck
6
- class Store
7
- def initialize(root)
8
- @root = root
9
- @buckets = []
10
- Dir[File.join(root,"*")].each do |bucket|
11
- @buckets << File.basename(bucket)
12
- end
13
- end
14
-
15
- def buckets
16
- output = ""
17
- xml = Builder::XmlMarkup.new(:target => output)
18
- xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
19
- xml.ListAllMyBucketsResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lam|
20
- lam.Owner { |owner|
21
- owner.ID("123")
22
- owner.DisplayName("Curtis Spencer")
23
- }
24
- lam.Buckets { |buckets|
25
- @buckets.each do |bucket|
26
- buckets.Bucket do |b|
27
- b.Name(bucket)
28
- b.CreationDate(Time.now.xmlschema)
29
- end
30
- end
31
- }
32
- }
33
- output
34
- end
35
-
36
- def get_bucket(bucket)
37
- output = ""
38
- xml = Builder::XmlMarkup.new(:target => output)
39
- xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
40
- xml.ListBucketResult(:xmlns => "http://s3.amazonaws.com/doc/2006-03-01/") { |lbr|
41
- lbr.Name(bucket)
42
- lbr.Prefix
43
- lbr.Marker
44
- lbr.MaxKeys("1000")
45
- lbr.IsTruncated("false")
46
- }
47
- output
48
- end
49
-
50
- def create_bucket(bucket)
51
- FileUtils.mkdir_p(File.join(@root,bucket))
52
- end
53
-
54
- def get_object(bucket,object)
55
- begin
56
- io = File.open(File.join(@root,bucket,object),'rb')
57
- return io
58
- rescue
59
- puts $!
60
- return nil
61
- end
62
- end
63
-
64
- def store_object(bucket,object,request)
65
- begin
66
- File.open(File.join(@root,bucket,object),'w') do |f|
67
- request.body do |chunk|
68
- f << chunk
69
- end
70
- end
71
- rescue
72
- puts $!
73
- end
74
- end
75
- end
76
- end