mingle-storage 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.
- checksums.yaml +15 -0
- data/lib/storage/filesystem_store.rb +47 -0
- data/lib/storage/s3_store.rb +105 -0
- data/lib/storage.rb +124 -0
- metadata +60 -0
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: []
|