plover-gtk/transactionhelper.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Jul 16 11:07:18 2016 +0100 (2016-07-16)
changeset 61 31fb35727621
parent 50 a4f43ad0e0c8
child 75 6575679d2e8e
permissions -rw-r--r--
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.
ali@24
     1
/*
ali@61
     2
 * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
ali@24
     3
 *
ali@24
     4
 * This program is free software; you can redistribute it and/or modify
ali@24
     5
 * it under the terms of the GNU General Public License as published by
ali@24
     6
 * the Free Software Foundation; either version 2 of the License, or
ali@24
     7
 * (at your option) any later version.
ali@24
     8
 *
ali@24
     9
 * This program is distributed in the hope that it will be useful,
ali@24
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ali@24
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ali@24
    12
 * GNU General Public License for more details.
ali@24
    13
 *
ali@24
    14
 * You should have received a copy of the GNU General Public License along
ali@24
    15
 * with this program; if not, write to the Free Software Foundation, Inc.,
ali@24
    16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ali@24
    17
 */
ali@24
    18
ali@24
    19
#include "config.h"
ali@24
    20
#include <stdlib.h>
ali@61
    21
#include <string.h>
ali@24
    22
#include <errno.h>
ali@24
    23
#include <gtk/gtk.h>
ali@24
    24
#include <plover/plover.h>
ali@24
    25
#include <plover/transaction.h>
ali@24
    26
#include <plover-gtk/transactionhelper.h>
ali@44
    27
#include "plover/uri-handler.h"
ali@24
    28
ali@24
    29
/*
ali@24
    30
 * A PloverTransactionHelper uses a GtkAssistant to help a user run a
ali@24
    31
 * transaction.
ali@24
    32
 */
ali@24
    33
ali@24
    34
G_DEFINE_TYPE(PloverTransactionHelper,plover_transaction_helper,G_TYPE_OBJECT)
ali@24
    35
ali@38
    36
enum plover_transaction_type {
ali@38
    37
    TRANSACTION_TYPE_NULL=0,
ali@38
    38
    TRANSACTION_TYPE_INSTALL=1UL<<0,
ali@38
    39
    TRANSACTION_TYPE_REMOVE=1UL<<1,
ali@38
    40
    TRANSACTION_TYPE_UPDATE=TRANSACTION_TYPE_INSTALL|TRANSACTION_TYPE_REMOVE
ali@38
    41
};
ali@38
    42
ali@38
    43
typedef struct _PloverTransactionHelperPrivate {
ali@38
    44
    enum plover_transaction_type transaction_type;
ali@38
    45
    gchar *default_prefix;
ali@38
    46
} PloverTransactionHelperPrivate;
ali@38
    47
ali@38
    48
#define PLOVER_TRANSACTION_HELPER_GET_PRIVATE(obj)\
ali@38
    49
                                G_TYPE_INSTANCE_GET_PRIVATE(obj,\
ali@38
    50
				  PLOVER_TYPE_TRANSACTION_HELPER,\
ali@38
    51
				  PloverTransactionHelperPrivate)
ali@38
    52
ali@24
    53
enum {
ali@24
    54
    CLOSE=0,
ali@24
    55
    N_SIGNALS
ali@24
    56
};
ali@24
    57
ali@24
    58
static guint signals[N_SIGNALS];
ali@24
    59
ali@24
    60
static void plover_transaction_helper_finalize(PloverTransactionHelper *helper)
ali@24
    61
{
ali@38
    62
    PloverTransactionHelperPrivate *priv;
ali@38
    63
    priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
ali@38
    64
    g_free(priv->default_prefix);
ali@24
    65
    g_free(helper->error_primary_text);
ali@24
    66
    g_free(helper->base);
ali@24
    67
    g_free(helper->unsatisfied);
ali@24
    68
    if (helper->comps)
ali@24
    69
	plover_comps_free(helper->comps);
ali@24
    70
    plover_vector_free(helper->report_adding);
ali@24
    71
    plover_vector_free(helper->report_removing);
ali@24
    72
}
ali@24
    73
ali@24
    74
static void plover_transaction_helper_dispose(PloverTransactionHelper *helper)
ali@24
    75
{
ali@24
    76
    g_clear_error(&helper->error);
ali@24
    77
    if (helper->error_dialog)
ali@24
    78
    {
ali@24
    79
	g_signal_handlers_disconnect_by_data(helper->error_dialog,helper);
ali@24
    80
	gtk_widget_destroy(helper->error_dialog);
ali@24
    81
	helper->error_dialog=NULL;
ali@24
    82
    }
ali@24
    83
    if (helper->assistant)
ali@24
    84
    {
ali@24
    85
	g_signal_handlers_disconnect_by_data(helper->assistant,helper);
ali@24
    86
	g_clear_object(&helper->assistant);
ali@24
    87
    }
ali@24
    88
    g_clear_object(&helper->ui);
ali@24
    89
    g_slist_foreach(helper->transactions,(GFunc)g_object_unref,NULL);
ali@24
    90
    g_slist_free(helper->transactions);
ali@24
    91
    helper->transactions=NULL;
ali@61
    92
    g_clear_object(&helper->alternate_installed);
ali@24
    93
    g_clear_object(&helper->installed);
ali@24
    94
    g_clear_object(&helper->upstream);
ali@24
    95
    g_clear_object(&helper->relocated_upstream);
ali@24
    96
}
ali@24
    97
ali@24
    98
static void
ali@24
    99
  plover_transaction_helper_class_init(PloverTransactionHelperClass *klass)
