pre-inst should install 'installer' group rather than the hardcoded plover-gtkui
2 * Copyright (C) 2014, 2016, 2018 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.
24 #include <plover/plover.h>
25 #include <plover/transaction.h>
26 #include <plover-gtk/transactionhelper.h>
27 #include "plover/uri-handler.h"
30 * A PloverTransactionHelper uses a GtkAssistant to help a user run a
34 G_DEFINE_TYPE(PloverTransactionHelper,plover_transaction_helper,G_TYPE_OBJECT)
36 enum plover_transaction_type {
37 TRANSACTION_TYPE_NULL=0,
38 TRANSACTION_TYPE_INSTALL=1UL<<0,
39 TRANSACTION_TYPE_REMOVE=1UL<<1,
40 TRANSACTION_TYPE_UPDATE=TRANSACTION_TYPE_INSTALL|TRANSACTION_TYPE_REMOVE
43 typedef struct _PloverTransactionHelperPrivate {
44 enum plover_transaction_type transaction_type;
45 gchar *default_prefix;
46 } PloverTransactionHelperPrivate;
48 #define PLOVER_TRANSACTION_HELPER_GET_PRIVATE(obj)\
49 G_TYPE_INSTANCE_GET_PRIVATE(obj,\
50 PLOVER_TYPE_TRANSACTION_HELPER,\
51 PloverTransactionHelperPrivate)
58 static guint signals[N_SIGNALS];
60 static PloverTransaction *
61 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
64 static void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
66 PloverTransactionHelperPrivate *priv;
67 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
68 g_free(priv->default_prefix);
69 g_free(helper->error_primary_text);
71 g_free(helper->unsatisfied);
73 plover_comps_free(helper->comps);
74 plover_vector_free(helper->report_adding);
75 plover_vector_free(helper->report_removing);
78 static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
80 g_clear_error(&helper->error);
81 if (helper->error_dialog)
83 g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
84 gtk_widget_destroy(helper->error_dialog);
85 helper->error_dialog=NULL;
87 if (helper->assistant)
89 g_signal_handlers_disconnect_by_data(helper->assistant,helper);
90 g_clear_object(&helper->assistant);
92 g_clear_object(&helper->ui);
93 g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
94 g_slist_free(helper->transactions);
95 helper->transactions=NULL;
96 g_clear_object(&helper->alternate_installed);
97 g_clear_object(&helper->installed);
98 g_clear_object(&helper->upstream);
99 g_clear_object(&helper->relocated_upstream);
103 plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
105 GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
106 gobject_class->finalize=
107 (void (*)(GObject *))plover_transaction_helper_finalize;
108 gobject_class->dispose=
109 (void (*)(GObject *))plover_transaction_helper_dispose;
110 g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
111 signals[CLOSE]=g_signal_newv("close",
112 G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
113 g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
116 static void plover_transaction_helper_init(PloverTransactionHelper *helper)
118 helper->report_adding=plover_vector_new();
119 helper->report_removing=plover_vector_new();
122 static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
123 PloverTransactionHelper *helper)
125 gtk_widget_hide(GTK_WIDGET(helper->assistant));
126 gtk_assistant_set_current_page(helper->assistant,0);
127 g_signal_emit(helper,signals[CLOSE],0);
130 static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
131 PloverTransactionHelper *helper)
133 gtk_widget_hide(GTK_WIDGET(helper->assistant));
134 gtk_assistant_set_current_page(helper->assistant,0);
135 g_signal_emit(helper,signals[CLOSE],0);
139 plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
141 gchar *package_list,*add,*remove,*s;
143 struct plover_vector *report;
144 if (helper->report_adding->len)
146 plover_vector_sort(helper->report_adding);
147 if (helper->report_adding_dependencies)
149 report=plover_vector_dup(helper->report_adding);
150 if (helper->report_adding->len==1)
151 plover_vector_append(report,"its dependencies");
153 plover_vector_append(report,"their dependencies");
154 package_list=plover_vector_format_for_display(report);
155 plover_vector_free(report);
159 plover_vector_format_for_display(helper->report_adding);
160 add=g_strconcat("Packages to be installed or updated: ",package_list,
162 g_free(package_list);
166 if (helper->report_removing->len)
168 plover_vector_sort(helper->report_removing);
169 if (helper->report_removing_dependants)
171 report=plover_vector_dup(helper->report_removing);
172 if (helper->report_adding->len==1)
173 plover_vector_append(report,"its dependants");
175 plover_vector_append(report,"their dependants");
176 package_list=plover_vector_format_for_display(report);
177 plover_vector_free(report);
181 plover_vector_format_for_display(helper->report_removing);
182 remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
183 g_free(package_list);
187 label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
189 s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
190 else if (add || remove)
191 s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
193 s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
194 gtk_label_set_markup(label,s);
200 static void plover_transaction_helper_run(PloverTransactionHelper *helper);
202 static void plover_transaction_helper_callback(GObject *source,
203 GAsyncResult *result,gpointer user_data)
206 PloverTransactionHelper *helper=user_data;
207 PloverTransaction *transaction=PLOVER_TRANSACTION(source);
208 if (!plover_transaction_commit_finish(transaction,result,&error))
210 plover_transaction_helper_set_error(helper,error,
211 "Software installation failed");
215 plover_transaction_helper_run(helper);
217 * There may be status updates queued by transaction as idle events.
218 * Process them now before we disconnect so that we don't lose them.
220 while(g_main_context_pending(NULL))
221 g_main_context_iteration(NULL,FALSE);
222 g_signal_handlers_disconnect_by_data(transaction,helper);
223 g_object_unref(transaction);
226 static void plover_transaction_helper_transaction_status_changed(
227 PloverTransaction *transaction,const char *status,
228 PloverTransactionHelper *helper)
231 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
232 gtk_progress_bar_set_text(bar,status);
235 static void plover_transaction_helper_run(PloverTransactionHelper *helper)
237 PloverTransaction *transaction;
239 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
240 if (helper->transactions)
242 if (helper->assistant)
243 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
244 transaction=helper->transactions->data;
245 helper->transactions=g_slist_delete_link(helper->transactions,
246 helper->transactions);
247 g_signal_connect(transaction,"status-changed",
248 G_CALLBACK(plover_transaction_helper_transaction_status_changed),
250 plover_transaction_commit_async(transaction,NULL,
251 plover_transaction_helper_callback,helper);
253 else if (helper->assistant)
254 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
257 static gboolean plover_transaction_helper_pulse(gpointer user_data)
259 PloverTransactionHelper *helper=user_data;
262 if (!helper->assistant)
264 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
265 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
266 if (gtk_assistant_get_page_complete(helper->assistant,w))
268 gtk_progress_bar_set_fraction(bar,1.0);
269 helper->pulse_handler=0;
274 gtk_progress_bar_pulse(bar);
280 plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
283 GtkToggleButton *button;
284 PloverTransaction *transaction;
285 GSList *save_transactions;
286 PloverTransactionHelperPrivate *priv;
287 enum plover_transaction_type save_transaction_type;
288 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
289 button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
290 "SIRemoveExisting"));
291 if (gtk_toggle_button_get_active(button))
293 transaction=plover_transaction_helper_new_transaction(helper,&error);
295 * I think we want switch to the alternate installed set in the case of
296 * alternate_database_clashes, but not in the case of
297 * active_database_is_incompatible (see
298 * plover_transaction_helper_update_summary_page).
299 * Whether testing for helper->alternate_installed is sufficient I'm
302 if (helper->alternate_installed)
303 plover_transaction_set_installed(transaction,
304 helper->alternate_installed);
305 if (transaction && !plover_transaction_remove(transaction,NULL,&error))
307 g_object_unref(transaction);
312 save_transactions=helper->transactions;
313 helper->transactions=NULL;
314 save_transaction_type=priv->transaction_type;
315 priv->transaction_type=0;
316 if (!plover_transaction_helper_add_transaction(helper,transaction,
317 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
319 g_object_unref(transaction);
321 helper->transactions=save_transactions;
322 priv->transaction_type=save_transaction_type;
326 g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
327 g_slist_free(save_transactions);
332 if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
333 g_clear_error(&error);
336 plover_transaction_helper_set_error(helper,error,
337 "Failed to remove existing packages");
344 * Note that PloverTransaction does support cancelling a transaction, but
345 * there are a number of challenges with using it:
346 * - cancellation is only supported during the file phase if razor
347 * has atomic rollback,
348 * - cancellation is not supported during post-transaction scripts at all
349 * (since by the time the first script is started the atomic has already
350 * been committed) and these can take quite some time,
351 * - where a transaction has an embedded COMMIT, any rollback won't
352 * go back beyond this point.
353 * To support user-cancel, then, we would need some mechanism to:
354 * - Comunicate that the operation is being cancelled and this may take
356 * - Not allow cancellation at all after the last post-transaction script
358 * - Report the partially completed transaction where cancellation
359 * occurred after a COMMIT point.
360 * At present, this doesn't appear worth the effort.
362 if (helper->assistant)
363 gtk_assistant_commit(helper->assistant);
364 plover_transaction_helper_run(helper);
365 helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
369 static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
370 GtkWidget *page,PloverTransactionHelper *helper)
372 if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
373 plover_transaction_helper_prepare_confirm(helper);
374 else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
375 plover_transaction_helper_prepare_progress(helper);
379 plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
380 PloverTransactionHelper *helper)
383 if (helper->assistant)
385 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
386 gtk_assistant_set_page_complete(helper->assistant,w,
387 gtk_toggle_button_get_active(button));
391 PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
394 gchar *s,*directory,*contents;
397 PloverTransactionHelper *helper;
398 g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
399 helper=PLOVER_TRANSACTION_HELPER(
400 g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
402 helper->ui=g_object_ref(ui);
404 helper->ui=gtk_builder_new();
406 GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
407 if (!helper->assistant)
409 directory=g_strdup(g_getenv("PLOVER_DATADIR"));
413 s=g_win32_get_package_installation_directory_of_module(NULL);
414 directory=g_build_filename(s,"share","plover",NULL);
417 directory=g_strdup(PLOVER_DATADIR);
420 s=g_build_filename(directory,"software-installation.ui",NULL);
422 (void)g_file_get_contents(s,&contents,&len,&error);
426 (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
431 g_critical("software-installation.ui: %s",error->message);
432 g_clear_error(&error);
433 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
434 "Internal error (no user interface)");
435 plover_transaction_helper_set_error(helper,error,
436 "Can't start installer");
439 helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
440 "SoftwareInstallation"));
442 if (!helper->assistant)
444 g_critical("\"SoftwareInstallation\" object not found");
445 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
446 "Internal error (missing wizard)");
447 plover_transaction_helper_set_error(helper,error,
448 "Can't start installer");
453 g_object_ref(helper->assistant);
454 if (!GTK_IS_ASSISTANT(helper->assistant))
456 g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
457 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
458 "Internal error (unexpected wizard type)");
459 plover_transaction_helper_set_error(helper,error,
460 "Can't start installer");
464 g_signal_connect(helper->assistant,"cancel",
465 G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
466 g_signal_connect(helper->assistant,"close",
467 G_CALLBACK(plover_transaction_helper_assistant_close),helper);
468 g_signal_connect(helper->assistant,"prepare",
469 G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
470 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
472 g_signal_connect(w,"toggled",
473 G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
474 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
476 gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
481 plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
483 gchar *s,*saved_database_uri;
484 char *install_root,*local_database,*active_database,*alternate_database;
487 PloverPackageSet *alternate_installed,*installed;
489 struct razor_error *razor_error=NULL;
490 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
491 if (!helper->installed)
493 comps=plover_transaction_helper_get_comps(helper,NULL);
496 g_warning("plover_transaction_helper_get_installed: No comps");
499 install_root=getenv("RAZOR_ROOT");
501 install_root="file:/";
502 prefix=plover_transaction_helper_get_prefix(helper,NULL);
505 s=g_strconcat(prefix,"/var/lib/razor",NULL);
506 local_database=razor_path_relative_to_uri(install_root,*s=='/'?s+1:s,
511 g_warning("plover_transaction_helper_get_installed: %s",
512 razor_error_get_msg(razor_error));
513 razor_error_free(razor_error);
519 switch(comps->database)
521 case COMPS_DATABASE_DISTRIBUTION_LOCAL:
522 active_database=local_database;
523 alternate_database=NULL;
525 case COMPS_DATABASE_GLOBAL:
526 active_database=NULL;
527 alternate_database=local_database;
530 saved_database_uri=g_strdup(razor_get_database_uri());
533 razor_set_database_uri(alternate_database);
534 alternate_installed=plover_package_set_new();
535 if (!plover_package_set_open(alternate_installed,install_root,TRUE,
538 g_object_unref(alternate_installed);
539 g_warning("plover_transaction_helper_get_installed: %s",
542 free(local_database);
543 razor_set_database_uri(saved_database_uri);
544 g_free(saved_database_uri);
549 alternate_installed=NULL;
550 razor_set_database_uri(active_database);
551 free(local_database);
552 installed=plover_package_set_new();
553 if (plover_package_set_open(installed,install_root,TRUE,&error))
555 helper->alternate_installed=alternate_installed;
556 helper->installed=installed;
560 g_object_unref(installed);
561 if (alternate_installed)
562 g_object_unref(alternate_installed);
563 g_warning("plover_transaction_helper_get_installed: %s",error->message);
566 razor_set_database_uri(saved_database_uri);
567 g_free(saved_database_uri);
569 return helper->installed;
572 void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
573 PloverPackageSet *installed)
575 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
576 g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
577 g_return_if_fail(helper->installed == NULL);
578 g_clear_object(&helper->alternate_installed);
579 helper->installed=g_object_ref(installed);
583 plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
587 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
588 if (!helper->upstream)
590 base=plover_transaction_helper_get_base(helper);
591 helper->upstream=plover_repository_new_from_yum(base,error);
593 return helper->upstream;
596 void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
597 PloverRepository *upstream)
599 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
600 g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
601 g_return_if_fail(helper->upstream == NULL);
602 helper->upstream=g_object_ref(upstream);
605 const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
607 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
611 void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
614 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
615 g_return_if_fail(helper->transactions == NULL);
616 g_free(helper->base);
617 helper->base=g_strdup(base);
621 plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
625 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
626 if (!helper->comps && helper->base)
628 s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
629 helper->comps=plover_comps_new_from_file(s);
631 g_set_error(error,PLOVER_GENERAL_ERROR,
632 PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
635 return helper->comps;
639 plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
644 PloverTransactionHelperPrivate *priv;
645 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
646 g_return_val_if_fail(helper->base != NULL || plover_transaction_helper_get_installed(helper) != NULL,NULL);
647 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
650 comps=plover_transaction_helper_get_comps(helper,error);
653 g_free(priv->default_prefix);
654 priv->default_prefix=plover_comps_get_default_prefix(comps);
655 return priv->default_prefix;
657 prefix=plover_package_set_guess_prefix(helper->installed,error);
662 static int plover_transaction_helper_package_count(void)
666 struct razor_set *set;
667 struct razor_package *package;
668 struct razor_package_iterator *pi;
669 install_root=getenv("RAZOR_ROOT");
672 set=razor_root_open_read_only(install_root,NULL);
675 pi=razor_package_iterator_create(set);
676 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
678 razor_package_iterator_destroy(pi);
679 razor_set_unref(set);
685 static gboolean prefix_clashes(const char *prefix,const char *alt)
687 return g_str_has_prefix(prefix,alt) &&
688 (prefix[strlen(alt)]=='\0' || prefix[strlen(alt)]=='/');
692 plover_transaction_helper_update_summary_page(PloverTransactionHelper *helper,
695 int i,remove_count=0;
696 gboolean alternate_database_clashes=FALSE;
697 gboolean active_database_is_incompatible=FALSE;
698 char *local_database,*active_database,*alternate_database;
699 const char *alternate_prefix;
700 gchar *prefix=NULL,*s;
701 struct comps *comps=NULL;
702 GtkWidget *container,*summary,*page;
705 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
706 comps=plover_transaction_helper_get_comps(helper,error);
708 prefix=plover_comps_get_default_prefix(comps);
711 button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
712 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
713 container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
714 "SIIncompatibleInstallation"));
715 summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
716 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
717 if (helper->check_vendor && prefix && helper->alternate_installed)
720 plover_package_set_guess_prefix(helper->alternate_installed,NULL);
721 if (alternate_prefix && prefix_clashes(prefix,alternate_prefix))
723 alternate_database_clashes=TRUE;
724 remove_count=g_slist_length(
725 plover_package_set_get_packages(helper->alternate_installed));
729 * Rather than try to be too clever, we only deal with one thing
730 * at a time. That means that if the alternate database clashes
731 * there's no point checking if the active database is compatible.
733 if (!alternate_database_clashes)
735 if (helper->check_vendor && prefix &&
736 !plover_package_set_files_match_prefix(helper->installed,prefix))
738 active_database_is_incompatible=TRUE;
740 g_slist_length(plover_package_set_get_packages(helper->installed));
743 if (alternate_database_clashes || active_database_is_incompatible)
745 g_assert(comps!=NULL);
746 label=GTK_LABEL(gtk_builder_get_object(helper->ui,
747 "SIIncompatibleInstallationLabel"));
748 if (alternate_database_clashes)
749 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
750 "There is an existing installation under %s\n"
751 "which is not compatible with this distribution. In order\n"
752 "to continue, the existing installation must be uninstalled.",
754 else /* active_database_is_incompatible */
755 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
756 "The existing installation is not from %s.\n In order "
757 "to continue, all the existing packages must be removed.",
759 gtk_label_set_markup(label,s);
761 s=g_strdup_printf("Remove %d existing package%s",remove_count,
762 remove_count==1?"":"s");
763 gtk_button_set_label(button,s);
765 gtk_widget_show(container);
766 gtk_widget_hide(summary);
767 if (helper->assistant)
768 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
772 gtk_widget_hide(container);
773 gtk_widget_show(summary);
774 if (helper->assistant)
775 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
780 void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
781 gboolean check_vendor)
783 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
784 if (helper->check_vendor!=check_vendor)
786 helper->check_vendor=check_vendor;
787 if (helper->transactions)
788 plover_transaction_helper_update_summary_page(helper,NULL);
793 * If plover_transaction_helper_add_transaction() fails with an error
794 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
795 * then plover_transaction_helper_get_unsatisfied() can be used to
796 * retrieve a textual description of the problem.
800 plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
802 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
803 return helper->unsatisfied;
806 #define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
807 ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
808 (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
809 (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
812 plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
813 PloverTransaction *transaction,struct plover_vector *report_packages,
814 PloverTransactionHelperReportAction report_action,GError **error)
817 gboolean other_packages;
819 enum razor_install_action action;
820 struct razor_install_iterator *ii;
821 struct razor_set *report_set;
822 struct razor_package *package;
823 struct plover_vector *tasked_packages;
824 PloverTransactionHelperPrivate *priv;
826 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
827 g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
828 g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
829 g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
830 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
831 g_free(helper->unsatisfied);
832 helper->unsatisfied=NULL;
833 if (!plover_transaction_resolve(transaction,error))
835 s=plover_transaction_get_unsatisfied(transaction);
836 helper->unsatisfied=g_strdup(s);
839 ii=plover_transaction_get_install_iterator(transaction,error);
842 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
843 report_set=plover_transaction_get_system_set(transaction);
845 report_set=plover_transaction_get_next_set(transaction,error);
848 tasked_packages=plover_vector_new();
849 other_packages=FALSE;
850 while (razor_install_iterator_next(ii,&package,&action,&count))
852 if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
853 report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
855 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
856 &name,RAZOR_DETAIL_LAST);
857 if (!report_packages ||
858 plover_vector_contains(report_packages,name))
859 plover_vector_append(tasked_packages,name);
864 if (!tasked_packages->len)
867 * If there are no reportable packages tasked for action there
868 * shouldn't by any packages at all, but let's be paranoid.
870 other_packages=FALSE;
871 razor_install_iterator_rewind(ii);
872 while (razor_install_iterator_next(ii,&package,&action,&count))
874 if (action==report_action)
876 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
877 &name,RAZOR_DETAIL_LAST);
878 plover_vector_append(tasked_packages,name);
882 if (!tasked_packages->len)
884 g_set_error(error,PLOVER_GENERAL_ERROR,
885 PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
886 report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
888 plover_vector_free(tasked_packages);
891 if (!helper->transactions)
892 plover_transaction_helper_update_summary_page(helper,error);
893 g_object_ref(transaction);
894 helper->transactions=g_slist_append(helper->transactions,transaction);
895 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
897 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
898 for(i=0;i<tasked_packages->len;i++)
900 s=tasked_packages->strings[i];
901 if (!plover_vector_contains(helper->report_removing,s))
902 plover_vector_append(helper->report_removing,s);
904 helper->report_removing_dependants|=other_packages;
908 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
909 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
910 priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
911 for(i=0;i<tasked_packages->len;i++)
913 s=tasked_packages->strings[i];
914 if (!plover_vector_contains(helper->report_adding,s))
915 plover_vector_append(helper->report_adding,s);
917 helper->report_adding_dependencies|=other_packages;
919 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
920 switch(priv->transaction_type)
922 case TRANSACTION_TYPE_INSTALL:
923 gtk_label_set_markup(GTK_LABEL(w),
924 "<b>Installing the Software</b>\n\n"
925 "Please wait while the Installation Assistant "
926 "installs the software.\n"
927 "This may take several minutes.");
929 case TRANSACTION_TYPE_REMOVE:
930 gtk_label_set_markup(GTK_LABEL(w),
931 "<b>Removing Packages</b>\n\n"
932 "Please wait while the Installation Assistant "
933 "removes packages.\n"
934 "This may take several minutes.");
937 case TRANSACTION_TYPE_UPDATE:
938 gtk_label_set_markup(GTK_LABEL(w),
939 "<b>Updating the Software</b>\n\n"
940 "Please wait while the Installation Assistant "
941 "updates the software.\n"
942 "This may take several minutes.");
945 plover_vector_free(tasked_packages);
949 static PloverTransaction *
950 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
954 const char *base,*prefix;
955 GError *tmp_error=NULL;
956 PloverTransaction *transaction;
957 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
958 g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,NULL);
959 prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
962 g_propagate_error(error,tmp_error);
965 transaction=plover_transaction_new();
966 plover_transaction_set_prefix(transaction,prefix);
967 plover_transaction_set_installed(transaction,helper->installed);
968 if (helper->upstream)
969 ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
972 base=plover_transaction_helper_get_base(helper);
973 ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
977 g_object_unref(transaction);
983 struct plover_vector *plover_transaction_helper_group_get_default_packages(
984 PloverTransactionHelper *helper,const char *group,GError **error)
988 struct comps_group *grp;
989 struct comps_requirement *pkg;
990 struct plover_vector *default_packages;
991 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
992 comps=plover_transaction_helper_get_comps(helper,error);
995 grp=plover_comps_lookup_group(comps,group);
998 g_set_error(error,PLOVER_GENERAL_ERROR,
999 PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
1002 default_packages=plover_vector_new();
1006 for(pkg=grp->packages;pkg;pkg=pkg->next)
1008 if (plover_vector_contains(default_packages,pkg->name))
1010 if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
1011 pkg->type==COMPS_REQUIREMENT_MANDATORY ||
1012 pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
1013 plover_vector_contains(default_packages,pkg->requires))
1016 plover_vector_append(default_packages,pkg->name);
1020 return default_packages;
1024 * Returns TRUE if there is work to be done or FALSE if the packages are
1025 * already installed or on error.
1028 plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
1029 struct plover_vector *packages,GError **error)
1032 PloverTransaction *transaction;
1033 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1034 g_return_val_if_fail(packages != NULL,FALSE);
1037 g_set_error(error,PLOVER_GENERAL_ERROR,
1038 PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
1041 transaction=plover_transaction_helper_new_transaction(helper,error);
1044 if (!plover_transaction_install(transaction,packages->strings,error))
1046 g_object_unref(transaction);
1049 retval=plover_transaction_helper_add_transaction(helper,transaction,
1050 packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
1051 g_object_unref(transaction);
1056 * Returns TRUE if there is work to be done or FALSE if the group is
1057 * already installed or on error.
1060 plover_transaction_helper_install_group(PloverTransactionHelper *helper,
1061 const char *group,GError **error)
1064 struct plover_vector *selected_packages;
1065 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1066 selected_packages=plover_transaction_helper_group_get_default_packages(
1067 helper,group,error);
1068 if (!selected_packages)
1070 if (!selected_packages->len)
1072 g_set_error(error,PLOVER_GENERAL_ERROR,
1073 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
1074 plover_vector_free(selected_packages);
1077 retval=plover_transaction_helper_install_packages(helper,selected_packages,
1079 plover_vector_free(selected_packages);
1084 * Returns TRUE if there is work to be done or FALSE if the group is
1085 * not installed or on error.
1087 gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
1088 const char *group,GError **error)
1091 struct plover_vector *selected_packages;
1092 PloverTransaction *transaction;
1093 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1094 g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,FALSE);
1095 selected_packages=plover_transaction_helper_group_get_default_packages(
1096 helper,group,error);
1097 if (!selected_packages)
1099 if (!selected_packages->len)
1101 g_set_error(error,PLOVER_GENERAL_ERROR,
1102 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
1103 plover_vector_free(selected_packages);
1106 transaction=plover_transaction_new();
1107 plover_transaction_set_installed(transaction,helper->installed);
1108 if (!plover_transaction_remove(transaction,selected_packages->strings,
1111 plover_vector_free(selected_packages);
1112 g_object_unref(transaction);
1115 retval=plover_transaction_helper_add_transaction(helper,transaction,
1116 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
1117 g_object_unref(transaction);
1118 plover_vector_free(selected_packages);
1123 * Returns TRUE if there is work to be done or FALSE if all updates have
1124 * already been applied or on error.
1126 gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
1130 PloverTransaction *transaction;
1131 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1132 transaction=plover_transaction_helper_new_transaction(helper,error);
1135 if (!plover_transaction_update(transaction,NULL,error))
1137 g_object_unref(transaction);
1140 retval=plover_transaction_helper_add_transaction(helper,transaction,
1141 NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
1142 g_object_unref(transaction);
1146 gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
1148 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1149 if (helper->error_dialog)
1151 else if (!helper->assistant)
1154 return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
1157 void plover_transaction_helper_present(PloverTransactionHelper *helper)
1159 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1160 if (helper->error_dialog)
1161 gtk_window_present(GTK_WINDOW(helper->error_dialog));
1162 else if (helper->assistant)
1163 gtk_window_present(GTK_WINDOW(helper->assistant));
1167 plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
1168 int response_id,PloverTransactionHelper *helper)
1170 g_signal_handlers_disconnect_by_data(error_dialog,helper);
1171 if ((GtkWidget *)error_dialog==helper->error_dialog)
1173 gtk_widget_destroy(helper->error_dialog);
1174 helper->error_dialog=NULL;
1175 if (helper->assistant)
1177 gtk_widget_hide(GTK_WIDGET(helper->assistant));
1178 gtk_assistant_set_current_page(helper->assistant,0);
1180 g_signal_emit(helper,signals[CLOSE],0);
1184 const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
1185 const GError **error)
1187 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1188 if (!helper->error_dialog)
1191 *error=helper->error;
1192 return helper->error_primary_text;
1195 void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
1196 const GError *error,const char *primary_text)
1198 GtkMessageType type;
1200 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1201 g_return_if_fail(error != NULL);
1202 g_return_if_fail(primary_text != NULL);
1203 if (helper->pulse_handler)
1205 g_source_remove(helper->pulse_handler);
1206 helper->pulse_handler=0;
1208 if (helper->error_dialog)
1210 gtk_widget_destroy(helper->error_dialog);
1211 helper->error_dialog=NULL;
1213 g_free(helper->error_primary_text);
1214 helper->error_primary_text=g_strdup(primary_text);
1215 g_clear_error(&helper->error);
1216 helper->error=g_error_copy(error);
1217 if (g_error_matches(error,PLOVER_GENERAL_ERROR,
1218 PLOVER_GENERAL_ERROR_NO_WORK))
1219 type=GTK_MESSAGE_INFO;
1221 type=GTK_MESSAGE_ERROR;
1222 if (helper->assistant)
1223 window=GTK_WINDOW(helper->assistant);
1226 helper->error_dialog=gtk_message_dialog_new(window,
1227 GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
1228 gtk_message_dialog_format_secondary_text(
1229 GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
1230 gtk_widget_show(helper->error_dialog);
1231 g_signal_connect(helper->error_dialog,"response",
1232 G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);