plover/transaction.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jul 08 08:26:29 2016 +0100 (2016-07-08)
changeset 59 296eac3183bc
parent 50 a4f43ad0e0c8
child 61 31fb35727621
permissions -rw-r--r--
Second steps towards adding updatez
ali@24
     1
/*
ali@38
     2
 * Copyright (C) 2009, 2011, 2012, 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@24
    21
#include <string.h>
ali@24
    22
#include <errno.h>
ali@24
    23
#include <unistd.h>
ali@24
    24
#include <glib-object.h>
ali@24
    25
#include "plover/transaction.h"
ali@24
    26
#include "plover/plover.h"
ali@24
    27
ali@24
    28
G_DEFINE_TYPE(PloverTransaction,plover_transaction,G_TYPE_OBJECT);
ali@24
    29
ali@24
    30
enum {
ali@24
    31
    STATUS_CHANGED=0,
ali@24
    32
    N_SIGNALS
ali@24
    33
};
ali@24
    34
ali@38
    35
typedef struct _PloverTransactionPrivate {
ali@38
    36
    GMutex mutex;
ali@38
    37
    gchar *status;
ali@38
    38
} PloverTransactionPrivate;
ali@38
    39
ali@38
    40
#define PLOVER_TRANSACTION_GET_PRIVATE(obj)\
ali@38
    41
				G_TYPE_INSTANCE_GET_PRIVATE(obj,\
ali@38
    42
				  PLOVER_TYPE_TRANSACTION,\
ali@38
    43
				  PloverTransactionPrivate)
ali@38
    44
ali@24
    45
static guint signals[N_SIGNALS];
ali@24
    46
ali@24
    47
static void plover_transaction_finalize(PloverTransaction *transaction)
ali@24
    48
{
ali@38
    49
    PloverTransactionPrivate *priv=PLOVER_TRANSACTION_GET_PRIVATE(transaction);
ali@38
    50
    g_free(priv->status);
ali@38
    51
    g_mutex_clear(&priv->mutex);
ali@24
    52
    g_free(transaction->base);
ali@24
    53
    g_free(transaction->prefix);
ali@24
    54
    g_free(transaction->unsatisfied);
ali@24
    55
    if (transaction->trans)
ali@24
    56
	razor_transaction_destroy(transaction->trans);
ali@24
    57
    if (transaction->relocations)
ali@24
    58
	razor_relocations_destroy(transaction->relocations);
ali@24
    59
    if (transaction->install_iterator)
ali@24
    60
	razor_install_iterator_destroy(transaction->install_iterator);
ali@24
    61
    if (transaction->next)
ali@24
    62
	razor_set_unref(transaction->next);
ali@24
    63
    if (transaction->system)
ali@24
    64
	razor_set_unref(transaction->system);
ali@24
    65
}
ali@24
    66
ali@24
    67
static void plover_transaction_dispose(PloverTransaction *transaction)
ali@24
    68
{
ali@24
    69
    g_clear_object(&transaction->installed);
ali@24
    70
    g_clear_object(&transaction->relocated);
ali@24
    71
    g_clear_object(&transaction->upstream);
ali@24
    72
}
ali@24
    73
ali@24
    74
static void plover_transaction_class_init(PloverTransactionClass *klass)
ali@24
    75
{
ali@24
    76
    GObjectClass *gobject_class=G_OBJECT_CLASS(klass);
ali@50
    77
    plover__uri_handler_init();
ali@24
    78
    gobject_class->finalize=(void (*)(GObject *))plover_transaction_finalize;
ali@24
    79
    gobject_class->dispose=(void (*)(GObject *))plover_transaction_dispose;
ali@24
    80
    signals[STATUS_CHANGED]=g_signal_new("status-changed",
ali@24
    81
      G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,0,NULL,NULL,
ali@24
    82
      g_cclosure_marshal_VOID__STRING,G_TYPE_NONE,1,G_TYPE_STRING);
ali@38
    83
    g_type_class_add_private(klass,sizeof(PloverTransactionPrivate));
ali@24
    84
}
ali@24
    85
ali@24
    86
static void plover_transaction_init(PloverTransaction *transaction)
ali@24
    87
{
ali@38
    88
    PloverTransactionPrivate *priv=PLOVER_TRANSACTION_GET_PRIVATE(transaction);
ali@38
    89
    g_mutex_init(&priv->mutex);
ali@24
    90
}
ali@24
    91
ali@24
    92
gboolean plover_transaction_resolve(PloverTransaction *transaction,
ali@24
    93
  GError **error)
ali@24
    94
{
ali@24
    95
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
    96
    if (!(transaction->flags&PLOVER_TRANSACTION_RESOLVED))
ali@24
    97
    {
ali@24
    98
	razor_transaction_resolve(transaction->trans);
ali@24
    99
	transaction->flags|=PLOVER_TRANSACTION_RESOLVED;
ali@24
   100
	g_free(transaction->unsatisfied);
ali@24
   101
	transaction->unsatisfied=NULL;
ali@24
   102
	if (razor_transaction_describe(transaction->trans)>0)
ali@24
   103
	    transaction->flags|=PLOVER_TRANSACTION_UNSATISFIED;
ali@24
   104
    }
ali@24
   105
    if (transaction->flags&PLOVER_TRANSACTION_UNSATISFIED)
ali@24
   106
    {
ali@24
   107
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   108
	  PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
ali@24
   109
	  "Package requirements not met");
ali@24
   110
	return FALSE;
ali@24
   111
    }
ali@24
   112
    return TRUE;
ali@24
   113
}
ali@24
   114
ali@24
   115
static void plover_transaction_unsatisfied_callback(const char *requirement,
ali@24
   116
  struct razor_package *package,const char *name,const char *version,
ali@24
   117
  const char *arch,void *data)
ali@24
   118
{
ali@24
   119
    GString *string=data;
ali@24
   120
    g_string_append_printf(string,"%s is needed by %s-%s.%s\n",requirement,name,
ali@24
   121
      version,arch);
ali@24
   122
}
ali@24
   123
ali@24
   124
const char *plover_transaction_get_unsatisfied(PloverTransaction *transaction)
ali@24
   125
{
ali@24
   126
    GString *unsatisfied;
ali@24
   127
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
ali@24
   128
    if (plover_transaction_resolve(transaction,NULL))
ali@24
   129
	return NULL;
ali@24
   130
    else if (!transaction->unsatisfied)
ali@24
   131
    {
ali@24
   132
	unsatisfied=g_string_new(NULL);
ali@24
   133
	if (!razor_transaction_unsatisfied(transaction->trans,
ali@24
   134
	  plover_transaction_unsatisfied_callback,unsatisfied))
ali@24
   135
	    /* Impossible */