ali@24
   100
{
ali@24
   101
    GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
ali@24
   102
    gobject_class->finalize=
ali@24
   103
      (void (*)(GObject *))plover_transaction_helper_finalize;
ali@24
   104
    gobject_class->dispose=
ali@24
   105
      (void (*)(GObject *))plover_transaction_helper_dispose;
ali@38
   106
    g_type_class_add_private(klass,sizeof(PloverTransactionHelperPrivate));
ali@24
   107
    signals[CLOSE]=g_signal_newv("close",
ali@24
   108
      G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
ali@24
   109
      g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
ali@24
   110
}
ali@24
   111
ali@24
   112
static void plover_transaction_helper_init(PloverTransactionHelper *helper)
ali@24
   113
{
ali@24
   114
    helper->report_adding=plover_vector_new();
ali@24
   115
    helper->report_removing=plover_vector_new();
ali@24
   116
}
ali@24
   117
ali@24
   118
static void plover_transaction_helper_assistant_cancel(GtkAssistant *assistant,
ali@24
   119
  PloverTransactionHelper *helper)
ali@24
   120
{
ali@24
   121
    gtk_widget_hide(GTK_WIDGET(helper->assistant));
ali@24
   122
    gtk_assistant_set_current_page(helper->assistant,0);
ali@24
   123
    g_signal_emit(helper,signals[CLOSE],0);
ali@24
   124
}
ali@24
   125
ali@24
   126
static void plover_transaction_helper_assistant_close(GtkAssistant *assistant,
ali@24
   127
  PloverTransactionHelper *helper)
ali@24
   128
{
ali@24
   129
    gtk_widget_hide(GTK_WIDGET(helper->assistant));
ali@24
   130
    gtk_assistant_set_current_page(helper->assistant,0);
ali@24
   131
    g_signal_emit(helper,signals[CLOSE],0);
ali@24
   132
}
ali@24
   133
ali@24
   134
static void
ali@24
   135
  plover_transaction_helper_prepare_confirm(PloverTransactionHelper *helper)
ali@24
   136
{
ali@24
   137
    gchar *package_list,*add,*remove,*s;
ali@24
   138
    GtkLabel *label;
ali@24
   139
    struct plover_vector *report;
ali@24
   140
    if (helper->report_adding->len)
ali@24
   141
    {
ali@24
   142
	plover_vector_sort(helper->report_adding);
ali@24
   143
	if (helper->report_adding_dependencies)
ali@24
   144
	{
ali@24
   145
	    report=plover_vector_dup(helper->report_adding);
ali@24
   146
	    if (helper->report_adding->len==1)
ali@24
   147
		plover_vector_append(report,"its dependencies");
ali@24
   148
	    else
ali@24
   149
		plover_vector_append(report,"their dependencies");
ali@24
   150
	    package_list=plover_vector_format_for_display(report);
ali@24
   151
	    plover_vector_free(report);
ali@24
   152
	}
ali@24
   153
	else
ali@24
   154
	    package_list=
ali@24
   155
	      plover_vector_format_for_display(helper->report_adding);
ali@24
   156
	add=g_strconcat("Packages to be installed or updated: ",package_list,
ali@24
   157
	  ".",NULL);
ali@24
   158
	g_free(package_list);
ali@24
   159
    }
ali@24
   160
    else
ali@24
   161
	add=NULL;
ali@24
   162
    if (helper->report_removing->len)
ali@24
   163
    {
ali@24
   164
	plover_vector_sort(helper->report_removing);
ali@24
   165
	if (helper->report_removing_dependants)
ali@24
   166
	{
ali@24
   167
	    report=plover_vector_dup(helper->report_removing);
ali@24
   168
	    if (helper->report_adding->len==1)
ali@24
   169
		plover_vector_append(report,"its dependants");
ali@24
   170
	    else
ali@24
   171
		plover_vector_append(report,"their dependants");
ali@24
   172
	    package_list=plover_vector_format_for_display(report);
ali@24
   173
	    plover_vector_free(report);
ali@24
   174
	}
ali@24
   175
	else
ali@24
   176
	    package_list=
ali@24
   177
	      plover_vector_format_for_display(helper->report_removing);
ali@24
   178
	remove=g_strconcat("Packages to be removed: ",package_list,".",NULL);
ali@24
   179
	g_free(package_list);
ali@24
   180
    }
ali@24
   181
    else
ali@24
   182
	remove=NULL;
ali@24
   183
    label=GTK_LABEL(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
ali@24
   184
    if (add && remove)
ali@24
   185
	s=g_strconcat("<b>Installation Summary</b>\n\n",remove,"\n\n",add,NULL);
ali@24
   186
    else if (add || remove)
ali@24
   187
	s=g_strconcat("<b>Installation Summary</b>\n\n",add?add:remove,NULL);
ali@24
   188
    else
ali@24
   189
	s=g_strdup("<b>Installation Summary</b>\n\nNo changes scheduled");
ali@24
   190
    gtk_label_set_markup(label,s);
ali@24
   191
    g_free(s);
ali@24
   192
    g_free(add);
ali@24
   193
    g_free(remove);
ali@24
   194
}
ali@24
   195
ali@24
   196
static void plover_transaction_helper_run(PloverTransactionHelper *helper);
ali@24
   197
ali@24
   198
static void plover_transaction_helper_callback(GObject *source,
ali@24
   199
  GAsyncResult *result,gpointer user_data)
ali@24
   200
{
ali@24
   201
    GError *error=NULL;
ali@24
   202
    PloverTransactionHelper *helper=user_data;
ali@24
   203
    PloverTransaction *transaction=PLOVER_TRANSACTION(source);
ali@24
   204
    if (!plover_transaction_commit_finish(transaction,result,&error))
ali@24
   205
    {
ali@24
   206
	plover_transaction_helper_set_error(helper,error,
ali@24
   207
	  "Software installation failed");
ali@24
   208
	g_error_free(error);
ali@24
   209
    }
ali@24
   210
    else
ali@24
   211
	plover_transaction_helper_run(helper);
ali@38
   212
    /*
ali@38
   213
     * There may be status updates queued by transaction as idle events.
ali@38
   214
     * Process them now before we disconnect so that we don't lose them.
ali@38
   215
     */
ali@38
   216
    while(g_main_context_pending(NULL))
ali@38
   217
	g_main_context_iteration(NULL,FALSE);
ali@24
   218
    g_signal_handlers_disconnect_by_data(transaction,helper);
ali@24
   219
    g_object_unref(transaction);
ali@24
   220
}
ali@24
   221
ali@24
   222
static void plover_transaction_helper_transaction_status_changed(
ali@24
   223
  PloverTransaction *transaction,const char *status,
ali@24
   224
  PloverTransactionHelper *helper)
ali@24
   225
{
ali@24
   226
    GtkProgressBar *bar;
ali@24
   227
    bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
ali@24
   228
    gtk_progress_bar_set_text(bar,status);
ali@24
   229
}
ali@24
   230
ali@24
   231
static void plover_transaction_helper_run(PloverTransactionHelper *helper)
ali@24
   232
{
ali@24
   233
    PloverTransaction *transaction;
ali@24
   234
    GtkWidget *page;
ali@24
   235
    page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
ali@24
   236
    if (helper->transactions)
ali@24
   237
    {
ali@24
   238
	if (helper->assistant)
ali@24
   239
	    gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
ali@24
   240
	transaction=helper->transactions->data;
ali@24
   241
	helper->transactions=g_slist_delete_link(helper->transactions,
ali@24
   242
	  helper->transactions);
ali@24
   243
	g_signal_connect(transaction,"status-changed",
ali@24
   244
	  G_CALLBACK(plover_transaction_helper_transaction_status_changed),
ali@24
   245
	  helper);
ali@24
   246
	plover_transaction_commit_async(transaction,NULL,
ali@24
   247
	  plover_transaction_helper_callback,helper);
ali@24
   248
    }
ali@24
   249
    else if (helper->assistant)
ali@24
   250
	gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
ali@24
   251
}
ali@24
   252
ali@24
   253
static gboolean plover_transaction_helper_pulse(gpointer user_data)
ali@24
   254
{
ali@24
   255
    PloverTransactionHelper *helper=user_data;
ali@24
   256
    GtkWidget *w;
ali@24
   257
    GtkProgressBar *bar;
ali@24
   258
    if (!helper->assistant)
ali@24
   259
	return FALSE;
ali@24
   260
    w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress"));
ali@24
   261
    bar=GTK_PROGRESS_BAR(gtk_builder_get_object(helper->ui,"SIProgressBar"));
ali@24
   262
    if (gtk_assistant_get_page_complete(helper->assistant,w))
ali@24
   263
    {
ali@24
   264
	gtk_progress_bar_set_fraction(bar,1.0);
ali@24
   265
	helper->pulse_handler=0;
ali@24
   266
	return FALSE;
ali@24
   267
    }
ali@24
   268
    else
ali@24
   269
    {
ali@24
   270
	gtk_progress_bar_pulse(bar);
ali@24
   271
	return TRUE;
ali@24
   272
    }
ali@24
   273
}
ali@24
   274
ali@24
   275
static void
ali@24
   276
  plover_transaction_helper_prepare_progress(PloverTransactionHelper *helper)
ali@24
   277
{
ali@24
   278
    GError *error=NULL;
ali@24
   279
    GtkToggleButton *button;
ali@24
   280
    PloverTransaction *transaction;
ali@38
   281
    GSList *save_transactions;
ali@38
   282
    PloverTransactionHelperPrivate *priv;
ali@38
   283
    enum plover_transaction_type save_transaction_type;
ali@38
   284
    priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
ali@24
   285
    button=GTK_TOGGLE_BUTTON(gtk_builder_get_object(helper->ui,
ali@24
   286
      "SIRemoveExisting"));
ali@24
   287
    if (gtk_toggle_button_get_active(button))
ali@24
   288
    {
ali@24
   289
	transaction=plover_transaction_new_remove(NULL,&error);
ali@38
   290
	if (transaction)
ali@38
   291
	{
ali@38
   292
	    save_transactions=helper->transactions;
ali@38
   293
	    helper->transactions=NULL;
ali@38
   294
	    save_transaction_type=priv->transaction_type;
ali@38
   295
	    priv->transaction_type=0;
ali@38
   296
	    if (!plover_transaction_helper_add_transaction(helper,transaction,
ali@38
   297
	      NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,&error))
ali@38
   298
	    {
ali@38
   299
		g_object_unref(transaction);
ali@38
   300
		transaction=NULL;
ali@38
   301
		helper->transactions=save_transactions;
ali@38
   302
		priv->transaction_type=save_transaction_type;
ali@38
   303
	    }
ali@38
   304
	    else
ali@38
   305
	    {
ali@38
   306
		g_slist_foreach(save_transactions,(GFunc)g_object_unref,NULL);
ali@38
   307
		g_slist_free(save_transactions);
ali@38
   308
	    }
ali@38
   309
	}
ali@24
   310
	if (!transaction)
ali@24
   311
	{
ali@24
   312
	    if (g_error_matches(error,PLOVER_POSIX_ERROR,ENOENT))
ali@24
   313
		g_clear_error(&error);
ali@24
   314
	    if (error)
ali@24
   315
	    {
ali@24
   316
		plover_transaction_helper_set_error(helper,error,
ali@38
   317
		  "Failed to remove existing packages");
ali@24
   318
		g_error_free(error);
ali@24
   319
		return;
ali@24
   320
	    }
ali@24
   321
	}
ali@24
   322
    }
ali@24
   323
    /*
ali@24
   324
     * Note that PloverTransaction does support cancelling a transaction, but
ali@24
   325
     * there are a number of challenges with using it:
ali@24
   326
     *	- cancellation is only supported during the file phase if razor
ali@24
   327
     *	  has atomic rollback,
ali@24
   328
     *  - cancellation is not supported during post-transaction scripts at all
ali@24
   329
     *    (since by the time the first script is started the atomic has already
ali@24
   330
     *    been committed) and these can take quite some time,
ali@24
   331
     *  - where a transaction has an embedded COMMIT, any rollback won't
ali@24
   332
     *    go back beyond this point.
ali@24
   333
     * To support user-cancel, then, we would need some mechanism to:
ali@24
   334
     *  - Comunicate that the operation is being cancelled and this may take
ali@24
   335
     *    some time,
ali@24
   336
     *  - Not allow cancellation at all after the last post-transaction script
ali@24
   337
     *    phase is started,
ali@24
   338
     *  - Report the partially completed transaction where cancellation
ali@24
   339
     *    occurred after a COMMIT point.
ali@24
   340
     * At present, this doesn't appear worth the effort.
ali@24
   341
     */
ali@24
   342
    if (helper->assistant)
ali@24
   343
	gtk_assistant_commit(helper->assistant);
ali@24
   344
    plover_transaction_helper_run(helper);
ali@24
   345
    helper->pulse_handler=g_timeout_add(100,plover_transaction_helper_pulse,
ali@24
   346
      helper);
ali@24
   347
}
ali@24
   348
ali@24
   349
static void plover_transaction_helper_assistant_prepare(GtkAssistant *assistant,
ali@24
   350
  GtkWidget *page,PloverTransactionHelper *helper)
ali@24
   351
{
ali@24
   352
    if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm")))
ali@24
   353
	plover_transaction_helper_prepare_confirm(helper);
ali@24
   354
    else if (page==GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgress")))
ali@24
   355
	plover_transaction_helper_prepare_progress(helper);
ali@24
   356
}
ali@24
   357
ali@24
   358
static void
ali@24
   359
  plover_transaction_helper_remove_existing_toggled(GtkToggleButton *button,
ali@24
   360
  PloverTransactionHelper *helper)
ali@24
   361
{
ali@24
   362
    GtkWidget *w;
ali@24
   363
    if (helper->assistant)
ali@24
   364
    {
ali@24
   365
	w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
ali@24
   366
	gtk_assistant_set_page_complete(helper->assistant,w,
ali@24
   367
	  gtk_toggle_button_get_active(button));
ali@24
   368
    }
ali@24
   369
}
ali@24
   370
ali@24
   371
PloverTransactionHelper *plover_transaction_helper_new(GtkBuilder *ui)
ali@24
   372
{
ali@24
   373
    gsize len;
ali@24
   374
    gchar *s,*directory,*contents;
ali@24
   375
    GError *error=NULL;
ali@24
   376
    GtkWidget *w;
ali@24
   377
    PloverTransactionHelper *helper;
ali@24
   378
    g_return_val_if_fail(ui == NULL || GTK_IS_BUILDER(ui),NULL);
ali@24
   379
    helper=PLOVER_TRANSACTION_HELPER(
ali@24
   380
      g_object_new(PLOVER_TYPE_TRANSACTION_HELPER,NULL));
ali@24
   381
    if (ui)
ali@24
   382
	helper->ui=g_object_ref(ui);
ali@24
   383
    else
ali@24
   384
	helper->ui=gtk_builder_new();
ali@24
   385
    helper->assistant=
ali@24
   386
      GTK_ASSISTANT(gtk_builder_get_object(helper->ui,"SoftwareInstallation"));
ali@24
   387
    if (!helper->assistant)
ali@24
   388
    {
ali@24
   389
	directory=g_strdup(g_getenv("PLOVER_DATADIR"));
ali@24
   390
	if (!directory)
ali@24
   391
	{
ali@24
   392
#ifdef WIN32
ali@24
   393
	    s=g_win32_get_package_installation_directory_of_module(NULL);
ali@24
   394
	    directory=g_build_filename(s,"share","plover",NULL);
ali@24
   395
	    g_free(s);
ali@24
   396
#else
ali@24
   397
	    directory=g_strdup(PLOVER_DATADIR);
ali@24
   398
#endif
ali@24
   399
	}
ali@24
   400
	s=g_build_filename(directory,"software-installation.ui",NULL);
ali@24
   401
	g_free(directory);
ali@24
   402
	(void)g_file_get_contents(s,&contents,&len,&error);
ali@24
   403
	g_free(s);
ali@24
   404
	if (!error)
ali@24
   405
	{
ali@24
   406
	    (void)gtk_builder_add_from_string(helper->ui,contents,len,&error);
ali@24
   407
	    g_free(contents);
ali@24
   408
	}
ali@24
   409
	if (error)
ali@24
   410
	{
ali@24
   411
	    g_critical("software-installation.ui: %s",error->message);
ali@24
   412
	    g_clear_error(&error);
ali@24
   413
	    g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   414
	      "Internal error (no user interface)");
ali@24
   415
	    plover_transaction_helper_set_error(helper,error,
ali@24
   416
	      "Can't start installer");
ali@24
   417
	    return helper;
ali@24
   418
	}
ali@24
   419
	helper->assistant=GTK_ASSISTANT(gtk_builder_get_object(helper->ui,
ali@24
   420
	  "SoftwareInstallation"));
ali@24
   421
    }
ali@24
   422
    if (!helper->assistant)
ali@24
   423
    {
ali@24
   424
	g_critical("\"SoftwareInstallation\" object not found");
ali@24
   425
	g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   426
	  "Internal error (missing wizard)");
ali@24
   427
	plover_transaction_helper_set_error(helper,error,
ali@24
   428
	  "Can't start installer");
ali@24
   429
	g_error_free(error);
ali@24
   430
	return helper;
ali@24
   431
    }
ali@24
   432
    else
ali@24
   433
	g_object_ref(helper->assistant);
ali@24
   434
    if (!GTK_IS_ASSISTANT(helper->assistant))
ali@24
   435
    {
ali@24
   436
	g_critical("\"SoftwareInstallation\" is not a GtkAssistant");
ali@24
   437
	g_set_error(&error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   438
	  "Internal error (unexpected wizard type)");
ali@24
   439
	plover_transaction_helper_set_error(helper,error,
ali@24
   440
	  "Can't start installer");
ali@24
   441
	g_error_free(error);
ali@24
   442
	return helper;
ali@24
   443
    }
ali@24
   444
    g_signal_connect(helper->assistant,"cancel",
ali@24
   445
      G_CALLBACK(plover_transaction_helper_assistant_cancel),helper);
ali@24
   446
    g_signal_connect(helper->assistant,"close",
ali@24
   447
      G_CALLBACK(plover_transaction_helper_assistant_close),helper);
ali@24
   448
    g_signal_connect(helper->assistant,"prepare",
ali@24
   449
      G_CALLBACK(plover_transaction_helper_assistant_prepare),helper);
ali@24
   450
    w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
ali@24
   451
    if (w)
ali@24
   452
	g_signal_connect(w,"toggled",
ali@24
   453
	  G_CALLBACK(plover_transaction_helper_remove_existing_toggled),helper);
ali@24
   454
    w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIIntroduction"));
ali@24
   455
    if (w)
ali@24
   456
	gtk_assistant_set_page_complete(helper->assistant,w,TRUE);
ali@24
   457
    return helper;
ali@24
   458
}
ali@24
   459
ali@24
   460
PloverPackageSet *
ali@24
   461
  plover_transaction_helper_get_installed(PloverTransactionHelper *helper)
ali@24
   462
{
ali@61
   463
    gchar *s,*saved_database_uri;
ali@61
   464
    char *install_root,*local_database,*active_database,*alternate_database;
ali@61
   465
    const char *prefix;
ali@61
   466
    struct comps *comps;
ali@61
   467
    PloverPackageSet *alternate_installed,*installed;
ali@61
   468
    GError *error=NULL;
ali@61
   469
    struct razor_error *razor_error=NULL;
ali@24
   470
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@61
   471
    if (!helper->installed)
ali@61
   472
    {
ali@61
   473
	comps=plover_transaction_helper_get_comps(helper,NULL);
ali@61
   474
	if (!comps)
ali@61
   475
	{
ali@61
   476
	    g_warning("plover_transaction_helper_get_installed: No comps");
ali@61
   477
	    return NULL;
ali@61
   478
	}
ali@61
   479
	install_root=getenv("RAZOR_ROOT");
ali@61
   480
	if (!install_root)
ali@61
   481
	    install_root="file:/";
ali@61
   482
	prefix=plover_transaction_helper_get_prefix(helper,NULL);
ali@61
   483
	if (prefix)
ali@61
   484
	{
ali@61
   485
	    s=g_strconcat(prefix,"/var/lib/razor",NULL);
ali@61
   486
	    local_database=razor_path_relative_to_uri(install_root,*s=='/'?s+1:s,
ali@61
   487
	      &razor_error);
ali@61
   488
	    g_free(s);
ali@61
   489
	    if (!local_database)
ali@61
   490
	    {
ali@61
   491
		g_warning("plover_transaction_helper_get_installed: %s",
ali@61
   492
		  razor_error_get_msg(razor_error));
ali@61
   493
		razor_error_free(razor_error);
ali@61
   494
		return NULL;
ali@61
   495
	    }
ali@61
   496
	}
ali@61
   497
	else
ali@61
   498
	    local_database=NULL;
ali@61
   499
	switch(comps->database)
ali@61
   500
	{
ali@61
   501
	    case COMPS_DATABASE_DISTRIBUTION_LOCAL:
ali@61
   502
		active_database=local_database;
ali@61
   503
		alternate_database=NULL;
ali@61
   504
		break;
ali@61
   505
	    case COMPS_DATABASE_GLOBAL:
ali@61
   506
		active_database=NULL;
ali@61
   507
		alternate_database=local_database;
ali@61
   508
		break;
ali@61
   509
	}
ali@61
   510
	saved_database_uri=g_strdup(razor_get_database_uri());
ali@61
   511
	if (prefix)
ali@61
   512
	{
ali@61
   513
	    razor_set_database_uri(alternate_database);
ali@61
   514
	    alternate_installed=plover_package_set_new();
ali@61
   515
	    if (!plover_package_set_open(alternate_installed,install_root,TRUE,
ali@61
   516
	      &error))
ali@61
   517
	    {
ali@61
   518
		g_object_unref(alternate_installed);
ali@61
   519
		g_warning("plover_transaction_helper_get_installed: %s",
ali@61
   520
		  error->message);
ali@61
   521
		g_error_free(error);
ali@61
   522
		free(local_database);
ali@61
   523
		razor_set_database_uri(saved_database_uri);
ali@61
   524
		g_free(saved_database_uri);
ali@61
   525
		return NULL;
ali@61
   526
	    }
ali@61
   527
	}
ali@61
   528
	else
ali@61
   529
	    alternate_installed=NULL;
ali@61
   530
	razor_set_database_uri(active_database);
ali@61
   531
	free(local_database);
ali@61
   532
	installed=plover_package_set_new();
ali@61
   533
	if (plover_package_set_open(installed,install_root,TRUE,&error))
ali@61
   534
	{
ali@61
   535
	    helper->alternate_installed=alternate_installed;
ali@61
   536
	    helper->installed=installed;
ali@61
   537
	}
ali@61
   538
	else
ali@61
   539
	{
ali@61
   540
	    g_object_unref(installed);
ali@61
   541
	    if (alternate_installed)
ali@61
   542
		g_object_unref(alternate_installed);
ali@61
   543
	    g_warning("plover_transaction_helper_get_installed: %s",error->message);
ali@61
   544
	    g_error_free(error);
ali@61
   545
	}
ali@61
   546
	razor_set_database_uri(saved_database_uri);
ali@61
   547
	g_free(saved_database_uri);
ali@61
   548
    }
ali@24
   549
    return helper->installed;
ali@24
   550
}
ali@24
   551
ali@24
   552
void plover_transaction_helper_set_installed(PloverTransactionHelper *helper,
ali@24
   553
  PloverPackageSet *installed)
ali@24
   554
{
ali@24
   555
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
   556
    g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
ali@24
   557
    g_return_if_fail(helper->installed == NULL);
ali@61
   558
    g_clear_object(&helper->alternate_installed);
ali@24
   559
    helper->installed=g_object_ref(installed);
ali@24
   560
}
ali@24
   561
ali@24
   562
PloverRepository *
ali@24
   563
  plover_transaction_helper_get_upstream(PloverTransactionHelper *helper,
ali@24
   564
  GError **error)
ali@24
   565
{
ali@24
   566
    const char *base;
ali@24
   567
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@24
   568
    if (!helper->upstream)
ali@24
   569
    {
ali@24
   570
	base=plover_transaction_helper_get_base(helper);
ali@24
   571
	helper->upstream=plover_repository_new_from_yum(base,error);
ali@24
   572
    }
ali@24
   573
    return helper->upstream;
ali@24
   574
}
ali@24
   575
ali@24
   576
void plover_transaction_helper_set_upstream(PloverTransactionHelper *helper,
ali@24
   577
  PloverRepository *upstream)
ali@24
   578
{
ali@24
   579
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
   580
    g_return_if_fail(PLOVER_IS_REPOSITORY(upstream));
ali@24
   581
    g_return_if_fail(helper->upstream == NULL);
ali@24
   582
    helper->upstream=g_object_ref(upstream);
ali@24
   583
}
ali@24
   584
ali@24
   585
const char *plover_transaction_helper_get_base(PloverTransactionHelper *helper)
ali@24
   586
{
ali@24
   587
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@24
   588
    return helper->base;
ali@24
   589
}
ali@24
   590
ali@24
   591
void plover_transaction_helper_set_base(PloverTransactionHelper *helper,
ali@24
   592
  const char *base)
ali@24
   593
{
ali@24
   594
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
   595
    g_return_if_fail(helper->transactions == NULL);
ali@24
   596
    g_free(helper->base);
ali@24
   597
    helper->base=g_strdup(base);
ali@24
   598
}
ali@24
   599
ali@24
   600
struct comps *
ali@24
   601
  plover_transaction_helper_get_comps(PloverTransactionHelper *helper,
ali@24
   602
  GError **error)
ali@24
   603
{
ali@24
   604
    gchar *s;
ali@24
   605
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@24
   606
    g_return_val_if_fail(helper->base != NULL,NULL);
ali@24
   607
    if (!helper->comps)
ali@24
   608
    {
ali@24
   609
	s=g_strconcat(helper->base,"/repodata/comps.xml",NULL);
ali@24
   610
	helper->comps=plover_comps_new_from_file(s);
ali@24
   611
	if (!helper->comps)
ali@24
   612
	    g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   613
	      PLOVER_GENERAL_ERROR_FAILED,"%s: %s",s,g_strerror(errno));
ali@24
   614
	g_free(s);
ali@24
   615
    }
ali@24
   616
    return helper->comps;
ali@24
   617
}
ali@24
   618
