6 from dialog
import Dialog
7 from zeroinstall
.injector
.iface_cache
import iface_cache
8 from zeroinstall
.injector
import basedir
, namespaces
, model
9 from treetips
import TreeTips
15 def pretty_size(size
):
16 if size
== 0: return ''
17 return gui
.pretty_size(size
)
19 def size_if_exists(path
):
20 "Get the size for a file, or 0 if it doesn't exist."
21 if path
and os
.path
.isfile(path
):
22 return os
.path
.getsize(path
)
26 "Get the size for a directory tree. Get the size from the .manifest if possible."
27 man
= os
.path
.join(path
, '.manifest')
28 if os
.path
.exists(man
):
29 size
= os
.path
.getsize(man
)
30 for line
in file(man
):
32 size
+= long(line
.split(' ', 4)[3])
35 for root
, dirs
, files
in os
.walk(path
):
37 size
+= getsize(join(root
, name
))
42 return iface
.get_name() + ' - ' + iface
.summary
43 return iface
.get_name()
47 class CacheExplorer(Dialog
):
50 self
.set_title('Zero Install Cache')
51 self
.set_default_size(gtk
.gdk
.screen_width() / 2, gtk
.gdk
.screen_height() / 2)
54 self
.model
= gtk
.TreeStore(str, str, str)
55 self
.tree_view
= gtk
.TreeView(self
.model
)
57 # Find cached implementations
59 unowned
= {} # Impl ID -> Store
62 for s
in iface_cache
.stores
.stores
:
63 for id in os
.listdir(s
.dir):
70 unused_interfaces
= []
72 # Look through cached interfaces for implementation owners
73 all
= iface_cache
.list_all_interfaces()
78 if uri
.startswith('/'):
81 cached_iface
= basedir
.load_first_cache(namespaces
.config_site
,
82 'interfaces', model
.escape(uri
))
83 user_overrides
= basedir
.load_first_config(namespaces
.config_site
,
84 namespaces
.config_prog
,
85 'user_overrides', model
.escape(uri
))
87 iface_size
= size_if_exists(cached_iface
) + size_if_exists(user_overrides
)
88 iface
= iface_cache
.get_interface(uri
)
90 error_interfaces
.append((uri
, str(ex
), iface_size
))
93 for impl
in iface
.implementations
.values():
94 if impl
.id in unowned
:
95 impl_path
= os
.path
.join(unowned
[impl
.id].dir, impl
.id)
96 impl_size
= get_size(impl_path
)
97 in_cache
.append((impl
, impl_size
))
99 iface_size
+= impl_size
102 ok_interfaces
.append((iface
, in_cache
, iface_size
))
104 unused_interfaces
.append((iface
, iface_size
))
107 total_size
= sum([size
for uri
, ex
, size
in error_interfaces
])
108 iter = self
.model
.append(None, ["Invalid interfaces (unreadable)",
109 pretty_size(total_size
),
110 _("These interfaces exist in the cache but cannot be "
111 "read. You should probably delete them.")])
112 for uri
, ex
, size
in error_interfaces
:
113 self
.model
.append(iter, [uri
, pretty_size(size
), ex
])
118 impl_path
= os
.path
.join(unowned
[id].dir, id)
119 unowned_sizes
.append((get_size(impl_path
), id, impl_path
))
120 total_size
= sum([size
for size
, id, path
in unowned_sizes
])
121 iter = self
.model
.append(None, ["Unowned implementations and temporary files",
122 pretty_size(total_size
),
123 _("These probably aren't needed any longer. You can "
126 for size
, id, impl_path
in unowned_sizes
:
127 self
.model
.append(iter, [id, pretty_size(size
), impl_path
])
129 if unused_interfaces
:
130 total_size
= sum([size
for iface
, size
in unused_interfaces
])
131 iter = self
.model
.append(None, ["Unused interfaces (no versions cached)",
132 pretty_size(total_size
),
133 _("These interfaces are cached, but no actual versions "
134 "are present. They might be useful, and they don't "
135 "take up much space.")])
136 unused_interfaces
.sort()
137 for iface
, size
in unused_interfaces
:
138 self
.model
.append(iter, [iface
.uri
, pretty_size(size
), summary(iface
)])
141 total_size
= sum([size
for iface
, in_cache
, size
in ok_interfaces
])
142 iter = self
.model
.append(None, ["Used interfaces", pretty_size(total_size
), None])
143 for iface
, in_cache
, iface_size
in ok_interfaces
:
144 iter2
= self
.model
.append(iter,
145 [iface
.uri
, pretty_size(iface_size
), summary(iface
)])
146 for impl
, size
in in_cache
:
147 self
.model
.append(iter2
,
148 ['Version %s : %s' % (impl
.get_version(), impl
.id),
153 swin
= gtk
.ScrolledWindow()
154 swin
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_ALWAYS
)
155 swin
.set_shadow_type(gtk
.SHADOW_IN
)
156 swin
.add(self
.tree_view
)
157 self
.vbox
.pack_start(swin
, True, True, 0)
158 self
.tree_view
.set_rules_hint(True)
161 column
= gtk
.TreeViewColumn('Item', gtk
.CellRendererText(), text
= ITEM
)
162 column
.set_resizable(True)
163 self
.tree_view
.append_column(column
)
165 cell
= gtk
.CellRendererText()
166 cell
.set_property('xalign', 1.0)
167 column
= gtk
.TreeViewColumn('Size', cell
, text
= SIZE
)
168 self
.tree_view
.append_column(column
)
171 def motion(tree_view
, ev
):
172 if ev
.window
is not tree_view
.get_bin_window():
174 pos
= tree_view
.get_path_at_pos(int(ev
.x
), int(ev
.y
))
177 row
= self
.model
[path
]
181 tips
.prime(tree_view
, tip
)
187 self
.tree_view
.connect('motion-notify-event', motion
)
188 self
.tree_view
.connect('leave-notify-event', lambda tv
, ev
: tips
.hide())
192 self
.add_button(gtk
.STOCK_HELP
, gtk
.RESPONSE_HELP
)
193 self
.add_button(gtk
.STOCK_CLOSE
, gtk
.RESPONSE_OK
)
194 self
.set_default_response(gtk
.RESPONSE_OK
)
196 def response(dialog
, resp
):
197 if resp
== gtk
.RESPONSE_OK
:
199 elif resp
== gtk
.RESPONSE_HELP
:
201 self
.connect('response', response
)
203 cache_help
= help_box
.HelpBox("Cache Explorer Help",
205 When you run a program using Zero Install, it downloads the program's 'interface' file, \
206 which gives information about which versions of the program are available. This interface \
207 file is stored in the cache to save downloading it next time you run the program.
209 When you have chosen which version (implementation) of the program you want to \
210 run, Zero Install downloads that version and stores it in the cache too. Zero Install lets \
211 you have many different versions of each program on your computer at once. This is useful, \
212 since it lets you use an old version if needed, and different programs may need to use \
213 different versions of libraries in some cases.
215 The cache viewer shows you all the interfaces and implementations in your cache. \
216 This is useful to find versions you don't need anymore, so that you can delete them and \
217 free up some disk space.
219 Note: the cache viewer isn't finished; it doesn't currently let you delete things!"""),
221 ('Invalid interfaces', """
222 The cache viewer gets a list of all interfaces in your cache. However, some may not \
223 be valid; they are shown in the 'Invalid interfaces' section. It should be fine to \
224 delete these. An invalid interface may be caused by a local interface that no longer \
225 exists, by a failed attempt to download an interface (the name ends in '.new'), or \
226 by the interface file format changing since the interface was downloaded."""),
228 ('Unowned implementations and temporary files', """
229 The cache viewer searches through all the interfaces to find out which implementations \
230 they use. If no interface uses an implementation, it is shown in the 'Unowned implementations' \
233 Unowned implementations can result from old versions of a program no longer being listed \
234 in the interface file. Temporary files are created when unpacking an implementation after \
235 downloading it. If the archive is corrupted, the unpacked files may be left there. Unless \
236 you are currently unpacking new programs, it should be fine to delete everything in this \
239 ('Unused interfaces', """
240 An unused interface is one which was downloaded, but you don't have any implementations in \
241 the cache. Since interface files are small, there is little point in deleting them. They may \
242 even be useful in some cases (for example, the injector sometimes checks multiple interfaces \
243 to find a usable version; if you delete one of them then it will have to fetch it again, because \
244 it will forget that it doesn't contain anything useful)."""),
246 ('Used interfaces', """
247 All remaining interfaces are listed in this section. You may wish to delete old versions of \
248 certain programs. Deleting a program which you may later want to run will require it to be downloaded \
249 again. Deleting a version of a program which is currently running may cause it to crash, so be careful!