pfuse 0.7.5

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/fusefs.rb ADDED
@@ -0,0 +1,114 @@
1
+ # FuseFS.rb
2
+ #
3
+ # The ruby portion of FuseFS main library
4
+ #
5
+ # Helper functions
6
+
7
+ # TODO sig handler?
8
+
9
+ require File.dirname(__FILE__) + '/../ext/fusefs_lib'
10
+
11
+ module FuseFS
12
+ S_IFDIR = 0o0040000
13
+ S_IFREG = 0o0100000
14
+
15
+ @running = true
16
+
17
+ class << self
18
+ def run
19
+ fd = fuse_fd
20
+
21
+ begin
22
+ io = IO.for_fd(fd)
23
+ rescue Errno::EBADF
24
+ raise "fuse is not mounted"
25
+ end
26
+
27
+ while @running
28
+ IO.select([io])
29
+ process
30
+ end
31
+ end
32
+
33
+ def unmount
34
+ system("umount #{@mountpoint}")
35
+ end
36
+
37
+ def exit
38
+ @running = false
39
+ end
40
+
41
+ def Entries(path, entries)
42
+ entries.map do |entry|
43
+ @root.getattr(File.join(path, entry))
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ class Stat
50
+ attr_accessor :st_mode
51
+ attr_accessor :st_nlink
52
+ attr_accessor :st_size
53
+ attr_accessor :st_uid
54
+ attr_accessor :st_gid
55
+ attr_accessor :st_mtime
56
+ attr_accessor :st_atime
57
+ attr_accessor :st_ctime
58
+ attr_accessor :name
59
+
60
+ def initialize(name='undefined')
61
+ @st_mode = 0o755 | mode_mask
62
+ @st_nlink = 3
63
+ @st_size = 0
64
+ @st_uid = Process.uid
65
+ @st_gid = Process.gid
66
+ @st_mtime = Time.now.to_i
67
+ @st_atime = Time.now.to_i
68
+ @st_ctime = Time.now.to_i
69
+ @name = name
70
+ end
71
+
72
+ def mode_mask
73
+ self.class == FileEntry ? S_IFREG : S_IFDIR
74
+ end
75
+ end
76
+
77
+ class FileEntry < Stat
78
+ end
79
+
80
+ class DirEntry < Stat
81
+ def initialize(*args)
82
+ super(*args)
83
+ @st_size = 4096
84
+ end
85
+ end
86
+
87
+ class StatVFS
88
+ attr_accessor :f_bsize
89
+ attr_accessor :f_frsize
90
+ attr_accessor :f_blocks
91
+ attr_accessor :f_bfree
92
+ attr_accessor :f_bavail
93
+ attr_accessor :f_files
94
+ attr_accessor :f_ffree
95
+ attr_accessor :f_favail
96
+ attr_accessor :f_fsid
97
+ attr_accessor :f_flag
98
+ attr_accessor :f_namemax
99
+
100
+ def initialize
101
+ @f_bsize = 0
102
+ @f_frsize = 0
103
+ @f_blocks = 0
104
+ @f_bfree = 0
105
+ @f_bavail = 0
106
+ @f_files = 0
107
+ @f_ffree = 0
108
+ @f_favail = 0
109
+ @f_fsid = 0
110
+ @f_flag = 0
111
+ @f_namemax = 0
112
+ end
113
+ end
114
+ end
data/pfuse.gemspec ADDED
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{pfuse}
8
+ s.version = "0.7.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["David Turnbull", "Kyle Maxwell"]
12
+ s.date = %q{2010-02-26}
13
+ s.description = %q{Gemified}
14
+ s.email = %q{dsturnbull@gmail.com}
15
+ s.extensions = ["ext/extconf.rb"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README",
19
+ "TODO"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "API.txt",
25
+ "Changes.txt",
26
+ "LICENSE",
27
+ "README",
28
+ "Rakefile",
29
+ "TODO",
30
+ "VERSION",
31
+ "ext/extconf.rb",
32
+ "ext/fusefs_fuse.c",
33
+ "ext/fusefs_fuse.h",
34
+ "ext/fusefs_lib.c",
35
+ "ext/fusefs_lib.h",
36
+ "hello.sh",
37
+ "lib/fusefs.rb",
38
+ "pfuse.gemspec",
39
+ "sample/demo.rb",
40
+ "sample/dictfs.rb",
41
+ "sample/hello.rb",
42
+ "sample/openurifs.rb",
43
+ "sample/railsfs.rb",
44
+ "sample/sqlfs.rb",
45
+ "sample/yamlfs.rb",
46
+ "test/fusefs_test.rb",
47
+ "test/test_helper.rb"
48
+ ]
49
+ s.homepage = %q{http://github.com/dsturnbull/pfuse}
50
+ s.rdoc_options = ["--charset=UTF-8"]
51
+ s.require_paths = ["lib"]
52
+ s.rubygems_version = %q{1.3.5}
53
+ s.summary = %q{fusefs}
54
+ s.test_files = [
55
+ "test/fusefs_test.rb",
56
+ "test/test_helper.rb"
57
+ ]
58
+
59
+ if s.respond_to? :specification_version then
60
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
+ s.specification_version = 3
62
+
63
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
+ else
65
+ end
66
+ else
67
+ end
68
+ end
69
+
data/sample/demo.rb ADDED
@@ -0,0 +1,100 @@
1
+ require "rubygems"
2
+ require 'fusefs'
3
+ include FuseFS
4
+
5
+ root = MetaDir.new
6
+
7
+ # if (ARGV.size != 1)
8
+ # puts "Usage: #{$0} <directory>"
9
+ # exit
10
+ # end
11
+
12
+ dirname = ARGV.shift
13
+
14
+ unless File.directory?(dirname)
15
+ puts "Usage: #{$0} <directory>"
16
+ exit
17
+ end
18
+
19
+ class DirLink
20
+ def initialize(dir)
21
+ File.directory?(dir) or raise ArgumentError, "DirLink.initialize expects a valid directory!"
22
+ @base = dir
23
+ end
24
+ def directory?(path)
25
+ File.directory?(File.join(@base,path))
26
+ end
27
+ def file?(path)
28
+ File.file?(File.join(@base,path))
29
+ end
30
+ def contents(path)
31
+ fn = File.join(@base,path)
32
+ Dir.entries(fn).map { |file|
33
+ file = file.sub(/^#{fn}\/?/,'')
34
+ if ['..','.'].include?(file)
35
+ nil
36
+ else
37
+ file
38
+ end
39
+ }.compact.sort
40
+ end
41
+ def read_file(path)
42
+ fn = File.join(@base,path)
43
+ if File.file?(fn)
44
+ IO.read(fn)
45
+ else
46
+ 'No such file'
47
+ end
48
+ end
49
+ end
50
+
51
+ class Counter
52
+ def initialize
53
+ @counter = 0
54
+ end
55
+ def to_s
56
+ @counter += 1
57
+ @counter.to_s + "\n"
58
+ end
59
+ def size
60
+ @counter.to_s.size
61
+ end
62
+ end
63
+
64
+ class Randwords
65
+ def initialize(*ary)
66
+ @ary = ary.flatten
67
+ end
68
+ def to_s
69
+ @ary[rand(@ary.size)].to_s + "\n"
70
+ end
71
+ def size
72
+ @size ||= @ary.map{|v| v.size}.max
73
+ end
74
+ end
75
+
76
+ root.write_to('/hello',"Hello, World!\n")
77
+
78
+ progress = '.'
79
+
80
+ root.write_to('/progress',progress)
81
+
82
+ Thread.new do
83
+ 20.times do
84
+ sleep 5
85
+ progress << '.'
86
+ end
87
+ end
88
+
89
+ root.write_to('/counter',Counter.new)
90
+ root.write_to('/color',Randwords.new('red','blue','green','purple','yellow','bistre','burnt sienna','jade'))
91
+ root.write_to('/animal',Randwords.new('duck','dog','cat','duck billed platypus','silly fella'))
92
+
93
+ root.mkdir("/#{ENV['USER']}",DirLink.new(ENV['HOME']))
94
+
95
+ # Set the root FuseFS
96
+ FuseFS.set_root(root)
97
+
98
+ FuseFS.mount_under(dirname, 'nolocalcaches', *ARGV)
99
+
100
+ FuseFS.run # This doesn't return until we're unmounted.
data/sample/dictfs.rb ADDED
@@ -0,0 +1,84 @@
1
+ # dictfs.rb
2
+ #
3
+
4
+ require "rubygems"
5
+ require 'fusefs'
6
+ include FuseFS
7
+
8
+ require 'dict'
9
+
10
+ class DictFS < FuseFS::FuseDir
11
+ def initialize
12
+ @servers = ['dict.org','alt0.dict.org']
13
+ @database = DICT::ALL_DATABASES
14
+ @strategy = 'exact'
15
+ @match_strategy = DICT::DEFAULT_MATCH_STRATEGY
16
+ @port = DICT::DEFAULT_PORT
17
+
18
+ @dict = DICT.new(@servers, @port, false, false)
19
+ @dict.client("%s v%s" % ["Dictionary","1.0"])
20
+ end
21
+ def contents(path)
22
+ # The 'readme' file
23
+ ['readme']
24
+ end
25
+ def file?(path)
26
+ base, rest = split_path(path)
27
+ rest.nil? # DictFS doesn't have subdirs.
28
+ end
29
+ def read_file(path)
30
+ word, rest = split_path(path)
31
+ word.downcase!
32
+ if word == "readme"
33
+ return %Q[
34
+ DictFS: You may not see the files, but if you cat any file here, it will look
35
+ that file up on dict.org!
36
+ ].lstrip
37
+ end
38
+ puts "Looking up #{word}"
39
+ m = @dict.match(@database, @strategy, word)
40
+ if m
41
+ contents = []
42
+ m.each do |db,words|
43
+ words.each do |w|
44
+ defs = @dict.define(db,w)
45
+ str = []
46
+ defs.each do |d|
47
+ str << "Definition of '#{w}' (by #{d.description})"
48
+ d.definition.each do |line|
49
+ str << " #{line.strip}"
50
+ end
51
+ contents << str.join("\n")
52
+ end
53
+ end
54
+ end
55
+ contents << ''
56
+ contents.join("\n")
57
+ else
58
+ "No dictionary definitions found\n"
59
+ end
60
+ end
61
+ end
62
+
63
+ if (File.basename($0) == File.basename(__FILE__))
64
+ if (ARGV.size != 1)
65
+ puts "Usage: #{$0} <directory>"
66
+ exit
67
+ end
68
+
69
+ dirname = ARGV.shift
70
+
71
+ unless File.directory?(dirname)
72
+ puts "Usage: #{dirname} is not a directory."
73
+ exit
74
+ end
75
+
76
+ root = DictFS.new
77
+
78
+ # Set the root FuseFS
79
+ FuseFS.set_root(root)
80
+
81
+ FuseFS.mount_under(dirname)
82
+
83
+ FuseFS.run # This doesn't return until we're unmounted.
84
+ end
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
@@ -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,134 @@
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
+
10
+ require 'mysql'
11
+
12
+ class SqlFS < FuseFS::FuseDir
13
+ class DBTable
14
+ attr_accessor :name, :key, :fields
15
+ end
16
+ def initialize(host,user,pass,db)
17
+ @sql = Mysql.connect(host,user,pass,db)
18
+ @tables = Hash.new(nil)
19
+
20
+ tables = @sql.query('show tables')
21
+
22
+ tables.each do |i,|
23
+ table = DBTable.new
24
+ table.name = i
25
+ table.fields = {}
26
+ res = @sql.query("describe #{i}")
27
+ res.each do |field,type,null,key,default,extra|
28
+ table.fields[field] = type
29
+ if (key =~ /pri/i)
30
+ table.key = field
31
+ end
32
+ end
33
+ @tables[i] = table if table.key
34
+ end
35
+ end
36
+ def directory?(path)
37
+ tname, key, field = scan_path(path)
38
+ table = @tables[tname]
39
+ case
40
+ when tname.nil?
41
+ true # This means "/"
42
+ when table.nil?
43
+ false
44
+ when field
45
+ false # Always a file
46
+ when key
47
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
48
+ res.num_rows > 0 # If there was a result, it exists.
49
+ else
50
+ true # It's just a table.
51
+ end
52
+ end
53
+ def file?(path)
54
+ tname, key, field = scan_path(path)
55
+ table = @tables[tname]
56
+ case
57
+ when field.nil?
58
+ false # Only field entries are files.
59
+ when table.nil?
60
+ false
61
+ when ! @tables[tname].fields.include?(field)
62
+ false # Invalid field.
63
+ when field
64
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} WHERE #{table.key} = '#{Mysql.escape_string(key)}'")
65
+ res.num_rows > 0
66
+ end
67
+ end
68
+ def can_delete?(path)
69
+ # This helps editors, but we don't really use it.
70
+ true
71
+ end
72
+ def can_write?(path)
73
+ # Since this is basically only for editing files,
74
+ # we just call file?
75
+ file?(path)
76
+ end
77
+ def contents(path)
78
+ # since this is only called when directory? is true,
79
+ # We'll assume valid entries.
80
+ tname, key, field = scan_path(path)
81
+ table = @tables[tname]
82
+ case
83
+ when tname.nil?
84
+ @tables.keys.sort # Just the tables.
85
+ when key
86
+ table.fields.keys.sort
87
+ else
88
+ # I limit to 200 so 'ls' doesn't hang all the time :D
89
+ res = @sql.query("SELECT #{table.key}, 1 FROM #{table.name} ORDER BY #{table.key} LIMIT 100")
90
+ ret = []
91
+ res.each do |val,one|
92
+ ret << val if val.size > 0
93
+ end
94
+ ret
95
+ end
96
+ end
97
+ def write_to(path,body)
98
+ # Since this is only called after can_write?(), we assume
99
+ # Valid fields.
100
+ tname, key, field = scan_path(path)
101
+ table = @tables[tname]
102
+ res = @sql.query("UPDATE #{table.name} SET #{field} = '#{Mysql.escape_string(body)}' WHERE #{table.key} = '#{key}'")
103
+ end
104
+ def read_file(path)
105
+ # Again, as this is only called after file?, assume valid fields.
106
+ tname, key, field = scan_path(path)
107
+ table = @tables[tname]
108
+ res = @sql.query("SELECT #{field} FROM #{table.name} WHERE #{table.key} = '#{key}'")
109
+ res.fetch_row[0]
110
+ end
111
+ end
112
+
113
+ if (File.basename($0) == File.basename(__FILE__))
114
+ if ARGV.size != 5
115
+ puts "Usage: #{$0} <directory> <host> <user> <pass> <db>"
116
+ exit
117
+ end
118
+
119
+ dirname, host, user, pass, db = ARGV
120
+
121
+ if (! File.directory?(dirname))
122
+ puts "#{dirname} is not a directory"
123
+ end
124
+
125
+ root = SqlFS.new(host,user,pass,db)
126
+
127
+ # Set the root FuseFS
128
+ FuseFS.set_root(root)
129
+
130
+ # root.contents("/quotes")
131
+
132
+ FuseFS.mount_under(dirname)
133
+ FuseFS.run # This doesn't return until we're unmounted.
134
+ end