ali@24
   619
const char *
ali@24
   620
  plover_transaction_helper_get_prefix(PloverTransactionHelper *helper,
ali@24
   621
  GError **error)
ali@24
   622
{
ali@24
   623
    const char *prefix;
ali@24
   624
    struct comps *comps;
ali@38
   625
    PloverTransactionHelperPrivate *priv;
ali@24
   626
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@61
   627
    g_return_val_if_fail(helper->base != NULL || plover_transaction_helper_get_installed(helper) != NULL,NULL);
ali@38
   628
    priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
ali@24
   629
    if (helper->base)
ali@24
   630
    {
ali@24
   631
	comps=plover_transaction_helper_get_comps(helper,error);
ali@24
   632
	if (!comps)
ali@24
   633
	    return NULL;
ali@38
   634
	g_free(priv->default_prefix);
ali@61
   635
	priv->default_prefix=plover_comps_get_default_prefix(comps);
ali@38
   636
	return priv->default_prefix;
ali@24
   637
    }
ali@24
   638
    prefix=plover_package_set_guess_prefix(helper->installed,error);
ali@24
   639
    return prefix;
ali@24
   640
}
ali@24
   641
ali@61
   642
#if 0
ali@24
   643
static int plover_transaction_helper_package_count(void)
ali@24
   644
{
ali@24
   645
    int count=0;
ali@24
   646
    char *install_root;
ali@24
   647
    struct razor_set *set;
ali@24
   648
    struct razor_package *package;
ali@24
   649
    struct razor_package_iterator *pi;
ali@24
   650
    install_root=getenv("RAZOR_ROOT");
ali@24
   651
    if (!install_root)
ali@24
   652
	install_root="";
ali@24
   653
    set=razor_root_open_read_only(install_root,NULL);
ali@24
   654
    if (set)
ali@24
   655
    {
ali@24
   656
	pi=razor_package_iterator_create(set);
ali@24
   657
	while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
ali@24
   658
	    count++;
ali@24
   659
	razor_package_iterator_destroy(pi);
ali@24
   660
	razor_set_unref(set);
ali@24
   661
    }
ali@24
   662
    return count;
ali@24
   663
}
ali@61
   664
