hysios-fusefs 0.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/.document +5 -0
- data/.gitignore +11 -0
- data/API.txt +279 -0
- data/Changes.txt +63 -0
- data/LICENSE +20 -0
- data/README +46 -0
- data/Rakefile +56 -0
- data/TODO +11 -0
- data/VERSION +1 -0
- data/ext/MANIFEST +4 -0
- data/ext/extconf.rb +7 -0
- data/ext/fusefs_fuse.c +149 -0
- data/ext/fusefs_fuse.h +22 -0
- data/ext/fusefs_lib.c +1525 -0
- data/fusefs.gemspec +69 -0
- data/hello.sh +10 -0
- data/lib/fusefs.rb +244 -0
- data/sample/demo.rb +100 -0
- data/sample/dictfs.rb +84 -0
- data/sample/hello.rb +27 -0
- data/sample/openurifs.rb +53 -0
- data/sample/railsfs.rb +77 -0
- data/sample/sqlfs.rb +143 -0
- data/sample/yamlfs.rb +168 -0
- data/test/fusefs_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +77 -0
data/sample/hello.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'fusefs'
|
3
|
+
|
4
|
+
class HelloDir
|
5
|
+
def contents(path)
|
6
|
+
['hello.txt']
|
7
|
+
end
|
8
|
+
|
9
|
+
def file?(path)
|
10
|
+
path == '/hello.txt'
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_file(path)
|
14
|
+
"Hello, World!\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
def size(path)
|
18
|
+
read_file(path).size
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
hellodir = HelloDir.new
|
23
|
+
FuseFS.set_root( hellodir )
|
24
|
+
|
25
|
+
# Mount under a directory given on the command line.
|
26
|
+
FuseFS.mount_under ARGV.shift
|
27
|
+
FuseFS.run
|
data/sample/openurifs.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# openurifs.rb
|
2
|
+
#
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require 'fusefs'
|
6
|
+
include FuseFS
|
7
|
+
|
8
|
+
require 'open-uri'
|
9
|
+
|
10
|
+
class OpenUriFS < FuseFS::FuseDir
|
11
|
+
def contents(path)
|
12
|
+
# The 'readme' file
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
def directory?(path)
|
16
|
+
uri = scan_path(path)
|
17
|
+
fn = uri.pop
|
18
|
+
return true if fn =~ /\.(com|org|net|us|de|jp|ru|uk|biz|info)$/
|
19
|
+
return true if fn =~ /^\d+\.\d+\.\d+\.\d+$/
|
20
|
+
! (fn =~ /\./) # Does the last item doesn't contain a '.' ?
|
21
|
+
end
|
22
|
+
def file?(path)
|
23
|
+
!directory?(path)
|
24
|
+
end
|
25
|
+
def read_file(path)
|
26
|
+
proto, rest = split_path(path)
|
27
|
+
uri = "#{proto}://#{rest}"
|
28
|
+
open(uri).read
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if (File.basename($0) == File.basename(__FILE__))
|
33
|
+
if (ARGV.size != 1)
|
34
|
+
puts "Usage: #{$0} <directory>"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
dirname = ARGV.shift
|
39
|
+
|
40
|
+
unless File.directory?(dirname)
|
41
|
+
puts "Usage: #{dirname} is not a directory."
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
|
45
|
+
root = OpenUriFS.new
|
46
|
+
|
47
|
+
# Set the root FuseFS
|
48
|
+
FuseFS.set_root(root)
|
49
|
+
|
50
|
+
FuseFS.mount_under(dirname)
|
51
|
+
|
52
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
53
|
+
end
|
data/sample/railsfs.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# RailsFS, as written by _why_the_lucky_stiff
|
4
|
+
#
|
5
|
+
# Full instructions:
|
6
|
+
# http://redhanded.hobix.com/inspect/railsfsAfterACoupleMinutesOfToolingWithFuseWhoa.html
|
7
|
+
#
|
8
|
+
=begin
|
9
|
+
Instructions cut and paste from _why's blog:
|
10
|
+
|
11
|
+
Save the railfs.rb script as script/filesys in your Rails app. (If you'd
|
12
|
+
rather not cut-and-paste the above, it's here.)
|
13
|
+
|
14
|
+
Now, run mkdir ~/railsmnt. Then, script/filesys ~/railsmnt. The rules are as
|
15
|
+
follows:
|
16
|
+
|
17
|
+
* ls ~/railsmnt will give you a list of tables.
|
18
|
+
* ls ~/railsmnt/table will list IDs from the table.
|
19
|
+
* cat ~/railsmnt/table/id will display a record in YAML.
|
20
|
+
* vim ~/railsmnt/table/id to edit the record in YAML!
|
21
|
+
|
22
|
+
=end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require 'fusefs'
|
26
|
+
require File.dirname(__FILE__) + '/../config/environment'
|
27
|
+
|
28
|
+
class RailsFS < FuseFS::FuseDir
|
29
|
+
def initialize
|
30
|
+
@classes = {}
|
31
|
+
require 'find'
|
32
|
+
Find.find( File.join(RAILS_ROOT, 'app/models') ) do |model|
|
33
|
+
if /(\w+)\.rb$/ =~ model
|
34
|
+
model = $1
|
35
|
+
( @classes[model] = Kernel::const_get( Inflector.classify( model ) ) ).
|
36
|
+
find :first rescue @classes.delete( model )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def directory? path
|
41
|
+
tname, key = scan_path path
|
42
|
+
table = @classes[tname]
|
43
|
+
if table.nil?; false # /table
|
44
|
+
elsif key; false # /table/id
|
45
|
+
else; true end
|
46
|
+
end
|
47
|
+
def file? path
|
48
|
+
tname, key = scan_path path
|
49
|
+
table = @classes[tname]
|
50
|
+
key and table and table.find( key )
|
51
|
+
end
|
52
|
+
def can_delete?; true end
|
53
|
+
def can_write? path; file? path end
|
54
|
+
def contents path
|
55
|
+
tname, key = scan_path path
|
56
|
+
table = @classes[tname]
|
57
|
+
if tname.nil?; @classes.keys.sort # /
|
58
|
+
else; table.find( :all ).map { |o| o.id.to_s } end # /table
|
59
|
+
end
|
60
|
+
def write_to path, body
|
61
|
+
obj = YAML::load( body )
|
62
|
+
obj.save
|
63
|
+
end
|
64
|
+
def read_file path
|
65
|
+
tname, key = scan_path path
|
66
|
+
table = @classes[tname]
|
67
|
+
YAML::dump( table.find( key ) )
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if (File.basename($0) == File.basename(__FILE__))
|
72
|
+
root = RailsFS.new
|
73
|
+
FuseFS.set_root(root)
|
74
|
+
FuseFS.mount_under(ARGV[0])
|
75
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
76
|
+
end
|
77
|
+
|
data/sample/sqlfs.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# sqlfs.rb
|
2
|
+
#
|
3
|
+
# The SQL-db proof of concept for FuseFS
|
4
|
+
#
|
5
|
+
# Author: Greg Millam
|
6
|
+
|
7
|
+
require "rubygems"
|
8
|
+
require 'fusefs'
|
9
|
+
require 'ruby_debug'
|
10
|
+
|
11
|
+
require 'mysql'
|
12
|
+
|
13
|
+
class SqlFS < FuseFS::FuseDir
|
14
|
+
class DBTable
|
15
|
+
attr_accessor :name, :key, :fields
|
16
|
+
end
|
17
|
+
def initialize(host,user,pass,db)
|
18
|
+
@sql = Mysql.connect(host,user,pass,db)
|
19
|
+
@tables = Hash.new(nil)
|
20
|
+
|
21
|
+
tables = @sql.query('show tables')
|
22
|
+
|
23
|
+
tables.each do |i,|
|
24
|
+
table = DBTable.new
|
25
|
+
table.name = i
|
26
|
+
table.fields = {}
|
27
|
+
res = @sql.query("describe #{i}")
|
28
|
+
res.each do |field,type,null,key,default,extra|
|
29
|
+
table.fields[field] = type
|
30
|
+
if (key =~ /pri/i)
|
31
|
+
table.key = field
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@tables[i] = table if table.key
|
35
|
+
end
|
36
|
+
end
|
37
|
+
def directory?(path)
|
38
|
+
tname, key, field = scan_path(path)
|
39
|
+
table = @tables[tname]
|
40
|
+
case
|
41
|
+
when tname.nil?
|
42
|
+
true # This means "/"
|
43
|
+
when table.nil?
|
44
|
+
false
|
45
|
+
when field
|
46
|
+
false # Always a file
|
47
|
+
when key
|
48
|
+
res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
|
49
|
+
res.num_rows > 0 # If there was a result, it exists.
|
50
|
+
else
|
51
|
+
true # It's just a table.
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def file?(path)
|
55
|
+
tname, key, field = scan_path(path)
|
56
|
+
|
57
|
+
table = @tables[tname]
|
58
|
+
case
|
59
|
+
when field.nil?
|
60
|
+
false # Only field entries are files.
|
61
|
+
when table.nil?
|
62
|
+
false
|
63
|
+
when ! @tables[tname].fields.include?(field)
|
64
|
+
false # Invalid field.
|
65
|
+
when field
|
66
|
+
res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
|
67
|
+
res.num_rows > 0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def can_delete?(path)
|
71
|
+
# This helps editors, but we don't really use it.
|
72
|
+
true
|
73
|
+
end
|
74
|
+
def can_write?(path)
|
75
|
+
# Since this is basically only for editing files,
|
76
|
+
# we just call file?
|
77
|
+
file?(path)
|
78
|
+
end
|
79
|
+
def contents(path)
|
80
|
+
# since this is only called when directory? is true,
|
81
|
+
# We'll assume valid entries.
|
82
|
+
tname, key, field = scan_path(path)
|
83
|
+
table = @tables[tname]
|
84
|
+
case
|
85
|
+
when tname.nil?
|
86
|
+
@tables.keys.sort # Just the tables.
|
87
|
+
when key
|
88
|
+
table.fields.keys.sort
|
89
|
+
else
|
90
|
+
# I limit to 200 so 'ls' doesn't hang all the time :D
|
91
|
+
res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} ORDER BY #{table.key} LIMIT 100")
|
92
|
+
ret = []
|
93
|
+
res.each do |val,one|
|
94
|
+
ret << val if val.size > 0
|
95
|
+
end
|
96
|
+
ret
|
97
|
+
end
|
98
|
+
end
|
99
|
+
def write_to(path,body)
|
100
|
+
# Since this is only called after can_write?(), we assume
|
101
|
+
# Valid fields.
|
102
|
+
tname, key, field = scan_path(path)
|
103
|
+
table = @tables[tname]
|
104
|
+
res = @sql.query("UPDATE #{table.name} SET #{field} = '#{Mysql.escape_string(body)}' WHERE #{table.key} = '#{key}'")
|
105
|
+
end
|
106
|
+
def read_file(path)
|
107
|
+
# Again, as this is only called after file?, assume valid fields.
|
108
|
+
tname, key, field = scan_path(path)
|
109
|
+
|
110
|
+
table = @tables[tname]
|
111
|
+
|
112
|
+
res = @sql.query("SELECT #{field} FROM #{table.name} WHERE #{table.key} = '#{key}'")
|
113
|
+
puts res.fetch_row
|
114
|
+
res.fetch_row.to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
def size(path)
|
118
|
+
read_file(path).size
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if (File.basename($0) == File.basename(__FILE__))
|
123
|
+
if ARGV.size != 5
|
124
|
+
puts "Usage: #{$0} <directory> <host> <user> <pass> <db>"
|
125
|
+
exit
|
126
|
+
end
|
127
|
+
|
128
|
+
dirname, host, user, pass, db = ARGV
|
129
|
+
|
130
|
+
if (! File.directory?(dirname))
|
131
|
+
puts "#{dirname} is not a directory"
|
132
|
+
end
|
133
|
+
|
134
|
+
root = SqlFS.new(host,user,pass,db)
|
135
|
+
|
136
|
+
# Set the root FuseFS
|
137
|
+
FuseFS.set_root(root)
|
138
|
+
|
139
|
+
# root.contents("/quotes")
|
140
|
+
|
141
|
+
FuseFS.mount_under(dirname)
|
142
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
143
|
+
end
|
data/sample/yamlfs.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
# yamlfs.rb
|
2
|
+
#
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require 'fusefs'
|
6
|
+
include FuseFS
|
7
|
+
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
class YAMLFS < FuseFS::FuseDir
|
11
|
+
def initialize(filename)
|
12
|
+
@filename = filename
|
13
|
+
begin
|
14
|
+
@fs = YAML.load(IO.read(filename))
|
15
|
+
rescue Exception
|
16
|
+
@fs = Hash.new()
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def save
|
20
|
+
File.open(@filename,'w') do |fout|
|
21
|
+
fout.puts(YAML.dump(@fs))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
def contents(path)
|
25
|
+
items = scan_path(path)
|
26
|
+
node = items.inject(@fs) do |node,item|
|
27
|
+
item ? node[item] : node
|
28
|
+
end
|
29
|
+
node.keys.sort
|
30
|
+
end
|
31
|
+
def directory?(path)
|
32
|
+
items = scan_path(path)
|
33
|
+
node = items.inject(@fs) do |node,item|
|
34
|
+
item ? node[item] : node
|
35
|
+
end
|
36
|
+
node.is_a?(Hash)
|
37
|
+
end
|
38
|
+
def file?(path)
|
39
|
+
items = scan_path(path)
|
40
|
+
node = items.inject(@fs) do |node,item|
|
41
|
+
item ? node[item] : node
|
42
|
+
end
|
43
|
+
node.is_a?(String)
|
44
|
+
end
|
45
|
+
def touch(path)
|
46
|
+
puts "#{path} has been pushed like a button!"
|
47
|
+
end
|
48
|
+
|
49
|
+
# File reading
|
50
|
+
def read_file(path)
|
51
|
+
items = scan_path(path)
|
52
|
+
node = items.inject(@fs) do |node,item|
|
53
|
+
item ? node[item] : node
|
54
|
+
end
|
55
|
+
node.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def size(path)
|
59
|
+
read_file(path).size
|
60
|
+
end
|
61
|
+
|
62
|
+
# File writing
|
63
|
+
def can_write?(path)
|
64
|
+
items = scan_path(path)
|
65
|
+
name = items.pop # Last is the filename.
|
66
|
+
node = items.inject(@fs) do |node,item|
|
67
|
+
item ? node[item] : node
|
68
|
+
end
|
69
|
+
node.is_a?(Hash)
|
70
|
+
rescue Exception => er
|
71
|
+
puts "Error! #{er}"
|
72
|
+
end
|
73
|
+
def write_to(path,body)
|
74
|
+
items = scan_path(path)
|
75
|
+
name = items.pop # Last is the filename.
|
76
|
+
node = items.inject(@fs) do |node,item|
|
77
|
+
item ? node[item] : node
|
78
|
+
end
|
79
|
+
node[name] = body
|
80
|
+
self.save
|
81
|
+
rescue Exception => er
|
82
|
+
puts "Error! #{er}"
|
83
|
+
end
|
84
|
+
|
85
|
+
# Delete a file
|
86
|
+
def can_delete?(path)
|
87
|
+
items = scan_path(path)
|
88
|
+
node = items.inject(@fs) do |node,item|
|
89
|
+
item ? node[item] : node
|
90
|
+
end
|
91
|
+
node.is_a?(String)
|
92
|
+
rescue Exception => er
|
93
|
+
puts "Error! #{er}"
|
94
|
+
end
|
95
|
+
def delete(path)
|
96
|
+
items = scan_path(path)
|
97
|
+
name = items.pop # Last is the filename.
|
98
|
+
node = items.inject(@fs) do |node,item|
|
99
|
+
item ? node[item] : node
|
100
|
+
end
|
101
|
+
node.delete(name)
|
102
|
+
self.save
|
103
|
+
rescue Exception => er
|
104
|
+
puts "Error! #{er}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# mkdirs
|
108
|
+
def can_mkdir?(path)
|
109
|
+
items = scan_path(path)
|
110
|
+
name = items.pop # Last is the filename.
|
111
|
+
node = items.inject(@fs) do |node,item|
|
112
|
+
item ? node[item] : node
|
113
|
+
end
|
114
|
+
node.is_a?(Hash)
|
115
|
+
rescue Exception => er
|
116
|
+
puts "Error! #{er}"
|
117
|
+
end
|
118
|
+
def mkdir(path)
|
119
|
+
items = scan_path(path)
|
120
|
+
name = items.pop # Last is the filename.
|
121
|
+
node = items.inject(@fs) do |node,item|
|
122
|
+
item ? node[item] : node
|
123
|
+
end
|
124
|
+
node[name] = Hash.new
|
125
|
+
self.save
|
126
|
+
end
|
127
|
+
|
128
|
+
# rmdir
|
129
|
+
def can_rmdir?(path)
|
130
|
+
items = scan_path(path)
|
131
|
+
node = items.inject(@fs) do |node,item|
|
132
|
+
item ? node[item] : node
|
133
|
+
end
|
134
|
+
node.is_a?(Hash) && node.empty?
|
135
|
+
end
|
136
|
+
def rmdir(path)
|
137
|
+
items = scan_path(path)
|
138
|
+
name = items.pop # Last is the filename.
|
139
|
+
node = items.inject(@fs) do |node,item|
|
140
|
+
item ? node[item] : node
|
141
|
+
end
|
142
|
+
node.delete(name)
|
143
|
+
self.save
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if (File.basename($0) == File.basename(__FILE__))
|
148
|
+
if (ARGV.size < 2)
|
149
|
+
puts "Usage: #{$0} <directory> <yamlfile> <options>"
|
150
|
+
exit
|
151
|
+
end
|
152
|
+
|
153
|
+
dirname, yamlfile = ARGV.shift, ARGV.shift
|
154
|
+
|
155
|
+
unless File.directory?(dirname)
|
156
|
+
puts "Usage: #{dirname} is not a directory."
|
157
|
+
exit
|
158
|
+
end
|
159
|
+
|
160
|
+
root = YAMLFS.new(yamlfile)
|
161
|
+
|
162
|
+
# Set the root FuseFS
|
163
|
+
FuseFS.set_root(root)
|
164
|
+
|
165
|
+
FuseFS.mount_under(dirname, *ARGV)
|
166
|
+
|
167
|
+
FuseFS.run # This doesn't return until we're unmounted.
|
168
|
+
end
|