thingfish-datastore-filesystem 0.0.1.pre20161103180658

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1498d5b69c1f4f510fb607cf14dc1ff35bd348a9
4
+ data.tar.gz: 29f913e3d212e727e05f0331701ec72629274ae8
5
+ SHA512:
6
+ metadata.gz: a64ee9f2af6c380c5c0351c2519fea01d270782c02d6c58ed108dfa099f6f019a76c44405e854db62daf47ee8aceda76a51c4944d66eee0f36b0591f97a8ca0a
7
+ data.tar.gz: e28eab9773d645bbffe9f2923fa9f5fc6abf3d7b132f2de21597b9f3ccf9d87ea25af6c90ce5abccf44526575a93c61b923d77b84dc23b425ef13caa2a1e94d7
checksums.yaml.gz.sig ADDED
Binary file
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ README.rdoc
3
+ ChangeLog.rdoc
4
+ LICENSE.txt
data/.simplecov ADDED
@@ -0,0 +1,9 @@
1
+ # Simplecov config
2
+
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ add_filter 'integration'
6
+ add_group "Needing tests" do |file|
7
+ file.covered_percent < 90
8
+ end
9
+ end
data/ChangeLog ADDED
@@ -0,0 +1,49 @@
1
+ 2015-11-02 Mahlon E. Smith <mahlon@martini.nu>
2
+
3
+ * LICENSE.rdoc, Manifest.txt, README.rdoc, Rakefile,
4
+ lib/thingfish/datastore/filesystem.rb:
5
+ Fix LICENSE file, ensure mode set on new directory creations.
6
+ [fa2c52af871c] [tip]
7
+
8
+ 2015-04-01 Mahlon E. Smith <mahlon@martini.nu>
9
+
10
+ * .gems, .rvm.gems, .rvmrc:
11
+ Bump development default ruby version, rename rvm gems file.
12
+ [3ed2e70a625b]
13
+
14
+ 2015-01-28 Michael Granger <ged@FaerieMUD.org>
15
+
16
+ * Rakefile, spec/thingfish/datastore/filesystem_spec.rb:
17
+ Convert specs to use the filesystem shared behavior.
18
+ [f21f6149df51]
19
+
20
+ 2014-12-22 Michael Granger <ged@FaerieMUD.org>
21
+
22
+ * .rvm.gems, ChangeLog, Rakefile,
23
+ lib/thingfish/datastore/filesystem.rb, spec/helpers.rb,
24
+ spec/thingfish/datastore/filesystem_spec.rb:
25
+ Finished up the initial implementation.
26
+ [23167299ded2]
27
+
28
+ 2014-12-10 Mahlon E. Smith <mahlon@martini.nu>
29
+
30
+ * README.rdoc:
31
+ First pass at a useful README.
32
+ [d5f1b3a85784]
33
+
34
+ 2014-12-03 Michael Granger <ged@FaerieMUD.org>
35
+
36
+ * .rvm.gems, .rvmrc, ChangeLog, Manifest.txt, Rakefile,
37
+ lib/thingfish/datastore/filesystem.rb, spec/helpers.rb,
38
+ spec/thingfish/datastore/filesystem_spec.rb:
39
+ Checkpoint of Commit! work
40
+ [c3c1d5b25633]
41
+
42
+ 2014-12-01 Michael Granger <ged@FaerieMUD.org>
43
+
44
+ * .document, .gitignore, .hgignore, .pryrc, .rvm.gems, .rvmrc,
45
+ .simplecov, History.rdoc, LICENSE.rdoc, README.rdoc, Rakefile,
46
+ lib/thingfish/datastore/filesystem.rb, spec/helpers.rb,
47
+ spec/thingfish/datastore/filesystem_spec.rb:
48
+ Started work
49
+ [d1f307e087fd]
data/History.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ == v0.0.1 [YYYY-MM-DD] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Initial release.
4
+
data/LICENSE.rdoc ADDED
@@ -0,0 +1,29 @@
1
+ Copyright (c) 2014-2015, Michael Granger and Mahlon E. Smith.
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are
6
+ permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice, this
12
+ list of conditions and the following disclaimer in the documentation and/or
13
+ other materials provided with the distribution.
14
+
15
+ * Neither the name of the authors, nor the names of its contributors may be used to
16
+ endorse or promote products derived from this software without specific prior
17
+ written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ .document
2
+ .simplecov
3
+ ChangeLog
4
+ History.rdoc
5
+ LICENSE.rdoc
6
+ Manifest.txt
7
+ README.rdoc
8
+ Rakefile
9
+ lib/thingfish/datastore/filesystem.rb
10
+ spec/helpers.rb
11
+ spec/thingfish/datastore/filesystem_spec.rb
data/README.rdoc ADDED
@@ -0,0 +1,138 @@
1
+ = Thingfish Filesystem Datastore
2
+
3
+ * http://bitbucket.org/ged/thingfish-datastore-filesystem
4
+
5
+
6
+ == Description
7
+
8
+ This is a data storage plugin for the Thingfish digital asset manager.
9
+ It provides persistent storage for uploaded data to a simple filesystem
10
+ path.
11
+
12
+
13
+ == Authors
14
+
15
+ * Michael Granger <ged@FaerieMUD.org>
16
+ * Mahlon E. Smith <mahlon@martini.nu>
17
+
18
+
19
+ == Installation
20
+
21
+ $ gem install thingfish-datastore-filesystem
22
+
23
+
24
+ == Basic Usage
25
+
26
+ By default, data will be stored in a 'thingfish' directory, underneath
27
+ your system's tmpdir. (For most systems, this will be /tmp/thingfish.)
28
+ This directory will need to exist before starting the Thingfish handler.
29
+
30
+ As with Thingfish itself, this plugin uses
31
+ Configurability[https://rubygems.org/gems/configurability] to modify
32
+ default behaviors.
33
+
34
+ Here's an example configuration file that enables this plugin and
35
+ modifies the default storage path:
36
+
37
+ ---
38
+ thingfish:
39
+ datastore: filesystem
40
+
41
+ filesystem_datastore:
42
+ root_path: /net/storage/thingfish-data
43
+
44
+
45
+ == Advanced Usage
46
+
47
+ This plugin can utilize various advanced features of the Mongrel2 daemon
48
+ that can offload large data transfers to the Mongrel2 daemon directly.
49
+ This frees the Thingfish handler(s) up for servicing new requests
50
+ quickly, and dramatically improves performance for concurrent data
51
+ transfers and large files.
52
+
53
+ === Assumptions
54
+
55
+ Because of Mongrel2's flexible architecture, you could equally run
56
+ everything under a single machine, or scale Thingfish out as a farm,
57
+ spanning hundreds of handlers across individual nodes, all with the same
58
+ configuration. In any case, Your Thingfish handlers need access to the
59
+ same physical storage device(s) that the Mongrel2 daemon does.
60
+
61
+ How you accomplish this is entirely up to you, though NFS is a likely
62
+ choice. There are two directories that the Mongrel2 server and the
63
+ Thingfish handlers will need access to -- one for downloads (this
64
+ plugin's 'root_path' directory), and one for uploads (the Mongrel2 async
65
+ spool directory.)
66
+
67
+
68
+ === Downloads
69
+
70
+ To enable this functionality for downloads, you'll need to add the
71
+ 'sendfile' filter in your Mongrel2 server configuration. The path to
72
+ this library will vary, depending on where Mongrel2 was installed on
73
+ your system -- but it should look like something that resembles:
74
+
75
+ xrequest '/usr/local/lib/mongrel2/filters/sendfile.so'
76
+
77
+ That filter is automatically built alongside Mongrel2, it just needs to
78
+ be switched on. Ensure the 'root_path' is accessible from the Thingfish
79
+ handler(s) and the Mongrel2 daemon.
80
+
81
+
82
+ === Uploads
83
+
84
+ Uploads also require altering Mongrel2 server settings:
85
+
86
+ setting 'limits.content_length', 65536
87
+
88
+ This switches on async uploads, for any upload larger than 64k.
89
+ Anything under 64k is kept in RAM, and handled internally by the
90
+ Thingfish handler. Adjust to taste.
91
+
92
+ setting 'upload.temp_store', '/network/storage/mongrel2.upload.XXXXXXX'
93
+
94
+ For files larger than 'limits.content_length' size, asynchronously
95
+ spool the upload to this location. When the file upload has completed,
96
+ Mongrel2 notifies Thingfish, and the spooled upload is properly stored.
97
+ This path must be accessible from the Thingfish handler(s) and the
98
+ Mongrel2 daemon.
99
+
100
+ setting 'upload.temp_store_mode', '0600'
101
+
102
+ While this is not required, it is recommended to spool files so they
103
+ are readable only to the Mongrel2 process. It is your responsibility
104
+ to ensure the user account running the Thingfish handler also has
105
+ read/write access to these files.
106
+
107
+
108
+ == License
109
+
110
+ Copyright (c) 2014-2016, Michael Granger and Mahlon E. Smith
111
+ All rights reserved.
112
+
113
+ Redistribution and use in source and binary forms, with or without
114
+ modification, are permitted provided that the following conditions are met:
115
+
116
+ * Redistributions of source code must retain the above copyright notice,
117
+ this list of conditions and the following disclaimer.
118
+
119
+ * Redistributions in binary form must reproduce the above copyright notice,
120
+ this list of conditions and the following disclaimer in the documentation
121
+ and/or other materials provided with the distribution.
122
+
123
+ * Neither the name of the author/s, nor the names of the project's
124
+ contributors may be used to endorse or promote products derived from this
125
+ software without specific prior written permission.
126
+
127
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
128
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
129
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
130
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
131
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
132
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
133
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
134
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
135
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
136
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137
+
138
+
data/Rakefile ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env rake
2
+
3
+ begin
4
+ require 'hoe'
5
+ rescue LoadError
6
+ abort "This Rakefile requires hoe (gem install hoe)"
7
+ end
8
+
9
+ GEMSPEC = 'thingfish-datastore-filesystem.gemspec'
10
+
11
+
12
+ Hoe.plugin :mercurial
13
+ Hoe.plugin :signing
14
+ Hoe.plugin :deveiate
15
+ Hoe.plugin :bundler
16
+
17
+ Hoe.plugins.delete :rubyforge
18
+ Hoe.plugins.delete :gemcutter
19
+
20
+ hoespec = Hoe.spec 'thingfish-datastore-filesystem' do |spec|
21
+ spec.readme_file = 'README.rdoc'
22
+ spec.history_file = 'History.rdoc'
23
+ spec.extra_rdoc_files = FileList[ '*.rdoc' ]
24
+ spec.license 'BSD'
25
+
26
+ if File.directory?( '.hg' )
27
+ spec.spec_extras[:rdoc_options] = ['-f', 'fivefish', '-t', 'Thingfish-Datastore-FileSystem']
28
+ end
29
+
30
+ spec.developer 'Michael Granger', 'ged@FaerieMUD.org'
31
+ spec.developer 'Mahlon E. Smith', 'mahlon@martini.nu'
32
+
33
+ spec.dependency 'thingfish', '~> 0.5'
34
+ spec.dependency 'configurability', '~> 2.2'
35
+
36
+ spec.dependency 'rspec', '~> 3.1', :developer
37
+ spec.dependency 'simplecov', '~> 0.9', :developer
38
+
39
+ spec.require_ruby_version( '>=2.0.0' )
40
+ spec.hg_sign_tags = true if spec.respond_to?( :hg_sign_tags= )
41
+
42
+ self.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}"
43
+ end
44
+
45
+
46
+ ENV['VERSION'] ||= hoespec.spec.version.to_s
47
+
48
+ # Run the tests before checking in
49
+ task 'hg:precheckin' => [ :check_history, :check_manifest, :spec ]
50
+
51
+ # Rebuild the ChangeLog immediately before release
52
+ task :prerelease => 'ChangeLog'
53
+ CLOBBER.include( 'ChangeLog' )
54
+
55
+ desc "Build a coverage report"
56
+ task :coverage do
57
+ ENV["COVERAGE"] = 'yes'
58
+ Rake::Task[:spec].invoke
59
+ end
60
+
61
+
62
+ task :gemspec => GEMSPEC
63
+ file GEMSPEC => __FILE__ do |task|
64
+ spec = $hoespec.spec
65
+ spec.files.delete( '.gemtest' )
66
+ spec.signing_key = nil
67
+ spec.version = "#{spec.version}.pre#{Time.now.strftime("%Y%m%d%H%M%S")}"
68
+ File.open( task.name, 'w' ) do |fh|
69
+ fh.write( spec.to_ruby )
70
+ end
71
+ end
72
+
73
+ task :default => :gemspec
74
+
@@ -0,0 +1,186 @@
1
+ # -*- ruby -*-
2
+ #encoding: utf-8
3
+
4
+ require 'fileutils'
5
+ require 'tmpdir'
6
+ require 'configurability'
7
+ require 'thingfish/datastore'
8
+ require 'strelka/mixins'
9
+
10
+
11
+ # A hashed-directory hierarchy filesystem datastore for Thingfish
12
+ class Thingfish::Datastore::Filesystem < Thingfish::Datastore
13
+ extend Configurability,
14
+ Loggability,
15
+ Strelka::MethodUtilities,
16
+ Thingfish::Normalization
17
+
18
+ # Package version
19
+ VERSION = '0.0.1'
20
+
21
+ # Version control revision
22
+ REVISION = %q$Revision: d5b8afa4a502 $
23
+
24
+ # The number of subdirectories to use in the hashed directory tree. Must be 2, 4, or 8
25
+ HASH_DEPTH = 4
26
+
27
+ # Configurability API -- default configuration
28
+ DEFAULT_CONFIG = {
29
+ root_path: Pathname( Dir.tmpdir ) + 'thingfish',
30
+ }
31
+
32
+
33
+ # Loggability API -- log to the thingfish logger
34
+ log_to :thingfish
35
+
36
+ ##
37
+ # The directory to use for the datastore
38
+ singleton_attr_accessor :root_path
39
+ @root_path = DEFAULT_CONFIG[ :root_path ]
40
+
41
+
42
+ # Configurability API -- the section of the config to use
43
+ config_key :filesystem_datastore
44
+
45
+
46
+ ### Configurability API -- configure the filesystem datastore.
47
+ def self::configure( config=nil )
48
+ config = self.defaults.merge( config || {} )
49
+
50
+ self.root_path = Pathname( config[:root_path] )
51
+ raise ArgumentError, "root path %s does not exist" % [ self.root_path ] unless
52
+ self.root_path.exist?
53
+ end
54
+
55
+
56
+ ### Create a new Filesystem Datastore.
57
+ def initialize
58
+ super
59
+ @root_path = self.class.root_path
60
+ end
61
+
62
+
63
+ ######
64
+ public
65
+ ######
66
+
67
+ ##
68
+ # The root path of the datastore
69
+ attr_reader :root_path
70
+
71
+
72
+
73
+ ### Save the +data+ read from the specified +io+ and return an ID that can be
74
+ ### used to fetch it later.
75
+ def save( io )
76
+ oid = make_object_id()
77
+
78
+ pos = io.pos
79
+ self.store( oid, io )
80
+
81
+ return oid
82
+ ensure
83
+ io.pos = pos if pos
84
+ end
85
+
86
+
87
+ ### Fetch the data corresponding to the given +oid+ as an IOish object.
88
+ def fetch( oid )
89
+ return self.retrieve( oid )
90
+ end
91
+
92
+
93
+ ### Returns +true+ if the datastore has a file for the specified +oid+.
94
+ def include?( oid )
95
+ return self.hashed_path( oid ).exist?
96
+ end
97
+
98
+
99
+ ### Remove the data associated with +oid+ from the Datastore.
100
+ def remove( oid )
101
+ return self.hashed_path( oid ).unlink
102
+ end
103
+
104
+
105
+ ### Replace the existing object associated with +oid+ with the data read from the
106
+ ### given +io+.
107
+ def replace( oid, io )
108
+ pos = io.pos
109
+ self.store( oid, io )
110
+
111
+ return true
112
+ ensure
113
+ io.pos = pos if pos
114
+ end
115
+
116
+
117
+
118
+ #########
119
+ protected
120
+ #########
121
+
122
+ ### Move the file behind the specified +io+ into the datastore.
123
+ def store( oid, io )
124
+ storefile = self.hashed_path( oid )
125
+ FileUtils.mkpath( storefile.dirname.to_s, :mode => 0711 )
126
+
127
+ if io.respond_to?( :path )
128
+ self.move_spoolfile( io.path, storefile )
129
+ else
130
+ self.log.debug "Spooling in-memory upload to %s" % [ storefile.to_s ]
131
+ spoolfile = self.spool_to_tempfile( io, storefile )
132
+ self.move_spoolfile( spoolfile, storefile )
133
+ end
134
+ end
135
+
136
+
137
+ ### Look up the file corresponding to the specified +oid+ and return a
138
+ ### File for it.
139
+ def retrieve( oid )
140
+ storefile = self.hashed_path( oid )
141
+ return nil unless storefile.exist?
142
+ return storefile.open( 'r', encoding: 'binary' )
143
+ end
144
+
145
+
146
+ ### Generate a Pathname for the file used to store the data for the
147
+ ### resource with the specified +oid+.
148
+ def hashed_path( oid )
149
+ oid = oid.to_s
150
+
151
+ # Split the first 8 characters of the UUID up into subdirectories, one for
152
+ # each HASH_DEPTH
153
+ chunksize = 8 / HASH_DEPTH
154
+ hashed_dir = 0.step( 7, chunksize ).inject( self.root_path ) do |path, i|
155
+ path + oid[i, chunksize]
156
+ end
157
+
158
+ return hashed_dir + oid
159
+ end
160
+
161
+
162
+ ### Move the file at the specified +source+ path to the +destination+ path using
163
+ ### atomic system calls.
164
+ def move_spoolfile( source, destination )
165
+ self.log.debug "Moving %s to %s" % [ source, destination ]
166
+ FileUtils.move( source.to_s, destination.to_s )
167
+ end
168
+
169
+
170
+ ### Spool the data from the given +io+ to a temporary file based on the
171
+ ### specified +storefile+.
172
+ def spool_to_tempfile( io, storefile )
173
+ io.rewind
174
+
175
+ extension = "-%d.%5f.%s.spool" % [ Process.pid, Time.now.to_f, SecureRandom.hex(6) ]
176
+ spoolfile = storefile.dirname + (storefile.basename.to_s + extension)
177
+ spoolfile.open( IO::EXCL|IO::CREAT|IO::WRONLY, 0600, encoding: 'binary' ) do |fh|
178
+ bytes = IO.copy_stream( io, fh )
179
+ self.log.debug "Copied %d bytes." % [ bytes ]
180
+ end
181
+
182
+ return spoolfile
183
+ end
184
+
185
+ end # module Thingfish::Datastore::Filesystem
186
+
data/spec/helpers.rb ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ BEGIN {
5
+ require 'pathname'
6
+ basedir = Pathname( __FILE__ ).dirname.parent
7
+
8
+ thingfishdir = basedir.parent + 'Thingfish'
9
+ thingfishlib = thingfishdir + 'lib'
10
+
11
+ strelkadir = basedir.parent + 'Strelka'
12
+ strelkalib = strelkadir + 'lib'
13
+
14
+ $LOAD_PATH.unshift( thingfishlib.to_s ) if thingfishlib.exist?
15
+ $LOAD_PATH.unshift( strelkalib.to_s ) if strelkalib.exist?
16
+ }
17
+
18
+
19
+ # SimpleCov test coverage reporting; enable this using the :coverage rake task
20
+ require 'simplecov' if ENV['COVERAGE']
21
+
22
+ require 'loggability'
23
+ require 'loggability/spechelpers'
24
+ require 'configurability'
25
+ require 'configurability/behavior'
26
+
27
+ require 'rspec'
28
+ require 'thingfish'
29
+ require 'thingfish/spechelpers'
30
+
31
+ Loggability.format_with( :color ) if $stdout.tty?
32
+
33
+
34
+ ### Mock with RSpec
35
+ RSpec.configure do |c|
36
+ include Thingfish::SpecHelpers
37
+ include Thingfish::SpecHelpers::Constants
38
+
39
+ c.run_all_when_everything_filtered = true
40
+ c.filter_run :focus
41
+ c.order = 'random'
42
+ c.mock_with( :rspec ) do |mock|
43
+ mock.syntax = :expect
44
+ end
45
+
46
+ c.include( Loggability::SpecHelpers )
47
+ end
48
+
49
+ # vim: set nosta noet ts=4 sw=4:
50
+
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../helpers'
4
+
5
+ require 'fileutils'
6
+ require 'rspec'
7
+
8
+ require 'thingfish/behaviors'
9
+ require 'thingfish/datastore/filesystem'
10
+
11
+
12
+ describe Thingfish::Datastore::Filesystem do
13
+
14
+ before( :each ) do
15
+ @testing_root_path = described_class.defaults[:root_path]
16
+ @testing_root_path.mkpath
17
+ described_class.configure( root_path: @testing_root_path )
18
+ end
19
+
20
+ after( :each ) do
21
+ @testing_root_path.rmtree
22
+ end
23
+
24
+
25
+ let( :test_spoolfile ) { @testing_root_path + 'test_io' }
26
+ let( :file_io ) do
27
+ io = test_spoolfile.open( 'w+' )
28
+ io.print( TEST_PNG_DATA )
29
+ io.rewind
30
+ io
31
+ end
32
+
33
+ let( :string_io ) do
34
+ StringIO.new( TEST_PNG_DATA )
35
+ end
36
+
37
+ let( :store ) { Thingfish::Datastore.create(:filesystem) }
38
+
39
+
40
+ it_behaves_like "a Thingfish datastore"
41
+
42
+
43
+ it "has a default root" do
44
+ expect( described_class.root_path ).to_not be_nil
45
+ end
46
+
47
+
48
+ it "raises an exception if the configured root directory doesn't exist" do
49
+ expect {
50
+ described_class.configure( root_path: '/nonexistent' )
51
+ }.to raise_error( ArgumentError, /root path \/nonexistent does not exist/ )
52
+ end
53
+
54
+
55
+ it "stores an IO with a path by moving it into place" do
56
+ new_uuid = store.save( file_io )
57
+
58
+ rval = store.fetch( new_uuid )
59
+ expect( rval ).to respond_to( :read )
60
+ expect( rval.read ).to eq( TEST_PNG_DATA )
61
+
62
+ expect( test_spoolfile ).to_not exist
63
+ end
64
+
65
+
66
+ it "spools an in-memory file to the datastore directory" do
67
+ io = string_io
68
+ io.seek( 0, IO::SEEK_END )
69
+ pos = io.pos
70
+
71
+ new_uuid = store.save( io )
72
+ rval = store.fetch( new_uuid )
73
+
74
+ expect( io.pos ).to eq( pos )
75
+ expect( rval.read ).to eq( TEST_PNG_DATA )
76
+ expect( test_spoolfile ).to_not exist
77
+ end
78
+
79
+ end
80
+
81
+ # vim: set nosta noet ts=4 sw=4 ft=rspec:
data.tar.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+  mʡ�sm<������T����p�0��\�=�u&�/]�
2
+ �؆�S�[�9 ��Z�$���\,�ޓw�i8�����h�(�Dm�p��?l��� ��6|��J@��r���깻+�����ě�^���R7~ �?=kO��>�W-�S|'�!�=�Ht��=�s��3Sܓ'�6�������x�� G������,~��A�]������>^�Iڼ$i��d�e�wr��i����m�������Jt�6��
metadata ADDED
@@ -0,0 +1,221 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thingfish-datastore-filesystem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre20161103180658
5
+ platform: ruby
6
+ authors:
7
+ - Michael Granger
8
+ - Mahlon E. Smith
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain:
12
+ - |
13
+ -----BEGIN CERTIFICATE-----
14
+ MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MQwwCgYDVQQDDANnZWQx
15
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
16
+ HhcNMTYwODIwMTgxNzQyWhcNMTcwODIwMTgxNzQyWjA+MQwwCgYDVQQDDANnZWQx
17
+ GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
18
+ ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
19
+ 83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
20
+ ENcvWVZS4iUzi4dsYJGY6yEOsXh2CcF46+QevV8iE+UmbkU75V7Dy1JCaUOyizEt
21
+ TH5UHsOtUU7k9TYARt/TgYZKuaoAMZZd5qyVqhF1vV+7/Qzmp89NGflXf2xYP26a
22
+ 4MAX2qqKX/FKXqmFO+AGsbwYTEds1mksBF3fGsFgsQWxftG8GfZQ9+Cyu2+l1eOw
23
+ cZ+lPcg834G9DrqW2zhqUoLr1MTly4pqxYGb7XoDhoR7dd1kFE2a067+DzWC/ADt
24
+ +QkcqWUm5oh1fN0eqr7NsZlVJDulFgdiiYPQiIN7UNsii4Wc9aZqBoGcYfBeQNPZ
25
+ soo/6za/bWajOKUmDhpqvaiRv9EDpVLzuj53uDoukMMwxCMfgb04+ckQ0t2G7wqc
26
+ /D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
27
+ BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
28
+ MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
29
+ YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQAPJzKiT0zBU7kpqe0aS2qb
30
+ FI0PJ4y5I8buU4IZGUD5NEt/N7pZNfOyBxkrZkXhS44Fp+xwBH5ebLbq/WY78Bqd
31
+ db0z6ZgW4LMYMpWFfbXsRbd9TU2f52L8oMAhxOvF7Of5qJMVWuFQ8FPagk2iHrdH
32
+ inYLQagqAF6goWTXgAJCdPd6SNeeSNqA6vlY7CV1Jh5kfNJJ6xu/CVij1GzCLu/5
33
+ DMOr26DBv+qLJRRC/2h34uX71q5QgeOyxvMg+7V3u/Q06DXyQ2VgeeqiwDFFpEH0
34
+ PFkdPO6ZqbTRcLfNH7mFgCBJjsfSjJrn0sPBlYyOXgCoByfZnZyrIMH/UY+lgQqS
35
+ 6Von1VDsfQm0eJh5zYZD64ZF86phSR7mUX3mXItwH04HrZwkWpvgd871DZVR3i1n
36
+ w8aNA5re5+Rt/Vvjxj5AcEnZnZiz5x959NaddQocX32Z1unHw44pzRNUur1GInfW
37
+ p4vpx2kUSFSAGjtCbDGTNV2AH8w9OU4xEmNz8c5lyoA=
38
+ -----END CERTIFICATE-----
39
+ date: 2016-11-04 00:00:00.000000000 Z
40
+ dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: thingfish
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: configurability
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: hoe-mercurial
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: hoe-deveiate
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.8'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.8'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hoe-highline
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.1'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.1'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.9'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rdoc
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '4.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: hoe
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.15'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.15'
167
+ description: |-
168
+ This is a data storage plugin for the Thingfish digital asset manager.
169
+ It provides persistent storage for uploaded data to a simple filesystem
170
+ path.
171
+ email:
172
+ - ged@FaerieMUD.org
173
+ - mahlon@martini.nu
174
+ executables: []
175
+ extensions: []
176
+ extra_rdoc_files:
177
+ - History.rdoc
178
+ - LICENSE.rdoc
179
+ - Manifest.txt
180
+ - README.rdoc
181
+ files:
182
+ - ".document"
183
+ - ".simplecov"
184
+ - ChangeLog
185
+ - History.rdoc
186
+ - LICENSE.rdoc
187
+ - Manifest.txt
188
+ - README.rdoc
189
+ - Rakefile
190
+ - lib/thingfish/datastore/filesystem.rb
191
+ - spec/helpers.rb
192
+ - spec/thingfish/datastore/filesystem_spec.rb
193
+ homepage: http://bitbucket.org/ged/thingfish-datastore-filesystem
194
+ licenses:
195
+ - BSD
196
+ metadata: {}
197
+ post_install_message:
198
+ rdoc_options:
199
+ - "-f"
200
+ - fivefish
201
+ - "-t"
202
+ - Thingfish-Datastore-FileSystem
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: 2.0.0
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">"
213
+ - !ruby/object:Gem::Version
214
+ version: 1.3.1
215
+ requirements: []
216
+ rubyforge_project:
217
+ rubygems_version: 2.5.1
218
+ signing_key:
219
+ specification_version: 4
220
+ summary: This is a data storage plugin for the Thingfish digital asset manager
221
+ test_files: []
metadata.gz.sig ADDED
Binary file