#endif
ali@61
   665
ali@61
   666
static gboolean prefix_clashes(const char *prefix,const char *alt)
ali@61
   667
{
ali@61
   668
    return g_str_has_prefix(prefix,alt) &&
ali@61
   669
      (prefix[strlen(alt)]=='\0' || prefix[strlen(alt)]=='/');
ali@61
   670
}
ali@24
   671
ali@24
   672
static gboolean
ali@24
   673
  plover_transaction_helper_check_vendor(PloverTransactionHelper *helper,
ali@24
   674
  GError **error)
ali@24
   675
{
ali@61
   676
    int i,remove_count=0;
ali@61
   677
    gboolean alternate_database_clashes=FALSE;
ali@61
   678
    gboolean active_database_is_incompatible=FALSE;
ali@61
   679
    char *local_database,*active_database,*alternate_database;
ali@61
   680
    const char *alternate_prefix;
ali@24
   681
    gchar *prefix=NULL,*s;
ali@24
   682
    struct comps *comps=NULL;
ali@38
   683
    GtkWidget *container,*summary,*page;
ali@24
   684
    GtkButton *button;
ali@24
   685
    GtkLabel *label;
ali@24
   686
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@61
   687
    comps=plover_transaction_helper_get_comps(helper,error);
ali@61
   688
    if (!comps)
ali@61
   689
	return FALSE;
ali@61
   690
    prefix=plover_comps_get_default_prefix(comps);
ali@24
   691
    button=GTK_BUTTON(gtk_builder_get_object(helper->ui,"SIRemoveExisting"));
ali@24
   692
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),FALSE);
ali@24
   693
    container=GTK_WIDGET(gtk_builder_get_object(helper->ui,
ali@24
   694
      "SIIncompatibleInstallation"));
