9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
24 #
25
26
27 import gettext
28 import sys
29 from threading import Thread
30 try:
31 import gobject
32 import gtk
33 import gtk.glade
34 import pygtk
35 pygtk.require("2.0")
36 except ImportError:
37 sys.exit(1)
38 import pkg.client.bootenv as bootenv
39 import pkg.client.imageplan as imageplan
40 import pkg.client.progress as progress
41 import pkg.gui.enumerations as enumerations
42 import pkg.gui.thread as guithread
43
44 class Remove(progress.ProgressTracker):
45 def __init__(self, remove_list, parent):
46 # XXX Workaround as BE is using msg(_("message"))
47 # which bypasses the self._ mechanism the GUI is using
48 gettext.install("pkg","/usr/lib/locale")
49 progress.ProgressTracker.__init__(self)
50 self.gui_thread = guithread.ThreadRun()
51 self.remove_list = remove_list
52 self.parent = parent
53 #This is hack since we should show proper dialog.
54 self.error = None
55 self.ip = None
56 w_tree_createplan = gtk.glade.XML(parent.gladefile, "createplandialog2")
57 w_tree_removedialog = gtk.glade.XML(parent.gladefile, "removedialog")
58 w_tree_removingdialog = gtk.glade.XML(parent.gladefile, "removingdialog")
59 self.w_createplan_dialog = \
60 w_tree_createplan.get_widget("createplandialog2")
61 self.w_createplan_textview = \
62 w_tree_createplan.get_widget("createplantextview2")
63 self.w_createplan_progressbar = \
64 w_tree_createplan.get_widget("createplanprogress2")
65 self.w_remove_dialog = w_tree_removedialog.get_widget("removedialog")
66 self.w_summary_label = w_tree_removedialog.get_widget("removelabel")
67 self.w_review_treeview = w_tree_removedialog.get_widget("treeview3")
68 self.w_next_button = w_tree_removedialog.get_widget("next_remove")
69 self.w_removing_dialog = \
70 w_tree_removingdialog.get_widget("removingdialog")
71 self.w_removing_progressbar = \
72 w_tree_removingdialog.get_widget("removingprogress")
73 self.w_createplan_progressbar.set_pulse_step(0.1)
74 remove_column = gtk.TreeViewColumn('Removed')
75 self.w_review_treeview.append_column(remove_column)
76 cell = gtk.CellRendererText()
77 remove_column.pack_start(cell, True)
78 remove_column.add_attribute(cell, 'text', 0)
79 self.w_review_treeview.expand_all()
80 try:
81 dic_createplan = \
82 {
83 "on_cancelcreateplan2_clicked": \
84 self.__on_cancelcreateplan_clicked,
85 }
86 dic_removedialog = \
87 {
88 "on_cancel_remove_clicked": \
89 self.__on_cancel_button_clicked,
90 "on_next_remove_clicked":self.__on_next_button_clicked,
91 }
92 w_tree_createplan.signal_autoconnect(dic_createplan)
93 w_tree_removedialog.signal_autoconnect(dic_removedialog)
94 except AttributeError, error:
95 print self.parent._('GUI will not respond to any event! %s. \
96 Check remove.py signals') \
97 % error
98 list_of_packages = self.__prepare_list_of_packages()
99 thread = Thread(target = self.__plan_the_removeimage, \
100 args = (list_of_packages, ))
101 thread.start()
102 self.w_createplan_dialog.run()
103 return
104
105 def __on_cancelcreateplan_clicked(self, widget):
106 self.gui_thread.cancel()
107 self.w_createplan_dialog.destroy()
108
109 def __on_next_button_clicked(self, widget):
110 remove_thread = Thread(target = self.__remove_stage, args = ())
111 remove_thread.start()
112
113 def __on_cancel_button_clicked(self, widget):
114 self.gui_thread.cancel()
115 self.w_remove_dialog.destroy()
116
117 def __update_createplan_progress(self, action):
118 buf = self.w_createplan_textview.get_buffer()
119 textiter = buf.get_end_iter()
120 buf.insert(textiter, action)
121 self.w_createplan_progressbar.pulse()
122
123 def __update_remove_progress(self, current, total):
124 prog = float(current)/total
125 self.w_removing_progressbar.set_fraction(prog)
126
127 def __prepare_list_of_packages(self):
128 ''' This method return the dictionary of images for removal'''
129 fmri_to_remove = {}
130 for row in self.remove_list:
131 if row[enumerations.MARK_COLUMN]:
132 image = row[enumerations.IMAGE_OBJECT_COLUMN]
133 package = row[enumerations.INSTALLED_OBJECT_COLUMN]
134 im = fmri_to_remove.get(image)
135 if im:
136 if package:
137 im.append(package)
138 else:
139 if package:
140 fmri_to_remove[image] = [package, ]
141 return fmri_to_remove
142
143 def __plan_the_removeimage(self, list_of_packages):
144 '''Function which plans the image'''
145 self.gui_thread.run()
146 filters = []
147 for image in list_of_packages:
148 self.ip = imageplan.ImagePlan(image, self, filters = filters)
149 fmris = list_of_packages.get(image)
150 for fmri in fmris:
151 if self.gui_thread.is_cancelled():
152 return
153 self.ip.propose_fmri_removal(fmri)
154 self.ip.state = imageplan.UNEVALUATED
155 self.ip.progtrack.evaluate_start()
156 for f in self.ip.target_rem_fmris[:]:
157 gobject.idle_add(self.__update_createplan_progress, \
158 self.parent._("Evaluating: %s\n") % f.get_fmri())
159 try:
160 self.ip.evaluate_fmri_removal(f)
161 except imageplan.NonLeafPackageException, e:
162 self.error = e[1]
163 gobject.idle_add(self.ip.progtrack.evaluate_done)
164 return
165 self.ip.state = imageplan.EVALUATED_OK
166 image.imageplan = self.ip
167 gobject.idle_add(self.ip.progtrack.evaluate_done)
168 return
169
170 def __remove_stage(self):
171 self.w_remove_dialog.hide()
172 self.w_removing_dialog.show()
173 self.ip.preexecute()
174 try:
175 be = bootenv.BootEnv(self.ip.image.get_root())
176 except RuntimeError:
177 be = bootenv.BootEnvNull(self.ip.image.get_root())
178 try:
179 self.ip.execute()
180 except RuntimeError:
181 be.restore_install_uninstall()
182 except Exception:
183 be.restore_install_uninstall()
184 raise
185
186 if self.ip.state == imageplan.EXECUTED_OK:
187 be.activate_install_uninstall()
188 else:
189 be.restore_install_uninstall()
190
191 def cat_output_start(self):
192 return
193
194 def cat_output_done(self):
195 return
196
197 def eval_output_start(self):
198 return
199
200 def eval_output_progress(self):
201 return
202
203 def eval_output_done(self):
204 self.w_createplan_dialog.hide()
205 if self.gui_thread.is_cancelled():
206 return
207 self.w_remove_dialog.show()
208 packaged_removed = \
209 [
210 ["Packages To Be Removed:"],
211 ]
212 if self.ip.state != imageplan.EVALUATED_OK:
213 packaged_removed = \
214 [
215 ["Cannot remove, due to the following dependencies:"],
216 ]
217 treestore = gtk.TreeStore(str)
218 remove_iter = None
219 remove_count = 0
220 if self.ip.state == imageplan.EVALUATED_OK:
221 self.w_next_button.set_sensitive(True)
222 for package_plan in self.ip.pkg_plans:
223 if package_plan.origin_fmri and not \
224 package_plan.destination_fmri:
225 if not remove_iter:
226 remove_iter = \
227 treestore.append(None, \
231 pkg_fmri.version.get_short_version()
232 pkg = package_plan.origin_fmri.get_name() + \
233 "@" + pkg_version
234 remove_count = remove_count + 1
235 treestore.append(remove_iter, [pkg])
236 else:
237 self.w_next_button.set_sensitive(False)
238 if self.error:
239 for package in self.error:
240 if not remove_iter:
241 remove_iter = \
242 treestore.append(None, \
243 packaged_removed[0])
244 treestore.append(remove_iter, [package])
245
246 self.w_review_treeview.set_model(treestore)
247 self.w_review_treeview.expand_all()
248 remove_str = self.parent._("%d packages will be removed\n\n")
249 if remove_count == 1:
250 remove_str = self.parent._("%d package will be removed\n\n")
251 self.w_summary_label.set_text(remove_str % remove_count)
252 return True
253
254 def ver_output(self):
255 return
256
257 def ver_output_error(self, actname, errors):
258 return
259
260 def dl_output(self):
261 return
262
263 def dl_output_done(self):
264 return
265
266 def act_output(self):
267 gobject.idle_add(self.__update_remove_progress, \
268 self.ip.progtrack.act_cur_nactions, \
269 self.ip.progtrack.act_goal_nactions)
270 return
271
272 def act_output_done(self):
273 if self.parent != None:
274 self.parent.update_package_list()
275 self.w_removing_dialog.hide()
276 return
277
278 def ind_output(self):
279 return
280
281 def ind_output_done(self):
282 return
|
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
24 #
25
26
27 import gettext
28 import sys
29 import time
30 from threading import Thread
31 try:
32 import gobject
33 import gtk
34 import gtk.glade
35 import pygtk
36 pygtk.require("2.0")
37 except ImportError:
38 sys.exit(1)
39 import pkg.client.bootenv as bootenv
40 import pkg.client.imageplan as imageplan
41 import pkg.search_errors as search_errors
42 import pkg.indexer as indexer
43 import pkg.client.progress as progress
44 import pkg.gui.enumerations as enumerations
45 import pkg.gui.thread as guithread
46
47 class Remove(progress.ProgressTracker):
48 def __init__(self, remove_list, parent):
49 # XXX Workaround as BE is using msg(_("message"))
50 # which bypasses the self._ mechanism the GUI is using
51 gettext.install("pkg","/usr/lib/locale")
52 progress.ProgressTracker.__init__(self)
53 self.gui_thread = guithread.ThreadRun()
54 self.remove_list = remove_list
55 self.parent = parent
56 #This is hack since we should show proper dialog.
57 self.error = None
58 self.ip = None
59 self.progress_stop_timer_thread = False
60 self.progress_stop_timer_running = False
61 w_tree_createplan = gtk.glade.XML(parent.gladefile, "createplandialog2")
62 w_tree_removedialog = gtk.glade.XML(parent.gladefile, "removedialog")
63 w_tree_removingdialog = gtk.glade.XML(parent.gladefile, "removingdialog")
64 self.w_createplan_dialog = \
65 w_tree_createplan.get_widget("createplandialog2")
66 self.w_createplan_textview = \
67 w_tree_createplan.get_widget("createplantextview2")
68 self.w_createplan_progressbar = \
69 w_tree_createplan.get_widget("createplanprogress2")
70 self.w_createplan_expander = \
71 w_tree_createplan.get_widget("expander7")
72 self.w_createplan_label = \
73 w_tree_createplan.get_widget("packagedependencies5")
74 self.w_createplancancel_button = \
75 w_tree_createplan.get_widget("cancelcreateplan2")
76 self.w_remove_dialog = w_tree_removedialog.get_widget("removedialog")
77 self.w_summary_label = w_tree_removedialog.get_widget("removelabel")
78 self.w_review_treeview = w_tree_removedialog.get_widget("treeview3")
79 self.w_next_button = w_tree_removedialog.get_widget("next_remove")
80 self.w_removing_dialog = \
81 w_tree_removingdialog.get_widget("removingdialog")
82 self.w_removing_progressbar = \
83 w_tree_removingdialog.get_widget("removingprogress")
84 self.w_removingdialog_label = \
85 w_tree_removingdialog.get_widget("packagedependencies4")
86 self.w_removingdialog_expander = \
87 w_tree_removingdialog.get_widget("expander6")
88 self.w_createplan_progressbar.set_pulse_step(0.1)
89 remove_column = gtk.TreeViewColumn('Removed')
90 self.w_review_treeview.append_column(remove_column)
91 cell = gtk.CellRendererText()
92 remove_column.pack_start(cell, True)
93 remove_column.add_attribute(cell, 'text', 0)
94 self.w_review_treeview.expand_all()
95 try:
96 dic_createplan = \
97 {
98 "on_cancelcreateplan2_clicked": \
99 self.__on_cancelcreateplan_clicked,
100 }
101 dic_removedialog = \
102 {
103 "on_cancel_remove_clicked": \
104 self.__on_cancel_button_clicked,
105 "on_next_remove_clicked":self.__on_next_button_clicked,
106 }
107 w_tree_createplan.signal_autoconnect(dic_createplan)
108 w_tree_removedialog.signal_autoconnect(dic_removedialog)
109 except AttributeError, error:
110 print self.parent._('GUI will not respond to any event! %s. \
111 Check remove.py signals') \
112 % error
113 list_of_packages = self.__prepare_list_of_packages()
114 # XXX Hidden until progress will give information about fmri
115 self.w_createplan_expander.hide()
116 self.w_removingdialog_expander.hide()
117 pulse_t = Thread(target = self.__progressdialog_progress_pulse)
118 thread = Thread(target = self.__plan_the_removeimage, \
119 args = (list_of_packages, ))
120 pulse_t.start()
121 thread.start()
122 self.w_createplan_label.set_text(\
123 self.parent._("Checking package dependencies..."))
124 self.w_createplancancel_button.set_sensitive(True)
125 self.w_createplan_dialog.run()
126 return
127
128 def __on_cancelcreateplan_clicked(self, widget):
129 self.w_createplan_label.set_text(\
130 self.parent._("Canceling..."))
131 self.w_createplancancel_button.set_sensitive(False)
132 self.gui_thread.cancel()
133
134 def __on_next_button_clicked(self, widget):
135 self.w_remove_dialog.hide()
136 self.w_removing_dialog.show()
137 remove_thread = Thread(target = self.__remove_stage, args = ())
138 remove_thread.start()
139
140 def __on_cancel_button_clicked(self, widget):
141 self.gui_thread.cancel()
142 self.w_remove_dialog.hide()
143
144 # XXX Not used until progress will give information about fmri
145 def __update_createplan_progress(self, action):
146 buf = self.w_createplan_textview.get_buffer()
147 textiter = buf.get_end_iter()
148 buf.insert(textiter, action)
149 self.w_createplan_progressbar.pulse()
150
151 def __update_remove_progress(self, current, total):
152 prog = float(current)/total
153 self.w_removing_progressbar.set_fraction(prog)
154
155 def __prepare_list_of_packages(self):
156 ''' This method return the dictionary of images for removal'''
157 fmri_to_remove = {}
158 for row in self.remove_list:
159 if row[enumerations.MARK_COLUMN]:
160 image = row[enumerations.IMAGE_OBJECT_COLUMN]
161 package = row[enumerations.INSTALLED_OBJECT_COLUMN]
162 im = fmri_to_remove.get(image)
163 if im:
164 if package:
165 im.append(package)
166 else:
167 if package:
168 fmri_to_remove[image] = [package, ]
169 return fmri_to_remove
170
171 def __plan_the_removeimage(self, list_of_packages):
172 '''Function which plans the image'''
173 self.gui_thread.run()
174 filters = []
175 for image in list_of_packages:
176 self.ip = imageplan.ImagePlan(image, self, filters = filters)
177 fmris = list_of_packages.get(image)
178 for fmri in fmris:
179 if self.gui_thread.is_cancelled():
180 self.progress_stop_timer_thread = True
181 gobject.idle_add(self.w_createplan_dialog.hide)
182 return
183 self.ip.propose_fmri_removal(fmri)
184 try:
185 self.ip.evaluate()
186 if self.gui_thread.is_cancelled():
187 self.progress_stop_timer_thread = True
188 gobject.idle_add(self.w_createplan_dialog.hide)
189 return
190 image.imageplan = self.ip
191 except imageplan.NonLeafPackageException, e:
192 self.error = e[1]
193 self.ip.progtrack.evaluate_done()
194 return
195 return
196
197 def __remove_stage(self):
198 self.ip.preexecute()
199 try:
200 be = bootenv.BootEnv(self.ip.image.get_root())
201 except RuntimeError:
202 be = bootenv.BootEnvNull(self.ip.image.get_root())
203 try:
204 ret_code = 0
205 self.ip.execute()
206 except RuntimeError:
207 be.restore_install_uninstall()
208 except search_errors.InconsistentIndexException, e:
209 ret_code = 2
210 except search_errors.PartialIndexingException, e:
211 ret_code = 2
212 except search_errors.ProblematicPermissionsIndexException, e:
213 ret_code = 2
214 except KeyError, e:
215 # XXX KeyError was seen while problem with
216 # creating index
217 ret_code = 2
218 except Exception:
219 be.restore_install_uninstall()
220 gobject.idle_add(self.w_removing_dialog.hide)
221 raise
222
223 if ret_code == 2:
224 return_code = 0
225 return_code = self.__rebuild_index()
226 if return_code == 1:
227 gobject.idle_add(self.w_removing_dialog.hide)
228 return
229
230 if self.ip.state == imageplan.EXECUTED_OK:
231 be.activate_install_uninstall()
232 else:
233 be.restore_install_uninstall()
234 gobject.idle_add(self.w_removing_dialog.hide)
235
236 def __rebuild_index(self):
237 '''Code duplication from pkg(1):
238 Forcibly rebuild the search indexes. Will remove existing indexes
239 and build new ones from scratch.'''
240 quiet = False
241
242 try:
243 self.ip.image.rebuild_search_index(self.ip.progtrack)
244 except search_errors.InconsistentIndexException, iie:
245 return 1
246 except search_errors.ProblematicPermissionsIndexException, ppie:
247 return 1
248
249 def __progressdialog_progress_pulse(self):
250 while not self.progress_stop_timer_thread:
251 gobject.idle_add(self.w_createplan_progressbar.pulse)
252 time.sleep(0.1)
253
254 def __removedialog_progress_pulse(self):
255 while not self.progress_stop_timer_thread:
256 self.progress_stop_timer_running = True
257 gobject.idle_add(self.w_removing_progressbar.pulse)
258 time.sleep(0.1)
259 self.progress_stop_timer_running = False
260
261 def cat_output_start(self):
262 return
263
264 def cat_output_done(self):
265 return
266
267 def eval_output_start(self):
268 return
269
270 def eval_output_progress(self):
271 return
272
273 def eval_output_done(self):
274 gobject.idle_add(self.__eval_output_done)
275
276 def __eval_output_done(self):
277 if self.gui_thread.is_cancelled():
278 self.progress_stop_timer_thread = True
279 self.w_createplan_dialog.hide()
280 return
281 packaged_removed = \
282 [
283 ["Packages To Be Removed:"],
284 ]
285 if self.ip.state != imageplan.EVALUATED_OK:
286 packaged_removed = \
287 [
288 ["Cannot remove, due to the following dependencies:"],
289 ]
290 treestore = gtk.TreeStore(str)
291 remove_iter = None
292 remove_count = 0
293 if self.ip.state == imageplan.EVALUATED_OK:
294 self.w_next_button.set_sensitive(True)
295 for package_plan in self.ip.pkg_plans:
296 if package_plan.origin_fmri and not \
297 package_plan.destination_fmri:
298 if not remove_iter:
299 remove_iter = \
300 treestore.append(None, \
304 pkg_fmri.version.get_short_version()
305 pkg = package_plan.origin_fmri.get_name() + \
306 "@" + pkg_version
307 remove_count = remove_count + 1
308 treestore.append(remove_iter, [pkg])
309 else:
310 self.w_next_button.set_sensitive(False)
311 if self.error:
312 for package in self.error:
313 if not remove_iter:
314 remove_iter = \
315 treestore.append(None, \
316 packaged_removed[0])
317 treestore.append(remove_iter, [package])
318
319 self.w_review_treeview.set_model(treestore)
320 self.w_review_treeview.expand_all()
321 remove_str = self.parent._("%d packages will be removed\n\n")
322 if remove_count == 1:
323 remove_str = self.parent._("%d package will be removed\n\n")
324 text = remove_str % remove_count
325 self.w_summary_label.set_text(text)
326 self.progress_stop_timer_thread = True
327 self.w_createplan_dialog.hide()
328 self.w_remove_dialog.show()
329
330 def ver_output(self):
331 return
332
333 def ver_output_error(self, actname, errors):
334 return
335
336 def dl_output(self):
337 return
338
339 def dl_output_done(self):
340 return
341
342 def act_output(self):
343 text = self.parent._("Removing Packages...")
344 gobject.idle_add(self.w_removingdialog_label.set_text, text)
345 gobject.idle_add(self.__update_remove_progress, \
346 self.ip.progtrack.act_cur_nactions, \
347 self.ip.progtrack.act_goal_nactions)
348 return
349
350 def act_output_done(self):
351 if self.parent != None:
352 gobject.idle_add(self.parent.update_package_list)
353 time.sleep(0.1)
354 return
355
356 def ind_output(self):
357 self.progress_stop_timer_thread = False
358 gobject.idle_add(self.__indexing_progress)
359 return
360
361 def __indexing_progress(self):
362 if not self.progress_stop_timer_running:
363 self.w_removingdialog_label.set_text(\
364 self.parent._("Creating packages index..."))
365 Thread(target = self.__removedialog_progress_pulse).start()
366
367 def ind_output_done(self):
368 self.progress_stop_timer_thread = True
369 return
|