rfusefs 1.0.2.RC1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,115 +0,0 @@
1
- require 'fusefs/pathmapper'
2
- require 'sqlite3'
3
- require 'thread'
4
-
5
- module FuseFS
6
-
7
- class SqliteMapperFS < PathMapperFS
8
-
9
- # The database file
10
- attr_reader :db_path
11
-
12
- # The database connection
13
- attr_reader :db
14
-
15
- # Maintains a count of the number of times through the scan loop
16
- attr_reader :scan_id
17
-
18
- #
19
- #
20
- # @param [String] db_path Path to Sqlite database
21
- # @param [String] sql query
22
- # @param [Hash] options see {PathMapperFS#initialize}
23
- # @yieldparam [Row] row to map
24
- # @yieldreturn [String,String,Hash<Symbol,Object>] newpath, realpath, options
25
- # * newpath - the mapped path
26
- # * realpath - path to the real file
27
- # * options - additional information to store with this path
28
- def initialize(db_path,sql,options = { },&row_mapper)
29
- @db_path = db_path.to_s
30
- @sql = sql.to_s
31
- define_singleton_method(:map_row,row_mapper) if block_given?
32
- super(options)
33
- end
34
-
35
- # Maps a row into a new filepath
36
- #
37
- # @param [Hash] row sqlite result hash for a row
38
- # @return [String,String,Hash<Symbol,Object>] newpath, realpath, options
39
- # * newpath - the mapped path
40
- # * realpath - path to the real file
41
- # * options - additional information to store with this path
42
- # @abstract
43
- def map_row(row)
44
- raise NotImplementedError, "abstract method #{__method__} not implemented"
45
- end
46
-
47
- # FuseFS callback when the filesystem is mounted
48
- # Starts the scanning loop and performs the initial scan
49
- # @api FuseFS
50
- def mounted()
51
- @mounted = true
52
- @mutex = Mutex.new
53
- @cv = ConditionVariable.new
54
- @scan_thread = Thread.new() { scan_loop() }
55
- end
56
-
57
- # FuseFS callback when filesystem is unmounted
58
- #
59
- # Stops the database watching threads
60
- # @api FuseFS
61
- def unmounted()
62
- @mounted = false
63
- @mutex.synchronize { @cv.signal() }
64
- @scan_thread.join
65
- end
66
-
67
-
68
- # Trigger a rescan of the database
69
- def rescan()
70
- @mutex.synchronize { @cv.signal() }
71
- end
72
-
73
- # Executes the sql query and passes each row to map_row (or the block passed in {#initialize})
74
- #
75
- # Subclasses can override this method for pre/post scan processing, calling super as required
76
- def scan()
77
- db.execute(@sql) do |row|
78
- new_path, real_path, options = map_row(row)
79
- options ||= {}
80
- options[:sqlite_scan_id] = @scan_id
81
- begin
82
- map_file(new_path, real_path, options)
83
- rescue StandardError => e
84
- puts e
85
- puts e.backtrace.join("\n")
86
- end
87
- end
88
- cleanup() { |file_node| file_node.options[:sqlite_scan_id] != @scan_id }
89
- end
90
-
91
- private
92
-
93
- def scan_loop()
94
- @mutex.synchronize() do
95
- @scan_id = 0
96
- while @mounted
97
- begin
98
- @db = SQLite3::Database.new(@db_path,:readonly => true)
99
- @db.results_as_hash = true
100
- @db.busy_timeout(10000)
101
- @scan_id = @scan_id + 1
102
- scan()
103
- rescue StandardError => e
104
- puts e
105
- puts e.backtrace.join("\n")
106
- ensure
107
- @db.close unless @db.closed?
108
- @db = nil
109
- end
110
- @cv.wait(@mutex)
111
- end
112
- end
113
- end
114
- end
115
- end
@@ -1,3 +0,0 @@
1
- module RFuseFS
2
- VERSION="1.0.2.RC1"
3
- end
@@ -1,31 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "rfusefs/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "rfusefs"
7
- s.version = RFuseFS::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Grant Gardner"]
10
- s.email = ["grant@lastweekend.com.au"]
11
- s.homepage = "http://rubygems.org/gems/rfusefs"
12
- s.summary = %q{Filesystem in Ruby Userspace}
13
- s.description = %q{A more Ruby like way to write FUSE filesystems - inspired by (compatible with) FuseFS, implemented over RFuse}
14
-
15
- s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,spec-fusefs}/*`.split("\n")
17
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- s.require_paths = ["lib"]
19
-
20
- s.has_rdoc = 'yard'
21
- s_extra_rdoc_files = 'History.rdoc'
22
-
23
- s.add_dependency("rfuse", ">= 1.0.5RC0")
24
- s.add_development_dependency("rake")
25
- s.add_development_dependency("rspec")
26
- s.add_development_dependency("yard")
27
- s.add_development_dependency("redcarpet")
28
- s.add_development_dependency("sqlite3")
29
- s.add_development_dependency("sys-filesystem")
30
- s.add_development_dependency("ffi-xattr", ">= 0.1.1")
31
- end
@@ -1,57 +0,0 @@
1
- require "rubygems"
2
- require 'rfusefs'
3
- require 'fusefs/metadir'
4
- require 'fusefs/dirlink'
5
-
6
- include FuseFS
7
-
8
- root = MetaDir.new
9
- root.stats.total_space = 1024*1024
10
- root.stats.total_nodes = 1024
11
- root.stats.strict = true
12
-
13
- class Counter
14
- def initialize
15
- @counter = 0
16
- end
17
- def to_s
18
- @counter += 1
19
- @counter.to_s + "\n"
20
- end
21
- def size
22
- @counter.to_s.size
23
- end
24
- end
25
-
26
- class Randwords
27
- def initialize(*ary)
28
- @ary = ary.flatten
29
- end
30
- def to_s
31
- @ary[rand(@ary.size)].to_s + "\n"
32
- end
33
- def size
34
- @size ||= @ary.map{|v| v.size}.max
35
- end
36
- end
37
-
38
- root.write_to('/hello',"Hello, World!\n")
39
-
40
- progress = '.'
41
-
42
- root.write_to('/progress',progress)
43
-
44
- Thread.new do
45
- 20.times do
46
- sleep 5
47
- progress << '.'
48
- end
49
- end
50
-
51
- root.write_to('/counter',Counter.new)
52
- root.write_to('/color',Randwords.new('red','blue','green','purple','yellow','bistre','burnt sienna','jade'))
53
- root.write_to('/animal',Randwords.new('duck','dog','cat','duck billed platypus','silly fella'))
54
-
55
- root.mkdir("/#{ENV['USER']}",FuseFS::DirLink.new(ENV['HOME']))
56
-
57
- FuseFS.main(ARGV) { | options | root }
@@ -1,74 +0,0 @@
1
- # dictfs.rb
2
-
3
- require "rubygems"
4
- require 'fusefs'
5
- include FuseFS
6
-
7
- #TODO: GG Don't know which "dict" this was referring to
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
- unless (ARGV.length > 0 && File.directory?(ARGV[0]))
65
- puts "Usage: #{$0} <mountpoint> <mount_options>"
66
- exit
67
- end
68
-
69
- root = DictFS.new
70
-
71
- # Set the root FuseFS
72
- FuseFS.start(root,*ARGV)
73
-
74
- end
@@ -1,20 +0,0 @@
1
- class HelloDir
2
- def contents(path)
3
- ['hello.txt']
4
- end
5
-
6
- def file?(path)
7
- path == '/hello.txt'
8
- end
9
-
10
- def read_file(path)
11
- "Hello, World!\n"
12
- end
13
-
14
- end
15
-
16
- if __FILE__ == $0
17
- require 'rfusefs'
18
- hellodir = HelloDir.new
19
- FuseFS.start(hellodir,*ARGV)
20
- end
@@ -1,53 +0,0 @@
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
@@ -1,77 +0,0 @@
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
-
@@ -1,134 +0,0 @@
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