ali@38
   695
    summary=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SISummaryOfWork"));
ali@24
   696
    page=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIConfirm"));
ali@61
   697
    if (helper->check_vendor && prefix && helper->alternate_installed)
ali@61
   698
    {
ali@61
   699
	alternate_prefix=
ali@61
   700
	  plover_package_set_guess_prefix(helper->alternate_installed,NULL);
ali@61
   701
	if (alternate_prefix && prefix_clashes(prefix,alternate_prefix))
ali@61
   702
	{
ali@61
   703
	    alternate_database_clashes=TRUE;
ali@61
   704
	    remove_count=g_slist_length(
ali@61
   705
	      plover_package_set_get_packages(helper->alternate_installed));
ali@61
   706
	}
ali@61
   707
    }
ali@61
   708
    /*
ali@61
   709
     * Rather than try to be too clever, we only deal with one thing
ali@61
   710
     * at a time. That means that if the alternate database clashes
ali@61
   711
     * there's no point checking if the active database is compatible.
ali@61
   712
     */
ali@61
   713
    if (!alternate_database_clashes)
ali@61
   714
    {
ali@61
   715
	if (helper->check_vendor && prefix &&
ali@61
   716
	  !plover_package_set_files_match_prefix(helper->installed,prefix))
ali@61
   717
	{
ali@61
   718
	    active_database_is_incompatible=TRUE;
ali@61
   719
	    remove_count=
ali@61
   720
	      g_slist_length(plover_package_set_get_packages(helper->installed));
ali@61
   721
	}
ali@61
   722
    }
ali@61
   723
    if (alternate_database_clashes || active_database_is_incompatible)
ali@24
   724
    {
ali@24
   725
	label=GTK_LABEL(gtk_builder_get_object(helper->ui,
ali@24
   726
	  "SIIncompatibleInstallationLabel"));
ali@61
   727
	if (alternate_database_clashes)
ali@61
   728
	    s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
ali@61
   729
	      "There is an existing installation under %s\n"
ali@61
   730
	      "which is not compatible with this distribution. In order\n"
ali@61
   731
	      "to continue, the existing installation must be uninstalled.",
ali@61
   732
	      comps->vendor);
ali@61
   733
	else /* active_database_is_incompatible */
ali@61
   734
	    s=g_strdup_printf("<b>Incompatible Installation</b>\n\n"
ali@61
   735
	      "The existing installation is not from %s.\n In order "
ali@61
   736
	      "to continue, all the existing packages must be removed.",
ali@61
   737
	      comps->vendor);
ali@24
   738
	gtk_label_set_markup(label,s);
ali@24
   739
	g_free(s);
ali@61
   740
	s=g_strdup_printf("Remove %d existing package%s",remove_count,
ali@61
   741
	  remove_count==1?"":"s");
ali@24
   742
	gtk_button_set_label(button,s);
ali@24
   743
	g_free(s);
ali@24
   744
	gtk_widget_show(container);
ali@38
   745
	gtk_widget_hide(summary);
ali@24
   746
	if (helper->assistant)
ali@24
   747
	    gtk_assistant_set_page_complete(helper->assistant,page,FALSE);
ali@24
   748
    }
ali@24
   749
    else
ali@24
   750
    {
ali@24
   751
	gtk_widget_hide(container);
ali@38
   752
	gtk_widget_show(summary);
ali@24
   753
	if (helper->assistant)
ali@24
   754
	    gtk_assistant_set_page_complete(helper->assistant,page,TRUE);
ali@24
   755
    }