ali@24
   136
	    g_string_assign(unsatisfied,
ali@24
   137
	      "Unknown package requirements unsatisfied");
ali@24
   138
	transaction->unsatisfied=g_string_free(unsatisfied,FALSE);
ali@24
   139
    }
ali@24
   140
    return transaction->unsatisfied;
ali@24
   141
}
ali@24
   142
ali@24
   143
struct razor_set *plover_transaction_get_system_set(
ali@24
   144
  PloverTransaction *transaction)
ali@24
   145
{
ali@24
   146
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
ali@24
   147
    if (!transaction->system && transaction->installed)
ali@24
   148
    {
ali@24
   149
	transaction->system=
ali@24
   150
	  plover_package_set_get_razor(transaction->installed);
ali@24
   151
	if (transaction->system)
ali@24
   152
	    razor_set_ref(transaction->system);
ali@24
   153
    }
ali@24
   154
    return transaction->system;
ali@24
   155
}
ali@24
   156
ali@24
   157
struct razor_set *plover_transaction_get_next_set(
ali@24
   158
  PloverTransaction *transaction,GError **error)
ali@24
   159
{
ali@24
   160
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
ali@24
   161
    if (!transaction->next)
ali@24
   162
    {
ali@24
   163
	if (!plover_transaction_resolve(transaction,error))
ali@24
   164
	    return NULL;
ali@24
   165
	transaction->next=razor_transaction_commit(transaction->trans);
ali@24
   166
    }
ali@24
   167
    return transaction->next;
ali@24
   168
}
ali@24
   169
ali@24
   170
struct razor_install_iterator *plover_transaction_get_install_iterator(
ali@24
   171
  PloverTransaction *transaction,GError **error)
ali@24
   172
{
ali@24
   173
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
ali@24
   174
    if (!transaction->install_iterator)
ali@24
   175
    {
ali@24
   176
	if (!plover_transaction_get_next_set(transaction,error))
ali@24
   177
	    return NULL;
ali@24
   178
	(void)plover_transaction_get_system_set(transaction);
ali@24
   179
	transaction->install_iterator=
ali@24
   180
	  razor_set_create_install_iterator(transaction->system,
ali@24
   181
	  transaction->next);
ali@24
   182
    }
ali@24
   183
    razor_install_iterator_rewind(transaction->install_iterator);
ali@24
   184
    return transaction->install_iterator;
ali@24
   185
}
ali@24
   186
ali@38
   187
static gboolean
ali@38
   188
  plover_transaction_emit_status_changed(PloverTransaction *transaction)
ali@38
   189
{
ali@38
   190
    gchar *status;
ali@38
   191
    PloverTransactionPrivate *priv=PLOVER_TRANSACTION_GET_PRIVATE(transaction);
ali@38
   192
    g_mutex_lock(&priv->mutex);
ali@38
   193
    status=g_strdup(priv->status);
ali@38
   194
    g_mutex_unlock(&priv->mutex);
ali@38
   195
    g_signal_emit(transaction,signals[STATUS_CHANGED],0,status);
ali@38
   196
    g_free(status);
ali@38
   197
    return FALSE;	/* No more calls */
ali@38
   198
}
ali@38
   199
ali@38
   200
static void plover_transaction_set_status(PloverTransaction *transaction,
ali@38
   201
  gboolean via_g_idle,const char *status)
ali@38
   202
{
ali@38
   203
    PloverTransactionPrivate *priv=PLOVER_TRANSACTION_GET_PRIVATE(transaction);
ali@38
   204
    g_mutex_lock(&priv->mutex);
ali@38
   205
    g_free(priv->status);
ali@38
   206
    priv->status=g_strdup(status);
ali@38
   207
    g_mutex_unlock(&priv->mutex);
ali@38
   208
    if (via_g_idle)
ali@38
   209
	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ali@38
   210
	  (GSourceFunc)plover_transaction_emit_status_changed,
ali@38
   211
	  g_object_ref(transaction),g_object_unref);
ali@38
   212
    else
ali@38
   213
	plover_transaction_emit_status_changed(transaction);
ali@38
   214
}
ali@38
   215
ali@24
   216
gboolean plover_transaction_commit(PloverTransaction *transaction,
ali@24
   217
  GCancellable *cancellable,GError **error)
