Support parallel installations. The idea is that for CAD screener, we want
to be able to install this on the same machine as a standard AVOT setup
(most notably for John's laptop). To allow for the possibility of a second
application that might have the same requirements, we add the concept of
vendor-specific distributions. Thus we can have one distribution for CAD
screener and one for The Next Big Thing. It doesn't seem trivial to have
both CAD screener and AVOT under the same vendor tag so we'll have to have
AVOT under "City Occupational" and CAD screener under "City Occupational Ltd"
or some such kludge.
Most of this is done although we are very short of test cases (in particular
we don't test that it's actually possible to install CAD screener in parallel
with AVOT or to update either of them once installed, which is fundamental).
We also have a lot of baggage left over, including an intercept of razor_set.
The problem that this was introduced to debug has been fixed but it looks
like there are a number of memory leaks which it might be useful to help
track down so it has been left in place for now.
There is still a lot of confusion in plover between path-based and URI-based
API. We should review the API, decide what we want and have a general clear up.
There is also confusion as to the purpose of RAZOR_ROOT (and meaning; path or
URI). This is not used at all in librazor (although it is used in razor.exe).
Ideally we shouldn't use it in plover or plover-gtk either although again, we
might want to support it or an equivalent in (some of) the various executables.
Work that would still to nice to do for CAD screener:
- uninstall (ideally as an installed program that hooks into Add/Remove programs
but even re-running the installer would be acceptable).
- xz support (smaller packages).
- repomd.xml and xml:base (would be needed for an Internet installer).
- graphical installer.
2 * Copyright (C) 2014, 2016 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 void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
62 PloverTransactionHelperPrivate *priv;
63 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
64 g_free(priv->default_prefix);
65 g_free(helper->error_primary_text);
67 g_free(helper->unsatisfied);
69 plover_comps_free(helper->comps);
70 plover_vector_free(helper->report_adding);
71 plover_vector_free(helper->report_removing);
74 static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
76 g_clear_error(&helper->error);
77 if (helper->error_dialog)
79 g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
80 gtk_widget_destroy(helper->error_dialog);
81 helper->error_dialog=NULL;
83 if (helper->assistant)
85 g_signal_handlers_disconnect_by_data(helper->assistant,helper);
86 g_clear_object(&helper->assistant);
88 g_clear_object(&helper->ui);
89 g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
90 g_slist_free(helper->transactions);
91 helper->transactions=NULL;
92 g_clear_object(&helper->alternate_installed);
93 g_clear_object(&helper->installed);
94 g_clear_object(&helper->upstream);
95 g_clear_object(&helper->relocated_upstream);
99 plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
101 GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
102 gobject_class->finalize=
103 (void (*)(GObject *))plover_transaction_helper_finalize;
104 gobject_class->dispose=
105 (void (*)(GObject *))plover_transaction_helper_dispose;
106 g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
107 signals[CLOSE]=g_signal_newv("close",
108 G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
109 g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
112 static void plover_transaction_helper_init(PloverTransactionHelper *helper)
114 helper->report_adding=plover_vector_new();
115 helper->report_removing=plover_vector_new();
118 static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
119 PloverTransactionHelper *helper)
121 gtk_widget_hide(GTK_WIDGET(helper->assistant));
122 gtk_assistant_set_current_page(helper->assistant,0);
123 g_signal_emit(helper,signals[CLOSE],0);
126 static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
127 PloverTransactionHelper *helper)
129 gtk_widget_hide(GTK_WIDGET(helper->assistant));
130 gtk_assistant_set_current_page(helper->assistant,0);
131 g_signal_emit(helper,signals[CLOSE],0);
135 plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
137 gchar *package_list,*add,*remove,*s;
139 struct plover_vector *report;
140 if (helper->report_adding->len)
142 plover_vector_sort(helper->report_adding);
143 if (helper->report_adding_dependencies)
145 report=plover_vector_dup(helper->report_adding);
146 if (helper->report_adding->len==1)
147 plover_vector_append(report,"its dependencies");
149 plover_vector_append(report,"their dependencies");
150 package_list=plover_vector_format_for_display(report);
151 plover_vector_free(report);
155 plover_vector_format_for_display(helper->report_adding);
156 add=g_strconcat("Packages to be installed or updated: ",package_list,
158 g_free(package_list);
162 if (helper->report_removing->len)
164 plover_vector_sort(helper->report_removing);
165 if (helper->report_removing_dependants)
167 report=plover_vector_dup(helper->report_removing);
168 if (helper->report_adding->len==1)
169 plover_vector_append(report,"its dependants");
171 plover_vector_append(report,"their dependants");
172 package_list=plover_vector_format_for_display(report);
173 plover_vector_free(report);
177 plover_vector_format_for_display(helper->report_removing);
178 remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
179 g_free(package_list);
183 label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
185 s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
186 else if (add || remove)
187 s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
189 s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
190 gtk_label_set_markup(label,s);
196 static void plover_transaction_helper_run(PloverTransactionHelper *helper);
198 static void plover_transaction_helper_callback(GObject *source,
199 GAsyncResult *result,gpointer user_data)
202 PloverTransactionHelper *helper=user_data;
203 PloverTransaction *transaction=PLOVER_TRANSACTION(source);
204 if (!plover_transaction_commit_finish(transaction,result,&error))
206 plover_transaction_helper_set_error(helper,error,
207 "Software installation failed");
211 plover_transaction_helper_run(helper);
213 * There may be status updates queued by transaction as idle events.
214 * Process them now before we disconnect so that we don't lose them.
216 while(g_main_context_pending(NULL))
217 g_main_context_iteration(NULL,FALSE);
218 g_signal_handlers_disconnect_by_data(transaction,helper);
219 g_object_unref(transaction);
222 static void plover_transaction_helper_transaction_status_changed(
223 PloverTransaction *transaction,const char *status,
224 PloverTransactionHelper *helper)
227 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
228 gtk_progress_bar_set_text(bar,status);
231 static void plover_transaction_helper_run(PloverTransactionHelper *helper)
233 PloverTransaction *transaction;
235 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
236 if (helper->transactions)
238 if (helper->assistant)
239 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
240 transaction=helper->transactions->data;
241 helper->transactions=g_slist_delete_link(helper->transactions,
242 helper->transactions);
243 g_signal_connect(transaction,"status-changed",
244 G_CALLBACK(plover_transaction_helper_transaction_status_changed),
246 plover_transaction_commit_async(transaction,NULL,
247 plover_transaction_helper_callback,helper);
249 else if (helper->assistant)
250 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
253 static gboolean plover_transaction_helper_pulse(gpointer user_data)
255 PloverTransactionHelper *helper=user_data;
258 if (!helper->assistant)
260 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
261 bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
262 if (gtk_assistant_get_page_complete(helper->assistant,w))
264 gtk_progress_bar_set_fraction(bar,1.0);
265 helper->pulse_handler=0;
270 gtk_progress_bar_pulse(bar);
276 plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
279 GtkToggleButton *button;
280 PloverTransaction *transaction;
281 GSList *save_transactions;
282 PloverTransactionHelperPrivate *priv;
283 enum plover_transaction_type save_transaction_type;
284 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
285 button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
286 "SIRemoveExisting"));
287 if (gtk_toggle_button_get_active(button))
289 transaction=plover_transaction_new_remove(NULL,&error);
292 save_transactions=helper->transactions;
293 helper->transactions=NULL;
294 save_transaction_type=priv->transaction_type;
295 priv->transaction_type=0;
296 if (!plover_transaction_helper_add_transaction(helper,transaction,
297 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
299 g_object_unref(transaction);
301 helper->transactions=save_transactions;
302 priv->transaction_type=save_transaction_type;
306 g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
307 g_slist_free(save_transactions);
312 if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
313 g_clear_error(&error);
316 plover_transaction_helper_set_error(helper,error,
317 "Failed to remove existing packages");
324 * Note that PloverTransaction does support cancelling a transaction, but
325 * there are a number of challenges with using it:
326 * - cancellation is only supported during the file phase if razor
327 * has atomic rollback,
328 * - cancellation is not supported during post-transaction scripts at all
329 * (since by the time the first script is started the atomic has already
330 * been committed) and these can take quite some time,
331 * - where a transaction has an embedded COMMIT, any rollback won't
332 * go back beyond this point.
333 * To support user-cancel, then, we would need some mechanism to:
334 * - Comunicate that the operation is being cancelled and this may take
336 * - Not allow cancellation at all after the last post-transaction script
338 * - Report the partially completed transaction where cancellation
339 * occurred after a COMMIT point.
340 * At present, this doesn't appear worth the effort.
342 if (helper->assistant)
343 gtk_assistant_commit(helper->assistant);
344 plover_transaction_helper_run(helper);
345 helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
349 static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
350 GtkWidget *page,PloverTransactionHelper *helper)
352 if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
353 plover_transaction_helper_prepare_confirm(helper);
354 else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
355 plover_transaction_helper_prepare_progress(helper);
359 plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
360 PloverTransactionHelper *helper)
363 if (helper->assistant)
365 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
366 gtk_assistant_set_page_complete(helper->assistant,w,
367 gtk_toggle_button_get_active(button));
371 PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
374 gchar *s,*directory,*contents;
377 PloverTransactionHelper *helper;
378 g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
379 helper=PLOVER_TRANSACTION_HELPER(
380 g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
382 helper->ui=g_object_ref(ui);
384 helper->ui=gtk_builder_new();
386 GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
387 if (!helper->assistant)
389 directory=g_strdup(g_getenv("PLOVER_DATADIR"));
393 s=g_win32_get_package_installation_directory_of_module(NULL);
394 directory=g_build_filename(s,"share","plover",NULL);
397 directory=g_strdup(PLOVER_DATADIR);
400 s=g_build_filename(directory,"software-installation.ui",NULL);
402 (void)g_file_get_contents(s,&contents,&len,&error);
406 (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
411 g_critical("software-installation.ui: %s",error->message);
412 g_clear_error(&error);
413 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
414 "Internal error (no user interface)");
415 plover_transaction_helper_set_error(helper,error,
416 "Can't start installer");
419 helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
420 "SoftwareInstallation"));
422 if (!helper->assistant)
424 g_critical("\"SoftwareInstallation\" object not found");
425 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
426 "Internal error (missing wizard)");
427 plover_transaction_helper_set_error(helper,error,
428 "Can't start installer");
433 g_object_ref(helper->assistant);
434 if (!GTK_IS_ASSISTANT(helper->assistant))
436 g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
437 g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
438 "Internal error (unexpected wizard type)");
439 plover_transaction_helper_set_error(helper,error,
440 "Can't start installer");
444 g_signal_connect(helper->assistant,"cancel",
445 G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
446 g_signal_connect(helper->assistant,"close",
447 G_CALLBACK(plover_transaction_helper_assistant_close),helper);
448 g_signal_connect(helper->assistant,"prepare",
449 G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
450 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
452 g_signal_connect(w,"toggled",
453 G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
454 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
456 gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
461 plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
463 gchar *s,*saved_database_uri;
464 char *install_root,*local_database,*active_database,*alternate_database;
467 PloverPackageSet *alternate_installed,*installed;
469 struct razor_error *razor_error=NULL;
470 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
471 if (!helper->installed)
473 comps=plover_transaction_helper_get_comps(helper,NULL);
476 g_warning("plover_transaction_helper_get_installed: No comps");
479 install_root=getenv("RAZOR_ROOT");
481 install_root="file:/";
482 prefix=plover_transaction_helper_get_prefix(helper,NULL);
485 s=g_strconcat(prefix,"/var/lib/razor",NULL);
486 local_database=razor_path_relative_to_uri(install_root,*s=='/'?s+1:s,
491 g_warning("plover_transaction_helper_get_installed: %s",
492 razor_error_get_msg(razor_error));
493 razor_error_free(razor_error);
499 switch(comps->database)
501 case COMPS_DATABASE_DISTRIBUTION_LOCAL:
502 active_database=local_database;
503 alternate_database=NULL;
505 case COMPS_DATABASE_GLOBAL:
506 active_database=NULL;
507 alternate_database=local_database;
510 saved_database_uri=g_strdup(razor_get_database_uri());
513 razor_set_database_uri(alternate_database);
514 alternate_installed=plover_package_set_new();
515 if (!plover_package_set_open(alternate_installed,install_root,TRUE,
518 g_object_unref(alternate_installed);
519 g_warning("plover_transaction_helper_get_installed: %s",
522 free(local_database);
523 razor_set_database_uri(saved_database_uri);
524 g_free(saved_database_uri);
529 alternate_installed=NULL;
530 razor_set_database_uri(active_database);
531 free(local_database);
532 installed=plover_package_set_new();
533 if (plover_package_set_open(installed,install_root,TRUE,&error))
535 helper->alternate_installed=alternate_installed;
536 helper->installed=installed;
540 g_object_unref(installed);
541 if (alternate_installed)
542 g_object_unref(alternate_installed);
543 g_warning("plover_transaction_helper_get_installed: %s",error->message);
546 razor_set_database_uri(saved_database_uri);
547 g_free(saved_database_uri);
549 return helper->installed;
552 void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
553 PloverPackageSet *installed)
555 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
556 g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
557 g_return_if_fail(helper->installed == NULL);
558 g_clear_object(&helper->alternate_installed);
559 helper->installed=g_object_ref(installed);
563 plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
567 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
568 if (!helper->upstream)
570 base=plover_transaction_helper_get_base(helper);
571 helper->upstream=plover_repository_new_from_yum(base,error);
573 return helper->upstream;
576 void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
577 PloverRepository *upstream)
579 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
580 g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
581 g_return_if_fail(helper->upstream == NULL);
582 helper->upstream=g_object_ref(upstream);
585 const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
587 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
591 void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
594 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
595 g_return_if_fail(helper->transactions == NULL);
596 g_free(helper->base);
597 helper->base=g_strdup(base);
601 plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
605 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
606 g_return_val_if_fail(helper->base != NULL,NULL);
609 s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
610 helper->comps=plover_comps_new_from_file(s);
612 g_set_error(error,PLOVER_GENERAL_ERROR,
613 PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
616 return helper->comps;
620 plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
625 PloverTransactionHelperPrivate *priv;
626 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
627 g_return_val_if_fail(helper->base != NULL || plover_transaction_helper_get_installed(helper) != NULL,NULL);
628 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
631 comps=plover_transaction_helper_get_comps(helper,error);
634 g_free(priv->default_prefix);
635 priv->default_prefix=plover_comps_get_default_prefix(comps);
636 return priv->default_prefix;
638 prefix=plover_package_set_guess_prefix(helper->installed,error);
643 static int plover_transaction_helper_package_count(void)
647 struct razor_set *set;
648 struct razor_package *package;
649 struct razor_package_iterator *pi;
650 install_root=getenv("RAZOR_ROOT");
653 set=razor_root_open_read_only(install_root,NULL);
656 pi=razor_package_iterator_create(set);
657 while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
659 razor_package_iterator_destroy(pi);
660 razor_set_unref(set);
666 static gboolean prefix_clashes(const char *prefix,const char *alt)
668 return g_str_has_prefix(prefix,alt) &&
669 (prefix[strlen(alt)]=='\0' || prefix[strlen(alt)]=='/');
673 plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
676 int i,remove_count=0;
677 gboolean alternate_database_clashes=FALSE;
678 gboolean active_database_is_incompatible=FALSE;
679 char *local_database,*active_database,*alternate_database;
680 const char *alternate_prefix;
681 gchar *prefix=NULL,*s;
682 struct comps *comps=NULL;
683 GtkWidget *container,*summary,*page;
686 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
687 comps=plover_transaction_helper_get_comps(helper,error);
690 prefix=plover_comps_get_default_prefix(comps);
691 button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
692 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
693 container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
694 "SIIncompatibleInstallation"));
695 summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
696 page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
697 if (helper->check_vendor && prefix && helper->alternate_installed)
700 plover_package_set_guess_prefix(helper->alternate_installed,NULL);
701 if (alternate_prefix && prefix_clashes(prefix,alternate_prefix))
703 alternate_database_clashes=TRUE;
704 remove_count=g_slist_length(
705 plover_package_set_get_packages(helper->alternate_installed));
709 * Rather than try to be too clever, we only deal with one thing
710 * at a time. That means that if the alternate database clashes
711 * there's no point checking if the active database is compatible.
713 if (!alternate_database_clashes)
715 if (helper->check_vendor && prefix &&
716 !plover_package_set_files_match_prefix(helper->installed,prefix))
718 active_database_is_incompatible=TRUE;
720 g_slist_length(plover_package_set_get_packages(helper->installed));
723 if (alternate_database_clashes || active_database_is_incompatible)
725 label=GTK_LABEL(gtk_builder_get_object(helper->ui,
726 "SIIncompatibleInstallationLabel"));
727 if (alternate_database_clashes)
728 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
729 "There is an existing installation under %s\n"
730 "which is not compatible with this distribution. In order\n"
731 "to continue, the existing installation must be uninstalled.",
733 else /* active_database_is_incompatible */
734 s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
735 "The existing installation is not from %s.\n In order "
736 "to continue, all the existing packages must be removed.",
738 gtk_label_set_markup(label,s);
740 s=g_strdup_printf("Remove %d existing package%s",remove_count,
741 remove_count==1?"":"s");
742 gtk_button_set_label(button,s);
744 gtk_widget_show(container);
745 gtk_widget_hide(summary);
746 if (helper->assistant)
747 gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
751 gtk_widget_hide(container);
752 gtk_widget_show(summary);
753 if (helper->assistant)
754 gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
760 void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
761 gboolean check_vendor)
763 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
764 if (helper->check_vendor!=check_vendor)
766 helper->check_vendor=check_vendor;
767 if (helper->transactions)
768 plover_transaction_helper_check_vendor(helper,NULL);
773 * If plover_transaction_helper_add_transaction() failes with an error
774 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
775 * then plover_transaction_helper_get_unsatisfied() can be used to
776 * retrieve a textual description of the problem.
780 plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
782 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
783 return helper->unsatisfied;
786 #define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
787 ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
788 (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
789 (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
792 plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
793 PloverTransaction *transaction,struct plover_vector *report_packages,
794 PloverTransactionHelperReportAction report_action,GError **error)
797 gboolean other_packages;
799 enum razor_install_action action;
800 struct razor_install_iterator *ii;
801 struct razor_set *report_set;
802 struct razor_package *package;
803 struct plover_vector *tasked_packages;
804 PloverTransactionHelperPrivate *priv;
806 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
807 g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
808 g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
809 g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
810 priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
811 g_free(helper->unsatisfied);
812 helper->unsatisfied=NULL;
813 if (!plover_transaction_resolve(transaction,error))
815 s=plover_transaction_get_unsatisfied(transaction);
816 helper->unsatisfied=g_strdup(s);
819 ii=plover_transaction_get_install_iterator(transaction,error);
822 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
823 report_set=plover_transaction_get_system_set(transaction);
825 report_set=plover_transaction_get_next_set(transaction,error);
828 tasked_packages=plover_vector_new();
829 other_packages=FALSE;
830 while (razor_install_iterator_next(ii,&package,&action,&count))
832 if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
833 report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
835 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
836 &name,RAZOR_DETAIL_LAST);
837 if (!report_packages ||
838 plover_vector_contains(report_packages,name))
839 plover_vector_append(tasked_packages,name);
844 if (!tasked_packages->len)
847 * If there are no reportable packages tasked for action there
848 * shouldn't by any packages at all, but let's be paranoid.
850 other_packages=FALSE;
851 razor_install_iterator_rewind(ii);
852 while (razor_install_iterator_next(ii,&package,&action,&count))
854 if (action==report_action)
856 razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
857 &name,RAZOR_DETAIL_LAST);
858 plover_vector_append(tasked_packages,name);
862 if (!tasked_packages->len)
864 g_set_error(error,PLOVER_GENERAL_ERROR,
865 PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
866 report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
868 plover_vector_free(tasked_packages);
871 if (!helper->transactions)
872 plover_transaction_helper_check_vendor(helper,error);
873 g_object_ref(transaction);
874 helper->transactions=g_slist_append(helper->transactions,transaction);
875 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
877 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
878 for(i=0;i<tasked_packages->len;i++)
880 s=tasked_packages->strings[i];
881 if (!plover_vector_contains(helper->report_removing,s))
882 plover_vector_append(helper->report_removing,s);
884 helper->report_removing_dependants|=other_packages;
888 if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
889 priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
890 priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
891 for(i=0;i<tasked_packages->len;i++)
893 s=tasked_packages->strings[i];
894 if (!plover_vector_contains(helper->report_adding,s))
895 plover_vector_append(helper->report_adding,s);
897 helper->report_adding_dependencies|=other_packages;
899 w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
900 switch(priv->transaction_type)
902 case TRANSACTION_TYPE_INSTALL:
903 gtk_label_set_markup(GTK_LABEL(w),
904 "<b>Installing the Software</b>\n\n"
905 "Please wait while the Installation Assistant "
906 "installs the software.\n"
907 "This may take several minutes.");
909 case TRANSACTION_TYPE_REMOVE:
910 gtk_label_set_markup(GTK_LABEL(w),
911 "<b>Removing Packages</b>\n\n"
912 "Please wait while the Installation Assistant "
913 "removes packages.\n"
914 "This may take several minutes.");
917 case TRANSACTION_TYPE_UPDATE:
918 gtk_label_set_markup(GTK_LABEL(w),
919 "<b>Updating the Software</b>\n\n"
920 "Please wait while the Installation Assistant "
921 "updates the software.\n"
922 "This may take several minutes.");
925 plover_vector_free(tasked_packages);
929 static PloverTransaction *
930 plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
934 const char *base,*prefix;
935 GError *tmp_error=NULL;
936 PloverTransaction *transaction;
937 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
938 g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,NULL);
939 prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
942 g_propagate_error(error,tmp_error);
945 transaction=plover_transaction_new();
946 plover_transaction_set_prefix(transaction,prefix);
947 plover_transaction_set_installed(transaction,helper->installed);
948 if (helper->upstream)
949 ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
952 base=plover_transaction_helper_get_base(helper);
953 ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
957 g_object_unref(transaction);
963 struct plover_vector *plover_transaction_helper_group_get_default_packages(
964 PloverTransactionHelper *helper,const char *group,GError **error)
968 struct comps_group *grp;
969 struct comps_requirement *pkg;
970 struct plover_vector *default_packages;
971 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
972 comps=plover_transaction_helper_get_comps(helper,error);
975 grp=plover_comps_lookup_group(comps,group);
978 g_set_error(error,PLOVER_GENERAL_ERROR,
979 PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
982 default_packages=plover_vector_new();
986 for(pkg=grp->packages;pkg;pkg=pkg->next)
988 if (plover_vector_contains(default_packages,pkg->name))
990 if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
991 pkg->type==COMPS_REQUIREMENT_MANDATORY ||
992 pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
993 plover_vector_contains(default_packages,pkg->requires))
996 plover_vector_append(default_packages,pkg->name);
1000 return default_packages;
1004 * Returns TRUE if there is work to be done or FALSE if the packages are
1005 * already installed or on error.
1008 plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
1009 struct plover_vector *packages,GError **error)
1012 PloverTransaction *transaction;
1013 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1014 g_return_val_if_fail(packages != NULL,FALSE);
1017 g_set_error(error,PLOVER_GENERAL_ERROR,
1018 PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
1021 transaction=plover_transaction_helper_new_transaction(helper,error);
1024 if (!plover_transaction_install(transaction,packages->strings,error))
1026 g_object_unref(transaction);
1029 retval=plover_transaction_helper_add_transaction(helper,transaction,
1030 packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
1031 g_object_unref(transaction);
1036 * Returns TRUE if there is work to be done or FALSE if the group is
1037 * already installed or on error.
1040 plover_transaction_helper_install_group(PloverTransactionHelper *helper,
1041 const char *group,GError **error)
1044 struct plover_vector *selected_packages;
1045 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1046 selected_packages=plover_transaction_helper_group_get_default_packages(
1047 helper,group,error);
1048 if (!selected_packages)
1050 if (!selected_packages->len)
1052 g_set_error(error,PLOVER_GENERAL_ERROR,
1053 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
1054 plover_vector_free(selected_packages);
1057 retval=plover_transaction_helper_install_packages(helper,selected_packages,
1059 plover_vector_free(selected_packages);
1064 * Returns TRUE if there is work to be done or FALSE if the group is
1065 * not installed or on error.
1067 gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
1068 const char *group,GError **error)
1071 struct plover_vector *selected_packages;
1072 PloverTransaction *transaction;
1073 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1074 g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,FALSE);
1075 selected_packages=plover_transaction_helper_group_get_default_packages(
1076 helper,group,error);
1077 if (!selected_packages)
1079 if (!selected_packages->len)
1081 g_set_error(error,PLOVER_GENERAL_ERROR,
1082 PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
1083 plover_vector_free(selected_packages);
1086 transaction=plover_transaction_new();
1087 plover_transaction_set_installed(transaction,helper->installed);
1088 if (!plover_transaction_remove(transaction,selected_packages->strings,
1091 plover_vector_free(selected_packages);
1092 g_object_unref(transaction);
1095 retval=plover_transaction_helper_add_transaction(helper,transaction,
1096 NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
1097 g_object_unref(transaction);
1098 plover_vector_free(selected_packages);
1103 * Returns TRUE if there is work to be done or FALSE if all updates have
1104 * already been applied or on error.
1106 gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
1110 PloverTransaction *transaction;
1111 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1112 transaction=plover_transaction_helper_new_transaction(helper,error);
1115 if (!plover_transaction_update(transaction,NULL,error))
1117 g_object_unref(transaction);
1120 retval=plover_transaction_helper_add_transaction(helper,transaction,
1121 NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
1122 g_object_unref(transaction);
1126 gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
1128 g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
1129 if (helper->error_dialog)
1131 else if (!helper->assistant)
1134 return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
1137 void plover_transaction_helper_present(PloverTransactionHelper *helper)
1139 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1140 if (helper->error_dialog)
1141 gtk_window_present(GTK_WINDOW(helper->error_dialog));
1142 else if (helper->assistant)
1143 gtk_window_present(GTK_WINDOW(helper->assistant));
1147 plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
1148 int response_id,PloverTransactionHelper *helper)
1150 g_signal_handlers_disconnect_by_data(error_dialog,helper);
1151 if ((GtkWidget *)error_dialog==helper->error_dialog)
1153 gtk_widget_destroy(helper->error_dialog);
1154 helper->error_dialog=NULL;
1155 if (helper->assistant)
1157 gtk_widget_hide(GTK_WIDGET(helper->assistant));
1158 gtk_assistant_set_current_page(helper->assistant,0);
1160 g_signal_emit(helper,signals[CLOSE],0);
1164 const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
1165 const GError **error)
1167 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1168 if (!helper->error_dialog)
1171 *error=helper->error;
1172 return helper->error_primary_text;
1175 void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
1176 const GError *error,const char *primary_text)
1178 GtkMessageType type;
1180 g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
1181 g_return_if_fail(error != NULL);
1182 g_return_if_fail(primary_text != NULL);
1183 if (helper->pulse_handler)
1185 g_source_remove(helper->pulse_handler);
1186 helper->pulse_handler=0;
1188 if (helper->error_dialog)
1190 gtk_widget_destroy(helper->error_dialog);
1191 helper->error_dialog=NULL;
1193 g_free(helper->error_primary_text);
1194 helper->error_primary_text=g_strdup(primary_text);
1195 g_clear_error(&helper->error);
1196 helper->error=g_error_copy(error);
1197 if (g_error_matches(error,PLOVER_GENERAL_ERROR,
1198 PLOVER_GENERAL_ERROR_NO_WORK))
1199 type=GTK_MESSAGE_INFO;
1201 type=GTK_MESSAGE_ERROR;
1202 if (helper->assistant)
1203 window=GTK_WINDOW(helper->assistant);
1206 helper->error_dialog=gtk_message_dialog_new(window,
1207 GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
1208 gtk_message_dialog_format_secondary_text(
1209 GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
1210 gtk_widget_show(helper->error_dialog);
1211 g_signal_connect(helper->error_dialog,"response",
1212 G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);