"Fossies" - the Fresh Open Source Software Archive

Member "pysize-0.2/pysize/core/pysize_fs_node.py" (11 Mar 2007, 10035 Bytes) of package /linux/privat/old/pysize-0.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # This program is free software; you can redistribute it and/or modify
    2 # it under the terms of the GNU General Public License as published by
    3 # the Free Software Foundation; either version 2 of the License, or
    4 # (at your option) any later version.
    5 #
    6 # This program is distributed in the hope that it will be useful,
    7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9 # GNU Library General Public License for more details.
   10 #
   11 # You should have received a copy of the GNU General Public License
   12 # along with this program; if not, write to the Free Software
   13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   14 #
   15 # See the COPYING file for license information.
   16 #
   17 # Copyright (c) 2006, 2007 Guillaume Chazarain <guichaz@yahoo.fr>
   18 
   19 import os
   20 import stat
   21 
   22 from pysize.core import chdir_browsing
   23 from pysize.core import compute_size
   24 from pysize.core.pysize_global_fs_cache import get_dev_ino, cache_add_dir
   25 from pysize.core.deletion import get_subtracted
   26 
   27 def _extract_prefix_suffixes(paths):
   28     """['/prefix/suffix1', '/prefix/suffix2', '/prefix/suffix3'] =>
   29         ('/prefix', ['suffix1', 'suffix2', 'suffix3'])"""
   30     prefix_len = os.path.commonprefix(paths).rfind('/') + 1
   31     prefix = paths[0][:prefix_len - 1]
   32     suffixes = [p[prefix_len:] for p in paths]
   33     return prefix, suffixes
   34 
   35 def _join_prefix_suffixes(prefix, suffixes):
   36     if len(suffixes) == 1:
   37         suffix = suffixes[0]
   38     else:
   39         suffix = '{' + ','.join(suffixes) + '}'
   40     return os.path.join(prefix, suffix)
   41 
   42 
   43 def _sort_nodes(nodes):
   44     def cmp_fn(n1, n2):
   45         return cmp(n2.size, n1.size) or cmp(n1.get_name(), n2.get_name())
   46     nodes.sort(cmp=cmp_fn)
   47 
   48 class _pysize_node(object):
   49     """The parent class of all displayed nodes, as these nodes are displayed on
   50     screen, there should be few instances."""
   51     def __init__(self, parent, basename, options):
   52         self.rectangle = None
   53         self.parent = parent
   54         self.children = []
   55         self.basename = basename
   56         if basename:
   57             self.size = compute_size.slow(basename, options.cross_device)
   58         else:
   59             self.size = 0
   60 
   61     def compute_height(self):
   62         if self.children:
   63             children_height = max([c.compute_height() for c in self.children])
   64             return children_height + 1
   65         return 0
   66 
   67     def compute_depth(self):
   68         depth = 0
   69         node = self
   70         while node:
   71             node = node.parent
   72             depth += 1
   73         return depth
   74 
   75     def minimum_node_size(self):
   76         res = self.size
   77         for child in self.children:
   78             child_min_node_size = child.minimum_node_size()
   79             res = min(res, child_min_node_size)
   80         return res
   81 
   82     def get_dirname(self):
   83         return os.path.dirname(self.get_fullpaths()[0])
   84 
   85     def is_dir(self):
   86         return False
   87 
   88     def is_real(self):
   89         """Does the node correspond to a path that actually exists?"""
   90         return True
   91 
   92     def get_fullname(self):
   93         fullpaths = self.get_fullpaths()
   94         prefix, suffixes = _extract_prefix_suffixes(fullpaths)
   95         fullname = _join_prefix_suffixes(prefix, suffixes)
   96         return fullname
   97 
   98     def get_fullpaths(self):
   99         parent = self.parent
  100         fullpath = self.basename
  101         while parent:
  102             fullpath = os.path.join(parent.basename, fullpath)
  103             parent = parent.parent
  104         return [fullpath]
  105 
  106     def get_name(self):
  107         """Return the name that should be displayed for this node."""
  108         return self.basename
  109 
  110     def __iter__(self):
  111         """The iterator is a depth first traversal."""
  112         yield self
  113         for child in self.children:
  114             for node in child:
  115                 yield node
  116 
  117     def contains_point(self, p):
  118         """Is the point p in the graphical representation of this node?"""
  119         if not self.rectangle:
  120             return False
  121         x0, x1, y0, y1 = self.rectangle
  122         return x0 < p.x and p.x < x1 and y0 < p.y and p.y < y1
  123 
  124 class _pysize_node_collection(_pysize_node):
  125     """A directory"""
  126     def __init__(self, parent, prefix, children, max_depth, min_size, options):
  127         super(_pysize_node_collection, self).__init__(parent, None, options)
  128         self.basename = prefix
  129         fullpaths = [os.path.join(prefix, p) for p in children]
  130         if max_depth == 0:
  131             self.size = compute_size.slow_sum(fullpaths, options.cross_device)
  132         else:
  133             children_size = 0
  134             remaining_size = 0
  135             remaining_nodes = []
  136             cookie = chdir_browsing.init(prefix)
  137             try:
  138                 for child in children:
  139                     try:
  140                         node = create_node(self, child, max_depth - 1, min_size,
  141                                            options)
  142                     except OSError:
  143                         print child, 'disappeared'
  144                         continue
  145                     if node.is_real():
  146                         self.children.append(node)
  147                         children_size += node.size
  148                     else:
  149                         node.__name = child
  150                         remaining_nodes.append(node)
  151                         remaining_size += node.size
  152 
  153                 _sort_nodes(self.children)
  154                 if remaining_size > min_size:
  155                     _sort_nodes(remaining_nodes)
  156                     names = [n.__name for n in remaining_nodes]
  157                     rem = _pysize_node_remaining(self, names, options)
  158                     self.children.append(rem)
  159             finally:
  160                 chdir_browsing.finalize(cookie)
  161             self.size = children_size + remaining_size
  162 
  163     def is_real(self):
  164         """This node does not actually exists, it is an aggregate."""
  165         return False
  166 
  167 class _pysize_node_forest(_pysize_node_collection):
  168     def __init__(self, parent, children, max_depth, min_size, options):
  169         prefix, suffixes = _extract_prefix_suffixes(children)
  170         super(_pysize_node_forest, self).__init__(parent, prefix, suffixes,
  171                                                   max_depth, min_size, options)
  172         self.basename = prefix
  173         self.forest_paths = suffixes
  174         self.forest_name = _join_prefix_suffixes(prefix, suffixes)
  175 
  176     def get_name(self):
  177         return self.forest_name
  178 
  179     def get_dirname(self):
  180         return self.basename
  181 
  182     def get_fullpaths(self):
  183         fullpaths = self.forest_paths
  184         parent = self
  185         while parent:
  186             fullpaths = [os.path.join(parent.basename, fp) for fp in fullpaths]
  187             parent = parent.parent
  188         return fullpaths
  189 
  190 class _pysize_node_dir(_pysize_node_collection):
  191     """A directory"""
  192     def __init__(self, parent, basename, max_depth, min_size, options):
  193         listing = chdir_browsing.listdir(basename, options.cross_device)
  194         super(_pysize_node_dir, self).__init__(parent, basename,
  195                                                listing, max_depth,
  196                                                min_size, options)
  197         self.basename = basename
  198         self.size += os.lstat(basename).st_blocks * 512
  199         # update size in cache, in case files were added/removed
  200         dev_ino = get_dev_ino(basename)
  201         cache_add_dir(dev_ino, self.size + get_subtracted(basename))
  202 
  203     def is_dir(self):
  204         return True
  205 
  206     def is_real(self):
  207         return True
  208 
  209     def get_name(self):
  210         name = self.basename
  211         if name != '/':
  212             name += '/'
  213         return name
  214 
  215 class _pysize_node_remaining(_pysize_node_collection):
  216     """The sum of a directory's children that are too small to be drawn."""
  217     def __init__(self, parent, elements, options):
  218         _pysize_node.__init__(self, parent, None, options)
  219         # The parent constructor would visit the files
  220         self.size = compute_size.slow_sum(elements, options.cross_device)
  221         self.remaining_elements = elements
  222 
  223     def get_name(self):
  224         return '{' + ','.join(self.remaining_elements) + '}'
  225 
  226     def get_fullname(self):
  227         if self.remaining_elements:
  228             return _pysize_node_collection.get_fullname(self)
  229         return '' # This is the initial node
  230 
  231     def get_fullpaths(self):
  232         fullpaths = self.remaining_elements
  233         parent = self.parent
  234         while parent:
  235             fullpaths = [os.path.join(parent.basename, fp) for fp in fullpaths]
  236             parent = parent.parent
  237         return fullpaths
  238 
  239 class _pysize_node_file(_pysize_node):
  240     """A file"""
  241     def __init__(self, parent, basename, options):
  242         super(_pysize_node_file, self).__init__(parent, basename, options)
  243 
  244 class _pysize_node_hardlink(_pysize_node_file):
  245     """A hardlink, the canonical one, or a link"""
  246     def __init__(self, parent, basename, options):
  247         super(_pysize_node_hardlink, self).__init__(parent, basename, options)
  248 
  249 def create_node(parent, what, max_depth, min_size, options):
  250     """Return a pysize_node for parent/basename traversing up to max_depth
  251     levels and only taking into account elements bigger than min_size."""
  252     if not what:
  253         return _pysize_node_remaining(parent, [], options)
  254 
  255     if isinstance(what, list):
  256         size = compute_size.slow_sum(what, options.cross_device)
  257         if len(what) == 1:
  258             what = what[0]
  259     else:
  260         size = compute_size.slow(what, options.cross_device)
  261 
  262     if size < min_size:
  263         if isinstance(what, str):
  264             what = [what]
  265         node = _pysize_node_remaining(parent, what, options)
  266     elif isinstance(what, list):
  267         node = _pysize_node_forest(parent, what, max_depth, min_size, options)
  268     else:
  269         st = os.lstat(what)
  270         if stat.S_ISDIR(st.st_mode):
  271             node = _pysize_node_dir(parent, what, max_depth, min_size, options)
  272         elif st.st_nlink > 1:
  273             node = _pysize_node_hardlink(parent, what, options)
  274         else:
  275             node = _pysize_node_file(parent, what, options)
  276     return node