shuck 0.0.1 → 0.0.2

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