ali@24
   218
{
ali@38
   219
    int r,count;
ali@38
   220
    unsigned files_action;
ali@24
   221
    gboolean retval;
ali@24
   222
    size_t pos;
ali@24
   223
    struct razor_set *set;
ali@38
   224
    struct razor_package *pkg;
ali@38
   225
    enum razor_install_action action;
ali@24
   226
    struct razor_install_iterator *ii;
ali@24
   227
    struct razor_atomic *atomic;
ali@24
   228
    PloverPackageSet *next;
ali@38
   229
    gboolean via_g_idle;
ali@24
   230
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   231
    if (g_cancellable_set_error_if_cancelled(cancellable,error))
ali@24
   232
	return FALSE;
ali@24
   233
    ii=plover_transaction_get_install_iterator(transaction,error);
ali@24
   234
    if (!ii)
ali@24
   235
	return FALSE;
ali@38
   236
    /*
ali@38
   237
     * If we are called from the default thread it is most useful to
ali@38
   238
     * emit signals directly however this is not safe when running in
ali@38
   239
     * a non-default thread and we want to use g_idle to emit signals
ali@38
   240
     * in the default thread instead.
ali@38
   241
     *
ali@38
   242
     * Note that the documentation for g_main_context_get_thread_default()
ali@38
   243
     * explicitly states that it may return a non-NULL value even when
ali@38
   244
     * called from the default thread. This would cause us to use g_idle
ali@38
   245
     * when not strictly necessary, but will still be safe.
ali@38
   246
     */
ali@38
   247
    via_g_idle=!!g_main_context_get_thread_default();
ali@24
   248
    do
ali@24
   249
    {
ali@24
   250
	if (g_cancellable_set_error_if_cancelled(cancellable,error))
ali@24
   251
	    return FALSE;
ali@24
   252
	pos=razor_install_iterator_tell(ii);
ali@38
   253
	plover_transaction_set_status(transaction,via_g_idle,
ali@24
   254
	  "Running pre-transaction scripts");
ali@24
   255
	atomic=razor_atomic_open("package transaction");
ali@24
   256
	next=plover_package_set_new_from_razor(transaction->next);
ali@24
   257
	r=plover_run_transaction(transaction->trans,ii,
ali@24
   258
	  plover_package_set_get_install_root(transaction->installed),
ali@24
   259
	  transaction->system,next,transaction->upstream,atomic,
ali@24
   260
	  transaction->relocations,RAZOR_STAGE_SCRIPTS_PRE,cancellable);
ali@24
   261
	if (r<0)
ali@24
   262
	{
ali@38
   263
	    plover_transaction_set_status(transaction,via_g_idle,
ali@24
   264
	      "Failed in pre-transaction scripts");
ali@24
   265
	    plover_propagate_razor_error_dup(error,
ali@24
   266
	      razor_atomic_get_error(atomic));
ali@24
   267
	    razor_atomic_destroy(atomic);
ali@24
   268
	    g_object_unref(next);
ali@24
   269
	    return FALSE;
ali@24
   270
	}
ali@24
   271
	else
ali@24
   272
	{
ali@38
   273
	    razor_install_iterator_seek(ii,pos);
ali@38
   274
	    files_action=0;
ali@38
   275
	    while (razor_install_iterator_next(ii,&pkg,&action,&count))
ali@38
   276
		if (action==RAZOR_INSTALL_ACTION_REMOVE)
ali@38
   277
		    files_action|=1;
ali@38
   278
		else if (action==RAZOR_INSTALL_ACTION_ADD)
ali@38
   279
		    files_action|=2;
ali@38
   280
		else
ali@38
   281
		    break;
ali@38
   282
	    plover_transaction_set_status(transaction,via_g_idle,
ali@38
   283
	      files_action==1?"Removing files":"Unpacking files");
ali@24
   284
	    razor_install_iterator_seek(ii,pos);
ali@24
   285
	    r=plover_run_transaction(transaction->trans,ii,
ali@24
   286
	      plover_package_set_get_install_root(transaction->installed),
ali@24
   287
	      transaction->system,next,transaction->upstream,
ali@24
   288
	      atomic,transaction->relocations,RAZOR_STAGE_FILES,
ali@24
   289
#if RAZOR_HAVE_ATOMIC_ROLLBACK
ali@24
   290
	      cancellable);
ali@24
   291
#else
ali@24
   292
	      NULL);
ali@24
   293
#endif
ali@24
   294
	    if (r==1)
ali@24
   295
	    {
ali@24
   296
		set=razor_install_iterator_commit_set(ii);
ali@24
   297
		plover_package_set_update(transaction->installed,set,atomic);
ali@24
   298
		razor_set_unref(set);
ali@24
   299
	    }
ali@24
   300
	    else if (!r)
ali@24
   301
		plover_package_set_update(transaction->installed,
ali@24
   302
		  transaction->next,atomic);
ali@24
   303
	    retval=!razor_atomic_commit(atomic);
ali@24
   304
	    if (!retval)
ali@24
   305
	    {
ali@38
   306
		plover_transaction_set_status(transaction,via_g_idle,
ali@24
   307
		  "Failed to unpack all files correctly");
ali@24
   308
		plover_propagate_razor_error_dup(error,
ali@24
   309
		  razor_atomic_get_error(atomic));
ali@24
   310
	    }
ali@24
   311
	    else
ali@24
   312
	    {
ali@38
   313
		plover_transaction_set_status(transaction,via_g_idle,
ali@24
   314
		  "Running post-transaction scripts");
ali@24
   315
		razor_install_iterator_seek(ii,pos);
ali@24
   316
		plover_run_transaction(transaction->trans,ii,
ali@24
   317
		  plover_package_set_get_install_root(transaction->installed),
ali@24
   318
		  transaction->system,next,transaction->upstream,
ali@24
   319
		  atomic,transaction->relocations,RAZOR_STAGE_SCRIPTS_POST,
ali@24
   320
		  NULL);
ali@24
   321
	    }
ali@24
   322
	}
ali@24
   323
	razor_atomic_destroy(atomic);
ali@24
   324
	g_object_unref(next);
ali@24
   325
    } while(retval && r==1);
ali@38
   326
    plover_transaction_set_status(transaction,via_g_idle,"Completed");
ali@24
   327
    return retval;
ali@24
   328
}
ali@24
   329
ali@24
   330
static void plover_transaction_commit_async_thread(GTask *task,
ali@24
   331
  gpointer source_object,gpointer task_data,GCancellable *cancellable)
