rfusefs 1.0.2.RC1 → 1.1.0

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.
@@ -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