ali@38
   756
    g_free(prefix);
ali@24
   757
    return TRUE;
ali@24
   758
}
ali@24
   759
ali@24
   760
void plover_transaction_helper_set_check_vendor(PloverTransactionHelper *helper,
ali@24
   761
  gboolean check_vendor)
ali@24
   762
{
ali@24
   763
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
   764
    if (helper->check_vendor!=check_vendor)
ali@24
   765
    {
ali@24
   766
	helper->check_vendor=check_vendor;
ali@24
   767
	if (helper->transactions)
ali@24
   768
	    plover_transaction_helper_check_vendor(helper,NULL);
ali@24
   769
    }
ali@24
   770
}
ali@24
   771
ali@24
   772
/*
ali@24
   773
 * If plover_transaction_helper_add_transaction() failes with an error
ali@24
   774
 * of PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET
ali@24
   775
 * then plover_transaction_helper_get_unsatisfied() can be used to
ali@24
   776
 * retrieve a textual description of the problem.
ali@24
   777
 */
ali@24
   778
ali@24
   779
const char *
ali@24
   780
  plover_transaction_helper_get_unsatisfied(PloverTransactionHelper *helper)
ali@24
   781
{
ali@24
   782
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@24
   783
    return helper->unsatisfied;
ali@24
   784
}
ali@24
   785
ali@38
   786
#define PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(action) \
ali@38
   787
  ((action)==PLOVER_TRANSACTION_HELPER_REPORT_INSTALL || \
ali@38
   788
  (action)==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE || \
ali@38
   789
  (action)==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
ali@38
   790
ali@24
   791
gboolean
ali@24
   792
  plover_transaction_helper_add_transaction(PloverTransactionHelper *helper,
ali@24
   793
  PloverTransaction *transaction,struct plover_vector *report_packages,
ali@38
   794
  PloverTransactionHelperReportAction report_action,GError **error)
ali@24
   795
{
ali@24
   796
    int i,count;
ali@24
   797
    gboolean other_packages;
ali@24
   798
    const char *s,*name;
ali@24
   799
    enum razor_install_action action;
ali@24
   800
    struct razor_install_iterator *ii;
ali@38
   801
    struct razor_set *report_set;
ali@24
   802
    struct razor_package *package;
ali@24
   803
    struct plover_vector *tasked_packages;
ali@38
   804
    PloverTransactionHelperPrivate *priv;
ali@38
   805
    GtkWidget *w;
ali@24
   806
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
   807
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@38
   808
    g_return_val_if_fail(PLOVER_TRANSACTION_HELPER_IS_VALID_REPORT_ACTION(report_action),FALSE);
ali@38
   809
    g_return_val_if_fail(plover_transaction_get_system_set(transaction)!=NULL,FALSE);
ali@38
   810
    priv=PLOVER_TRANSACTION_HELPER_GET_PRIVATE(helper);
ali@24
   811
    g_free(helper->unsatisfied);
ali@24
   812
    helper->unsatisfied=NULL;
ali@24
   813
    if (!plover_transaction_resolve(transaction,error))
ali@24
   814
    {
ali@24
   815
	s=plover_transaction_get_unsatisfied(transaction);
ali@24
   816
	helper->unsatisfied=g_strdup(s);
ali@24
   817
	return FALSE;
ali@24
   818
    }
ali@24
   819
    ii=plover_transaction_get_install_iterator(transaction,error);
ali@24
   820
    if (!ii)
ali@24
   821
	return FALSE;
ali@38
   822
    if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
ali@38
   823
	report_set=plover_transaction_get_system_set(transaction);
ali@38
   824
    else
ali@38
   825
	report_set=plover_transaction_get_next_set(transaction,error);
ali@38
   826
    if (!report_set)
ali@24
   827
	return FALSE;
ali@24
   828
    tasked_packages=plover_vector_new();
ali@24
   829
    other_packages=FALSE;
ali@24
   830
    while (razor_install_iterator_next(ii,&package,&action,&count))
ali@24
   831
    {
ali@38
   832
	if (action==report_action || action==RAZOR_INSTALL_ACTION_ADD &&
ali@38
   833
	  report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
ali@24
   834
	{
ali@38
   835
	    razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
ali@38
   836
	      &name,RAZOR_DETAIL_LAST);
ali@24
   837
	    if (!report_packages ||
ali@24
   838
	      plover_vector_contains(report_packages,name))
ali@24
   839
		plover_vector_append(tasked_packages,name);
ali@24
   840
	    else
ali@24
   841
		other_packages=TRUE;
ali@24
   842
	}
ali@24
   843
    }
ali@24
   844
    if (!tasked_packages->len)
ali@24
   845
    {
ali@24
   846
	/*
ali@24
   847
	 * If there are no reportable packages tasked for action there
ali@24
   848
	 * shouldn't by any packages at all, but let's be paranoid.
ali@24
   849
	 */
ali@24
   850
	other_packages=FALSE;
ali@24
   851
	razor_install_iterator_rewind(ii);
ali@24
   852
	while (razor_install_iterator_next(ii,&package,&action,&count))
ali@24
   853
	{
ali@24
   854
	    if (action==report_action)
ali@24
   855
	    {
ali@38
   856
		razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
ali@38
   857
		  &name,RAZOR_DETAIL_LAST);
ali@24
   858
		plover_vector_append(tasked_packages,name);
ali@24
   859
	    }
ali@24
   860
	}
ali@24
   861
    }
ali@24
   862
    if (!tasked_packages->len)
ali@24
   863
    {
ali@24
   864
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   865
	  PLOVER_GENERAL_ERROR_NO_WORK,"Transaction includes no %s actions",
ali@38
   866
	  report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE?
ali@38
   867
	  "remove":"add");
ali@24
   868
	plover_vector_free(tasked_packages);
ali@24
   869
	return FALSE;
ali@24
   870
    }
ali@24
   871
    if (!helper->transactions)
ali@24
   872
	plover_transaction_helper_check_vendor(helper,error);
ali@24
   873
    g_object_ref(transaction);
ali@24
   874
    helper->transactions=g_slist_append(helper->transactions,transaction);
ali@38
   875
    if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_REMOVE)
ali@24
   876
    {
ali@38
   877
	priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
ali@38
   878
	for(i=0;i<tasked_packages->len;i++)
ali@38
   879
	{
ali@38
   880
	    s=tasked_packages->strings[i];
ali@38
   881
	    if (!plover_vector_contains(helper->report_removing,s))
ali@38
   882
		plover_vector_append(helper->report_removing,s);
ali@38
   883
	}
ali@38
   884
	helper->report_removing_dependants|=other_packages;
ali@38
   885
    }
ali@38
   886
    else
ali@38
   887
    {
ali@38
   888
	if (report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
ali@38
   889
	    priv->transaction_type|=TRANSACTION_TYPE_REMOVE;
ali@38
   890
	priv->transaction_type|=TRANSACTION_TYPE_INSTALL;
ali@24
   891
	for(i=0;i<tasked_packages->len;i++)
ali@24
   892
	{
ali@24
   893
	    s=tasked_packages->strings[i];
ali@24
   894
	    if (!plover_vector_contains(helper->report_adding,s))
ali@24
   895
		plover_vector_append(helper->report_adding,s);
ali@24
   896
	}
ali@24
   897
	helper->report_adding_dependencies|=other_packages;
ali@24
   898
    }
ali@38
   899
    w=GTK_WIDGET(gtk_builder_get_object(helper->ui,"SIProgressLabel"));
ali@38
   900
    switch(priv->transaction_type)
ali@24
   901
    {
ali@38
   902
	case TRANSACTION_TYPE_INSTALL:
ali@38
   903
	    gtk_label_set_markup(GTK_LABEL(w),
ali@38
   904
	      "<b>Installing the Software</b>\n\n"
ali@38
   905
	      "Please wait while the Installation Assistant "
ali@38
   906
	      "installs the software.\n"
ali@38
   907
	      "This may take several minutes.");
ali@38
   908
	    break;
ali@38
   909
	case TRANSACTION_TYPE_REMOVE:
ali@38
   910
	    gtk_label_set_markup(GTK_LABEL(w),
ali@38
   911
	      "<b>Removing Packages</b>\n\n"
ali@38
   912
	      "Please wait while the Installation Assistant "
ali@38
   913
	      "removes packages.\n"
ali@38
   914
	      "This may take several minutes.");
ali@38
   915
	    break;
ali@38
   916
	default:
ali@38
   917
	case TRANSACTION_TYPE_UPDATE:
ali@38
   918
	    gtk_label_set_markup(GTK_LABEL(w),
ali@38
   919
	      "<b>Updating the Software</b>\n\n"
ali@38
   920
	      "Please wait while the Installation Assistant "
ali@38
   921
	      "updates the software.\n"
ali@38
   922
	      "This may take several minutes.");
ali@38
   923
	    break;
ali@24
   924
    }
ali@24
   925
    plover_vector_free(tasked_packages);
ali@24
   926
    return TRUE;
ali@24
   927
}
ali@24
   928