ali@24
   332
{
ali@24
   333
    PloverTransaction *transaction=source_object;
ali@24
   334
    GError *error=NULL;
ali@38
   335
    GMainContext *context;
ali@38
   336
    gboolean retval;
ali@38
   337
    context=g_main_context_new();
ali@38
   338
    g_main_context_push_thread_default(context);
ali@38
   339
    retval=plover_transaction_commit(transaction,cancellable,&error);
ali@38
   340
    g_main_context_pop_thread_default(context);
ali@38
   341
    g_main_context_unref(context);
ali@38
   342
    if (!retval)
ali@24
   343
	g_task_return_error(task,error);
ali@24
   344
    else
ali@24
   345
	g_task_return_boolean(task,TRUE);
ali@24
   346
}
ali@24
   347
ali@24
   348
void plover_transaction_commit_async(PloverTransaction *transaction,
ali@24
   349
  GCancellable *cancellable,GAsyncReadyCallback callback,gpointer user_data)
ali@24
   350
{
ali@24
   351
    GTask *task;
ali@24
   352
    g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
ali@24
   353
    task=g_task_new(transaction,cancellable,callback,user_data);
ali@24
   354
    g_task_run_in_thread(task,plover_transaction_commit_async_thread);
ali@38
   355
    g_object_unref(task);
ali@24
   356
}
ali@24
   357
ali@24
   358
gboolean plover_transaction_commit_finish(PloverTransaction *transaction,
ali@24
   359
  GAsyncResult *result,GError **error)
ali@24
   360
{
ali@24
   361
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   362
    g_return_val_if_fail(g_task_is_valid(result,transaction),FALSE);
ali@24
   363
    return g_task_propagate_boolean(G_TASK(result),error);
ali@24
   364
}
ali@24
   365
ali@24
   366
static int plover_mark_package_for_update(struct razor_transaction *trans,
ali@24
   367
  struct razor_set *set,const char *pkg)
ali@24
   368
{
ali@24
   369
    struct razor_package_iterator *pi;
ali@24
   370
    struct razor_package *package;
ali@24
   371
    const char *name;
ali@24
   372
    int retval=-1;
ali@24
   373
    pi=razor_package_iterator_create(set);
ali@24
   374
    while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
ali@24
   375
      RAZOR_DETAIL_LAST))
ali@24
   376
    {
ali@24
   377
	if (!strcmp(name,pkg))
ali@24
   378
	{
ali@24
   379
	    razor_transaction_update_package(trans,package);
ali@24
   380
	    retval=0;
ali@24
   381
	    break;
ali@24
   382
	}
ali@24
   383
    }
ali@24
   384
    razor_package_iterator_destroy(pi);
ali@24
   385
    return retval;
ali@24
   386
}
ali@24
   387
ali@24
   388
PloverTransaction *plover_transaction_new(void)
ali@24
   389
{
ali@24
   390
    return PLOVER_TRANSACTION(g_object_new(PLOVER_TYPE_TRANSACTION,NULL));
ali@24
   391
}
ali@24
   392
ali@24
   393
void plover_transaction_set_prefix(PloverTransaction *transaction,
ali@24
   394
  const char *prefix)
ali@24
   395
{
ali@24
   396
    g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
ali@24
   397
    g_return_if_fail(transaction->upstream == NULL);
ali@24
   398
    if (!g_strcmp0(prefix,transaction->prefix))
ali@24
   399
	return;
ali@24
   400
    if (transaction->relocations)
ali@24
   401
	razor_relocations_destroy(transaction->relocations);
ali@24
   402
    g_free(transaction->prefix);
ali@24
   403
    if (prefix)
ali@24
   404
    {
ali@24
   405
	transaction->relocations=razor_relocations_create();
ali@24
   406
	razor_relocations_add(transaction->relocations,"/usr",prefix);
ali@24
   407
    }
ali@24
   408
    else
ali@24
   409
	transaction->relocations=NULL;
ali@24
   410
    transaction->prefix=g_strdup(prefix);
ali@24
   411
}
ali@24
   412
ali@24
   413
void plover_transaction_set_installed(PloverTransaction *transaction,
ali@24
   414
  PloverPackageSet *installed)
ali@24
   415
{
ali@24
   416
    g_return_if_fail(PLOVER_IS_TRANSACTION(transaction));
ali@24
   417
    g_return_if_fail(PLOVER_IS_PACKAGE_SET(installed));
ali@38
   418
    if (transaction->system)
ali@38
   419
    {
ali@38
   420
	razor_set_unref(transaction->system);
ali@38
   421
	transaction->system=NULL;
ali@38
   422
    }
ali@24
   423
    if (transaction->installed)
ali@24
   424
	g_object_unref(transaction->installed);
ali@24
   425
    transaction->installed=g_object_ref(installed);
ali@24
   426
}
ali@24
   427
ali@24
   428
gboolean plover_transaction_root_open(PloverTransaction *transaction,
ali@24
   429
  const char *install_root,GError **error)
