Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

adding to README, added project URL, added documentation to ``xzip/fs…

….py``

- bumping version number (changed mount.xzip options)
- added signal.SIGHUP handler to release unused meta data
- added docstrings
- added -o style options
  • Loading branch information...
commit 2de65bb508f296fbcf2e1830e1501fb7e78cf7e4 1 parent 9c1f1e9
Terence Honles authored May 02, 2012
21  README.rst
Source Rendered
@@ -31,10 +31,16 @@ The file structure for an exploded zip is the following::
31 31
         ├── name-of-zip.zip.jump
32 32
         └── name-of-zip.zip.stream
33 33
 
  34
+The file structure would be mounted by::
34 35
 
35  
-Data files may be shared between an arbitrary number of exploded zips files,
36  
-and the meta tuple (``*.dir``, ``*.jump``, ``*.stream``) describe the original
37  
-zip file.
  36
+    $ mount.xzip . path/to/mount/point
  37
+    $ ls path/to/mount/point
  38
+    name-of-zip.zip
  39
+
  40
+
  41
+Data files may be shared between any number of exploded zips files, and the
  42
+meta tuple (``*.dir``, ``*.jump``, ``*.stream``) describe the original zip
  43
+file.
38 44
 
39 45
 
40 46
 ``zipexplode`` accepts two options ``--directory`` and ``--depth`` to modify
@@ -49,9 +55,12 @@ what needed to be stored per zip file. This executable is mainly of historical
49 55
 use.
50 56
 
51 57
 ``mount.xzip`` will mount the directory structure described above, and needs to
52  
-be supplied with matching ``--directory`` and ``--depth`` arguments to when
53  
-``zipexplode`` was called.  Additional arguments ``--debug``, ``--background``,
54  
-and ``--single-threaded`` which are passed to FUSE_ and control underlying
  58
+be supplied with matching ``directory`` and ``--depth`` arguments to when
  59
+``zipexplode`` was called.  Additional arguments ``--debug``, ``--foreground``,
  60
+and ``--single-threaded`` are passed to FUSE_ and control underlying
55 61
 functionality. For more information see the ``--help`` for ``mount.xzip``.
  62
+(``mount.xzip`` also takes ``-o`` style options)
  63
+
  64
+**Note: At this time  xzip is not zip64 safe**
56 65
 
57 66
 .. _FUSE: http://fuse.sourceforge.net/
3  setup.py
@@ -14,7 +14,7 @@
14 14
 
15 15
 setup(
16 16
         name = 'xzip',
17  
-        version = '0.9',
  17
+        version = '0.10',
18 18
         packages = find_packages(),
19 19
 
20 20
         install_requires = ['fusepy>=1.1'],
@@ -25,6 +25,7 @@
25 25
         long_description = documentation,
26 26
         license = 'PSF',
27 27
         keywords = 'FS FileSystem File System Zip Deduplication',
  28
+        url = 'https://github.com/terencehonles/xzip',
28 29
 
29 30
         entry_points = {
30 31
             'console_scripts': [
84  xzip/fs.py
@@ -4,9 +4,11 @@
4 4
 import errno
5 5
 import fuse
6 6
 import os
  7
+import signal
7 8
 import stat
8 9
 import threading
9 10
 import time
  11
+import weakref
10 12
 
11 13
 from argparse import ArgumentParser
12 14
 from binascii import b2a_hex
@@ -33,6 +35,11 @@
33 35
          'filename_len', 'extra_field_len', 'descriptor_len', 'sha'))
34 36
 
35 37
 class SeekTree(object):
  38
+    '''
  39
+    Create an object which maps a source offset range to a destination
  40
+    offset supporting logarithmic read access.
  41
+    '''
  42
+
36 43
     __slots__ = ('location', 'left', 'right')
37 44
 
38 45
     def __init__(self, location, left=None, right=None):
@@ -42,6 +49,11 @@ def __init__(self, location, left=None, right=None):
42 49
 
43 50
     @staticmethod
44 51
     def load(iterator):
  52
+        '''
  53
+        Create a ``SeekTree`` from a sorted sequence of pairs
  54
+        (source, destination)
  55
+        '''
  56
+
45 57
         last_level = ((SeekTree(i), i[0]) for i in iterator)
46 58
         top_level = []
47 59
         loop = True
@@ -71,6 +83,8 @@ def load(iterator):
71 83
             return
72 84
 
73 85
     def find(self, offset):
  86
+        'Finds the original range mapping that ``offset`` specifies'
  87
+
74 88
         if isinstance(self.location, tuple):
75 89
             return self
76 90
         elif offset < self.location:
@@ -87,6 +101,7 @@ def _unpack_stream(stream, struct):
87 101
                           'filesize directory_offset jump_tree')
88 102
 
89 103
 class ExplodedZip(Operations):
  104
+    'Create an E[x]ploded Zip FUSE handler'
90 105
     def __init__(self, base='.', depth=0):
91 106
         self.base = path.realpath(base)
92 107
         self.depth = depth
@@ -97,7 +112,11 @@ def __init__(self, base='.', depth=0):
97 112
         self.__fh_lock = threading.Lock()
98 113
 
99 114
     def _exploded_info(self, path):
100  
-        if path in self.__exploded_info: return self.__exploded_info[path]
  115
