mingle-storage 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTliODIxMzIzMDNmMTYzOTNmNmZiOWEyYTY5YmEwMTUwNDVkZjAyMg==
5
+ data.tar.gz: !binary |-
6
+ M2UzMGQ5MjNkNTE0MDk0YmIwZmY3Njc3OWU4ZTVlM2U0NDdmNzhlMA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTdjNGFkYjEzODllMzFlNGUyZWM4YzA4ZmJjMDljNmI3MGY5MTYzY2M3NDA1
10
+ MTNkYTFmZTMyMjY4ZjkzMWNiNGEwYTY2NzY3Y2UyM2QyNzdhYmU3MmZkNjNk
11
+ NzUzZTczZmNmYmZhZWNjNTQ0Nzk5NTI0NjhkMzMzMThiYmI0MzQ=
12
+ data.tar.gz: !binary |-
13
+ OTZkYTEwMzYyZjMwOTZmOGEwYTg1MjgwNzJkMTJiYWY3ZjNhMmI1NTgxMDU2
14
+ YTQxZjBlMTNkOTk5NWMwMzI3OWJhM2JhMGY2ZmY0Y2NkMmIzMjZjMmE4OTYx
15
+ Njg5YzJlYTQyMWNjYTg0NWFkMDA4ZTYwMDVkYmJmMDI0MmM2ODk=
@@ -0,0 +1,47 @@
1
+ module Storage
2
+ class FilesystemStore
3
+ def initialize(path_prefix, options={})
4
+ @dir = options[:root_path] || raise('Must define root path for file system store')
5
+ @path_prefix = path_prefix
6
+ FileUtils.mkdir_p File.join(@dir, @path_prefix)
7
+ end
8
+
9
+ def copy(path, to_local_path)
10
+ raise "File(#{path}) does not exist" unless File.exists?(absolute_path(path))
11
+ FileUtils.cp(absolute_path(path), to_local_path)
12
+ end
13
+
14
+ def read(path)
15
+ File.read(absolute_path(path))
16
+ end
17
+
18
+ def upload(path, local_file)
19
+ FileUtils.mkdir_p(absolute_path(path))
20
+ FileUtils.mv(local_file, absolute_path(path))
21
+ end
22
+
23
+ def upload_dir(path, local_dir)
24
+ FileUtils.rm_rf(absolute_path(path))
25
+ Dir[File.join(local_dir, "*")].each do |f|
26
+ upload(path, f)
27
+ end
28
+ end
29
+
30
+ #todo: this should be interface that retrive a lazy file object
31
+ def absolute_path(*relative_paths)
32
+ File.join(@dir, @path_prefix, *relative_paths)
33
+ end
34
+
35
+ def exists?(path)
36
+ File.exists?(absolute_path(path))
37
+ end
38
+
39
+ def delete(path)
40
+ FileUtils.rm_rf(absolute_path(path))
41
+ end
42
+
43
+ def clear
44
+ FileUtils.rm_rf File.join(@dir, @path_prefix)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,105 @@
1
+ module Storage
2
+ class S3Store
3
+
4
+ HALF_AN_HOUR = 30 * 60
5
+
6
+ def initialize(path_prefix, options)
7
+ @path_prefix = path_prefix
8
+ @url_expires = options[:url_expires] || HALF_AN_HOUR
9
+ @bucket_name = options[:bucket_name]
10
+ end
11
+
12
+ def upload(path, local_file)
13
+ local_file_name = File.basename(local_file)
14
+ bucket.objects.create(
15
+ s3_path(path, local_file_name),
16
+ File.read(local_file),
17
+ { :content_type => derive_content_type(local_file_name) }
18
+ )
19
+ end
20
+
21
+ def upload_dir(path, local_dir)
22
+ bucket.objects.with_prefix(s3_path(path)).delete_all
23
+ Dir[File.join(local_dir, "*")].each do |f|
24
+ upload(path, f)
25
+ end
26
+ end
27
+
28
+ def content_type(path)
29
+ object(path).content_type
30
+ end
31
+
32
+ def copy(path, to_local_path)
33
+ obj = object(path)
34
+ raise "File(#{path}) does not exist in the bucket #{bucket.name}" unless obj.exists?
35
+ File.open(to_local_path, 'w') do |f|
36
+ obj.read do |c|
37
+ f.write(c)
38
+ end
39
+ end
40
+ end
41
+
42
+ def write_to_file(path, content)
43
+ object(path).write(content)
44
+ end
45
+
46
+ def read(path)
47
+ object(path).read
48
+ end
49
+
50
+ def exists?(path)
51
+ object(path).exists?
52
+ end
53
+
54
+ def url_for(path)
55
+ object(path).url_for(:read, :expires => @url_expires).to_s
56
+ end
57
+
58
+ #todo: this should be interface that retrive a lazy file object
59
+ def absolute_path(*relative_paths)
60
+ File.join("s3:#{bucket_name}://", *relative_paths)
61
+ end
62
+
63
+ def delete(path)
64
+ bucket.objects.with_prefix(s3_path(path)).delete_all
65
+ end
66
+
67
+ def clear
68
+ if s3_path.blank?
69
+ bucket.clear
70
+ else
71
+ bucket.objects.with_prefix(s3_path).delete_all
72
+ end
73
+ end
74
+
75
+ def objects(path)
76
+ bucket.objects.with_prefix(s3_path(path))
77
+ end
78
+
79
+ private
80
+ def derive_content_type(file_name)
81
+ file_extension = file_name.split(".").last
82
+ Storage::CONTENT_TYPES[file_extension]
83
+ end
84
+
85
+ def s3
86
+ AWS::S3.new
87
+ end
88
+
89
+ def object(path)
90
+ bucket.objects[s3_path(path)]
91
+ end
92
+
93
+ def s3_path(*paths)
94
+ File.join(*([@path_prefix, *paths].compact))
95
+ end
96
+
97
+ def bucket
98
+ @bucket ||= s3.buckets[bucket_name]
99
+ end
100
+
101
+ def bucket_name
102
+ @bucket_name.is_a?(String) ? @bucket_name : @bucket_name[@path_prefix]
103
+ end
104
+ end
105
+ end
data/lib/storage.rb ADDED
@@ -0,0 +1,124 @@
1
+ require 'rubygems'
2
+ require 'aws-sdk'
3
+ require 'storage/filesystem_store.rb'
4
+ require 'storage/s3_store.rb'
5
+
6
+ module Storage
7
+
8
+ CONTENT_TYPES = {
9
+ "html" => "text/html",
10
+ "htm" => "text/html",
11
+ "shtml" => "text/html",
12
+ "css" => "text/css",
13
+ "xml" => "text/xml",
14
+ "gif" => "image/gif",
15
+ "jpeg" => "image/jpeg",
16
+ "jpg" => "image/jpeg",
17
+ "js" => "application/x-javascript",
18
+ "atom" => "application/atom+xml",
19
+ "rss" => "application/rss+xml",
20
+ "json" => "application/json",
21
+ "mml" => "text/mathml",
22
+ "txt" => "text/plain",
23
+ "jad" => "text/vnd.sun.j2me.app-descriptor",
24
+ "wml" => "text/vnd.wap.wml",
25
+ "htc" => "text/x-component",
26
+ "png" => "image/png",
27
+ "tif" => "image/tiff",
28
+ "tiff" => "image/tiff",
29
+ "wbmp" => "image/vnd.wap.wbmp",
30
+ "ico" => "image/x-icon",
31
+ "jng" => "image/x-jng",
32
+ "bmp" => "image/x-ms-bmp",
33
+ "svg" => "image/svg+xml",
34
+ "jar" => "application/java-archive",
35
+ "war" => "application/java-archive",
36
+ "ear" => "application/java-archive",
37
+ "hqx" => "application/mac-binhex40",
38
+ "doc" => "application/msword",
39
+ "pdf" => "application/pdf",
40
+ "ps" => "application/postscript",
41
+ "eps" => "application/postscript",
42
+ "ai" => "application/postscript",
43
+ "rtf" => "application/rtf",
44
+ "xls" => "application/vnd.ms-excel",
45
+ "ppt" => "application/vnd.ms-powerpoint",
46
+ "wmlc" => "application/vnd.wap.wmlc",
47
+ "xhtml" => "application/vnd.wap.xhtml+xml",
48
+ "kml" => "application/vnd.google-earth.kml+xml",
49
+ "kmz" => "application/vnd.google-earth.kmz",
50
+ "7z" => "application/x-7z-compressed",
51
+ "cco" => "application/x-cocoa",
52
+ "jardiff" => "application/x-java-archive-diff",
53
+ "jnlp" => "application/x-java-jnlp-file",
54
+ "run" => "application/x-makeself",
55
+ "pl" => "application/x-perl",
56
+ "pm" => "application/x-perl",
57
+ "prc" => "application/x-pilot",
58
+ "pdb" => "application/x-pilot",
59
+ "rar" => "application/x-rar-compressed",
60
+ "rpm" => "application/x-redhat-package-manager",
61
+ "sea" => "application/x-sea",
62
+ "swf" => "application/x-shockwave-flash",
63
+ "sit" => "application/x-stuffit",
64
+ "tcl" => "application/x-tcl",
65
+ "tk" => "application/x-tcl",
66
+ "der" => "application/x-x509-ca-cert",
67
+ "pem" => "application/x-x509-ca-cert",
68
+ "crt" => "application/x-x509-ca-cert",
69
+ "xpi" => "application/x-xpinstall",
70
+ "zip" => "application/zip",
71
+ "bin" => "application/octet-stream",
72
+ "exe" => "application/octet-stream",
73
+ "dll" => "application/octet-stream",
74
+ "deb" => "application/octet-stream",
75
+ "dmg" => "application/octet-stream",
76
+ "eot" => "application/octet-stream",
77
+ "iso" => "application/octet-stream",
78
+ "img" => "application/octet-stream",
79
+ "msi" => "application/octet-stream",
80
+ "msp" => "application/octet-stream",
81
+ "msm" => "application/octet-stream",
82
+ "mid" => "audio/midi",
83
+ "midi" => "audio/midi",
84
+ "kar" => "audio/midi",
85
+ "mp3" => "audio/mpeg",
86
+ "ra" => "audio/x-realaudio",
87
+ "3gpp" => "video/3gpp",
88
+ "3gp" => "video/3gpp",
89
+ "mpeg" => "video/mpeg",
90
+ "mpg" => "video/mpeg",
91
+ "mov" => "video/quicktime",
92
+ "flv" => "video/x-flv",
93
+ "mng" => "video/x-mng",
94
+ "asx" => "video/x-ms-asf",
95
+ "asf" => "video/x-ms-asf",
96
+ "wmv" => "video/x-ms-wmv",
97
+ "avi" => "video/x-msvideo"
98
+ }
99
+
100
+ class Builder
101
+ def initialize(type)
102
+ @type = type
103
+ end
104
+
105
+ def build(path_prefix, options={})
106
+ store_class.new(path_prefix, options)
107
+ end
108
+
109
+ private
110
+
111
+ def store_class
112
+ {
113
+ :filesystem => Storage::FilesystemStore,
114
+ :s3 => Storage::S3Store
115
+ }[@type.to_sym]
116
+ end
117
+ end
118
+
119
+ def self.store(type, path_prefix, options={})
120
+ builder = Builder.new(type)
121
+ builder.build(path_prefix, options)
122
+ end
123
+
124
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mingle-storage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - ThoughtWorks Studios
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-16 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: 1.11.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.11.3
27
+ description: Mingle storage API to support filesystem and AWS S3 backed storage
28
+ email: mingle-dev@thoughtworks.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/storage/filesystem_store.rb
34
+ - lib/storage/s3_store.rb
35
+ - lib/storage.rb
36
+ homepage: http://www.thoughtworks.com/products
37
+ licenses:
38
+ - MIT
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.0.7
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Mingle storage API to support filesystem and AWS S3 backed storage
60
+ test_files: []