ali@24
   430
{
ali@24
   431
    PloverPackageSet *installed;
ali@42
   432
    const char *install_uri;
ali@42
   433
    gchar *install_path;
ali@42
   434
    GFile *file;
ali@42
   435
    gboolean retval;
ali@24
   436
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   437
    if (!install_root)
ali@42
   438
    {
ali@42
   439
	install_uri=g_getenv("RAZOR_ROOT");
ali@42
   440
	if (install_uri)
ali@42
   441
	{
ali@42
   442
	    file=g_file_new_for_uri(install_uri);
ali@42
   443
	    install_path=g_file_get_path(file);
ali@42
   444
	    g_object_unref(file);
ali@42
   445
	    if (!install_path)
ali@42
   446
	    {
ali@42
   447
		g_set_error(error,PLOVER_GENERAL_ERROR,
ali@42
   448
		  PLOVER_GENERAL_ERROR_FAILED,
ali@42
   449
		  "%s: Not a local URI",install_uri);
ali@42
   450
		return FALSE;
ali@42
   451
	    }
ali@42
   452
	}
ali@42
   453
	else
ali@42
   454
	    install_path=g_strdup("/");
ali@42
   455
    }
ali@42
   456
    else
ali@42
   457
	install_path=g_strdup(install_root);
ali@42
   458
    if (transaction->installed && !g_strcmp0(install_path,
ali@24
   459
      plover_package_set_get_install_root(transaction->installed)))
ali@42
   460
    {
ali@42
   461
	g_free(install_path);
ali@24
   462
	return TRUE;
ali@42
   463
    }
ali@24
   464
    installed=plover_package_set_new();
ali@42
   465
    retval=plover_package_set_open(installed,install_path,TRUE,error);
ali@42
   466
    if (retval)
ali@42
   467
	plover_transaction_set_installed(transaction,installed);
ali@42
   468
    else
ali@24
   469
	g_object_unref(installed);
ali@42
   470
    g_free(install_path);
ali@42
   471
    return retval;
ali@24
   472
}
ali@24
   473
ali@24
   474
struct razor_set *plover_transaction_import_yum(PloverTransaction *transaction,
ali@24
   475
  const char *base,GError **error)
ali@24
   476
{
ali@24
   477
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),NULL);
ali@24
   478
    g_return_val_if_fail(transaction->base == NULL,NULL);
ali@24
   479
    transaction->base=g_strdup(base);
ali@24
   480
    return plover_razor_set_create_from_yum(base,error);
ali@24
   481
}
ali@24
   482
ali@24
   483
gboolean plover_transaction_set_upstream(PloverTransaction *transaction,
ali@24
   484
  PloverRepository *upstream,GError **error)
ali@24
   485
{
ali@24
   486
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   487
    g_return_val_if_fail(PLOVER_IS_REPOSITORY(upstream),FALSE);
ali@24
   488
    g_return_val_if_fail(transaction->upstream == NULL,FALSE);
ali@24
   489
    transaction->relocated=plover_package_set_new_from_repository(upstream,
ali@24
   490
      transaction->relocations,error);
ali@24
   491
    if (transaction->relocated)
ali@24
   492
	transaction->upstream=g_object_ref(upstream);
ali@24
   493
    return !!transaction->relocated;
ali@24
   494
}
ali@24
   495
ali@24
   496
gboolean
ali@43
   497
  plover_transaction_set_upstream_from_yum_uri(PloverTransaction *transaction,
ali@43
   498
  const char *base_uri,GError **error)
ali@24
   499
{
ali@24
   500
    gboolean retval;
ali@24
   501
    PloverRepository *upstream;
ali@24
   502
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   503
    g_return_val_if_fail(transaction->upstream == NULL,FALSE);
ali@43
   504
    upstream=plover_repository_new_from_yum_uri(base_uri,error);
ali@24
   505
    if (!upstream)
ali@24
   506
	return FALSE;
ali@24
   507
    retval=plover_transaction_set_upstream(transaction,upstream,error);
ali@24
   508
    g_object_unref(upstream);
ali@24
   509
    return retval;
ali@24
   510
}
ali@24
   511
ali@43
   512
gboolean
ali@43
   513
  plover_transaction_set_upstream_from_yum(PloverTransaction *transaction,
ali@43
   514
  const char *base,GError **error)
ali@43
   515
{
ali@43
   516
    gboolean retval;
ali@43
   517
    gchar *base_uri;
ali@43
   518
    GFile *file;
ali@43
   519
    file=g_file_new_for_path(base);
ali@43
   520
    base_uri=g_file_get_uri(file);
ali@43
   521
    g_object_unref(file);
ali@43
   522
    retval=plover_transaction_set_upstream_from_yum_uri(transaction,base_uri,error);
ali@43
   523
    g_free(base_uri);
ali@43
   524
    return retval;
ali@43
   525
}
ali@43
   526
ali@24
   527
gboolean plover_transaction_install(PloverTransaction *transaction,
ali@24
   528
  char **pkgs,GError **error)
ali@24
   529
{
ali@24
   530
    int i;
ali@24
   531
    struct razor_set *system,*upstream;
ali@24
   532
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   533
    g_return_val_if_fail(transaction->upstream != NULL,FALSE);
ali@24
   534
    g_return_val_if_fail(transaction->trans == NULL,FALSE);
ali@24
   535
    if (!plover_transaction_root_open(transaction,NULL,error))
ali@24
   536
	return FALSE;
ali@24
   537
    system=plover_transaction_get_system_set(transaction);
ali@24
   538
    if (!system)
ali@24
   539
    {
ali@38
   540
	/* Impossible */
ali@24
   541
	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   542
	  "Internal error: No system set");
ali@24
   543
	return FALSE;
ali@24
   544
    }
ali@24
   545
    upstream=plover_package_set_get_razor(transaction->relocated);
ali@24
   546
    transaction->trans=razor_transaction_create(system,upstream);
ali@24
   547
    for(i=0;pkgs[i];i++)
ali@24
   548
	if (plover_mark_package_for_update(transaction->trans,system,pkgs[i]) &&
ali@24
   549
	  plover_mark_package_for_update(transaction->trans,upstream,pkgs[i]))
ali@24
   550
	{
ali@24
   551
	    g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   552
	      PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
ali@24
   553
	      "Package not found");
ali@24
   554
	    razor_transaction_destroy(transaction->trans);
ali@24
   555
	    transaction->trans=NULL;
ali@24
   556
	    return FALSE;
ali@24
   557
	    break;
ali@24
   558
	}
ali@24
   559
    return TRUE;
ali@24
   560
}
ali@24
   561
ali@24
   562
