Package libxyz :: Package vfs :: Module dispatcher |
[hide private]
[frames] | no frames]

# Source Code for Module libxyz.vfs.dispatcher

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <mek@mek.uz.ua> 2008-2009
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  """
     18  VFSDispatcher - Dispatching to appropriate VFS module based on path.
     19  Path format is following:
     20  [<prefix>]:<path_to_archive>#vfs#<path_inside_archive>
     21  """
     22
     23  import os
     24  import re
     25  import time
     26
     27  from libxyz.vfs import VFSObject
     28  from libxyz.exceptions import VFSError
     29
     30 -class VFSDispatcher(object):
     31 -    def __init__(self, xyz):
     32          self.xyz = xyz
     33          self._handlers = {}
     34          self._cache = {}
     35          self._cache_data = {}
     36
     37          self.vfsre = re.compile(r'(#vfs-\w+#)')
     38          self.vfsre2 = re.compile(r'^#vfs-(\w+)#$')
     39
     40      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     41
     42 -    def register(self, prefix, vfs_obj_class):
     43          """
     44          Register new VFS handler
     45
     46          @param prefix: Patch prefix
     47          @param vfs_obj_class: VFSObject derived class
     48          """
     49
     50          if not issubclass(vfs_obj_class, VFSObject):
     51              raise VFSError(
     52                  _(u"Invalid class: %s. VFSObject dervied expected.") %
     53                  str(vfs_obj_class))
     54
     55          self._handlers[prefix] = vfs_obj_class
     56
     57      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     58
     59 -    def dispatch(self, path, enc=None, **kwargs):
     60          """
     61          Dispatch provided path to corresponding VFS object handler
     62          """
     63
     64          enc = enc or xyzenc
     65          data = self._parse_path(path)
     66
     67          if not data:
     68              raise VFSError(_(u"Invalid path: %s.") % path)
     69
     70          handler = None
     71
     72          kw = {}
     73
     74          for p, vfs in data:
     75              if vfs not in self._handlers:
     76                  raise VFSError(
     77                      _(u"Unable to find VFS handler for %s.") % vfs)
     78              else:
     79                  full_path = self.get_full_path(p, vfs, handler)
     80                  ext_path = self.get_ext_path(handler, vfs)
     81                  kwtmp = self.get_cache(p)
     82                  kw.update(kwtmp)
     83                  kw.update(kwargs)
     84
     85                  handler = self._handlers[vfs](
     86                      self.xyz,
     87                      os.path.abspath(os.path.normpath(p)),
     88                      full_path,
     89                      ext_path,
     90                      vfs,
     91                      handler,
     92                      enc,
     93                      **kw)
     94
     95          return handler
     96
     97      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     98
     99 -    def set_cache(self, path, data):
    100          """
    101          Save some data for VFS object
    102          This data dict is appended to VFSObject's kwargs dict
    103          every time dispatch() is called
    104          """
    105
    106          self._cache[path] = data
    107
    108      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    109
    110 -    def get_cache(self, path):
    111          """
    112          Return saved cache for the object or {} if none was saved
    113          """
    114
    115          atime = self._cache_data.get(path, None)
    116          now = int(time.time())
    117
    118          # Cache obsoleted
    119          if atime is not None and \
    120                 now - atime >= self.xyz.conf["vfs"]["cache_time"]:
    121
    122              self.clear_cache(path)
    123              del(self._cache_data[path])
    124
    125              data = {}
    126          else:
    127              data = self._cache.get(path, {}).copy()
    128
    129          # Update access timestamp
    130          if data:
    131              self._cache_data[path] = now
    132
    133          return data
    134
    135      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    136
    137 -    def clear_cache(self, path):
    138          """
    139          Clear cache for given path
    140          """
    141
    142          try:
    143              del(self._cache[path])
    144          except KeyError:
    145              pass
    146
    147      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    148
    149 -    def _parse_path(self, path):
    150          files = []
    151
    152          driver = None
    153
    154          for entry in re.split(self.vfsre, path):
    155              if not entry:
    156                  entry = os.sep
    157
    158              vfs = self.vfsre2.search(entry)
    159
    160              if driver is not None:
    161                  files.append((entry, driver))
    162                  driver = None
    163              elif vfs:
    164                  driver = vfs.group(1)
    165              else:
    166                  files.append((entry, None))
    167
    168          return files
    169
    170      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    171
    172 -    def get_parent(self, path, enc):
    173          _parent = self.xyz.vfs.dispatch(
    174              os.path.abspath(os.path.dirname(path)), enc)
    175          _parent.name = ".."
    176
    177          return _parent
    178
    179      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    180
    181 -    def get_full_path(self, path, vfs, parent):
    182          """
    183          Return full path
    184          """
    185
    186          if parent:
    187              p = parent.full_path
    188          else:
    189              p = ""
    190
    191          if vfs:
    192              v = "#vfs-%s#" % vfs
    193          else:
    194              v = ""
    195
    196          return p + v + path
    197
    198      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    199
    200 -    def get_ext_path(self, parent, vfs):
    201          """
    202          Return external path
    203          """
    204
    205          if parent:
    206              p = parent.full_path
    207          else:
    208              p = ""
    209
    210          if vfs:
    211              v = "#vfs-%s#" % vfs
    212          else:
    213              v = ""
    214
    215          return p + v
    216