Class: FedoraFS

Inherits:
FuseFS::FuseDir
  • Object
show all
Includes:
FuseFS, Traceable
Defined in:
lib/fedorafs.rb

Defined Under Namespace

Classes: PathError

Constant Summary collapse

FOXML_XML =
'foxml.xml'
PROPERTIES_XML =
'profile.xml'
RISEARCH_CONTENTS_PARAMS =
{ :query => "select $object from <#ri> where $object <info:fedora/fedora-system:def/model#label> $label", :type => 'tuples', :lang => 'itql', :format => 'CSV' }
SPECIAL_FILES =
{
  :attributes => ["last_refresh", "next_refresh", "object_cache", "object_count"],
  :signals    => ["log_level", "read_only", "attribute_xml", "refresh_time"]
}
DEFAULT_OPTS =
{
  :url => 'http://localhost:8983/fedora/', :user => nil, :password => nil,
  :cert_file => nil, :key_file => nil, :key_pass => '',
  :logdev => $stderr, :log_level => Logger::INFO,
  :cache_size => 1000, :refresh_time => 120,
  :attribute_xml => false, :read_only => false,
  :splitters => {},
}
DEFAULT_SPLITTERS =
{ :default => /.+/, 'fedora-system' => /.+/ }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Traceable

included

Constructor Details

#initialize(init_opts = {}) ⇒ FedoraFS

Returns a new instance of FedoraFS.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/fedorafs.rb', line 42

def initialize(init_opts = {})
  traceables = Array(init_opts.delete(:trace_methods))
  self.class.trace(*traceables) unless traceables.empty?

  @opts = OpenStruct.new(DEFAULT_OPTS.merge(init_opts))

  rest_opts = { :user => opts.user, :password => opts.password }
  unless opts.cert_file.nil?
    rest_opts[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(opts.cert_file))
  end
  unless opts.key_file.nil?
    rest_opts[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(opts.key_file), opts.key_pass)
  end
  @repo = RestClient::Resource.new(opts.url, rest_opts)
  
  @last_refresh = nil
  @cache = LruHash.new(opts.cache_size)
  @pids = nil
  
  opts.splitters = DEFAULT_SPLITTERS.merge(opts.splitters)
  opts.splitters.each_pair do |k,v| 
    if v.is_a?(String)
      opts.splitters[k] = Regexp.compile(v.gsub(/^\/|\/$/,''))
    end
  end
end

Instance Attribute Details

#attribute_xmlObject

Attribute accessors



257
258
259
# File 'lib/fedorafs.rb', line 257

def attribute_xml
  @attribute_xml
end

#last_refreshObject (readonly)

Returns the value of attribute last_refresh.



39
40
41
# File 'lib/fedorafs.rb', line 39

def last_refresh
  @last_refresh
end

#loggerObject (readonly)

Returns the value of attribute logger.



39
40
41
# File 'lib/fedorafs.rb', line 39

def logger
  @logger
end

#optsObject (readonly)

Returns the value of attribute opts.



39
40
41
# File 'lib/fedorafs.rb', line 39

def opts
  @opts
end

#read_onlyObject

Returns the value of attribute read_only.



40
41
42
# File 'lib/fedorafs.rb', line 40

def read_only
  @read_only
end

#refresh_timeObject

Returns the value of attribute refresh_time.



40
41
42
# File 'lib/fedorafs.rb', line 40

def refresh_time
  @refresh_time
end

#repoObject (readonly)

Returns the value of attribute repo.



39
40
41
# File 'lib/fedorafs.rb', line 39

def repo
  @repo
end

Instance Method Details

#atime(path) ⇒ Object

atime, ctime, mtime, and utime aren’t implemented in FuseFS yet



158
159
160
# File 'lib/fedorafs.rb', line 158

def atime(path)
  utime(path)
end

#cache(pid) ⇒ Object



265
266
267
268
269
270
# File 'lib/fedorafs.rb', line 265

def cache(pid)
  unless @cache.has_key?(pid)
    @cache[pid] = {}
  end
  @cache[pid]
end

#can_delete?(path) ⇒ Boolean

Returns:

  • (Boolean)


252
253
254
# File 'lib/fedorafs.rb', line 252

def can_delete?(path)
  return true # We're never actually going to delete anything, though.
end

#can_mkdir?(path) ⇒ Boolean

Returns:

  • (Boolean)


244
245
246
# File 'lib/fedorafs.rb', line 244

def can_mkdir?(path)
  return false
end

#can_rmdir?(path) ⇒ Boolean

Returns:

  • (Boolean)


248
249
250
# File 'lib/fedorafs.rb', line 248

def can_rmdir?(path)
  return false
end

#can_write?(path) ⇒ Boolean

Returns:

  • (Boolean)


207
208
209
210
211
212
213
214
215
216
# File 'lib/fedorafs.rb', line 207