gboolean plover_transaction_update(PloverTransaction *transaction,
ali@24
   563
  char **pkgs,GError **error)
ali@24
   564
{
ali@24
   565
    int i;
ali@24
   566
    struct razor_set *system,*upstream;
ali@24
   567
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   568
    g_return_val_if_fail(transaction->upstream != NULL,FALSE);
ali@24
   569
    g_return_val_if_fail(transaction->trans == NULL,FALSE);
ali@24
   570
    if (!plover_transaction_root_open(transaction,NULL,error))
ali@24
   571
	return FALSE;
ali@24
   572
    system=plover_transaction_get_system_set(transaction);
ali@24
   573
    if (!system)
ali@24
   574
    {
ali@38
   575
	/* Impossible */
ali@24
   576
	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   577
	  "Internal error: No system set");
ali@24
   578
	return FALSE;
ali@24
   579
    }
ali@24
   580
    upstream=plover_package_set_get_razor(transaction->relocated);
ali@24
   581
    transaction->trans=razor_transaction_create(system,upstream);
ali@24
   582
    if (!pkgs)
ali@24
   583
	razor_transaction_update_all(transaction->trans);
ali@24
   584
    else
ali@24
   585
	for(i=0;pkgs[i];i++)
ali@24
   586
	    if (plover_mark_package_for_update(transaction->trans,system,
ali@24
   587
	      pkgs[i]))
ali@24
   588
	    {
ali@24
   589
		g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   590
		  PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
ali@24
   591
		  "Package not found");
ali@24
   592
		razor_transaction_destroy(transaction->trans);
ali@24
   593
		transaction->trans=NULL;
ali@24
   594
		return FALSE;
ali@24
   595
		break;
ali@24
   596
	    }
ali@24
   597
    return TRUE;
ali@24
   598
}
ali@24
   599
ali@43
   600
PloverTransaction *plover_transaction_new_install_uri(const char *base_uri,
ali@24
   601
  const char *prefix,char **pkgs,GError **error)
ali@24
   602
{
ali@24
   603
    PloverTransaction *transaction;
ali@24
   604
    transaction=plover_transaction_new();
ali@24
   605
    plover_transaction_set_prefix(transaction,prefix);
ali@43
   606
    if (!plover_transaction_set_upstream_from_yum_uri(transaction,base_uri,error))
ali@24
   607
    {
ali@24
   608
	g_object_unref(transaction);
ali@24
   609
	return NULL;
ali@24
   610
    }
ali@24
   611
    if (!plover_transaction_install(transaction,pkgs,error))
ali@24
   612
    {
ali@24
   613
	g_object_unref(transaction);
ali@24
   614
	return NULL;
ali@24
   615
    }
ali@24
   616
    return transaction;
ali@24
   617
}
ali@24
   618
ali@43
   619
PloverTransaction *plover_transaction_new_install(const char *base,
ali@43
   620
  const char *prefix,char **pkgs,GError **error)
ali@43
   621
{
ali@43
   622
    PloverTransaction *transaction;
ali@43
   623
    gchar *base_uri;
ali@43
   624
    GFile *file;
ali@43
   625
    file=g_file_new_for_path(base);
ali@43
   626
    base_uri=g_file_get_uri(file);
ali@43
   627
    g_object_unref(file);
ali@43
   628
    transaction=plover_transaction_new_install_uri(base_uri,prefix,pkgs,error);
ali@43
   629
    g_free(base_uri);
ali@43
   630
    return transaction;
ali@43
   631
}
ali@43
   632
ali@59
   633
PloverTransaction *plover_transaction_new_update_uri(const char *base_uri,
ali@59
   634
  const char *prefix,char **pkgs,GError **error)
ali@59
   635
{
ali@59
   636
    PloverTransaction *transaction;
ali@59
   637
    transaction=plover_transaction_new();
ali@59
   638
    plover_transaction_set_prefix(transaction,prefix);
ali@59
   639
    if (!plover_transaction_set_upstream_from_yum_uri(transaction,base_uri,
ali@59
   640
      error))
ali@59
   641
    {
ali@59
   642
	g_object_unref(transaction);
ali@59
   643
	return NULL;
ali@59
   644
    }
ali@59
   645
    if (!plover_transaction_update(transaction,pkgs,error))
ali@59
   646
    {
ali@59
   647
	g_object_unref(transaction);
ali@59
   648
	return NULL;
ali@59
   649
    }
ali@59
   650
    return transaction;
ali@59
   651
}
ali@59
   652
ali@24
   653
PloverTransaction *plover_transaction_new_update(const char *base,
ali@24
   654
  const char *prefix,char **pkgs,GError **error)
ali@24
   655
{
ali@24
   656
    PloverTransaction *transaction;
ali@24
   657
    transaction=plover_transaction_new();
ali@24
   658
    plover_transaction_set_prefix(transaction,prefix);
ali@24
   659
    if (!plover_transaction_set_upstream_from_yum(transaction,base,error))
ali@24
   660
    {
ali@24
   661
	g_object_unref(transaction);
ali@24
   662
	return NULL;
ali@24
   663
    }
ali@24
   664
    if (!plover_transaction_update(transaction,pkgs,error))
ali@24
   665
    {
ali@24
   666
	g_object_unref(transaction);
ali@24
   667
	return NULL;
ali@24
   668
    }
ali@24
   669
    return transaction;
ali@24
   670
}
ali@24
   671
ali@24
   672
static int plover_mark_packages_for_removal(struct razor_transaction *trans,
ali@24
   673
  struct razor_set *set,const char *pkg)
ali@24
   674
{
ali@24
   675
    struct razor_package_iterator *pi;
ali@24
   676
    struct razor_package *package;
ali@24
   677
    const char *name;
ali@24
   678
    int retval=pkg?-1:0;
ali@24
   679
    pi=razor_package_iterator_create(set);
ali@24
   680
    while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
ali@24
   681
      RAZOR_DETAIL_LAST))
