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 GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
100 gobject_class->finalize=
101 (void (*)(GObject *))plover_transaction_helper_finalize;
102 gobject_class->dispose=
103 (void (*)(GObject *))plover_transaction_helper_dispose;
104 g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
105 signals[CLOSE]=g_signal_newv("close",
106 G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
107 g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
110 static void plover_transaction_helper_init(PloverTransactionHelper *helper)
112 helper->report_adding=plover_vector_new();
113 helper->report_removing=plover_vector_new();
116 static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
117 PloverTransactionHelper *helper)
119 gtk_widget_hide(GTK_WIDGET(helper->assistant));
120 gtk_assistant_set_current_page(helper->assistant,0);
121 g_signal_emit(helper,signals[CLOSE],0);
124 static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
125 PloverTransactionHelper *helper)
127 gtk_widget_hide(GTK_WIDGET(helper->assistant));
128 gtk_assistant_set_current_page(helper->assistant,0);
129 g_signal_emit(helper,signals[CLOSE],0);
133 plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
135 gchar *package_list,*add,*remove,*s;
137 struct plover_vector *report;
138 if (helper->report_adding->len)
140 plover_vector_sort(helper->report_adding);
141 if (helper->report_adding_dependencies)
143 report=plover_vector_dup(helper->report_adding);
144 if (helper->report_adding->len==1)
145 plover_vector_append(report,"its dependencies");
147 plover_vector_append(report,"their dependencies");
148 package_list=plover_vector_format_for_display(report);
149 plover_vector_free(report);
153 plover_vector_format_for_display(helper->report_adding);
154 add=g_strconcat("Packages to be installed or updated: ",package_list,
156 g_free(package_list);
160 if (helper->report_removing->len)
162 plover_vector_sort(helper->report_removing);
163 if (helper->report_removing_dependants)
165 report=plover_vector_dup(helper->report_removing);
166 if (helper->report_adding->len==1)
167 plover_vector_append(report,"its dependants");
169 plover_vector_append(report,"their dependants");
170 package_list=plover_vector_format_for_display(report);
171 plover_vector_free(report);
175 plover_vector_format_for_display(helper->report_removing);
176 remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
177 g_free(package_list);
181 label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
183 s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
184 else if (add || remove)
185 s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
187 s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
188 gtk_label_set_markup(label,s);
194 static void plover_transaction_helper_run(PloverTransactionHelper *helper);
196 static void plover_transaction_helper_callback(GObject *source,
197 GAsyncResult *result,gpointer user_data)
200 PloverTransactionHelper *helper=user_data;
201 PloverTransaction *transaction=PLOVER_TRANSACTION(source);
202 if (!plover_transaction_commit_finish(transaction,result,&error))
204 plover_transaction_helper_set_error(helper,error,
205 "Software installation failed");
209 plover_transaction_helper_run(helper);
211 * There may be status updates queued by transaction as idle events.
212 * Process them now before we disconnect so that we don't lose them.
214 while(g_main_context_pending(NULL))
215 g_main_context_iteration(NULL,FALSE);
216 g_signal_handlers_disconnect_by_data(transaction,helper);
217 g_object_unref(transaction);
220 static void plover_transaction_helper_transaction_status_changed(
221 PloverTransaction *transaction,const char *status,
222 PloverTransactionHelper *helper)
225 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
226 gtk_progress_bar_set_text(bar,status);
229 static void plover_transaction_helper_run(PloverTransactionHelper *helper)
231 PloverTransaction *transaction;
233 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
234 if (helper->transactions)
236 if (helper->assistant)
237 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
238 transaction=helper->transactions->data;
239 helper->transactions=g_slist_delete_link(helper->transactions,
240 helper->transactions);
241 g_signal_connect(transaction,"status-changed",
242 G_CALLBACK(plover_transaction_helper_transaction_status_changed),
244 plover_transaction_commit_async(transaction,NULL,
245 plover_transaction_helper_callback,helper);
247 else if (helper->assistant)
248 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
251 static gboolean plover_transaction_helper_pulse(gpointer user_data)
253 PloverTransactionHelper *helper=user_data;
256 if (!helper->assistant)
258 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
259 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
260 if (gtk_assistant_get_page_complete(helper->assistant,w))
262 gtk_progress_bar_set_fraction(bar,1.0);
263 helper->pulse_handler=0;
268 gtk_progress_bar_pulse(bar);
274 plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
277 GtkToggleButton *button;
278 PloverTransaction *transaction;
279 GSList *save_transactions;
280 PloverTransactionHelperPrivate *priv;
281 enum plover_transaction_type save_transaction_type;
282 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
283 button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
284 "SIRemoveExisting"));
285 if (gtk_toggle_button_get_active(button))
287 transaction=plover_transaction_new_remove(NULL,&error);
290 save_transactions=helper->transactions;
291 helper->transactions=NULL;
292 save_transaction_type=priv->transaction_type;
293 priv->transaction_type=0;
294 if (!plover_transaction_helper_add_transaction(helper,transaction,
295 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
297 g_object_unref(transaction);
299 helper->transactions=save_transactions;
300 priv->transaction_type=save_transaction_type;
304 g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
305 g_slist_free(save_transactions);
310 if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
311 g_clear_error(&error);
314 plover_transaction_helper_set_error(helper,error,
315 "Failed to remove existing packages");
322 * Note that PloverTransaction does support cancelling a transaction, but
323 * there are a number of challenges with using it:
324 * - cancellation is only supported during the file phase if razor
325 * has atomic rollback,
326 * - cancellation is not supported during post-transaction scripts at all
327 * (since by the time the first script is started the atomic has already
328 * been committed) and these can take quite some time,
329 * - where a transaction has an embedded COMMIT, any rollback won't
330 * go back beyond this point.
331 * To support user-cancel, then, we would need some mechanism to:
332 * - Comunicate that the operation is being cancelled and this may take
334 * - Not allow cancellation at all after the last post-transaction script
336 * - Report the partially completed transaction where cancellation
337 * occurred after a COMMIT point.
338 * At present, this doesn't appear worth the effort.
340 if (helper->assistant)
341 gtk_assistant_commit(helper->assistant);
342 plover_transaction_helper_run(helper);
343 helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
347 static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
348 GtkWidget *page,PloverTransactionHelper *helper)
350 if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
351 plover_transaction_helper_prepare_confirm(helper);
352 else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
353 plover_transaction_helper_prepare_progress(helper);
357 plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
358 PloverTransactionHelper *helper)
361 if (helper->assistant)
363 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
364 gtk_assistant_set_page_complete(helper->assistant,w,
365 gtk_toggle_button_get_active(button));
369 PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
372 gchar *s,*directory,*contents;
375 PloverTransactionHelper *helper;
376 g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
377 helper=PLOVER_TRANSACTION_HELPER(
378 g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
380 helper->ui=g_object_ref(ui);
382 helper->ui=gtk_builder_new();
384 GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
385 if (!helper->assistant)
387 directory=g_strdup(g_getenv("PLOVER_DATADIR"));
391 s=g_win32_get_package_installation_directory_of_module(NULL);
392 directory=g_build_filename(s,"share","plover",NULL);
395 directory=g_strdup(PLOVER_DATADIR);
398 s=g_build_filename(directory,"software-installation.ui",NULL);
400 (void)g_file_get_contents(s,&contents,&len,&error);
404 (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
409 g_critical("software-installation.ui: %s",error->message);
410 g_clear_error(&error);
411 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
412 "Internal error (no user interface)");
413 plover_transaction_helper_set_error(helper,error,
414 "Can't start installer");
417 helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
418 "SoftwareInstallation"));
420 if (!helper->assistant)
422 g_critical("\"SoftwareInstallation\" object not found");
423 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
424 "Internal error (missing wizard)");
425 plover_transaction_helper_set_error(helper,error,
426 "Can't start installer");
431 g_object_ref(helper->assistant);
432 if (!GTK_IS_ASSISTANT(helper->assistant))
434 g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
435 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
436 "Internal error (unexpected wizard type)");
437 plover_transaction_helper_set_error(helper,error,
438 "Can't start installer");
442 g_signal_connect(helper->assistant,"cancel",
443 G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
444 g_signal_connect(helper->assistant,"close",
445 G_CALLBACK(plover_transaction_helper_assistant_close),helper);
446 g_signal_connect(helper->assistant,"prepare",
447 G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
448 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
450 g_signal_connect(w,"toggled",
451 G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
452 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
454 gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
459 plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
461 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
462 return helper->installed;
465 void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
466 PloverPackageSet *installed)
468 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
469 g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
470 g_return_if_fail(helper->installed == NULL);
471 helper->installed=g_object_ref(installed);
475 plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
479 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
480 if (!helper->upstream)
482 base=plover_transaction_helper_get_base(helper);
483 helper->upstream=plover_repository_new_from_yum(base,error);
485 return helper->upstream;
488 void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
489 PloverRepository *upstream)
491 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
492 g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
493 g_return_if_fail(helper->upstream == NULL);
494 helper->upstream=g_object_ref(upstream);
497 const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
499 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
503 void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
506 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
507 g_return_if_fail(helper->transactions == NULL);
508 g_free(helper->base);
509 helper->base=g_strdup(base);
513 plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
517 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
518 g_return_val_if_fail(helper->base != NULL,NULL);
521 s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
522 helper->comps=plover_comps_new_from_file(s);
524 g_set_error(error,PLOVER_GENERAL_ERROR,
525 PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
528 return helper->comps;
532 plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
537 PloverTransactionHelperPrivate *priv;
538 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
539 g_return_val_if_fail(helper->base != NULL || helper->installed != NULL,NULL);
540 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
543 comps=plover_transaction_helper_get_comps(helper,error);
546 g_free(priv->default_prefix);
547 priv->default_prefix=plover_default_prefix_for_vendor(comps->vendor);
548 return priv->default_prefix;
550 prefix=plover_package_set_guess_prefix(helper->installed,error);
554 static int plover_transaction_helper_package_count(void)
558 struct razor_set *set;
559 struct razor_package *package;
560 struct razor_package_iterator *pi;
561 install_root=getenv("RAZOR_ROOT");
564 set=razor_root_open_read_only(install_root,NULL);
567 pi=razor_package_iterator_create(set);
568 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
570 razor_package_iterator_destroy(pi);
571 razor_set_unref(set);
577 plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
581 gchar *prefix=NULL,*s;
582 struct comps *comps=NULL;
583 GtkWidget *container,*summary,*page;
586 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
587 if (helper->check_vendor)
589 comps=plover_transaction_helper_get_comps(helper,error);
592 prefix=plover_default_prefix_for_vendor(comps->vendor);
594 button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
595 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
596 container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
597 "SIIncompatibleInstallation"));
598 summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
599 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
600 if (helper->check_vendor && prefix &&
601 !plover_installed_files_match_prefix(prefix))
603 label=GTK_LABEL(gtk_builder_get_object(helper->ui,
604 "SIIncompatibleInstallationLabel"));
605 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
606 "The existing installation is not from %s.\n"
607 "In order to continue, all the existing packages must be removed.",
609 gtk_label_set_markup(label,s);
611 i=plover_transaction_helper_package_count();
612 s=g_strdup_printf("Remove %d existing package%s",i,i==1?"":"s");
613 gtk_button_set_label(button,s);
615 gtk_widget_show(container);
616 gtk_widget_hide(summary);
617 if (helper->assistant)
618 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
622 gtk_widget_hide(container);
623 gtk_widget_show(summary);
624 if (helper->assistant)
625 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
631 void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
632 gboolean check_vendor)
634 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
635 if (helper->check_vendor!=check_vendor)
637 helper->check_vendor=check_vendor;
638 if (helper->transactions)
639 plover_transaction_helper_check_vendor(helper,NULL);
644 * If plover_transaction_helper_add_transaction() failes with an error
645 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
646 * then plover_transaction_helper_get_unsatisfied() can be used to
647 * retrieve a textual description of the problem.
651 plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
653 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
654 return helper->unsatisfied;
657 #define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
658 ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
659 (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
660 (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
663 plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
664 PloverTransaction *transaction,struct plover_vector *report_packages,
665 PloverTransactionHelperReportAction report_action,GError **error)
668 gboolean other_packages;
670 enum razor_install_action action;
671 struct razor_install_iterator *ii;
672 struct razor_set *report_set;
673 struct razor_package *package;
674 struct plover_vector *tasked_packages;
675 PloverTransactionHelperPrivate *priv;
677 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
678 g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
679 g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
680 g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
681 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
682 g_free(helper->unsatisfied);
683 helper->unsatisfied=NULL;
684 if (!plover_transaction_resolve(transaction,error))
686 s=plover_transaction_get_unsatisfied(transaction);
687 helper->unsatisfied=g_strdup(s);
690 ii=plover_transaction_get_install_iterator(transaction,error);
693 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
694 report_set=plover_transaction_get_system_set(transaction);
696 report_set=plover_transaction_get_next_set(transaction,error);
699 tasked_packages=plover_vector_new();
700 other_packages=FALSE;
701 while (razor_install_iterator_next(ii,&package,&action,&count))
703 if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
704 report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
706 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
707 &name,RAZOR_DETAIL_LAST);
708 if (!report_packages ||
709 plover_vector_contains(report_packages,name))
710 plover_vector_append(tasked_packages,name);
715 if (!tasked_packages->len)
718 * If there are no reportable packages tasked for action there
719 * shouldn't by any packages at all, but let's be paranoid.
721 other_packages=FALSE;
722 razor_install_iterator_rewind(ii);
723 while (razor_install_iterator_next(ii,&package,&action,&count))
725 if (action==report_action)
727 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
728 &name,RAZOR_DETAIL_LAST);
729 plover_vector_append(tasked_packages,name);
733 if (!tasked_packages->len)
735 g_set_error(error,PLOVER_GENERAL_ERROR,
736 PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
737 report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
739 plover_vector_free(tasked_packages);
742 if (!helper->transactions)
743 plover_transaction_helper_check_vendor(helper,error);
744 g_object_ref(transaction);
745 helper->transactions=g_slist_append(helper->transactions,transaction);
746 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
748 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
749 for(i=0;i<tasked_packages->len;i++)
751 s=tasked_packages->strings[i];
752 if (!plover_vector_contains(helper->report_removing,s))
753 plover_vector_append(helper->report_removing,s);
755 helper->report_removing_dependants|=other_packages;
759 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
760 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
761 priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
762 for(i=0;i<tasked_packages->len;i++)
764 s=tasked_packages->strings[i];
765 if (!plover_vector_contains(helper->report_adding,s))
766 plover_vector_append(helper->report_adding,s);
768 helper->report_adding_dependencies|=other_packages;
770 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
771 switch(priv->transaction_type)
773 case TRANSACTION_TYPE_INSTALL:
774 gtk_label_set_markup(GTK_LABEL(w),
775 "<b>Installing the Software</b>\n\n"
776 "Please wait while the Installation Assistant "
777 "installs the software.\n"
778 "This may take several minutes.");
780 case TRANSACTION_TYPE_REMOVE:
781 gtk_label_set_markup(GTK_LABEL(w),
782 "<b>Removing Packages</b>\n\n"
783 "Please wait while the Installation Assistant "
784 "removes packages.\n"
785 "This may take several minutes.");
788 case TRANSACTION_TYPE_UPDATE:
789 gtk_label_set_markup(GTK_LABEL(w),
790 "<b>Updating the Software</b>\n\n"
791 "Please wait while the Installation Assistant "
792 "updates the software.\n"
793 "This may take several minutes.");
796 plover_vector_free(tasked_packages);
800 static PloverTransaction *
801 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
805 const char *base,*prefix;
806 GError *tmp_error=NULL;
807 PloverTransaction *transaction;
808 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
809 g_return_val_if_fail(helper->installed != NULL,NULL);
810 prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
813 g_propagate_error(error,tmp_error);
816 transaction=plover_transaction_new();
817 plover_transaction_set_prefix(transaction,prefix);
818 plover_transaction_set_installed(transaction,helper->installed);
819 if (helper->upstream)
820 ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
823 base=plover_transaction_helper_get_base(helper);
824 ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
828 g_object_unref(transaction);
834 struct plover_vector *plover_transaction_helper_group_get_default_packages(
835 PloverTransactionHelper *helper,const char *group,GError **error)
839 struct comps_group *grp;
840 struct comps_requirement *pkg;
841 struct plover_vector *default_packages;
842 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
843 comps=plover_transaction_helper_get_comps(helper,error);
846 grp=plover_comps_lookup_group(comps,group);
849 g_set_error(error,PLOVER_GENERAL_ERROR,
850 PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
853 default_packages=plover_vector_new();
857 for(pkg=grp->packages;pkg;pkg=pkg->next)
859 if (plover_vector_contains(default_packages,pkg->name))
861 if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
862 pkg->type==COMPS_REQUIREMENT_MANDATORY ||
863 pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
864 plover_vector_contains(default_packages,pkg->requires))
867 plover_vector_append(default_packages,pkg->name);
871 return default_packages;
875 * Returns TRUE if there is work to be done or FALSE if the packages are
876 * already installed or on error.
879 plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
880 struct plover_vector *packages,GError **error)
883 PloverTransaction *transaction;
884 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
885 g_return_val_if_fail(packages != NULL,FALSE);
888 g_set_error(error,PLOVER_GENERAL_ERROR,
889 PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
892 transaction=plover_transaction_helper_new_transaction(helper,error);
895 if (!plover_transaction_install(transaction,packages->strings,error))
897 g_object_unref(transaction);
900 retval=plover_transaction_helper_add_transaction(helper,transaction,
901 packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
902 g_object_unref(transaction);
907 * Returns TRUE if there is work to be done or FALSE if the group is
908 * already installed or on error.
911 plover_transaction_helper_install_group(PloverTransactionHelper *helper,
912 const char *group,GError **error)
915 struct plover_vector *selected_packages;
916 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
917 selected_packages=plover_transaction_helper_group_get_default_packages(
919 if (!selected_packages)
921 if (!selected_packages->len)
923 g_set_error(error,PLOVER_GENERAL_ERROR,
924 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
925 plover_vector_free(selected_packages);
928 retval=plover_transaction_helper_install_packages(helper,selected_packages,
930 plover_vector_free(selected_packages);
935 * Returns TRUE if there is work to be done or FALSE if the group is
936 * not installed or on error.
938 gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
939 const char *group,GError **error)
942 struct plover_vector *selected_packages;
943 PloverTransaction *transaction;
944 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
945 g_return_val_if_fail(helper->installed != NULL,FALSE);
946 selected_packages=plover_transaction_helper_group_get_default_packages(
948 if (!selected_packages)
950 if (!selected_packages->len)
952 g_set_error(error,PLOVER_GENERAL_ERROR,
953 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
954 plover_vector_free(selected_packages);
957 transaction=plover_transaction_new();
958 plover_transaction_set_installed(transaction,helper->installed);
959 if (!plover_transaction_remove(transaction,selected_packages->strings,
962 plover_vector_free(selected_packages);
963 g_object_unref(transaction);
966 retval=plover_transaction_helper_add_transaction(helper,transaction,
967 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
968 g_object_unref(transaction);
969 plover_vector_free(selected_packages);
974 * Returns TRUE if there is work to be done or FALSE if all updates have
975 * already been applied or on error.
977 gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
981 PloverTransaction *transaction;
982 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
983 transaction=plover_transaction_helper_new_transaction(helper,error);
986 if (!plover_transaction_update(transaction,NULL,error))
988 g_object_unref(transaction);
991 retval=plover_transaction_helper_add_transaction(helper,transaction,
992 NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
993 g_object_unref(transaction);
997 gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
999 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1000 if (helper->error_dialog)
1002 else if (!helper->assistant)
1005 return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
1008 void plover_transaction_helper_present(PloverTransactionHelper *helper)
1010 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1011 if (helper->error_dialog)
1012 gtk_window_present(GTK_WINDOW(helper->error_dialog));
1013 else if (helper->assistant)
1014 gtk_window_present(GTK_WINDOW(helper->assistant));
1018 plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
1019 int response_id,PloverTransactionHelper *helper)
1021 g_signal_handlers_disconnect_by_data(error_dialog,helper);
1022 if ((GtkWidget *)error_dialog==helper->error_dialog)
1024 gtk_widget_destroy(helper->error_dialog);
1025 helper->error_dialog=NULL;
1026 if (helper->assistant)
1028 gtk_widget_hide(GTK_WIDGET(helper->assistant));
1029 gtk_assistant_set_current_page(helper->assistant,0);
1031 g_signal_emit(helper,signals[CLOSE],0);
1035 const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
1036 const GError **error)
1038 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1039 if (!helper->error_dialog)
1042 *error=helper->error;
1043 return helper->error_primary_text;
1046 void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
1047 const GError *error,const char *primary_text)
1049 GtkMessageType type;
1051 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1052 g_return_if_fail(error != NULL);
1053 g_return_if_fail(primary_text != NULL);
1054 if (helper->pulse_handler)
1056 g_source_remove(helper->pulse_handler);
1057 helper->pulse_handler=0;
1059 if (helper->error_dialog)
1061 gtk_widget_destroy(helper->error_dialog);
1062 helper->error_dialog=NULL;
1064 g_free(helper->error_primary_text);
1065 helper->error_primary_text=g_strdup(primary_text);
1066 g_clear_error(&helper->error);
1067 helper->error=g_error_copy(error);
1068 if (g_error_matches(error,PLOVER_GENERAL_ERROR,
1069 PLOVER_GENERAL_ERROR_NO_WORK))
1070 type=GTK_MESSAGE_INFO;
1072 type=GTK_MESSAGE_ERROR;
1073 if (helper->assistant)
1074 window=GTK_WINDOW(helper->assistant);
1077 helper->error_dialog=gtk_message_dialog_new(window,
1078 GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
1079 gtk_message_dialog_format_secondary_text(
1080 GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
1081 gtk_widget_show(helper->error_dialog);
1082 g_signal_connect(helper->error_dialog,"response",
1083 G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);