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>
26 #include "plover/uri-handler.h"
29 * A PloverTransactionHelper uses a GtkAssistant to help a user run a
33 G_DEFINE_TYPE(PloverTransactionHelper,plover_transaction_helper,G_TYPE_OBJECT)
35 enum plover_transaction_type {
36 TRANSACTION_TYPE_NULL=0,
37 TRANSACTION_TYPE_INSTALL=1UL<<0,
38 TRANSACTION_TYPE_REMOVE=1UL<<1,
39 TRANSACTION_TYPE_UPDATE=TRANSACTION_TYPE_INSTALL|TRANSACTION_TYPE_REMOVE
42 typedef struct _PloverTransactionHelperPrivate {
43 enum plover_transaction_type transaction_type;
44 gchar *default_prefix;
45 } PloverTransactionHelperPrivate;
47 #define PLOVER_TRANSACTION_HELPER_GET_PRIVATE(obj)\
48 G_TYPE_INSTANCE_GET_PRIVATE(obj,\
49 PLOVER_TYPE_TRANSACTION_HELPER,\
50 PloverTransactionHelperPrivate)
57 static guint signals[N_SIGNALS];
59 static void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
61 PloverTransactionHelperPrivate *priv;
62 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
63 g_free(priv->default_prefix);
64 g_free(helper->error_primary_text);
66 g_free(helper->unsatisfied);
68 plover_comps_free(helper->comps);
69 plover_vector_free(helper->report_adding);
70 plover_vector_free(helper->report_removing);
73 static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
75 g_clear_error(&helper->error);
76 if (helper->error_dialog)
78 g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
79 gtk_widget_destroy(helper->error_dialog);
80 helper->error_dialog=NULL;
82 if (helper->assistant)
84 g_signal_handlers_disconnect_by_data(helper->assistant,helper);
85 g_clear_object(&helper->assistant);
87 g_clear_object(&helper->ui);
88 g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
89 g_slist_free(helper->transactions);
90 helper->transactions=NULL;
91 g_clear_object(&helper->installed);
92 g_clear_object(&helper->upstream);
93 g_clear_object(&helper->relocated_upstream);
97 plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
99 plover__uri_handler_init();
100 GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
101 gobject_class->finalize=
102 (void (*)(GObject *))plover_transaction_helper_finalize;
103 gobject_class->dispose=
104 (void (*)(GObject *))plover_transaction_helper_dispose;
105 g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
106 signals[CLOSE]=g_signal_newv("close",
107 G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
108 g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
111 static void plover_transaction_helper_init(PloverTransactionHelper *helper)
113 helper->report_adding=plover_vector_new();
114 helper->report_removing=plover_vector_new();
117 static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
118 PloverTransactionHelper *helper)
120 gtk_widget_hide(GTK_WIDGET(helper->assistant));
121 gtk_assistant_set_current_page(helper->assistant,0);
122 g_signal_emit(helper,signals[CLOSE],0);
125 static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
126 PloverTransactionHelper *helper)
128 gtk_widget_hide(GTK_WIDGET(helper->assistant));
129 gtk_assistant_set_current_page(helper->assistant,0);
130 g_signal_emit(helper,signals[CLOSE],0);
134 plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
136 gchar *package_list,*add,*remove,*s;
138 struct plover_vector *report;
139 if (helper->report_adding->len)
141 plover_vector_sort(helper->report_adding);
142 if (helper->report_adding_dependencies)
144 report=plover_vector_dup(helper->report_adding);
145 if (helper->report_adding->len==1)
146 plover_vector_append(report,"its dependencies");
148 plover_vector_append(report,"their dependencies");
149 package_list=plover_vector_format_for_display(report);
150 plover_vector_free(report);
154 plover_vector_format_for_display(helper->report_adding);
155 add=g_strconcat("Packages to be installed or updated: ",package_list,
157 g_free(package_list);
161 if (helper->report_removing->len)
163 plover_vector_sort(helper->report_removing);
164 if (helper->report_removing_dependants)
166 report=plover_vector_dup(helper->report_removing);
167 if (helper->report_adding->len==1)
168 plover_vector_append(report,"its dependants");
170 plover_vector_append(report,"their dependants");
171 package_list=plover_vector_format_for_display(report);
172 plover_vector_free(report);
176 plover_vector_format_for_display(helper->report_removing);
177 remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
178 g_free(package_list);
182 label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
184 s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
185 else if (add || remove)
186 s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
188 s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
189 gtk_label_set_markup(label,s);
195 static void plover_transaction_helper_run(PloverTransactionHelper *helper);
197 static void plover_transaction_helper_callback(GObject *source,
198 GAsyncResult *result,gpointer user_data)
201 PloverTransactionHelper *helper=user_data;
202 PloverTransaction *transaction=PLOVER_TRANSACTION(source);
203 if (!plover_transaction_commit_finish(transaction,result,&error))
205 plover_transaction_helper_set_error(helper,error,
206 "Software installation failed");
210 plover_transaction_helper_run(helper);
212 * There may be status updates queued by transaction as idle events.
213 * Process them now before we disconnect so that we don't lose them.
215 while(g_main_context_pending(NULL))
216 g_main_context_iteration(NULL,FALSE);
217 g_signal_handlers_disconnect_by_data(transaction,helper);
218 g_object_unref(transaction);
221 static void plover_transaction_helper_transaction_status_changed(
222 PloverTransaction *transaction,const char *status,
223 PloverTransactionHelper *helper)
226 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
227 gtk_progress_bar_set_text(bar,status);
230 static void plover_transaction_helper_run(PloverTransactionHelper *helper)
232 PloverTransaction *transaction;
234 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
235 if (helper->transactions)
237 if (helper->assistant)
238 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
239 transaction=helper->transactions->data;
240 helper->transactions=g_slist_delete_link(helper->transactions,
241 helper->transactions);
242 g_signal_connect(transaction,"status-changed",
243 G_CALLBACK(plover_transaction_helper_transaction_status_changed),
245 plover_transaction_commit_async(transaction,NULL,
246 plover_transaction_helper_callback,helper);
248 else if (helper->assistant)
249 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
252 static gboolean plover_transaction_helper_pulse(gpointer user_data)
254 PloverTransactionHelper *helper=user_data;
257 if (!helper->assistant)
259 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
260 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
261 if (gtk_assistant_get_page_complete(helper->assistant,w))
263 gtk_progress_bar_set_fraction(bar,1.0);
264 helper->pulse_handler=0;
269 gtk_progress_bar_pulse(bar);
275 plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
278 GtkToggleButton *button;
279 PloverTransaction *transaction;
280 GSList *save_transactions;
281 PloverTransactionHelperPrivate *priv;
282 enum plover_transaction_type save_transaction_type;
283 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
284 button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
285 "SIRemoveExisting"));
286 if (gtk_toggle_button_get_active(button))
288 transaction=plover_transaction_new_remove(NULL,&error);
291 save_transactions=helper->transactions;
292 helper->transactions=NULL;
293 save_transaction_type=priv->transaction_type;
294 priv->transaction_type=0;
295 if (!plover_transaction_helper_add_transaction(helper,transaction,
296 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
298 g_object_unref(transaction);
300 helper->transactions=save_transactions;
301 priv->transaction_type=save_transaction_type;
305 g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
306 g_slist_free(save_transactions);
311 if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
312 g_clear_error(&error);
315 plover_transaction_helper_set_error(helper,error,
316 "Failed to remove existing packages");
323 * Note that PloverTransaction does support cancelling a transaction, but
324 * there are a number of challenges with using it:
325 * - cancellation is only supported during the file phase if razor
326 * has atomic rollback,
327 * - cancellation is not supported during post-transaction scripts at all
328 * (since by the time the first script is started the atomic has already
329 * been committed) and these can take quite some time,
330 * - where a transaction has an embedded COMMIT, any rollback won't
331 * go back beyond this point.
332 * To support user-cancel, then, we would need some mechanism to:
333 * - Comunicate that the operation is being cancelled and this may take
335 * - Not allow cancellation at all after the last post-transaction script
337 * - Report the partially completed transaction where cancellation
338 * occurred after a COMMIT point.
339 * At present, this doesn't appear worth the effort.
341 if (helper->assistant)
342 gtk_assistant_commit(helper->assistant);
343 plover_transaction_helper_run(helper);
344 helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
348 static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
349 GtkWidget *page,PloverTransactionHelper *helper)
351 if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
352 plover_transaction_helper_prepare_confirm(helper);
353 else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
354 plover_transaction_helper_prepare_progress(helper);
358 plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
359 PloverTransactionHelper *helper)
362 if (helper->assistant)
364 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
365 gtk_assistant_set_page_complete(helper->assistant,w,
366 gtk_toggle_button_get_active(button));
370 PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
373 gchar *s,*directory,*contents;
376 PloverTransactionHelper *helper;
377 g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
378 helper=PLOVER_TRANSACTION_HELPER(
379 g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
381 helper->ui=g_object_ref(ui);
383 helper->ui=gtk_builder_new();
385 GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
386 if (!helper->assistant)
388 directory=g_strdup(g_getenv("PLOVER_DATADIR"));
392 s=g_win32_get_package_installation_directory_of_module(NULL);
393 directory=g_build_filename(s,"share","plover",NULL);
396 directory=g_strdup(PLOVER_DATADIR);
399 s=g_build_filename(directory,"software-installation.ui",NULL);
401 (void)g_file_get_contents(s,&contents,&len,&error);
405 (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
410 g_critical("software-installation.ui: %s",error->message);
411 g_clear_error(&error);
412 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
413 "Internal error (no user interface)");
414 plover_transaction_helper_set_error(helper,error,
415 "Can't start installer");
418 helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
419 "SoftwareInstallation"));
421 if (!helper->assistant)
423 g_critical("\"SoftwareInstallation\" object not found");
424 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
425 "Internal error (missing wizard)");
426 plover_transaction_helper_set_error(helper,error,
427 "Can't start installer");
432 g_object_ref(helper->assistant);
433 if (!GTK_IS_ASSISTANT(helper->assistant))
435 g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
436 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
437 "Internal error (unexpected wizard type)");
438 plover_transaction_helper_set_error(helper,error,
439 "Can't start installer");
443 g_signal_connect(helper->assistant,"cancel",
444 G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
445 g_signal_connect(helper->assistant,"close",
446 G_CALLBACK(plover_transaction_helper_assistant_close),helper);
447 g_signal_connect(helper->assistant,"prepare",
448 G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
449 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
451 g_signal_connect(w,"toggled",
452 G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
453 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
455 gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
460 plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
462 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
463 return helper->installed;
466 void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
467 PloverPackageSet *installed)
469 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
470 g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
471 g_return_if_fail(helper->installed == NULL);
472 helper->installed=g_object_ref(installed);
476 plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
480 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
481 if (!helper->upstream)
483 base=plover_transaction_helper_get_base(helper);
484 helper->upstream=plover_repository_new_from_yum(base,error);
486 return helper->upstream;
489 void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
490 PloverRepository *upstream)
492 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
493 g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
494 g_return_if_fail(helper->upstream == NULL);
495 helper->upstream=g_object_ref(upstream);
498 const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
500 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
504 void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
507 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
508 g_return_if_fail(helper->transactions == NULL);
509 g_free(helper->base);
510 helper->base=g_strdup(base);
514 plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
518 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
519 g_return_val_if_fail(helper->base != NULL,NULL);
522 s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
523 helper->comps=plover_comps_new_from_file(s);
525 g_set_error(error,PLOVER_GENERAL_ERROR,
526 PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
529 return helper->comps;
533 plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
538 PloverTransactionHelperPrivate *priv;
539 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
540 g_return_val_if_fail(helper->base != NULL || helper->installed != NULL,NULL);
541 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
544 comps=plover_transaction_helper_get_comps(helper,error);
547 g_free(priv->default_prefix);
548 priv->default_prefix=plover_default_prefix_for_vendor(comps->vendor);
549 return priv->default_prefix;
551 prefix=plover_package_set_guess_prefix(helper->installed,error);
555 static int plover_transaction_helper_package_count(void)
559 struct razor_set *set;
560 struct razor_package *package;
561 struct razor_package_iterator *pi;
562 install_root=getenv("RAZOR_ROOT");
565 set=razor_root_open_read_only(install_root,NULL);
568 pi=razor_package_iterator_create(set);
569 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
571 razor_package_iterator_destroy(pi);
572 razor_set_unref(set);
578 plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
582 gchar *prefix=NULL,*s;
583 struct comps *comps=NULL;
584 GtkWidget *container,*summary,*page;
587 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
588 if (helper->check_vendor)
590 comps=plover_transaction_helper_get_comps(helper,error);
593 prefix=plover_default_prefix_for_vendor(comps->vendor);
595 button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
596 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
597 container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
598 "SIIncompatibleInstallation"));
599 summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
600 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
601 if (helper->check_vendor && prefix &&
602 !plover_installed_files_match_prefix(prefix))
604 label=GTK_LABEL(gtk_builder_get_object(helper->ui,
605 "SIIncompatibleInstallationLabel"));
606 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
607 "The existing installation is not from %s.\n"
608 "In order to continue, all the existing packages must be removed.",
610 gtk_label_set_markup(label,s);
612 i=plover_transaction_helper_package_count();
613 s=g_strdup_printf("Remove %d existing package%s",i,i==1?"":"s");
614 gtk_button_set_label(button,s);
616 gtk_widget_show(container);
617 gtk_widget_hide(summary);
618 if (helper->assistant)
619 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
623 gtk_widget_hide(container);
624 gtk_widget_show(summary);
625 if (helper->assistant)
626 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
632 void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
633 gboolean check_vendor)
635 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
636 if (helper->check_vendor!=check_vendor)
638 helper->check_vendor=check_vendor;
639 if (helper->transactions)
640 plover_transaction_helper_check_vendor(helper,NULL);
645 * If plover_transaction_helper_add_transaction() failes with an error
646 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
647 * then plover_transaction_helper_get_unsatisfied() can be used to
648 * retrieve a textual description of the problem.
652 plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
654 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
655 return helper->unsatisfied;
658 #define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
659 ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
660 (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
661 (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
664 plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
665 PloverTransaction *transaction,struct plover_vector *report_packages,
666 PloverTransactionHelperReportAction report_action,GError **error)
669 gboolean other_packages;
671 enum razor_install_action action;
672 struct razor_install_iterator *ii;
673 struct razor_set *report_set;
674 struct razor_package *package;
675 struct plover_vector *tasked_packages;
676 PloverTransactionHelperPrivate *priv;
678 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
679 g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
680 g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
681 g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
682 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
683 g_free(helper->unsatisfied);
684 helper->unsatisfied=NULL;
685 if (!plover_transaction_resolve(transaction,error))
687 s=plover_transaction_get_unsatisfied(transaction);
688 helper->unsatisfied=g_strdup(s);
691 ii=plover_transaction_get_install_iterator(transaction,error);
694 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
695 report_set=plover_transaction_get_system_set(transaction);
697 report_set=plover_transaction_get_next_set(transaction,error);
700 tasked_packages=plover_vector_new();
701 other_packages=FALSE;
702 while (razor_install_iterator_next(ii,&package,&action,&count))
704 if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
705 report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
707 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
708 &name,RAZOR_DETAIL_LAST);
709 if (!report_packages ||
710 plover_vector_contains(report_packages,name))
711 plover_vector_append(tasked_packages,name);
716 if (!tasked_packages->len)
719 * If there are no reportable packages tasked for action there
720 * shouldn't by any packages at all, but let's be paranoid.
722 other_packages=FALSE;
723 razor_install_iterator_rewind(ii);
724 while (razor_install_iterator_next(ii,&package,&action,&count))
726 if (action==report_action)
728 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
729 &name,RAZOR_DETAIL_LAST);
730 plover_vector_append(tasked_packages,name);
734 if (!tasked_packages->len)
736 g_set_error(error,PLOVER_GENERAL_ERROR,
737 PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
738 report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
740 plover_vector_free(tasked_packages);
743 if (!helper->transactions)
744 plover_transaction_helper_check_vendor(helper,error);
745 g_object_ref(transaction);
746 helper->transactions=g_slist_append(helper->transactions,transaction);
747 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
749 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
750 for(i=0;i<tasked_packages->len;i++)
752 s=tasked_packages->strings[i];
753 if (!plover_vector_contains(helper->report_removing,s))
754 plover_vector_append(helper->report_removing,s);
756 helper->report_removing_dependants|=other_packages;
760 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
761 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
762 priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
763 for(i=0;i<tasked_packages->len;i++)
765 s=tasked_packages->strings[i];
766 if (!plover_vector_contains(helper->report_adding,s))
767 plover_vector_append(helper->report_adding,s);
769 helper->report_adding_dependencies|=other_packages;
771 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
772 switch(priv->transaction_type)
774 case TRANSACTION_TYPE_INSTALL:
775 gtk_label_set_markup(GTK_LABEL(w),
776 "<b>Installing the Software</b>\n\n"
777 "Please wait while the Installation Assistant "
778 "installs the software.\n"
779 "This may take several minutes.");
781 case TRANSACTION_TYPE_REMOVE:
782 gtk_label_set_markup(GTK_LABEL(w),
783 "<b>Removing Packages</b>\n\n"
784 "Please wait while the Installation Assistant "
785 "removes packages.\n"
786 "This may take several minutes.");
789 case TRANSACTION_TYPE_UPDATE:
790 gtk_label_set_markup(GTK_LABEL(w),
791 "<b>Updating the Software</b>\n\n"
792 "Please wait while the Installation Assistant "
793 "updates the software.\n"
794 "This may take several minutes.");
797 plover_vector_free(tasked_packages);
801 static PloverTransaction *
802 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
806 const char *base,*prefix;
807 GError *tmp_error=NULL;
808 PloverTransaction *transaction;
809 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
810 g_return_val_if_fail(helper->installed != NULL,NULL);
811 prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
814 g_propagate_error(error,tmp_error);
817 transaction=plover_transaction_new();
818 plover_transaction_set_prefix(transaction,prefix);
819 plover_transaction_set_installed(transaction,helper->installed);
820 if (helper->upstream)
821 ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
824 base=plover_transaction_helper_get_base(helper);
825 ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
829 g_object_unref(transaction);
835 struct plover_vector *plover_transaction_helper_group_get_default_packages(
836 PloverTransactionHelper *helper,const char *group,GError **error)
840 struct comps_group *grp;
841 struct comps_requirement *pkg;
842 struct plover_vector *default_packages;
843 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
844 comps=plover_transaction_helper_get_comps(helper,error);
847 grp=plover_comps_lookup_group(comps,group);
850 g_set_error(error,PLOVER_GENERAL_ERROR,
851 PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
854 default_packages=plover_vector_new();
858 for(pkg=grp->packages;pkg;pkg=pkg->next)
860 if (plover_vector_contains(default_packages,pkg->name))
862 if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
863 pkg->type==COMPS_REQUIREMENT_MANDATORY ||
864 pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
865 plover_vector_contains(default_packages,pkg->requires))
868 plover_vector_append(default_packages,pkg->name);
872 return default_packages;
876 * Returns TRUE if there is work to be done or FALSE if the packages are
877 * already installed or on error.
880 plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
881 struct plover_vector *packages,GError **error)
884 PloverTransaction *transaction;
885 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
886 g_return_val_if_fail(packages != NULL,FALSE);
889 g_set_error(error,PLOVER_GENERAL_ERROR,
890 PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
893 transaction=plover_transaction_helper_new_transaction(helper,error);
896 if (!plover_transaction_install(transaction,packages->strings,error))
898 g_object_unref(transaction);
901 retval=plover_transaction_helper_add_transaction(helper,transaction,
902 packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
903 g_object_unref(transaction);
908 * Returns TRUE if there is work to be done or FALSE if the group is
909 * already installed or on error.
912 plover_transaction_helper_install_group(PloverTransactionHelper *helper,
913 const char *group,GError **error)
916 struct plover_vector *selected_packages;
917 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
918 selected_packages=plover_transaction_helper_group_get_default_packages(
920 if (!selected_packages)
922 if (!selected_packages->len)
924 g_set_error(error,PLOVER_GENERAL_ERROR,
925 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
926 plover_vector_free(selected_packages);
929 retval=plover_transaction_helper_install_packages(helper,selected_packages,
931 plover_vector_free(selected_packages);
936 * Returns TRUE if there is work to be done or FALSE if the group is
937 * not installed or on error.
939 gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
940 const char *group,GError **error)
943 struct plover_vector *selected_packages;
944 PloverTransaction *transaction;
945 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
946 g_return_val_if_fail(helper->installed != NULL,FALSE);
947 selected_packages=plover_transaction_helper_group_get_default_packages(
949 if (!selected_packages)
951 if (!selected_packages->len)
953 g_set_error(error,PLOVER_GENERAL_ERROR,
954 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
955 plover_vector_free(selected_packages);
958 transaction=plover_transaction_new();
959 plover_transaction_set_installed(transaction,helper->installed);
960 if (!plover_transaction_remove(transaction,selected_packages->strings,
963 plover_vector_free(selected_packages);
964 g_object_unref(transaction);
967 retval=plover_transaction_helper_add_transaction(helper,transaction,
968 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
969 g_object_unref(transaction);
970 plover_vector_free(selected_packages);
975 * Returns TRUE if there is work to be done or FALSE if all updates have
976 * already been applied or on error.
978 gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
982 PloverTransaction *transaction;
983 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
984 transaction=plover_transaction_helper_new_transaction(helper,error);
987 if (!plover_transaction_update(transaction,NULL,error))
989 g_object_unref(transaction);
992 retval=plover_transaction_helper_add_transaction(helper,transaction,
993 NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
994 g_object_unref(transaction);
998 gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
1000 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1001 if (helper->error_dialog)
1003 else if (!helper->assistant)
1006 return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
1009 void plover_transaction_helper_present(PloverTransactionHelper *helper)
1011 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1012 if (helper->error_dialog)
1013 gtk_window_present(GTK_WINDOW(helper->error_dialog));
1014 else if (helper->assistant)
1015 gtk_window_present(GTK_WINDOW(helper->assistant));
1019 plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
1020 int response_id,PloverTransactionHelper *helper)
1022 g_signal_handlers_disconnect_by_data(error_dialog,helper);
1023 if ((GtkWidget *)error_dialog==helper->error_dialog)
1025 gtk_widget_destroy(helper->error_dialog);
1026 helper->error_dialog=NULL;
1027 if (helper->assistant)
1029 gtk_widget_hide(GTK_WIDGET(helper->assistant));
1030 gtk_assistant_set_current_page(helper->assistant,0);
1032 g_signal_emit(helper,signals[CLOSE],0);
1036 const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
1037 const GError **error)
1039 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1040 if (!helper->error_dialog)
1043 *error=helper->error;
1044 return helper->error_primary_text;
1047 void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
1048 const GError *error,const char *primary_text)
1050 GtkMessageType type;
1052 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1053 g_return_if_fail(error != NULL);
1054 g_return_if_fail(primary_text != NULL);
1055 if (helper->pulse_handler)
1057 g_source_remove(helper->pulse_handler);
1058 helper->pulse_handler=0;
1060 if (helper->error_dialog)
1062 gtk_widget_destroy(helper->error_dialog);
1063 helper->error_dialog=NULL;
1065 g_free(helper->error_primary_text);
1066 helper->error_primary_text=g_strdup(primary_text);
1067 g_clear_error(&helper->error);
1068 helper->error=g_error_copy(error);
1069 if (g_error_matches(error,PLOVER_GENERAL_ERROR,
1070 PLOVER_GENERAL_ERROR_NO_WORK))
1071 type=GTK_MESSAGE_INFO;
1073 type=GTK_MESSAGE_ERROR;
1074 if (helper->assistant)
1075 window=GTK_WINDOW(helper->assistant);
1078 helper->error_dialog=gtk_message_dialog_new(window,
1079 GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
1080 gtk_message_dialog_format_secondary_text(
1081 GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
1082 gtk_widget_show(helper->error_dialog);
1083 g_signal_connect(helper->error_dialog,"response",
1084 G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);