2 * Copyright (C) 2014 J. Ali Harlow <ali@juiblex.co.uk>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <plover/plover.h>
24 #include <plover/transaction.h>
25 #include <plover-gtk/transactionhelper.h>
28 * A PloverTransactionHelper uses a GtkAssistant to help a user run a
32 G_DEFINE_TYPE(PloverTransactionHelper,plover_transaction_helper,G_TYPE_OBJECT)
34 enum plover_transaction_type {
35 TRANSACTION_TYPE_NULL=0,
36 TRANSACTION_TYPE_INSTALL=1UL<<0,
37 TRANSACTION_TYPE_REMOVE=1UL<<1,
38 TRANSACTION_TYPE_UPDATE=TRANSACTION_TYPE_INSTALL|TRANSACTION_TYPE_REMOVE
41 typedef struct _PloverTransactionHelperPrivate {
42 enum plover_transaction_type transaction_type;
43 gchar *default_prefix;
44 } PloverTransactionHelperPrivate;
46 #define PLOVER_TRANSACTION_HELPER_GET_PRIVATE(obj)\
47 G_TYPE_INSTANCE_GET_PRIVATE(obj,\
48 PLOVER_TYPE_TRANSACTION_HELPER,\
49 PloverTransactionHelperPrivate)
56 static guint signals[N_SIGNALS];
58 static void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
60 PloverTransactionHelperPrivate *priv;
61 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
62 g_free(priv->default_prefix);
63 g_free(helper->error_primary_text);
65 g_free(helper->unsatisfied);
67 plover_comps_free(helper->comps);
68 plover_vector_free(helper->report_adding);
69 plover_vector_free(helper->report_removing);
72 static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
74 g_clear_error(&helper->error);
75 if (helper->error_dialog)
77 g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
78 gtk_widget_destroy(helper->error_dialog);
79 helper->error_dialog=NULL;
81 if (helper->assistant)
83 g_signal_handlers_disconnect_by_data(helper->assistant,helper);
84 g_clear_object(&helper->assistant);
86 g_clear_object(&helper->ui);
87 g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
88 g_slist_free(helper->transactions);
89 helper->transactions=NULL;
90 g_clear_object(&helper->installed);
91 g_clear_object(&helper->upstream);
92 g_clear_object(&helper->relocated_upstream);
96 plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
98 GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
99 gobject_class->finalize=
100 (void (*)(GObject *))plover_transaction_helper_finalize;
101 gobject_class->dispose=
102 (void (*)(GObject *))plover_transaction_helper_dispose;
103 g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
104 signals[CLOSE]=g_signal_newv("close",
105 G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
106 g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
109 static void plover_transaction_helper_init(PloverTransactionHelper *helper)
111 helper->report_adding=plover_vector_new();
112 helper->report_removing=plover_vector_new();
115 static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
116 PloverTransactionHelper *helper)
118 gtk_widget_hide(GTK_WIDGET(helper->assistant));
119 gtk_assistant_set_current_page(helper->assistant,0);
120 g_signal_emit(helper,signals[CLOSE],0);
123 static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
124 PloverTransactionHelper *helper)
126 gtk_widget_hide(GTK_WIDGET(helper->assistant));
127 gtk_assistant_set_current_page(helper->assistant,0);
128 g_signal_emit(helper,signals[CLOSE],0);
132 plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
134 gchar *package_list,*add,*remove,*s;
136 struct plover_vector *report;
137 if (helper->report_adding->len)
139 plover_vector_sort(helper->report_adding);
140 if (helper->report_adding_dependencies)
142 report=plover_vector_dup(helper->report_adding);
143 if (helper->report_adding->len==1)
144 plover_vector_append(report,"its dependencies");
146 plover_vector_append(report,"their dependencies");
147 package_list=plover_vector_format_for_display(report);
148 plover_vector_free(report);
152 plover_vector_format_for_display(helper->report_adding);
153 add=g_strconcat("Packages to be installed or updated: ",package_list,
155 g_free(package_list);
159 if (helper->report_removing->len)
161 plover_vector_sort(helper->report_removing);
162 if (helper->report_removing_dependants)
164 report=plover_vector_dup(helper->report_removing);
165 if (helper->report_adding->len==1)
166 plover_vector_append(report,"its dependants");
168 plover_vector_append(report,"their dependants");
169 package_list=plover_vector_format_for_display(report);
170 plover_vector_free(report);
174 plover_vector_format_for_display(helper->report_removing);
175 remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
176 g_free(package_list);
180 label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
182 s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
183 else if (add || remove)
184 s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
186 s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
187 gtk_label_set_markup(label,s);
193 static void plover_transaction_helper_run(PloverTransactionHelper *helper);
195 static void plover_transaction_helper_callback(GObject *source,
196 GAsyncResult *result,gpointer user_data)
199 PloverTransactionHelper *helper=user_data;
200 PloverTransaction *transaction=PLOVER_TRANSACTION(source);
201 if (!plover_transaction_commit_finish(transaction,result,&error))
203 plover_transaction_helper_set_error(helper,error,
204 "Software installation failed");
208 plover_transaction_helper_run(helper);
210 * There may be status updates queued by transaction as idle events.
211 * Process them now before we disconnect so that we don't lose them.
213 while(g_main_context_pending(NULL))
214 g_main_context_iteration(NULL,FALSE);
215 g_signal_handlers_disconnect_by_data(transaction,helper);
216 g_object_unref(transaction);
219 static void plover_transaction_helper_transaction_status_changed(
220 PloverTransaction *transaction,const char *status,
221 PloverTransactionHelper *helper)
224 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
225 gtk_progress_bar_set_text(bar,status);
228 static void plover_transaction_helper_run(PloverTransactionHelper *helper)
230 PloverTransaction *transaction;
232 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
233 if (helper->transactions)
235 if (helper->assistant)
236 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
237 transaction=helper->transactions->data;
238 helper->transactions=g_slist_delete_link(helper->transactions,
239 helper->transactions);
240 g_signal_connect(transaction,"status-changed",
241 G_CALLBACK(plover_transaction_helper_transaction_status_changed),
243 plover_transaction_commit_async(transaction,NULL,
244 plover_transaction_helper_callback,helper);
246 else if (helper->assistant)
247 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
250 static gboolean plover_transaction_helper_pulse(gpointer user_data)
252 PloverTransactionHelper *helper=user_data;
255 if (!helper->assistant)
257 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
258 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
259 if (gtk_assistant_get_page_complete(helper->assistant,w))
261 gtk_progress_bar_set_fraction(bar,1.0);
262 helper->pulse_handler=0;
267 gtk_progress_bar_pulse(bar);
273 plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
276 GtkToggleButton *button;
277 PloverTransaction *transaction;
278 GSList *save_transactions;
279 PloverTransactionHelperPrivate *priv;
280 enum plover_transaction_type save_transaction_type;
281 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
282 button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
283 "SIRemoveExisting"));
284 if (gtk_toggle_button_get_active(button))
286 transaction=plover_transaction_new_remove(NULL,&error);
289 save_transactions=helper->transactions;
290 helper->transactions=NULL;
291 save_transaction_type=priv->transaction_type;
292 priv->transaction_type=0;
293 if (!plover_transaction_helper_add_transaction(helper,transaction,
294 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
296 g_object_unref(transaction);
298 helper->transactions=save_transactions;
299 priv->transaction_type=save_transaction_type;
303 g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
304 g_slist_free(save_transactions);
309 if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
310 g_clear_error(&error);
313 plover_transaction_helper_set_error(helper,error,
314 "Failed to remove existing packages");
321 * Note that PloverTransaction does support cancelling a transaction, but
322 * there are a number of challenges with using it:
323 * - cancellation is only supported during the file phase if razor
324 * has atomic rollback,
325 * - cancellation is not supported during post-transaction scripts at all
326 * (since by the time the first script is started the atomic has already
327 * been committed) and these can take quite some time,
328 * - where a transaction has an embedded COMMIT, any rollback won't
329 * go back beyond this point.
330 * To support user-cancel, then, we would need some mechanism to:
331 * - Comunicate that the operation is being cancelled and this may take
333 * - Not allow cancellation at all after the last post-transaction script
335 * - Report the partially completed transaction where cancellation
336 * occurred after a COMMIT point.
337 * At present, this doesn't appear worth the effort.
339 if (helper->assistant)
340 gtk_assistant_commit(helper->assistant);
341 plover_transaction_helper_run(helper);
342 helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
346 static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
347 GtkWidget *page,PloverTransactionHelper *helper)
349 if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
350 plover_transaction_helper_prepare_confirm(helper);
351 else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
352 plover_transaction_helper_prepare_progress(helper);
356 plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
357 PloverTransactionHelper *helper)
360 if (helper->assistant)
362 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
363 gtk_assistant_set_page_complete(helper->assistant,w,
364 gtk_toggle_button_get_active(button));
368 PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
371 gchar *s,*directory,*contents;
374 PloverTransactionHelper *helper;
375 g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
376 helper=PLOVER_TRANSACTION_HELPER(
377 g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
379 helper->ui=g_object_ref(ui);
381 helper->ui=gtk_builder_new();
383 GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
384 if (!helper->assistant)
386 directory=g_strdup(g_getenv("PLOVER_DATADIR"));
390 s=g_win32_get_package_installation_directory_of_module(NULL);
391 directory=g_build_filename(s,"share","plover",NULL);
394 directory=g_strdup(PLOVER_DATADIR);
397 s=g_build_filename(directory,"software-installation.ui",NULL);
399 (void)g_file_get_contents(s,&contents,&len,&error);
403 (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
408 g_critical("software-installation.ui: %s",error->message);
409 g_clear_error(&error);
410 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
411 "Internal error (no user interface)");
412 plover_transaction_helper_set_error(helper,error,
413 "Can't start installer");
416 helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
417 "SoftwareInstallation"));
419 if (!helper->assistant)
421 g_critical("\"SoftwareInstallation\" object not found");
422 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
423 "Internal error (missing wizard)");
424 plover_transaction_helper_set_error(helper,error,
425 "Can't start installer");
430 g_object_ref(helper->assistant);
431 if (!GTK_IS_ASSISTANT(helper->assistant))
433 g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
434 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
435 "Internal error (unexpected wizard type)");
436 plover_transaction_helper_set_error(helper,error,
437 "Can't start installer");
441 g_signal_connect(helper->assistant,"cancel",
442 G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
443 g_signal_connect(helper->assistant,"close",
444 G_CALLBACK(plover_transaction_helper_assistant_close),helper);
445 g_signal_connect(helper->assistant,"prepare",
446 G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
447 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
449 g_signal_connect(w,"toggled",
450 G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
451 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
453 gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
458 plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
460 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
461 return helper->installed;
464 void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
465 PloverPackageSet *installed)
467 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
468 g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
469 g_return_if_fail(helper->installed == NULL);
470 helper->installed=g_object_ref(installed);
474 plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
478 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
479 if (!helper->upstream)
481 base=plover_transaction_helper_get_base(helper);
482 helper->upstream=plover_repository_new_from_yum(base,error);
484 return helper->upstream;
487 void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
488 PloverRepository *upstream)
490 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
491 g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
492 g_return_if_fail(helper->upstream == NULL);
493 helper->upstream=g_object_ref(upstream);
496 const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
498 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
502 void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
505 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
506 g_return_if_fail(helper->transactions == NULL);
507 g_free(helper->base);
508 helper->base=g_strdup(base);
512 plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
516 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
517 g_return_val_if_fail(helper->base != NULL,NULL);
520 s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
521 helper->comps=plover_comps_new_from_file(s);
523 g_set_error(error,PLOVER_GENERAL_ERROR,
524 PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
527 return helper->comps;
531 plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
536 PloverTransactionHelperPrivate *priv;
537 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
538 g_return_val_if_fail(helper->base != NULL || helper->installed != NULL,NULL);
539 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
542 comps=plover_transaction_helper_get_comps(helper,error);
545 g_free(priv->default_prefix);
546 priv->default_prefix=plover_default_prefix_for_vendor(comps->vendor);
547 return priv->default_prefix;
549 prefix=plover_package_set_guess_prefix(helper->installed,error);
553 static int plover_transaction_helper_package_count(void)
557 struct razor_set *set;
558 struct razor_package *package;
559 struct razor_package_iterator *pi;
560 install_root=getenv("RAZOR_ROOT");
563 set=razor_root_open_read_only(install_root,NULL);
566 pi=razor_package_iterator_create(set);
567 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
569 razor_package_iterator_destroy(pi);
570 razor_set_unref(set);
576 plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
580 gchar *prefix=NULL,*s;
581 struct comps *comps=NULL;
582 GtkWidget *container,*summary,*page;
585 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
586 if (helper->check_vendor)
588 comps=plover_transaction_helper_get_comps(helper,error);
591 prefix=plover_default_prefix_for_vendor(comps->vendor);
593 button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
594 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
595 container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
596 "SIIncompatibleInstallation"));
597 summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
598 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
599 if (helper->check_vendor && prefix &&
600 !plover_installed_files_match_prefix(prefix))
602 label=GTK_LABEL(gtk_builder_get_object(helper->ui,
603 "SIIncompatibleInstallationLabel"));
604 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
605 "The existing installation is not from %s.\n"
606 "In order to continue, all the existing packages must be removed.",
608 gtk_label_set_markup(label,s);
610 i=plover_transaction_helper_package_count();
611 s=g_strdup_printf("Remove %d existing package%s",i,i==1?"":"s");
612 gtk_button_set_label(button,s);
614 gtk_widget_show(container);
615 gtk_widget_hide(summary);
616 if (helper->assistant)
617 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
621 gtk_widget_hide(container);
622 gtk_widget_show(summary);
623 if (helper->assistant)
624 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
630 void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
631 gboolean check_vendor)
633 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
634 if (helper->check_vendor!=check_vendor)
636 helper->check_vendor=check_vendor;
637 if (helper->transactions)
638 plover_transaction_helper_check_vendor(helper,NULL);
643 * If plover_transaction_helper_add_transaction() failes with an error
644 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
645 * then plover_transaction_helper_get_unsatisfied() can be used to
646 * retrieve a textual description of the problem.
650 plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
652 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
653 return helper->unsatisfied;
656 #define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
657 ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
658 (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
659 (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
662 plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
663 PloverTransaction *transaction,struct plover_vector *report_packages,
664 PloverTransactionHelperReportAction report_action,GError **error)
667 gboolean other_packages;
669 enum razor_install_action action;
670 struct razor_install_iterator *ii;
671 struct razor_set *report_set;
672 struct razor_package *package;
673 struct plover_vector *tasked_packages;
674 PloverTransactionHelperPrivate *priv;
676 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
677 g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
678 g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
679 g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
680 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
681 g_free(helper->unsatisfied);
682 helper->unsatisfied=NULL;
683 if (!plover_transaction_resolve(transaction,error))
685 s=plover_transaction_get_unsatisfied(transaction);
686 helper->unsatisfied=g_strdup(s);
689 ii=plover_transaction_get_install_iterator(transaction,error);
692 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
693 report_set=plover_transaction_get_system_set(transaction);
695 report_set=plover_transaction_get_next_set(transaction,error);
698 tasked_packages=plover_vector_new();
699 other_packages=FALSE;
700 while (razor_install_iterator_next(ii,&package,&action,&count))
702 if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
703 report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
705 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
706 &name,RAZOR_DETAIL_LAST);
707 if (!report_packages ||
708 plover_vector_contains(report_packages,name))
709 plover_vector_append(tasked_packages,name);
714 if (!tasked_packages->len)
717 * If there are no reportable packages tasked for action there
718 * shouldn't by any packages at all, but let's be paranoid.
720 other_packages=FALSE;
721 razor_install_iterator_rewind(ii);
722 while (razor_install_iterator_next(ii,&package,&action,&count))
724 if (action==report_action)
726 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
727 &name,RAZOR_DETAIL_LAST);
728 plover_vector_append(tasked_packages,name);
732 if (!tasked_packages->len)
734 g_set_error(error,PLOVER_GENERAL_ERROR,
735 PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
736 report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
738 plover_vector_free(tasked_packages);
741 if (!helper->transactions)
742 plover_transaction_helper_check_vendor(helper,error);
743 g_object_ref(transaction);
744 helper->transactions=g_slist_append(helper->transactions,transaction);
745 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
747 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
748 for(i=0;i<tasked_packages->len;i++)
750 s=tasked_packages->strings[i];
751 if (!plover_vector_contains(helper->report_removing,s))
752 plover_vector_append(helper->report_removing,s);
754 helper->report_removing_dependants|=other_packages;
758 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
759 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
760 priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
761 for(i=0;i<tasked_packages->len;i++)
763 s=tasked_packages->strings[i];
764 if (!plover_vector_contains(helper->report_adding,s))
765 plover_vector_append(helper->report_adding,s);
767 helper->report_adding_dependencies|=other_packages;
769 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
770 switch(priv->transaction_type)
772 case TRANSACTION_TYPE_INSTALL:
773 gtk_label_set_markup(GTK_LABEL(w),
774 "<b>Installing the Software</b>\n\n"
775 "Please wait while the Installation Assistant "
776 "installs the software.\n"
777 "This may take several minutes.");
779 case TRANSACTION_TYPE_REMOVE:
780 gtk_label_set_markup(GTK_LABEL(w),
781 "<b>Removing Packages</b>\n\n"
782 "Please wait while the Installation Assistant "
783 "removes packages.\n"
784 "This may take several minutes.");
787 case TRANSACTION_TYPE_UPDATE:
788 gtk_label_set_markup(GTK_LABEL(w),
789 "<b>Updating the Software</b>\n\n"
790 "Please wait while the Installation Assistant "
791 "updates the software.\n"
792 "This may take several minutes.");
795 plover_vector_free(tasked_packages);
799 static PloverTransaction *
800 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
804 const char *base,*prefix;
805 GError *tmp_error=NULL;
806 PloverTransaction *transaction;
807 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
808 g_return_val_if_fail(helper->installed != NULL,NULL);
809 prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
812 g_propagate_error(error,tmp_error);
815 transaction=plover_transaction_new();
816 plover_transaction_set_prefix(transaction,prefix);
817 plover_transaction_set_installed(transaction,helper->installed);
818 if (helper->upstream)
819 ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
822 base=plover_transaction_helper_get_base(helper);
823 ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
827 g_object_unref(transaction);
833 struct plover_vector *plover_transaction_helper_group_get_default_packages(
834 PloverTransactionHelper *helper,const char *group,GError **error)
838 struct comps_group *grp;
839 struct comps_requirement *pkg;
840 struct plover_vector *default_packages;
841 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
842 comps=plover_transaction_helper_get_comps(helper,error);
845 grp=plover_comps_lookup_group(comps,group);
848 g_set_error(error,PLOVER_GENERAL_ERROR,
849 PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
852 default_packages=plover_vector_new();
856 for(pkg=grp->packages;pkg;pkg=pkg->next)
858 if (plover_vector_contains(default_packages,pkg->name))
860 if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
861 pkg->type==COMPS_REQUIREMENT_MANDATORY ||
862 pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
863 plover_vector_contains(default_packages,pkg->requires))
866 plover_vector_append(default_packages,pkg->name);
870 return default_packages;
874 * Returns TRUE if there is work to be done or FALSE if the packages are
875 * already installed or on error.
878 plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
879 struct plover_vector *packages,GError **error)
882 PloverTransaction *transaction;
883 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
884 g_return_val_if_fail(packages != NULL,FALSE);
887 g_set_error(error,PLOVER_GENERAL_ERROR,
888 PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
891 transaction=plover_transaction_helper_new_transaction(helper,error);
894 if (!plover_transaction_install(transaction,packages->strings,error))
896 g_object_unref(transaction);
899 retval=plover_transaction_helper_add_transaction(helper,transaction,
900 packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
901 g_object_unref(transaction);
906 * Returns TRUE if there is work to be done or FALSE if the group is
907 * already installed or on error.
910 plover_transaction_helper_install_group(PloverTransactionHelper *helper,
911 const char *group,GError **error)
914 struct plover_vector *selected_packages;
915 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
916 selected_packages=plover_transaction_helper_group_get_default_packages(
918 if (!selected_packages)
920 if (!selected_packages->len)
922 g_set_error(error,PLOVER_GENERAL_ERROR,
923 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
924 plover_vector_free(selected_packages);
927 retval=plover_transaction_helper_install_packages(helper,selected_packages,
929 plover_vector_free(selected_packages);
934 * Returns TRUE if there is work to be done or FALSE if the group is
935 * not installed or on error.
937 gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
938 const char *group,GError **error)
941 struct plover_vector *selected_packages;
942 PloverTransaction *transaction;
943 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
944 g_return_val_if_fail(helper->installed != NULL,FALSE);
945 selected_packages=plover_transaction_helper_group_get_default_packages(
947 if (!selected_packages)
949 if (!selected_packages->len)
951 g_set_error(error,PLOVER_GENERAL_ERROR,
952 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
953 plover_vector_free(selected_packages);
956 transaction=plover_transaction_new();
957 plover_transaction_set_installed(transaction,helper->installed);
958 if (!plover_transaction_remove(transaction,selected_packages->strings,
961 plover_vector_free(selected_packages);
962 g_object_unref(transaction);
965 retval=plover_transaction_helper_add_transaction(helper,transaction,
966 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
967 g_object_unref(transaction);
968 plover_vector_free(selected_packages);
973 * Returns TRUE if there is work to be done or FALSE if all updates have
974 * already been applied or on error.
976 gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
980 PloverTransaction *transaction;
981 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
982 transaction=plover_transaction_helper_new_transaction(helper,error);
985 if (!plover_transaction_update(transaction,NULL,error))
987 g_object_unref(transaction);
990 retval=plover_transaction_helper_add_transaction(helper,transaction,
991 NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
992 g_object_unref(transaction);
996 gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
998 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
999 if (helper->error_dialog)
1001 else if (!helper->assistant)
1004 return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
1007 void plover_transaction_helper_present(PloverTransactionHelper *helper)
1009 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1010 if (helper->error_dialog)
1011 gtk_window_present(GTK_WINDOW(helper->error_dialog));
1012 else if (helper->assistant)
1013 gtk_window_present(GTK_WINDOW(helper->assistant));
1017 plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
1018 int response_id,PloverTransactionHelper *helper)
1020 g_signal_handlers_disconnect_by_data(error_dialog,helper);
1021 if ((GtkWidget *)error_dialog==helper->error_dialog)
1023 gtk_widget_destroy(helper->error_dialog);
1024 helper->error_dialog=NULL;
1025 if (helper->assistant)
1027 gtk_widget_hide(GTK_WIDGET(helper->assistant));
1028 gtk_assistant_set_current_page(helper->assistant,0);
1030 g_signal_emit(helper,signals[CLOSE],0);
1034 const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
1035 const GError **error)
1037 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1038 if (!helper->error_dialog)
1041 *error=helper->error;
1042 return helper->error_primary_text;
1045 void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
1046 const GError *error,const char *primary_text)
1048 GtkMessageType type;
1050 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1051 g_return_if_fail(error != NULL);
1052 g_return_if_fail(primary_text != NULL);
1053 if (helper->pulse_handler)
1055 g_source_remove(helper->pulse_handler);
1056 helper->pulse_handler=0;
1058 if (helper->error_dialog)
1060 gtk_widget_destroy(helper->error_dialog);
1061 helper->error_dialog=NULL;
1063 g_free(helper->error_primary_text);
1064 helper->error_primary_text=g_strdup(primary_text);
1065 g_clear_error(&helper->error);
1066 helper->error=g_error_copy(error);
1067 if (g_error_matches(error,PLOVER_GENERAL_ERROR,
1068 PLOVER_GENERAL_ERROR_NO_WORK))
1069 type=GTK_MESSAGE_INFO;
1071 type=GTK_MESSAGE_ERROR;
1072 if (helper->assistant)
1073 window=GTK_WINDOW(helper->assistant);
1076 helper->error_dialog=gtk_message_dialog_new(window,
1077 GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
1078 gtk_message_dialog_format_secondary_text(
1079 GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
1080 gtk_widget_show(helper->error_dialog);
1081 g_signal_connect(helper->error_dialog,"response",
1082 G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);