ali@24
   682
    {
ali@24
   683
	if (!pkg || !strcmp(name,pkg))
ali@24
   684
	{
ali@24
   685
	    razor_transaction_remove_package(trans,package);
ali@24
   686
	    retval=0;
ali@24
   687
	}
ali@24
   688
    }
ali@24
   689
    razor_package_iterator_destroy(pi);
ali@24
   690
    return retval;
ali@24
   691
}
ali@24
   692
ali@24
   693
gboolean plover_transaction_remove(PloverTransaction *transaction,
ali@24
   694
  char **pkgs,GError **error)
ali@24
   695
{
ali@24
   696
    int i;
ali@24
   697
    struct razor_set *system,*empty;
ali@24
   698
    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
ali@24
   699
    g_return_val_if_fail(transaction->trans == NULL,FALSE);
ali@24
   700
    if (!plover_transaction_root_open(transaction,NULL,error))
ali@24
   701
	return FALSE;
ali@24
   702
    system=plover_transaction_get_system_set(transaction);
ali@24
   703
    if (!system)
ali@24
   704
    {
ali@38
   705
	/* Impossible */
ali@24
   706
	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@24
   707
	  "Internal error: No system set");
ali@24
   708
	return FALSE;
ali@24
   709
    }
ali@24
   710
    empty=razor_set_create_without_root();
ali@24
   711
    transaction->trans=razor_transaction_create(system,empty);
ali@24
   712
    razor_set_unref(empty);
ali@24
   713
    if (!pkgs)
ali@24
   714
	plover_mark_packages_for_removal(transaction->trans,system,NULL);
ali@24
   715
    else
ali@24
   716
	for(i=0;pkgs[i];i++)
ali@24
   717
	    if (plover_mark_packages_for_removal(transaction->trans,system,
ali@24
   718
	      pkgs[i]))
ali@24
   719
	    {
ali@24
   720
		g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   721
		  PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
ali@24
   722
		  "Package not found");
ali@24
   723
		razor_transaction_destroy(transaction->trans);
ali@24
   724
		transaction->trans=NULL;
ali@24
   725
		return FALSE;
ali@24
   726
		break;
ali@24
   727
	    }
ali@24
   728
    return TRUE;
ali@24
   729
}
ali@24
   730
ali@24
   731
PloverTransaction *plover_transaction_new_remove(char **pkgs,GError **error)
ali@24
   732
{
ali@24
   733
    PloverTransaction *transaction;
ali@24
   734
    transaction=plover_transaction_new();
ali@24
   735
    if (!plover_transaction_remove(transaction,pkgs,error))
ali@24
   736
    {
ali@24
   737
	g_object_unref(transaction);
ali@24
   738
	return NULL;
ali@24
   739
    }
ali@24
   740
    return transaction;
ali@24
   741
}
ali@24
   742
ali@38
   743
static GList *plover_what_has_property(struct razor_set *set,uint32_t prop_type,
ali@38
   744
  const char *ref_name)
ali@24
   745
{
ali@24
   746
    const char *name,*version;
ali@24
   747
    uint32_t flags;
ali@24
   748
    GList *list=NULL;
ali@24
   749
    struct razor_property *property;
ali@24
   750
    struct razor_package *package;
ali@38
   751
    struct razor_package_iterator *what_has;
ali@24
   752
    struct razor_property_iterator *all_props;
ali@24
   753
    all_props=razor_property_iterator_create(set,NULL);
ali@24
   754
    while (razor_property_iterator_next(all_props,&property,&name,&flags,
ali@24
   755
      &version))
ali@24
   756
    {
ali@38
   757
	if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=prop_type)
ali@24
   758
	    continue;
ali@24
   759
	if (strcmp(name,ref_name))
ali@24
   760
	    continue;
ali@38
   761
	what_has=razor_package_iterator_create_for_property(set,property);
ali@38
   762
	while(razor_package_iterator_next(what_has,&package,
ali@24
   763
	  RAZOR_DETAIL_LAST))
ali@24
   764
	    list=g_list_prepend(list,package);
ali@38
   765
	razor_package_iterator_destroy(what_has);
ali@24
   766
    }
ali@24
   767
    razor_property_iterator_destroy(all_props);
ali@24
   768
    return list;
ali@24
   769
}
ali@24
   770
ali@38
   771
static GList *plover_what_provides(struct razor_set *set,const char *ref_name)
ali@38
   772
{
ali@38
   773
    return plover_what_has_property(set,RAZOR_PROPERTY_PROVIDES,ref_name);
ali@38
   774
}
ali@38
   775
ali@38
   776
static GList *plover_what_requires(struct razor_set *set,const char *ref_name)
ali@38
   777
{
ali@38
   778
    return plover_what_has_property(set,RAZOR_PROPERTY_REQUIRES,ref_name);
ali@38
   779
}
ali@38
   780
ali@24
   781
PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs,
ali@24
   782
  GError **error)
