4 from pysize
.core
import chdir_browsing
5 from pysize
.core
import compute_size
8 """The parent class of all displayed nodes, as these nodes are displayed on
9 screen, there should be few instances."""
10 def __init__(self
, parent
, basename
):
11 self
.rectangle
= (0, 0, 0, 0)
14 self
.basename
= basename
16 self
.size
= compute_size
.slow(basename
)
20 def compute_height(self
):
22 children_height
= max([c
.compute_height() for c
in self
.children
])
23 return children_height
+ 1
26 def compute_depth(self
):
34 def minimum_real_size(self
):
36 for child
in self
.children
:
37 child_min_real_size
= child
.minimum_real_size()
38 if child_min_real_size
>= 0 and child_min_real_size
< res
:
39 res
= child_min_real_size
42 def get_dirname(self
):
43 return os
.path
.dirname(self
.get_fullpaths()[0])
49 """Does the node correspond to a path that actually exists?"""
52 def get_fullname(self
):
53 return self
.get_dirname() + '/' + self
.get_name()
55 def get_fullpaths(self
):
57 fullpath
= self
.basename
59 fullpath
= parent
.basename
+ '/' + fullpath
60 parent
= parent
.parent
64 """Return the name that should be displayed for this node."""
68 """The iterator is a depth first traversal."""
70 for child
in self
.children
:
74 def contains_point(self
, p
):
75 """Is the point p in the graphical representation of this node?"""
76 (x0
, x1
, y0
, y1
) = self
.rectangle
77 return x0
< p
.x
and p
.x
< x1
and y0
< p
.y
and p
.y
< y1
79 class _pysize_node_collection(_pysize_node
):
81 def __init__(self
, parent
, prefix
, children
, max_depth
, min_size
):
82 _pysize_node
.__init
__(self
, parent
, None)
83 self
.basename
= prefix
84 self
.size
= sum([compute_size
.slow(prefix
+ '/' + p
) for p
in children
])
89 cookie
= chdir_browsing
.init(prefix
)
91 for child
in children
:
92 node
= create_node(self
, child
, max_depth
- 1, min_size
)
94 self
.children
.append(node
)
95 children_size
+= node
.size
97 remaining_items
.append(child
)
98 remaining_size
+= node
.size
100 self
.children
.sort(key
=lambda t
: t
.size
, reverse
=True)
101 if remaining_size
> min_size
:
102 remaining_items
.sort(key
=compute_size
.slow
, reverse
=True)
103 rem
= _pysize_node_remaining(self
, remaining_items
)
104 self
.children
.append(rem
)
106 chdir_browsing
.finalize(cookie
)
107 self
.size
= max(children_size
, self
.size
)
110 """This node does not actually exists, it is an aggregate."""
113 class _pysize_node_forest(_pysize_node_collection
):
114 def __init__(self
, parent
, children
, max_depth
, min_size
):
115 (prefix
, suffixes
) = self
._extract
_prefix
_suffixes
(children
)
116 _pysize_node_collection
.__init
__(self
, parent
, prefix
, suffixes
,
118 self
.basename
= prefix
119 self
.forest_name
= prefix
+ '/{' + ','.join(suffixes
) + '}'
122 return self
.forest_name
124 def get_dirname(self
):
128 def _extract_prefix_suffixes(paths
):
129 """['/prefix/suffix1', '/prefix/suffix2', '/prefix/suffix3'] =>
130 ('/prefix', ['suffix1', 'suffix2', 'suffix3'])"""
131 prefix_len
= os
.path
.commonprefix(paths
).rfind('/') + 1
132 prefix
= paths
[0][:prefix_len
- 1]
133 suffixes
= [p
[prefix_len
:] for p
in paths
]
134 return (prefix
, suffixes
)
136 class _pysize_node_dir(_pysize_node_collection
):
138 def __init__(self
, parent
, basename
, max_depth
, min_size
):
139 zuper
= _pysize_node_collection
.__init
__
140 zuper(self
, parent
, basename
, os
.listdir(basename
), max_depth
, min_size
)
141 self
.basename
= basename
142 self
.size
= max(self
.size
, compute_size
.slow(basename
))
151 return self
.basename
+ '/'
153 class _pysize_node_remaining(_pysize_node_collection
):
154 """The sum of a directory's children that are too small to be drawn."""
155 def __init__(self
, parent
, elements
):
156 _pysize_node
.__init
__(self
, parent
, None)
157 # The parent constructor would visit the files
158 self
.size
= sum(map(compute_size
.slow
, elements
))
159 self
.remaining_elements
= elements
161 def minimum_real_size(self
):
165 return '{' + ','.join(self
.remaining_elements
) + '}'
167 def get_fullname(self
):
168 if self
.remaining_elements
:
169 return _pysize_node_collection
.get_fullname(self
)
170 return '' # This is the initial node
172 def get_fullpaths(self
):
173 fullpaths
= self
.remaining_elements
176 fullpaths
= [parent
.basename
+ '/' + fp
for fp
in fullpaths
]
177 parent
= parent
.parent
180 class _pysize_node_file(_pysize_node
):
182 def __init__(self
, parent
, basename
):
183 _pysize_node
.__init
__(self
, parent
, basename
)
185 class _pysize_node_hardlink(_pysize_node_file
):
186 """A hardlink, the canonical one, or a link"""
187 def __init__(self
, parent
, basename
):
188 _pysize_node_file
.__init
__(self
, parent
, basename
)
190 def create_node(parent
, what
, max_depth
, min_size
):
191 """Return a pysize_node for parent/basename traversing up to max_depth
192 levels and only taking into account elements bigger than min_size."""
194 return _pysize_node_remaining(parent
, [])
196 if isinstance(what
, list):
197 size
= sum(map(compute_size
.slow
, what
))
201 size
= compute_size
.slow(what
)
204 if isinstance(what
, str):
206 node
= _pysize_node_remaining(parent
, what
)
207 elif isinstance(what
, list):
208 node
= _pysize_node_forest(parent
, what
, max_depth
, min_size
)
211 if stat
.S_ISDIR(st
.st_mode
):
212 node
= _pysize_node_dir(parent
, what
, max_depth
, min_size
)
213 elif st
.st_nlink
> 1:
214 node
= _pysize_node_hardlink(parent
, what
)
216 node
= _pysize_node_file(parent
, what
)