def can_write?(path)
  if is_signal_file?(path) or (path =~ /\._/) # We'll fake it out in #write_to()
    return true
  elsif read_only or is_attribute_file?(path)
    return false
  else
    parts = scan_path(path)
    return (file?(path) and (parts.last != FOXML_XML) and (parts.last !~ /#{PROPERTIES_XML}$/))
  end
end

#contents(path) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/fedorafs.rb', line 69

def contents(path)
  parts = scan_path(path)
  if parts.empty?
    return pid_tree.keys
  else
    current_dir, dir_part, parts, pid = traverse(parts)
    if current_dir.nil?
      files = [FOXML_XML]
      files << PROPERTIES_XML if attribute_xml
      with_exception_logging([]) do
        datastreams(pid).each do |ds|
          mime = MIME::Types[ds_properties(pid,ds)['dsmime']].first
          files << (mime.nil? ? ds : "#{ds}.#{mime.extensions.first}")
          files << "#{ds}.#{PROPERTIES_XML}" if attribute_xml
        end
      end
      if parts.empty?
        files
      else
        fname = parts.shift
        files.select { |f| f == fname }
      end
    else
      return current_dir.keys
    end
  end
end

#ctime(path) ⇒ Object



162
163
164
# File 'lib/fedorafs.rb', line 162

def ctime(path)
  utime(path)
end

#directory?(path) ⇒ Boolean

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/fedorafs.rb', line 97

def directory?(path)
  return false if path =~ /\._/
  return false if is_attribute_file?(path)
  parts = scan_path(path)
  return true if parts.empty?
  current_dir, dir_part, parts, pid = begin
    traverse(parts)
  rescue PathError
    return false
  end
  if current_dir.nil?
    return parts.empty?
  else
    return true
  end
end

#file?(path) ⇒ Boolean

Returns:

  • (Boolean)


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/fedorafs.rb', line 114

def file?(path)
  return false if path =~ /\._/
  return true if is_attribute_file?(path) or is_signal_file?(path)
  parts = scan_path(path)
  current_dir, dir_part, parts, pid = begin
    traverse(parts)
  rescue PathError
    return false
  end
  if parts.empty?
    return true
  else
    file = parts.last
    list = contents(File.dirname(path))
    list.any? { |entry| entry == file or PROPERTIES_XML == file or File.basename(entry,File.extname(entry))+'.'+PROPERTIES_XML == file }
  end
end

#log_levelObject



272
273
274
# File 'lib/fedorafs.rb', line 272

def log_level
  logger.level
end

#log_level=(value) ⇒ Object



276
277
278
# File 'lib/fedorafs.rb', line 276

def log_level=(value)
  logger.level = opts.log_level = value.to_i
end

#mtime(path) ⇒ Object



166
167
168
# File 'lib/fedorafs.rb', line 166

def mtime(path)
  utime(path)
end

#next_refreshObject



286
287
288
# File 'lib/fedorafs.rb', line 286

def next_refresh
  @last_refresh.nil? ? Time.now : (@last_refresh + opts.refresh_time)
end

#object_cacheObject



290
291
292
# File 'lib/fedorafs.rb', line 290

def object_cache
  @cache.to_json
end

#object_count(hash = @pids) ⇒ Object



294
295
296
297
298
# File 'lib/fedorafs.rb', line 294

def object_count(hash = @pids)
  result = 0
  hash.each_pair { |k,v| result += v.nil? ? 1 : object_count(v) }
  result
end

#read_file(path) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/fedorafs.rb', line 177

def read_file(path)
  return '' if path =~ /\._/
  unless write_stack[path].nil?
    write_stack[path]
  else
    with_exception_logging do
      if is_attribute_file?(path) or is_signal_file?(path)
        accessor = File.basename(path,File.extname(path)).sub(/^\.+/,'').to_sym
        content = self.send(accessor)
        "#{content.to_s}\n"
      else
        parts = scan_path(path)
        current_dir, dir_part, parts, pid = traverse(parts)
        fname = parts.last
        if fname == FOXML_XML
          @repo["objects/#{pid}/export"].get
        elsif fname == PROPERTIES_XML
          @repo["objects/#{pid}?format=xml"].get
        elsif fname =~ /^(.+)\.#{PROPERTIES_XML}$/
          dsid = $1
          @repo["objects/#{pid}/datastreams/#{dsid}.xml"].get
        else
          dsid = dsid_from_filename(fname)
          @repo["objects/#{pid}/datastreams/#{dsid}/content"].get
        end
      end
    end
  end
end

#size(path) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/fedorafs.rb', line 132

def size(path)
  return false if path =~ /\._/
  if is_attribute_file?(path) or is_signal_file?(path)
    return read_file(path).length
  elsif write_stack.has_key?(path)
    write_stack[path].length
  else
    parts = scan_path(path)
    current_dir, dir_part, parts, pid = begin
      traverse(parts)
    rescue PathError
      return false
    end

    if parts.last == FOXML_XML
      read_file(path).length
    elsif parts.last =~ /#{PROPERTIES_XML}$/
      read_file(path).length
    else
      dsid = dsid_from_filename(parts.last)
      ds_properties(pid, dsid)['dssize'].to_i
    end
  end
end

#utime(path) ⇒ Object



170
171
172
173
174
175
# File 'lib/fedorafs.rb', line 170

def utime(path)
  parts = scan_path(path)
  current_dir, dir_part, parts, pid = traverse(parts)
  dsid = dsid_from_filename(parts.last)
  Time.parse(ds_properties(pid, dsid)['dscreatedate'])
end

#write_to(path, content) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/fedorafs.rb', line 218

def write_to(path,content)
  if content.empty? and write_stack[path].nil?
    write_stack[path] = content
  else
    write_stack.delete(path)
    with_exception_logging do
      if is_signal_file?(path)
        logger.debug("Setting #{File.basename(path)} to #{content.chomp.inspect}")
        accessor = "#{File.basename(path)}=".to_sym
        self.send(accessor, content)
      else
        unless read_only or (path =~ /\._/) or (path =~ /#{FOXML_XML}$/) or (path =~ /#{PROPERTIES_XML}$/)
          parts = scan_path(path)
          current_dir, dir_part, parts, pid = traverse(parts)
          fname = parts.last
          dsid = dsid_from_filename(fname)
          mime = ds_properties(pid,dsid)['dsmime'] || 'application/octet-stream'
          resource = @repo["objects/#{pid}/datastreams/#{dsid}?logMessage=Fedora+FUSE+FS"]
          resource.put(content, :content_type => mime)
        end
      end
    end
  end
  return content
end