ali@24
   783
{
ali@24
   784
    int i,changed,is_leaf;
ali@24
   785
    uint32_t flags;
ali@42
   786
    gchar *install_path;
ali@42
   787
    const char *install_uri;
ali@24
   788
    const char *name,*version,*maybe_unused_name;
ali@24
   789
    struct razor_set *system,*upstream;
ali@24
   790
    struct razor_transaction *trans;
ali@24
   791
    PloverPackageSet *installed;
ali@24
   792
    PloverTransaction *transaction;
ali@38
   793
    struct plover_vector *package_names;
ali@38
   794
    GList *to_remove,*lnk,*lnk2,*what_requires,*what_provides;
ali@42
   795
    GFile *file;
ali@38
   796
    struct razor_package *package,*maybe_unused_package;
ali@38
   797
    struct razor_property *property;
ali@38
   798
    struct razor_package_query *query;
ali@38
   799
    struct razor_package_iterator *all_packages,*removed;
ali@38
   800
    struct razor_property_iterator *removed_props;
ali@24
   801
    if (!pkgs)
ali@24
   802
	return plover_transaction_new_remove(NULL,error);
ali@42
   803
    install_uri=g_getenv("RAZOR_ROOT");
ali@42
   804
    if (install_uri)
ali@42
   805
    {
ali@42
   806
	file=g_file_new_for_uri(install_uri);
ali@42
   807
	install_path=g_file_get_path(file);
ali@42
   808
	g_object_unref(file);
ali@42
   809
	if (!install_path)
ali@42
   810
	{
ali@42
   811
	    g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
ali@42
   812
	      "%s: Not a local URI",install_uri);
ali@42
   813
	    return NULL;
ali@42
   814
	}
ali@42
   815
    }
ali@42
   816
    else
ali@42
   817
	install_path=g_strdup("/");
ali@24
   818
    installed=plover_package_set_new();
ali@42
   819
    if (!plover_package_set_open(installed,install_path,TRUE,error))
ali@24
   820
    {
ali@24
   821
	g_object_unref(installed);
ali@42
   822
	g_free(install_path);
ali@24
   823
	return NULL;
ali@24
   824
    }
ali@42
   825
    g_free(install_path);
ali@24
   826
    system=plover_package_set_get_razor(installed);
ali@24
   827
    package_names=plover_vector_new();
ali@24
   828
    for(i=0;pkgs[i];i++)
ali@24
   829
	plover_vector_append(package_names,pkgs[i]);
ali@24
   830
    to_remove=NULL;
ali@24
   831
    all_packages=razor_package_iterator_create(system);
ali@24
   832
    while (razor_package_iterator_next(all_packages,&package,
ali@24
   833
      RAZOR_DETAIL_NAME,&name,RAZOR_DETAIL_LAST))
ali@24
   834
	if (plover_vector_remove(package_names,name))
ali@24
   835
	    to_remove=g_list_prepend(to_remove,package);
ali@24
   836
    razor_package_iterator_destroy(all_packages);
ali@24
   837
    if (package_names->len)
ali@24
   838
    {
ali@24
   839
	g_set_error(error,PLOVER_GENERAL_ERROR,
ali@24
   840
	  PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",
ali@24
   841
	  package_names->strings[0],"Package not found");
ali@24
   842
	plover_vector_free(package_names);
ali@24
   843
	g_list_free(to_remove);
ali@24
   844
	g_object_unref(installed);
ali@24
   845
	return NULL;
ali@24
   846
    }
ali@24
   847
    plover_vector_free(package_names);
ali@24
   848
    do
ali@24
   849
    {
ali@24
   850
	changed=FALSE;
ali@24
   851
	query=razor_package_query_create(system);
ali@24
   852
	for(lnk=to_remove;lnk;lnk=lnk->next)
ali@24
   853
	    razor_package_query_add_package(query,lnk->data);
ali@24
   854
	removed=razor_package_query_finish(query);
ali@24
   855
	while(razor_package_iterator_next(removed,&package,RAZOR_DETAIL_LAST))
ali@24
   856
	{
ali@24
   857
	    removed_props=razor_property_iterator_create(system,package);
ali@24
   858
	    while (razor_property_iterator_next(removed_props,&property,&name,
ali@24
   859
	      &flags,&version))
ali@24
   860
	    {
ali@24
   861
		if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=RAZOR_PROPERTY_REQUIRES)
ali@24
   862
		    continue;
ali@38
   863
		what_provides=plover_what_provides(system,name);
ali@38
   864
		for(lnk2=what_provides;lnk2;lnk2=lnk2->next)
ali@24
   865
		{
ali@38
   866
		    maybe_unused_package=lnk2->data;
ali@24
   867
		    if (g_list_find(to_remove,maybe_unused_package))
ali@24
   868
			continue;
ali@24
   869
		    is_leaf=TRUE;
ali@38
   870
		    razor_package_get_details(system,maybe_unused_package,
ali@38
   871
		      RAZOR_DETAIL_NAME,&maybe_unused_name,RAZOR_DETAIL_LAST);
ali@24
   872
		    what_requires=plover_what_requires(system,
ali@24
   873
		      maybe_unused_name);
ali@24
   874
		    for(lnk=what_requires;lnk;lnk=lnk->next)
ali@24
   875
			if (!g_list_find(to_remove,lnk->data))
ali@24
   876
			{
ali@24
   877
			    is_leaf=FALSE;
ali@24
   878
			    break;
ali@24
   879
			}
ali@24
   880
		    g_list_free(what_requires);
ali@24
   881
		    if (is_leaf)
ali@24
   882
		    {
ali@24
   883
			to_remove=g_list_prepend(to_remove,
ali@24
   884
			  maybe_unused_package);
ali@24
   885
			changed=TRUE;
ali@24
   886
		    }
ali@24
   887
		}
ali@24
   888
	    }
ali@24
   889
	    razor_property_iterator_destroy(removed_props);
ali@24
   890
	}
ali@24
   891
	razor_package_iterator_destroy(removed);
ali@24
   892
    } while(changed);
ali@24
   893
    upstream=razor_set_create_without_root();
ali@24
   894
    trans=razor_transaction_create(system,upstream);
ali@24
   895
    razor_set_unref(upstream);
ali@24
   896
    for(lnk=to_remove;lnk;lnk=lnk->next)
ali@24
   897
	razor_transaction_remove_package(trans,lnk->data);
ali@24
   898
    transaction=plover_transaction_new();
ali@24
   899
    transaction->trans=trans;
ali@24
   900
    transaction->installed=installed;
ali@24
   901
    return transaction;
ali@24
   902
}