dshelf 0.1
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/lib/dshelf.rb +49 -0
- data/lib/dshelf/dfile.rb +111 -0
- data/lib/dshelf/dir.rb +67 -0
- data/lib/dshelf/file.rb +82 -0
- data/lib/dshelf/stat.rb +112 -0
- metadata +119 -0
data/lib/dshelf.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module DistributedShelf
|
2
|
+
VERSION = '0.1'
|
3
|
+
|
4
|
+
@@config = {}
|
5
|
+
|
6
|
+
def override_class_method method, &b
|
7
|
+
(class << self; self; end).class_eval do
|
8
|
+
alias_method "_#{method.to_s}".to_sym, method
|
9
|
+
define_method method, &b
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def distributed? file
|
14
|
+
@@config[:distributed_path] and not File.absolute_path(file).match(@@config[:distributed_path]).nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def proxy_method(method, &b)
|
18
|
+
old_method = :"_#{method}"
|
19
|
+
override_class_method(method) do |*args, &bl|
|
20
|
+
if distributed? args[0]
|
21
|
+
b.call(*args, &bl)
|
22
|
+
else
|
23
|
+
self.send(old_method, *args, &bl)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.config= conf
|
29
|
+
@@config = conf
|
30
|
+
@@config[:distributed_path] == Regexp.new('^' + @@config[:distributed_path] + '/')
|
31
|
+
end
|
32
|
+
|
33
|
+
def server_url
|
34
|
+
@@config[:storage_url]
|
35
|
+
end
|
36
|
+
|
37
|
+
def absolutepath
|
38
|
+
File.expand_path path, Dir.pwd
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
43
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
44
|
+
|
45
|
+
require 'dshelf/dir'
|
46
|
+
require 'dshelf/dfile'
|
47
|
+
require 'dshelf/file'
|
48
|
+
require 'dshelf/stat'
|
49
|
+
|
data/lib/dshelf/dfile.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
class DistributedFile
|
5
|
+
include DistributedShelf
|
6
|
+
|
7
|
+
# "r" | Read-only, starts at beginning of file (default mode).
|
8
|
+
# -----+--------------------------------------------------------
|
9
|
+
# "r+" | Read-write, starts at beginning of file.
|
10
|
+
# -----+--------------------------------------------------------
|
11
|
+
# "w" | Write-only, truncates existing file
|
12
|
+
# | to zero length or creates a new file for writing.
|
13
|
+
# -----+--------------------------------------------------------
|
14
|
+
# "w+" | Read-write, truncates existing file to zero length
|
15
|
+
# | or creates a new file for reading and writing.
|
16
|
+
# -----+--------------------------------------------------------
|
17
|
+
# "a" | Write-only, starts at end of file if file exists,
|
18
|
+
# | otherwise creates a new file for writing.
|
19
|
+
# -----+--------------------------------------------------------
|
20
|
+
# "a+" | Read-write, starts at end of file if file exists,
|
21
|
+
# | otherwise creates a new file for reading and
|
22
|
+
# | writing.
|
23
|
+
# -----+--------------------------------------------------------
|
24
|
+
# "b" | Binary file mode (may appear with
|
25
|
+
# | any of the key letters listed above).
|
26
|
+
# | Suppresses EOL <-> CRLF conversion on Windows. And
|
27
|
+
# | sets external encoding to ASCII-8BIT unless explicitly
|
28
|
+
# | specified.
|
29
|
+
# -----+--------------------------------------------------------
|
30
|
+
# "t" | Text file mode (may appear with
|
31
|
+
# | any of the key letters listed above except "b").
|
32
|
+
def initialize filename, mode='r', *args, &block
|
33
|
+
@filename = filename
|
34
|
+
@mode = mode
|
35
|
+
end
|
36
|
+
|
37
|
+
def path
|
38
|
+
@filename
|
39
|
+
end
|
40
|
+
|
41
|
+
def mimetype
|
42
|
+
return @mimetype if @mimetype
|
43
|
+
@mimetype = MIME::Types.type_for(File.basename path)
|
44
|
+
@mimetype = if @mimetype.empty?
|
45
|
+
""
|
46
|
+
else
|
47
|
+
@mimetype[0]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
[:atime, :ctime, :mtime].each do |method|
|
52
|
+
define_method method do
|
53
|
+
parse RestClient.get("#{server_url}/#{method}", {:params => {:pwd => Dir.pwd, :filename => path}, :accept => :json})
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def close
|
58
|
+
# p "#{path}: closing"
|
59
|
+
end
|
60
|
+
|
61
|
+
[:lstat, :stat].each do |method|
|
62
|
+
define_method method do
|
63
|
+
DistributedStat.new path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
[:truncate].each do |method|
|
68
|
+
define_method method do |integer|
|
69
|
+
"#{path}: distributed truncate #{method} to #{integer} bytes"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def read length=0, offset=0
|
74
|
+
params = {}
|
75
|
+
params[:length] = length unless length == 0
|
76
|
+
params[:offset] = offset unless offset == 0
|
77
|
+
RestClient.get("#{server_url}/storage#{absolutepath}",
|
78
|
+
{:params => params}) do |response, request, result|
|
79
|
+
case response.code
|
80
|
+
when 200
|
81
|
+
response
|
82
|
+
when 404
|
83
|
+
raise Errno::ENOENT
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def write string
|
89
|
+
resource = RestClient::Resource.new "#{server_url}/storage#{absolutepath}"
|
90
|
+
resource.put string, :content_type => mimetype
|
91
|
+
end
|
92
|
+
|
93
|
+
# File.open(filename, mode="r" [, opt]) => file
|
94
|
+
# File.open(filename [, mode [, perm]] [, opt]) => file
|
95
|
+
# File.open(filename, mode="r" [, opt]) {|file| block } => obj
|
96
|
+
# File.open(filename [, mode [, perm]] [, opt]) {|file| block } => obj
|
97
|
+
|
98
|
+
def self.open filename, *args, &b
|
99
|
+
f = self.new filename, *args
|
100
|
+
if b
|
101
|
+
b.call(f)
|
102
|
+
f.close
|
103
|
+
else
|
104
|
+
f
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def method_missing method
|
109
|
+
raise "Distributed File error: #{method} not implemented"
|
110
|
+
end
|
111
|
+
end
|
data/lib/dshelf/dir.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class Dir
|
2
|
+
class << self; include DistributedShelf end
|
3
|
+
|
4
|
+
override_class_method(:chdir) do |dir|
|
5
|
+
if distributed? dir
|
6
|
+
p "remote chdir"
|
7
|
+
@@dpwd = dir
|
8
|
+
else
|
9
|
+
@@dpwd = ''
|
10
|
+
Dir._chdir dir
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
@@dpwd = ''
|
15
|
+
[:getwd, :pwd].each do |method|
|
16
|
+
override_class_method(method) do
|
17
|
+
if distributed? @@dpwd
|
18
|
+
p "remote pwd"
|
19
|
+
@@dpwd
|
20
|
+
else
|
21
|
+
Dir._pwd
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[:delete, :rmdir, :unlink].each do |method|
|
27
|
+
proxy_method(method) do |dir|
|
28
|
+
p "remote rmdir"
|
29
|
+
0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
proxy_method(:entries) do |dir|
|
34
|
+
p "remote entries"
|
35
|
+
end
|
36
|
+
|
37
|
+
proxy_method(:mkdir) do |dir|
|
38
|
+
p "remote mkdir"
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
# foreach(dirname, &b)
|
44
|
+
#
|
45
|
+
# init (name)
|
46
|
+
#
|
47
|
+
# open(name)
|
48
|
+
#
|
49
|
+
# open(name, &b)
|
50
|
+
#
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
# ?close
|
56
|
+
#
|
57
|
+
# each &b
|
58
|
+
#
|
59
|
+
# path
|
60
|
+
#
|
61
|
+
# ?seek
|
62
|
+
# ?pos
|
63
|
+
# ?tell
|
64
|
+
#
|
65
|
+
# read
|
66
|
+
#
|
67
|
+
end
|
data/lib/dshelf/file.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
|
3
|
+
class File
|
4
|
+
class << self; include DistributedShelf end
|
5
|
+
def absolutepath; File.expand_path path, Dir.pwd end
|
6
|
+
|
7
|
+
[:'pipe?', :'socket?', :'sticky?'].each do |method|
|
8
|
+
proxy_method(method) do |filename| false end
|
9
|
+
end
|
10
|
+
|
11
|
+
[:atime, :ctime, :mtime, :'directory?', :'file?', :'owned?', :size, :'symlink?', :'zero?',
|
12
|
+
:'readable?', :'writable?', :'readable_real?', :'writable_real?'].each do |method|
|
13
|
+
proxy_method(method) do |filename|
|
14
|
+
File.stat(filename).send(method)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
[:'exist?', :'exists?'].each do |method|
|
19
|
+
proxy_method(method) do |filename|
|
20
|
+
begin
|
21
|
+
File.stat(filename)
|
22
|
+
true
|
23
|
+
rescue
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
[:delete, :unlink].each do |method|
|
30
|
+
proxy_method(method) do |*args|
|
31
|
+
args = args.map do |filename| File.expand_path(filename, Dir.pwd) end
|
32
|
+
RestClient.get("#{server_url}/meta", {:params => {:method => method, :args => args}}) do |response, request, result|
|
33
|
+
case response.code
|
34
|
+
when 200
|
35
|
+
args.size
|
36
|
+
when 404
|
37
|
+
raise Errno::ENOENT
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[:rename, :link, :symlink].each do |method|
|
44
|
+
proxy_method(method) do |*args|
|
45
|
+
args = args.map do |filename| File.expand_path(filename, Dir.pwd) end
|
46
|
+
RestClient.get("#{server_url}/meta", {:params => {:method => method, :args => args}}) do |response, request, result|
|
47
|
+
case response.code
|
48
|
+
when 200
|
49
|
+
0
|
50
|
+
when 404
|
51
|
+
raise Errno::ENOENT
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
proxy_method(:truncate) do |filename, size|
|
58
|
+
absolutepath = File.expand_path filename, Dir.pwd
|
59
|
+
RestClient.get("#{server_url}/truncate#{absolutepath}", {:params => {:size => size}}) do |response, request, result|
|
60
|
+
case response.code
|
61
|
+
when 200
|
62
|
+
0
|
63
|
+
when 404
|
64
|
+
raise Errno::ENOENT
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
[:stat, :lstat].each do |method|
|
70
|
+
proxy_method(method) do |filename|
|
71
|
+
Stat.new(filename)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
proxy_method(:new) do |*args|
|
76
|
+
DistributedFile.new(*args)
|
77
|
+
end
|
78
|
+
|
79
|
+
proxy_method(:open) do |*args, &b|
|
80
|
+
DistributedFile.open(*args, &b)
|
81
|
+
end
|
82
|
+
end
|
data/lib/dshelf/stat.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
class DistributedStat
|
5
|
+
include DistributedShelf
|
6
|
+
def path
|
7
|
+
@dpath
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize filename
|
11
|
+
@dpath = filename
|
12
|
+
RestClient.get("#{server_url}/stat#{absolutepath}", {:accept => :json}) do |response, request, result|
|
13
|
+
case response.code
|
14
|
+
when 200
|
15
|
+
parse_stat response
|
16
|
+
when 404
|
17
|
+
raise Errno::ENOENT
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_stat stat
|
23
|
+
parsed = JSON.parse stat
|
24
|
+
@dstat = {}
|
25
|
+
@dstat[:size] = parsed['size']
|
26
|
+
@dstat[:readable] = !parsed['access'].match(/read/).nil?
|
27
|
+
@dstat[:writable] = !parsed['access'].match(/write/).nil?
|
28
|
+
@dstat[:atime] = Time.parse parsed['atime']
|
29
|
+
@dstat[:ctime] = Time.parse parsed['ctime']
|
30
|
+
@dstat[:mtime] = Time.parse parsed['mtime']
|
31
|
+
@dstat[:is_file] = parsed['is_file']
|
32
|
+
@dstat[:is_dir] = parsed['is_dir']
|
33
|
+
@dstat[:is_regular] = parsed['is_regular']
|
34
|
+
end
|
35
|
+
|
36
|
+
def setgid?; true end
|
37
|
+
def setuid?; true end
|
38
|
+
|
39
|
+
def size
|
40
|
+
@dstat[:size]
|
41
|
+
end
|
42
|
+
|
43
|
+
def zero?
|
44
|
+
size == 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def atime
|
48
|
+
@dstat[:atime]
|
49
|
+
end
|
50
|
+
|
51
|
+
def ctime
|
52
|
+
@dstat[:ctime]
|
53
|
+
end
|
54
|
+
|
55
|
+
def mtime
|
56
|
+
@dstat[:mtime]
|
57
|
+
end
|
58
|
+
|
59
|
+
def <=> stat
|
60
|
+
mtime <=> stat.mtime
|
61
|
+
end
|
62
|
+
|
63
|
+
[:'pipe?', :'socket?', :'sticky?', :'blockdev?', :'chardev?', :'executable?', :'executable_real?'].each do |method|
|
64
|
+
define_method(method) do || false end
|
65
|
+
end
|
66
|
+
|
67
|
+
[:blksize, :blocks, :dev, :dev_minor, :dev_major, :rdev, :rdev_minor, :rdev_major, :uid, :gid, :ino].each do |method|
|
68
|
+
define_method(method) do || nil end
|
69
|
+
end
|
70
|
+
|
71
|
+
[:'grpowned?', :'owned?'].each do |method|
|
72
|
+
define_method(method) do || true end
|
73
|
+
end
|
74
|
+
|
75
|
+
def file?
|
76
|
+
@dstat[:is_regular]
|
77
|
+
end
|
78
|
+
|
79
|
+
def directory?
|
80
|
+
@dstat[:is_dir]
|
81
|
+
end
|
82
|
+
|
83
|
+
def symlink?
|
84
|
+
not @dstat[:is_file]
|
85
|
+
end
|
86
|
+
|
87
|
+
def ftype
|
88
|
+
return 'link' if symlink?
|
89
|
+
return 'directory' if directory?
|
90
|
+
'file'
|
91
|
+
end
|
92
|
+
|
93
|
+
[:'readable?', :'readable_real?'].each do |method|
|
94
|
+
define_method(method) do || @dstat[:readable] end
|
95
|
+
end
|
96
|
+
|
97
|
+
[:'writable?', :'writable_real?'].each do |method|
|
98
|
+
define_method(method) do || @dstat[:writable] end
|
99
|
+
end
|
100
|
+
|
101
|
+
# todo: mode nlink
|
102
|
+
end
|
103
|
+
|
104
|
+
class File
|
105
|
+
class Stat
|
106
|
+
class << self; include DistributedShelf end
|
107
|
+
|
108
|
+
proxy_method(:new) do |filename|
|
109
|
+
DistributedStat.new filename
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dshelf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Phil Pirozhkov
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-09-18 00:00:00 +04:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: rest-client
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 1
|
28
|
+
- 4
|
29
|
+
- 0
|
30
|
+
version: 1.4.0
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: json
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 1
|
42
|
+
- 2
|
43
|
+
- 0
|
44
|
+
version: 1.2.0
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: multipart-post
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 1
|
56
|
+
- 0
|
57
|
+
- 0
|
58
|
+
version: 1.0.0
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: mime-types
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 1
|
70
|
+
- 0
|
71
|
+
version: "1.0"
|
72
|
+
type: :runtime
|
73
|
+
version_requirements: *id004
|
74
|
+
description: ""
|
75
|
+
email: pirj@mail.ru
|
76
|
+
executables: []
|
77
|
+
|
78
|
+
extensions: []
|
79
|
+
|
80
|
+
extra_rdoc_files: []
|
81
|
+
|
82
|
+
files:
|
83
|
+
- lib/dshelf.rb
|
84
|
+
- lib/dshelf/dfile.rb
|
85
|
+
- lib/dshelf/dir.rb
|
86
|
+
- lib/dshelf/file.rb
|
87
|
+
- lib/dshelf/stat.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://distributedshelf.com
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options:
|
94
|
+
- --charset=UTF-8
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.6
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: ""
|
118
|
+
test_files: []
|
119
|
+
|