ali@24
   929
static PloverTransaction *
ali@24
   930
  plover_transaction_helper_new_transaction(PloverTransactionHelper *helper,
ali@24
   931
  GError **error)
ali@24
   932
{
ali@24
   933
    gboolean ok;
ali@24
   934
    const char *base,*prefix;
ali@24
   935
    GError *tmp_error=NULL;
ali@24
   936
    PloverTransaction *transaction;
ali@24
   937
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),NULL);
ali@61
   938
    g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,NULL);
ali@24
   939
    prefix=plover_transaction_helper_get_prefix(helper,&tmp_error);
ali@24
   940
    if (tmp_error)
ali@24
   941
    {
ali@24
   942
	g_propagate_error(error,tmp_error);
ali@24
   943
	return NULL;
ali@24
   944
    }
ali@24
   945
    transaction=plover_transaction_new();
ali@24
   946
    plover_transaction_set_prefix(transaction,prefix);
ali@24
   947
    plover_transaction_set_installed(transaction,helper->installed);
ali@24
   948
    if (helper->upstream)
ali@24
   949
	ok=plover_transaction_set_upstream(transaction,helper->upstream,error);
ali@24
   950
    else
ali@24
   951
    {
ali@24
   952
	base=plover_transaction_helper_get_base(helper);
ali@24
   953
	ok=plover_transaction_set_upstream_from_yum(transaction,base,error);
ali@24
   954
    }
ali@24
   955
    if (!ok)
ali@24
   956
    {
ali@24
   957
	g_object_unref(transaction);
ali@24
   958
	transaction=NULL;
ali@24
   959
    }
ali@24
   960
    return transaction;
ali@24
   961
}
ali@24
   962
ali@24
   963
struct plover_vector *plover_transaction_helper_group_get_default_packages(
ali@24
   964
  PloverTransactionHelper *helper,const char *group,GError **error)
ali@24
   965
{
ali@24
   966
    gboolean changed;
ali@24
   967
    struct comps *comps;
ali@24
   968
    struct comps_group *grp;
ali@24
   969
    struct comps_requirement *pkg;
ali@24
   970
    struct plover_vector *default_packages;
ali@24
   971
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
   972
    comps=plover_transaction_helper_get_comps(helper,error);
ali@24
   973
    if (!comps)
ali@24
   974
	return NULL;
ali@24
   975
    grp=plover_comps_lookup_group(comps,group);
ali@24
   976
    if (!grp)
ali@24
   977
    {
ali@24
   978
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   979
	  PLOVER_GENERAL_ERROR_FAILED,"%s: group not found",group);
ali@24
   980
	return NULL;
ali@24
   981
    }
ali@24
   982
    default_packages=plover_vector_new();
ali@24
   983
    do
ali@24
   984
    {
ali@24
   985
	changed=FALSE;
ali@24
   986
	for(pkg=grp->packages;pkg;pkg=pkg->next)
ali@24
   987
	{
ali@24
   988
	    if (plover_vector_contains(default_packages,pkg->name))
ali@24
   989
		continue;
ali@24
   990
	    if (pkg->type==COMPS_REQUIREMENT_DEFAULT ||
ali@24
   991
	      pkg->type==COMPS_REQUIREMENT_MANDATORY ||
ali@38
   992
	      pkg->type==COMPS_REQUIREMENT_CONDITIONAL && pkg->requires &&
ali@24
   993
	      plover_vector_contains(default_packages,pkg->requires))
ali@24
   994
	    {
ali@24
   995
		changed=TRUE;
ali@24
   996
		plover_vector_append(default_packages,pkg->name);
ali@24
   997
	    }
ali@24
   998
	}
ali@24
   999
    } while(changed);
ali@24
  1000
    return default_packages;
ali@24
  1001
}
ali@24
  1002
ali@24
  1003
/*
ali@24
  1004
 * Returns TRUE if there is work to be done or FALSE if the packages are
ali@24
  1005
 * already installed or on error.
ali@24
  1006
 */
ali@24
  1007
gboolean
ali@24
  1008
  plover_transaction_helper_install_packages(PloverTransactionHelper *helper,
ali@24
  1009
  struct plover_vector *packages,GError **error)
ali@24
  1010
{
ali@24
  1011
    gboolean retval;
ali@24
  1012
    PloverTransaction *transaction;
ali@24
  1013
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
  1014
    g_return_val_if_fail(packages != NULL,FALSE);
ali@24
  1015
    if (!packages->len)
ali@24
  1016
    {
ali@24
  1017
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
  1018
	  PLOVER_GENERAL_ERROR_NO_WORK,"No packages listed to be installed");
ali@24
  1019
	return FALSE;
ali@24
  1020
    }
ali@24
  1021
    transaction=plover_transaction_helper_new_transaction(helper,error);
ali@24
  1022
    if (!transaction)
ali@24
  1023
	return FALSE;
ali@24
  1024
    if (!plover_transaction_install(transaction,packages->strings,error))
ali@24
  1025
    {
ali@24
  1026
	g_object_unref(transaction);
ali@24
  1027
	return FALSE;
ali@24
  1028
    }
ali@24
  1029
    retval=plover_transaction_helper_add_transaction(helper,transaction,
ali@38
  1030
      packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,error);
ali@24
  1031
    g_object_unref(transaction);
ali@24
  1032
    return retval;
ali@24
  1033
}
ali@24
  1034
ali@24
  1035
/*
ali@24
  1036
 * Returns TRUE if there is work to be done or FALSE if the group is
ali@24
  1037
 * already installed or on error.
ali@24
  1038
 */
ali@24
  1039
gboolean
ali@24
  1040
  plover_transaction_helper_install_group(PloverTransactionHelper *helper,
ali@24
  1041
  const char *group,GError **error)
ali@24
  1042
{
ali@24
  1043
    gboolean retval;
ali@24
  1044
    struct plover_vector *selected_packages;
ali@24
  1045
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
  1046
    selected_packages=plover_transaction_helper_group_get_default_packages(
ali@24
  1047
      helper,group,error);
ali@24
  1048
    if (!selected_packages)
ali@24
  1049
	return FALSE;
ali@24
  1050
    if (!selected_packages->len)
ali@24
  1051
    {
ali@24
  1052
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
  1053
	  PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
ali@24
  1054
	plover_vector_free(selected_packages);
ali@24
  1055
	return FALSE;
ali@24
  1056
    }
ali@24
  1057
    retval=plover_transaction_helper_install_packages(helper,selected_packages,
ali@24
  1058
      error);
ali@24
  1059
    plover_vector_free(selected_packages);
ali@24
  1060
    return retval;
ali@24
  1061
}
ali@24
  1062
ali@24
  1063
/*
ali@24
  1064
 * Returns TRUE if there is work to be done or FALSE if the group is
ali@24
  1065
 * not installed or on error.
ali@24
  1066
 */
