"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