+        'Loads the jump list and file info into memory'
  116
+
  117
+        # safer with _reset and _release
  118
+        info = self.__exploded_info.get(path)
  119
+        if info: return info
101 120
 
102 121
         jump_name = os.path.join(self.base, 'meta',
103 122
                                  os.path.basename(path) + '.jump')
@@ -119,6 +138,23 @@ def _metafiles(self, path):
119 138
     def _not_supported(*args, **kargs):
120 139
         raise FuseOSError(fuse.ENOTSUP)
121 140
 
  141
+    def _release(self):
  142
+        'Releases all unused meta data information'
  143
+
  144
+        with self.__fh_lock:
  145
+            if not self.__handles: self.__fh = 0
  146
+
  147
+        self.__exploded_info = \
  148
+                dict(weakref.WeakValueDictionary(self.__exploded_info))
  149
+
  150
+    def _reset(self):
  151
+        'Releases all meta data information'
  152
+
  153
+        with self.__fh_lock:
  154
+            if not self.__handles: self.__fh = 0
  155
+
  156
+        self.__exploded_info = {}
  157
+
122 158
     def access(self, path, amode):
123 159
         # this is a read only file system
124 160
         if amode & os.W_OK: return -errno.EACCES
@@ -227,6 +263,8 @@ def link(self, target, source):
227 263
 
228 264
     def open(self, path, flags):
229 265
         with self.__fh_lock:
  266
+            if not self.__handles: self.__fh = 0
  267
+
230 268
             raw = File(path, flags, self._exploded_info(path), fh=self.__fh,
231 269
                        base=self.base, depth=self.depth)
232 270
 
@@ -295,6 +333,8 @@ def utimens(self, path, time=None):
295 333
 
296 334
 
297 335
 class File(RawIOBase):
  336
+    'Create a file object wrapping an e[x]ploded zip file'
  337
+
298 338
     HEADER = 0
299 339
     DATA = 1
300 340
     DESCRIPTOR = 2
@@ -334,6 +374,8 @@ def __init__(self, path, flags, info, fh=None, base='.', depth=0):
334 374
         self.lock = threading.Lock()
335 375
 
336 376
     def _load_stream_item(self):
  377
+        'Sets the next stream item as current.'
  378
+
337 379
         if self.data:
338 380
             self.data.close()
339 381
             self.data = None
@@ -582,29 +624,53 @@ def writeable(self):
582 624
 parser = ArgumentParser(description='Exposes exploded zip file(s) as a FUSE '
583 625
                                     'file system.')
584 626
 
585  
-parser.add_argument('-d', '--directory', metavar='DIR', default='.',
586  
-                    help='alternate base for the exploded files')
587  
-
588  
-parser.add_argument('--depth', type=int, default=0,
  627
+parser.add_argument('-d', '--depth', type=int, default=0,
589 628
                     help='data subdirectory depth')
590 629
 
591 630
 parser.add_argument('-D', '--debug', action='store_true', default=False,
592 631
                     help='enable FUSE debugging mode')
593 632
 
594  
-parser.add_argument('-b', '--background', action='store_true', default=False,
  633
+parser.add_argument('-f', '--foreground', action='store_true', default=False,
595 634
                     help='do not exit until the file system is unmounted')
596 635
 
597 636
 parser.add_argument('-s', '--single-threaded', action='store_true',
598 637
                     default=False, help='do not run in multi-threaded mode')
599 638
 
  639
+parser.add_argument('-o', action='append', metavar='OPTIONS', default=None,
  640
+                    help='''"traditional" mount style options
  641
+                            (high priorty, but full spelling required),
  642
+                            --single-threaded -> nothread''')
  643
+
  644
+parser.add_argument('directory', help='base for the exploded files')
600 645
 parser.add_argument('mount', help='mount point')
601 646
 
  647
+def parse_o_options(options):
  648
+    for item in ','.join(options).split(','):
  649
+        try:
  650
+            k, v = item.split('=', 1)
  651
+        except ValueError:
  652
+            k, v = item, True
  653
+
  654
+        yield k, v
  655
+
602 656
 def main():
  657
+    'mounts an e[x]ploded zip file system'
  658
+
603 659
     args = parser.parse_args()
  660
+    opts = dict(parse_o_options(args.o or []))
  661
+
  662
+    if 'depth' in opts: args.depth = int(opts['depth'])
  663
+    if 'debug' in opts: args.debug = True
  664
+    if 'foreground' in opts: args.foreground = True
  665
+    if 'nothread' in opts: args.single_threaded = True
  666
+
  667
+    operations = ExplodedZip(base=args.directory, depth=args.depth)
  668
+
  669
+    def release(*_): operations._release()
  670
+    signal.signal(signal.SIGHUP, release)
604 671
 
605  
-    fuse = FUSE(ExplodedZip(base=args.directory, depth=args.depth),
606  
-                args.mount, foreground=not args.background, ro=True,
607  
-                debug=args.debug, nothreads=args.single_threaded)
  672
+    fuse = FUSE(operations, args.mount, foreground=args.foreground,
  673
+                ro=True, debug=args.debug, nothreads=args.single_threaded)
608 674
 
609 675
 if __name__ == '__main__':
610 676
     main()

0 notes on commit 2de65bb

Please sign in to comment.
Something went wrong with that request. Please try again.