ali@24
  1067
gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
ali@24
  1068
  const char *group,GError **error)
ali@24
  1069
{
ali@24
  1070
    gboolean retval;
ali@24
  1071
    struct plover_vector *selected_packages;
ali@24
  1072
    PloverTransaction *transaction;
ali@24
  1073
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@61
  1074
    g_return_val_if_fail(plover_transaction_helper_get_installed(helper) != NULL,FALSE);
ali@24
  1075
    selected_packages=plover_transaction_helper_group_get_default_packages(
ali@24
  1076
      helper,group,error);
ali@24
  1077
    if (!selected_packages)
ali@24
  1078
	return FALSE;
ali@24
  1079
    if (!selected_packages->len)
ali@24
  1080
    {
ali@24
  1081
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
  1082
	  PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
ali@24
  1083
	plover_vector_free(selected_packages);
ali@24
  1084
	return FALSE;
ali@24
  1085
    }
ali@24
  1086
    transaction=plover_transaction_new();
ali@24
  1087
    plover_transaction_set_installed(transaction,helper->installed);
ali@24
  1088
    if (!plover_transaction_remove(transaction,selected_packages->strings,
ali@24
  1089
      error))
ali@24
  1090
    {
ali@24
  1091
	plover_vector_free(selected_packages);
ali@24
  1092
	g_object_unref(transaction);
ali@24
  1093
	return FALSE;
ali@24
  1094
    }
ali@24
  1095
    retval=plover_transaction_helper_add_transaction(helper,transaction,
ali@38
  1096
      NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
ali@24
  1097
    g_object_unref(transaction);
ali@24
  1098
    plover_vector_free(selected_packages);
ali@24
  1099
    return retval;
ali@24
  1100
}
ali@24
  1101
ali@24
  1102
/*
ali@24
  1103
 * Returns TRUE if there is work to be done or FALSE if all updates have
ali@24
  1104
 * already been applied or on error.
ali@24
  1105
 */
ali@24
  1106
gboolean plover_transaction_helper_update(PloverTransactionHelper *helper,
ali@24
  1107
  GError **error)
ali@24
  1108
{
ali@24
  1109
    gboolean retval;
ali@24
  1110
    PloverTransaction *transaction;
ali@24
  1111
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
  1112
    transaction=plover_transaction_helper_new_transaction(helper,error);
ali@24
  1113
    if (!transaction)
ali@24
  1114
	return FALSE;
ali@24
  1115
    if (!plover_transaction_update(transaction,NULL,error))
ali@24
  1116
    {
ali@24
  1117
	g_object_unref(transaction);
ali@24
  1118
	return FALSE;
ali@24
  1119
    }
ali@24
  1120
    retval=plover_transaction_helper_add_transaction(helper,transaction,
ali@38
  1121
      NULL,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,error);
ali@24
  1122
    g_object_unref(transaction);
ali@24
  1123
    return retval;
ali@24
  1124
}
ali@24
  1125
ali@24
  1126
gboolean plover_transaction_helper_get_visible(PloverTransactionHelper *helper)
ali@24
  1127
{
ali@24
  1128
    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
ali@24
  1129
    if (helper->error_dialog)
ali@24
  1130
	return TRUE;
ali@24
  1131
    else if (!helper->assistant)
ali@24
  1132
	return FALSE;
ali@24
  1133
    else
ali@24
  1134
	return gtk_widget_get_visible(GTK_WIDGET(helper->assistant));
ali@24
  1135
}
ali@24
  1136
ali@24
  1137
void plover_transaction_helper_present(PloverTransactionHelper *helper)
ali@24
  1138
{
ali@24
  1139
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
  1140
    if (helper->error_dialog)
ali@24
  1141
	gtk_window_present(GTK_WINDOW(helper->error_dialog));
ali@24
  1142
    else if (helper->assistant)
ali@24
  1143
	gtk_window_present(GTK_WINDOW(helper->assistant));
ali@24
  1144
}
ali@24
  1145
ali@24
  1146
static void
ali@24
  1147
  plover_transaction_helper_error_dialog_response(GtkDialog *error_dialog,
ali@24
  1148
  int response_id,PloverTransactionHelper *helper)
ali@24
  1149
{
ali@24
  1150
    g_signal_handlers_disconnect_by_data(error_dialog,helper);
ali@24
  1151
    if ((GtkWidget *)error_dialog==helper->error_dialog)
ali@24
  1152
    {
ali@24
  1153
	gtk_widget_destroy(helper->error_dialog);
ali@24
  1154
	helper->error_dialog=NULL;
ali@24
  1155
	if (helper->assistant)
ali@24
  1156
	{
ali@24
  1157
	    gtk_widget_hide(GTK_WIDGET(helper->assistant));
ali@24
  1158
	    gtk_assistant_set_current_page(helper->assistant,0);
ali@24
  1159
	}
ali@24
  1160
	g_signal_emit(helper,signals[CLOSE],0);
ali@24
  1161
    }
ali@24
  1162
}
ali@24
  1163
ali@24
  1164
const char *plover_transaction_helper_get_error(PloverTransactionHelper *helper,
ali@24
  1165
  const GError **error)
ali@24
  1166
{
ali@24
  1167
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
  1168
    if (!helper->error_dialog)
ali@24
  1169
	return NULL;
ali@24
  1170
    if (error)
ali@24
  1171
	*error=helper->error;
ali@24
  1172
    return helper->error_primary_text;
ali@24
  1173
}
ali@24
  1174
ali@24
  1175
void plover_transaction_helper_set_error(PloverTransactionHelper *helper,
ali@24
  1176
  const GError *error,const char *primary_text)
ali@24
  1177
{
ali@24
  1178
    GtkMessageType type;
ali@24
  1179
    GtkWindow *window;
ali@24
  1180
    g_return_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper));
ali@24
  1181
    g_return_if_fail(error != NULL);
ali@24
  1182
    g_return_if_fail(primary_text != NULL);
ali@24
  1183
    if (helper->pulse_handler)
ali@24
  1184
    {
ali@24
  1185
	g_source_remove(helper->pulse_handler);
ali@24
  1186
	helper->pulse_handler=0;
ali@24
  1187
    }
ali@24
  1188
    if (helper->error_dialog)
ali@24
  1189
    {
ali@24
  1190
	gtk_widget_destroy(helper->error_dialog);
ali@24
  1191
	helper->error_dialog=NULL;
ali@24
  1192
    }
ali@24
  1193
    g_free(helper->error_primary_text);
ali@24
  1194
    helper->error_primary_text=g_strdup(primary_text);
ali@24
  1195
    g_clear_error(&helper->error);
ali@24
  1196
    helper->error=g_error_copy(error);
ali@24
  1197
    if (g_error_matches(error,PLOVER_GENERAL_ERROR,
ali@24
  1198
      PLOVER_GENERAL_ERROR_NO_WORK))
ali@24
  1199
	type=GTK_MESSAGE_INFO;
ali@24
  1200
    else
ali@24
  1201
	type=GTK_MESSAGE_ERROR;
ali@24
  1202
    if (helper->assistant)
ali@24
  1203
	window=GTK_WINDOW(helper->assistant);
ali@24
  1204
    else
ali@24
  1205
    	window=NULL;
ali@24
  1206
    helper->error_dialog=gtk_message_dialog_new(window,
ali@24
  1207
      GTK_DIALOG_DESTROY_WITH_PARENT,type,GTK_BUTTONS_CLOSE,primary_text);
ali@24
  1208
    gtk_message_dialog_format_secondary_text(
ali@24
  1209
      GTK_MESSAGE_DIALOG(helper->error_dialog),error->message);
ali@24
  1210
    gtk_widget_show(helper->error_dialog);
ali@24
  1211
    g_signal_connect(helper->error_dialog,"response",
ali@24
  1212
      G_CALLBACK(plover_transaction_helper_error_dialog_response),helper);
ali@24
  1213
}