Add support for --default-action in app-manager
authorJ. Ali Harlow <ali@juiblex.co.uk>
Mon Aug 31 07:07:40 2020 +0100 (2020-08-31)
changeset 103c4b0d5cc34bc
parent 102 fd3bee6d1637
child 104 5cb36c12ac49
Add support for --default-action in app-manager
app-manager/Makefile.am
app-manager/app-manager.c
app-manager/app-manager.h
app-manager/default_action.c
plover-gtk/transactionhelper.c
plover-gtk/transactionhelper.h
plover/transaction.c
plover/transaction.h
     1.1 --- a/app-manager/Makefile.am	Thu Jul 16 23:03:08 2020 +0100
     1.2 +++ b/app-manager/Makefile.am	Mon Aug 31 07:07:40 2020 +0100
     1.3 @@ -3,7 +3,7 @@
     1.4  
     1.5  bin_PROGRAMS=app-manager fetch
     1.6  app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \
     1.7 -	localmedia.c localmedia.h setup.c update.c
     1.8 +	localmedia.c localmedia.h setup.c update.c default_action.c
     1.9  fetch_SOURCES=fetch.c
    1.10  fetch_LDADD=$(LDADD) $(FETCH_LIBS)
    1.11  if HAVE_WINDRES
     2.1 --- a/app-manager/app-manager.c	Thu Jul 16 23:03:08 2020 +0100
     2.2 +++ b/app-manager/app-manager.c	Mon Aug 31 07:07:40 2020 +0100
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
     2.6 + * Copyright (C) 2010, 2020  J. Ali Harlow <ali@juiblex.co.uk>
     2.7   *
     2.8   * This program is free software; you can redistribute it and/or modify
     2.9   * it under the terms of the GNU General Public License as published by
    2.10 @@ -217,6 +217,7 @@
    2.11      GtkWidget *w;
    2.12      gchar *s,*database_uri,*contents;
    2.13      gchar *database=NULL,*setup_base=NULL,*update_base=NULL;
    2.14 +    gchar *default_action_base=NULL;
    2.15      gsize len;
    2.16      struct comps *comps;
    2.17      PloverPackageSet *set=NULL;
    2.18 @@ -229,6 +230,8 @@
    2.19  	  "Setup from installation media","uri"},
    2.20  	{"update",0,0,G_OPTION_ARG_STRING,&update_base,
    2.21  	  "Update from upgrade media","uri"},
    2.22 +	{"default-action",0,0,G_OPTION_ARG_STRING,&default_action_base,
    2.23 +	  "Install, remove or update from repository","uri"},
    2.24  	{NULL}
    2.25      };
    2.26  #ifdef WIN32
    2.27 @@ -256,9 +259,10 @@
    2.28  	g_printerr("%s\n",err->message);
    2.29  	exit(1);
    2.30      }
    2.31 -    if (setup_base && update_base)
    2.32 +    if (!!setup_base+!!update_base+!!default_action_base>1)
    2.33      {
    2.34 -	g_printerr("--setup and --update are mutually exclusive\n");
    2.35 +	g_printerr(
    2.36 +	  "--setup, --update and --default_action are mutually exclusive\n");
    2.37  	exit(1);
    2.38      }
    2.39  #ifdef WIN32
    2.40 @@ -294,6 +298,8 @@
    2.41  	started=setup(setup_base);
    2.42      else if (update_base)
    2.43  	started=update(update_base);
    2.44 +    else if (default_action_base)
    2.45 +	started=default_action(default_action_base);
    2.46      else
    2.47      {
    2.48  	if (database)
    2.49 @@ -357,6 +363,7 @@
    2.50      g_free(prefix);
    2.51      g_free(setup_base);
    2.52      g_free(update_base);
    2.53 +    g_free(default_action_base);
    2.54      g_free(database);
    2.55      exit(0);
    2.56  }
     3.1 --- a/app-manager/app-manager.h	Thu Jul 16 23:03:08 2020 +0100
     3.2 +++ b/app-manager/app-manager.h	Mon Aug 31 07:07:40 2020 +0100
     3.3 @@ -9,3 +9,4 @@
     3.4  PloverPackage *get_active_package(void);
     3.5  gboolean setup(const char *base);
     3.6  gboolean update(const char *base);
     3.7 +gboolean default_action(const char *base);
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/app-manager/default_action.c	Mon Aug 31 07:07:40 2020 +0100
     4.3 @@ -0,0 +1,78 @@
     4.4 +/*
     4.5 + * Copyright (C) 2014, 2016, 2020  J. Ali Harlow <ali@juiblex.co.uk>
     4.6 + *
     4.7 + * This program is free software; you can redistribute it and/or modify
     4.8 + * it under the terms of the GNU General Public License as published by
     4.9 + * the Free Software Foundation; either version 2 of the License, or
    4.10 + * (at your option) any later version.
    4.11 + *
    4.12 + * This program is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 + * GNU General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU General Public License along
    4.18 + * with this program; if not, write to the Free Software Foundation, Inc.,
    4.19 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    4.20 + */
    4.21 +
    4.22 +#include "config.h"
    4.23 +#include <stdlib.h>
    4.24 +#include <string.h>
    4.25 +#include <errno.h>
    4.26 +#include <glib.h>
    4.27 +#include <gio/gio.h>
    4.28 +#include <gtk/gtk.h>
    4.29 +#include <plover/plover.h>
    4.30 +#include <plover/transaction.h>
    4.31 +#include <plover/packageset.h>
    4.32 +#include <plover-gtk/transactionhelper.h>
    4.33 +#include "app-manager.h"
    4.34 +
    4.35 +gboolean default_action(const char *base)
    4.36 +{
    4.37 +    gchar *s;
    4.38 +    const char *prefix;
    4.39 +    GError *error=NULL;
    4.40 +    static PloverTransactionHelper *helper=NULL;
    4.41 +    if (!helper)
    4.42 +    {
    4.43 +	helper=plover_transaction_helper_new(ui);
    4.44 +	plover_transaction_helper_set_base_uri(helper,base);
    4.45 +	prefix=plover_transaction_helper_get_prefix(helper,&error);
    4.46 +	if (error)
    4.47 +	    g_clear_error(&error);
    4.48 +	else
    4.49 +	{
    4.50 +	    s=g_strconcat(prefix?prefix:"","/var/log/default-action",NULL);
    4.51 +	    plover_log_open(s);
    4.52 +	    g_free(s);
    4.53 +	}
    4.54 +	plover_transaction_helper_set_check_vendor(helper,TRUE);
    4.55 +	g_signal_connect(helper,"close",G_CALLBACK(gtk_main_quit),NULL);
    4.56 +    }
    4.57 +    if (!plover_transaction_helper_get_visible(helper))
    4.58 +    {
    4.59 +	if (!plover_transaction_helper_default_action_on_group(helper,"base",
    4.60 +	  &error))
    4.61 +	{
    4.62 +	    if (g_error_matches(error,PLOVER_GENERAL_ERROR,
    4.63 +	      PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET))
    4.64 +	    {
    4.65 +		g_error_free(error);
    4.66 +		error=g_error_new_literal(PLOVER_GENERAL_ERROR,
    4.67 +		  PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET,
    4.68 +		  "Software cannot be installed because of missing updates. "
    4.69 +		  "Installing all updates first should resolve this problem");
    4.70 +		plover_transaction_helper_set_error(helper,error,
    4.71 +		  "Software installation failed");
    4.72 +	    }
    4.73 +	    else
    4.74 +		plover_transaction_helper_set_error(helper,error,
    4.75 +		  "Software installation failed");
    4.76 +	    g_error_free(error);
    4.77 +	}
    4.78 +    }
    4.79 +    plover_transaction_helper_present(helper);
    4.80 +    return TRUE;
    4.81 +}
     5.1 --- a/plover-gtk/transactionhelper.c	Thu Jul 16 23:03:08 2020 +0100
     5.2 +++ b/plover-gtk/transactionhelper.c	Mon Aug 31 07:07:40 2020 +0100
     5.3 @@ -1,5 +1,5 @@
     5.4  /*
     5.5 - * Copyright (C) 2014, 2016, 2018  J. Ali Harlow <ali@juiblex.co.uk>
     5.6 + * Copyright (C) 2014, 2016, 2018, 2020  J. Ali Harlow <ali@juiblex.co.uk>
     5.7   *
     5.8   * This program is free software; you can redistribute it and/or modify
     5.9   * it under the terms of the GNU General Public License as published by
    5.10 @@ -903,7 +903,7 @@
    5.11      {
    5.12  	/*
    5.13  	 * If there are no reportable packages tasked for action there
    5.14 -	 * shouldn't by any packages at all, but let's be paranoid.
    5.15 +	 * shouldn't be any packages at all, but let's be paranoid.
    5.16  	 */
    5.17  	other_packages=FALSE;
    5.18  	razor_install_iterator_rewind(ii);
    5.19 @@ -915,7 +915,9 @@
    5.20  		action=PLOVER_TRANSACTION_HELPER_REPORT_REMOVE;
    5.21  	    else
    5.22  		continue;
    5.23 -	    if (action==report_action)
    5.24 +	    if (action==report_action ||
    5.25 +	      razor_action==RAZOR_INSTALL_ACTION_ADD &&
    5.26 +	      report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE)
    5.27  	    {
    5.28  		razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME,
    5.29  		  &name,RAZOR_DETAIL_LAST);
    5.30 @@ -1165,6 +1167,114 @@
    5.31  }
    5.32  
    5.33  /*
    5.34 + * Returns TRUE if there is work to be done or FALSE if the group is
    5.35 + * empty or on error.
    5.36 + *
    5.37 + * The default action is to:
    5.38 + *	- install (and update all) if any of the packages in @group are
    5.39 + *	  missing or out of date,
    5.40 + *	- otherwise update all if any packages are out of date,
    5.41 + *	- otherwise remove ALL packages for distribution-local comps,
    5.42 + *	- otherwise remove all packages in @group, their dependants and leaves.
    5.43 + */
    5.44 +gboolean plover_transaction_helper_default_action_on_group(
    5.45 +  PloverTransactionHelper *helper,const char *group,GError **error)
    5.46 +{
    5.47 +    gboolean distribution_local=FALSE,retval;
    5.48 +    GError *tmp_err=NULL;
    5.49 +    struct comps *comps;
    5.50 +    struct plover_vector *selected_packages;
    5.51 +    PloverTransaction *transaction;
    5.52 +    g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE);
    5.53 +    selected_packages=plover_transaction_helper_group_get_default_packages(
    5.54 +      helper,group,error);
    5.55 +    if (!selected_packages)
    5.56 +	return FALSE;
    5.57 +    if (!selected_packages->len)
    5.58 +    {
    5.59 +	g_set_error(error,PLOVER_GENERAL_ERROR,
    5.60 +	  PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group);
    5.61 +	plover_vector_free(selected_packages);
    5.62 +	return FALSE;
    5.63 +    }
    5.64 +    comps=plover_transaction_helper_get_comps(helper,NULL);
    5.65 +    if (comps && comps->database==COMPS_DATABASE_DISTRIBUTION_LOCAL)
    5.66 +	distribution_local=TRUE;
    5.67 +    transaction=plover_transaction_helper_new_transaction(helper,error);
    5.68 +    if (!transaction)
    5.69 +    {
    5.70 +	plover_vector_free(selected_packages);
    5.71 +	return FALSE;
    5.72 +    }
    5.73 +    if (!plover_transaction_install_with_update_all(transaction,
    5.74 +      selected_packages->strings,error))
    5.75 +    {
    5.76 +	g_object_unref(transaction);
    5.77 +	plover_vector_free(selected_packages);
    5.78 +	return FALSE;
    5.79 +    }
    5.80 +    retval=plover_transaction_helper_add_transaction(helper,transaction,
    5.81 +      selected_packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,&tmp_err);
    5.82 +    g_object_unref(transaction);
    5.83 +    if (!retval)
    5.84 +    {
    5.85 +	if (!g_error_matches(tmp_err,PLOVER_GENERAL_ERROR,
    5.86 +	  PLOVER_GENERAL_ERROR_NO_WORK))
    5.87 +	{
    5.88 +	    g_propagate_error(error,tmp_err);
    5.89 +	    plover_vector_free(selected_packages);
    5.90 +	    return FALSE;
    5.91 +	}
    5.92 +	g_clear_error(&tmp_err);
    5.93 +	transaction=plover_transaction_helper_new_transaction(helper,error);
    5.94 +	if (!transaction)
    5.95 +	{
    5.96 +	    plover_vector_free(selected_packages);
    5.97 +	    return FALSE;
    5.98 +	}
    5.99 +	if (!plover_transaction_update(transaction,NULL,error))
   5.100 +	{
   5.101 +	    g_object_unref(transaction);
   5.102 +	    plover_vector_free(selected_packages);
   5.103 +	    return FALSE;
   5.104 +	}
   5.105 +	retval=plover_transaction_helper_add_transaction(helper,transaction,
   5.106 +	  selected_packages,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,&tmp_err);
   5.107 +	g_object_unref(transaction);
   5.108 +	if (!retval)
   5.109 +	{
   5.110 +	    if (!g_error_matches(tmp_err,PLOVER_GENERAL_ERROR,
   5.111 +	      PLOVER_GENERAL_ERROR_NO_WORK))
   5.112 +	    {
   5.113 +		g_propagate_error(error,tmp_err);
   5.114 +		plover_vector_free(selected_packages);
   5.115 +		return FALSE;
   5.116 +	    }
   5.117 +	    g_clear_error(&tmp_err);
   5.118 +	    transaction=plover_transaction_helper_new_transaction(helper,error);
   5.119 +	    if (!transaction)
   5.120 +	    {
   5.121 +		plover_vector_free(selected_packages);
   5.122 +		return FALSE;
   5.123 +	    }
   5.124 +	    if (!plover_transaction_remove_with_dependants_and_leaves(
   5.125 +	      transaction,distribution_local?NULL:selected_packages->strings,
   5.126 +	      error))
   5.127 +	    {
   5.128 +		g_object_unref(transaction);
   5.129 +		plover_vector_free(selected_packages);
   5.130 +		return FALSE;
   5.131 +	    }
   5.132 +	    retval=plover_transaction_helper_add_transaction(helper,transaction,
   5.133 +	      NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error);
   5.134 +	    g_object_unref(transaction);
   5.135 +	}
   5.136 +    }
   5.137 +    plover_vector_free(selected_packages);
   5.138 +    return retval;
   5.139 +}
   5.140 +
   5.141 +/*
   5.142   * Returns TRUE if there is work to be done or FALSE if all updates have
   5.143   * already been applied or on error.
   5.144   */
     6.1 --- a/plover-gtk/transactionhelper.h	Thu Jul 16 23:03:08 2020 +0100
     6.2 +++ b/plover-gtk/transactionhelper.h	Mon Aug 31 07:07:40 2020 +0100
     6.3 @@ -99,6 +99,8 @@
     6.4  gboolean
     6.5    plover_transaction_helper_remove_group(PloverTransactionHelper *helper,
     6.6    const char *group,GError **error);
     6.7 +gboolean plover_transaction_helper_default_action_on_group(
     6.8 +  PloverTransactionHelper *helper,const char *group,GError **error);
     6.9  gboolean
    6.10    plover_transaction_helper_update(PloverTransactionHelper *helper,
    6.11    GError **error);
     7.1 --- a/plover/transaction.c	Thu Jul 16 23:03:08 2020 +0100
     7.2 +++ b/plover/transaction.c	Mon Aug 31 07:07:40 2020 +0100
     7.3 @@ -1,5 +1,6 @@
     7.4  /*
     7.5 - * Copyright (C) 2009, 2011, 2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     7.6 + * Copyright (C) 2009, 2011, 2012, 2014, 2016, 2020
     7.7 + * J. Ali Harlow <ali@juiblex.co.uk>
     7.8   *
     7.9   * This program is free software; you can redistribute it and/or modify
    7.10   * it under the terms of the GNU General Public License as published by
    7.11 @@ -580,6 +581,74 @@
    7.12      return TRUE;
    7.13  }
    7.14  
    7.15 +/*
    7.16 + * Note that if the install is a NOP, no update all is done.
    7.17 + */
    7.18 +gboolean
    7.19 +  plover_transaction_install_with_update_all(PloverTransaction *transaction,
    7.20 +  char **pkgs,GError **error)
    7.21 +{
    7.22 +    int i;
    7.23 +    gboolean update_all=FALSE;
    7.24 +    struct razor_set *system,*upstream;
    7.25 +    struct razor_install_iterator *ii;
    7.26 +    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
    7.27 +    g_return_val_if_fail(transaction->upstream != NULL,FALSE);
    7.28 +    g_return_val_if_fail(transaction->trans == NULL,FALSE);
    7.29 +    if (!plover_transaction_root_open(transaction,NULL,error))
    7.30 +	return FALSE;
    7.31 +    system=plover_transaction_get_system_set(transaction);
    7.32 +    if (!system)
    7.33 +    {
    7.34 +	/* Impossible */
    7.35 +	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
    7.36 +	  "Internal error: No system set");
    7.37 +	return FALSE;
    7.38 +    }
    7.39 +    upstream=plover_package_set_get_razor(transaction->relocated);
    7.40 +    do
    7.41 +    {
    7.42 +	transaction->trans=razor_transaction_create(system,upstream);
    7.43 +	for(i=0;pkgs[i];i++)
    7.44 +	    if (plover_mark_package_for_update(transaction->trans,system,
    7.45 +	      pkgs[i]) &&
    7.46 +	      plover_mark_package_for_update(transaction->trans,upstream,
    7.47 +	      pkgs[i]))
    7.48 +	    {
    7.49 +		g_set_error(error,PLOVER_GENERAL_ERROR,
    7.50 +		  PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
    7.51 +		  "Package not found");
    7.52 +		razor_transaction_destroy(transaction->trans);
    7.53 +		transaction->trans=NULL;
    7.54 +		return FALSE;
    7.55 +		break;
    7.56 +	    }
    7.57 +	if (update_all)
    7.58 +	{
    7.59 +	    razor_transaction_update_all(transaction->trans);
    7.60 +	    break;
    7.61 +	}
    7.62 +	if (plover_transaction_resolve(transaction,NULL))
    7.63 +	{
    7.64 +	    ii=plover_transaction_get_install_iterator(transaction,NULL);
    7.65 +	    if (ii && razor_install_iterator_seek(ii,1))
    7.66 +		update_all=TRUE;
    7.67 +	    transaction->flags&=~PLOVER_TRANSACTION_RESOLVED;
    7.68 +	    if (transaction->install_iterator)
    7.69 +	    {
    7.70 +		razor_install_iterator_destroy(transaction->install_iterator);
    7.71 +		transaction->install_iterator=NULL;
    7.72 +	    }
    7.73 +	    if (transaction->next)
    7.74 +	    {
    7.75 +		razor_set_unref(transaction->next);
    7.76 +		transaction->next=NULL;
    7.77 +	    }
    7.78 +	}
    7.79 +    } while(update_all);
    7.80 +    return TRUE;
    7.81 +}
    7.82 +
    7.83  PloverTransaction *plover_transaction_new_install_uri(const char *base_uri,
    7.84    const char *prefix,char **pkgs,GError **error)
    7.85  {
    7.86 @@ -659,17 +728,20 @@
    7.87  {
    7.88      struct razor_package_iterator *pi;
    7.89      struct razor_package *package;
    7.90 -    const char *name;
    7.91 +    const char *name,*version,*arch;
    7.92 +    gchar *s;
    7.93      int retval=pkg?-1:0;
    7.94      pi=razor_package_iterator_create(set);
    7.95      while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
    7.96 -      RAZOR_DETAIL_LAST))
    7.97 +      RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST))
    7.98      {
    7.99 -	if (!pkg || !strcmp(name,pkg))
   7.100 +	s=g_strconcat(name,"-",version,".",arch,NULL);
   7.101 +	if (!pkg || !strcmp(name,pkg) || !strcmp(s,pkg))
   7.102  	{
   7.103  	    razor_transaction_remove_package(trans,package);
   7.104  	    retval=0;
   7.105  	}
   7.106 +	g_free(s);
   7.107      }
   7.108      razor_package_iterator_destroy(pi);
   7.109      return retval;
   7.110 @@ -725,6 +797,94 @@
   7.111      return transaction;
   7.112  }
   7.113  
   7.114 +static void
   7.115 +  plover_transaction_remove_with_dependants_callback(const char *requirement,
   7.116 +  struct razor_package *package,const char *name,const char *version,
   7.117 +  const char *arch,void *data)
   7.118 +{
   7.119 +    gchar *s;
   7.120 +    struct plover_vector *dependants=data;
   7.121 +    s=g_strdup_printf("%s-%s.%s",name,version,arch);
   7.122 +    plover_vector_append(dependants,s);
   7.123 +    g_free(s);
   7.124 +}
   7.125 +
   7.126 +/*
   7.127 + * Remove pkgs and any that depend on them (default behaviour of yum remove).
   7.128 + */
   7.129 +
   7.130 +gboolean
   7.131 +  plover_transaction_remove_with_dependants(PloverTransaction *transaction,
   7.132 +  char **pkgs,GError **error)
   7.133 +{
   7.134 +    int i;
   7.135 +    struct plover_vector *dependants=NULL;
   7.136 +    struct razor_set *system,*empty;
   7.137 +    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
   7.138 +    g_return_val_if_fail(transaction->trans == NULL,FALSE);
   7.139 +    if (!pkgs)
   7.140 +	return plover_transaction_remove(transaction,NULL,error);
   7.141 +    if (!plover_transaction_root_open(transaction,NULL,error))
   7.142 +	return FALSE;
   7.143 +    system=plover_transaction_get_system_set(transaction);
   7.144 +    if (!system)
   7.145 +    {
   7.146 +	/* Impossible */
   7.147 +	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
   7.148 +	  "Internal error: No system set");
   7.149 +	return FALSE;
   7.150 +    }
   7.151 +    empty=razor_set_create_without_root();
   7.152 +    transaction->trans=razor_transaction_create(system,empty);
   7.153 +    razor_set_unref(empty);
   7.154 +    do
   7.155 +    {
   7.156 +	for(i=0;pkgs[i];i++)
   7.157 +	{
   7.158 +	    if (plover_mark_packages_for_removal(transaction->trans,system,
   7.159 +	      pkgs[i]))
   7.160 +	    {
   7.161 +		if (dependants)
   7.162 +		{
   7.163 +		    /*
   7.164 +		     * Unfortunately we can't trivially work out which
   7.165 +		     * of the packages that we were originally asked to
   7.166 +		     * remove has caused this dependant package to be
   7.167 +		     * marked for removal, but this case should be
   7.168 +		     * impossible anyway.
   7.169 +		     */
   7.170 +		    g_set_error(error,PLOVER_GENERAL_ERROR,
   7.171 +		      PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
   7.172 +		      "Recorded as a dependant package but not found");
   7.173 +		    plover_vector_free(dependants);
   7.174 +		}
   7.175 +		else
   7.176 +		    g_set_error(error,PLOVER_GENERAL_ERROR,
   7.177 +		      PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i],
   7.178 +		      "Package not found");
   7.179 +		razor_transaction_destroy(transaction->trans);
   7.180 +		transaction->trans=NULL;
   7.181 +		return FALSE;
   7.182 +		break;
   7.183 +	    }
   7.184 +	}
   7.185 +	pkgs=NULL;
   7.186 +	if (dependants)
   7.187 +	{
   7.188 +	    plover_vector_free(dependants);
   7.189 +	    dependants=NULL;
   7.190 +	}
   7.191 +	razor_transaction_resolve(transaction->trans);
   7.192 +	dependants=plover_vector_new();
   7.193 +	razor_transaction_unsatisfied(transaction->trans,
   7.194 +	  plover_transaction_remove_with_dependants_callback,dependants);
   7.195 +	pkgs=dependants->strings;
   7.196 +    } while(pkgs && pkgs[0]);
   7.197 +    if (dependants)
   7.198 +	plover_vector_free(dependants);
   7.199 +    return TRUE;
   7.200 +}
   7.201 +
   7.202  static GList *plover_what_has_property(struct razor_set *set,uint32_t prop_type,
   7.203    const char *ref_name)
   7.204  {
   7.205 @@ -763,6 +923,137 @@
   7.206      return plover_what_has_property(set,RAZOR_PROPERTY_REQUIRES,ref_name);
   7.207  }
   7.208  
   7.209 +gboolean plover_transaction_remove_with_leaves(PloverTransaction *transaction,
   7.210 +  char **pkgs,GError **error)
   7.211 +{
   7.212 +    int i,changed,is_leaf;
   7.213 +    uint32_t flags;
   7.214 +    const char *name,*version,*maybe_unused_name;
   7.215 +    struct razor_set *system,*upstream;
   7.216 +    struct plover_vector *package_names;
   7.217 +    GList *to_remove,*lnk,*lnk2,*what_requires,*what_provides;
   7.218 +    struct razor_package *package,*maybe_unused_package;
   7.219 +    struct razor_property *property;
   7.220 +    struct razor_package_query *query;
   7.221 +    struct razor_package_iterator *all_packages,*removed;
   7.222 +    struct razor_property_iterator *removed_props;
   7.223 +    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
   7.224 +    g_return_val_if_fail(transaction->upstream != NULL,FALSE);
   7.225 +    g_return_val_if_fail(transaction->trans == NULL,FALSE);
   7.226 +    if (!pkgs)
   7.227 +	return plover_transaction_remove(transaction,NULL,error);
   7.228 +    system=plover_transaction_get_system_set(transaction);
   7.229 +    if (!system)
   7.230 +    {
   7.231 +	/* Impossible */
   7.232 +	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
   7.233 +	  "Internal error: No system set");
   7.234 +	return FALSE;
   7.235 +    }
   7.236 +    upstream=plover_package_set_get_razor(transaction->relocated);
   7.237 +    package_names=plover_vector_new();
   7.238 +    for(i=0;pkgs[i];i++)
   7.239 +	plover_vector_append(package_names,pkgs[i]);
   7.240 +    to_remove=NULL;
   7.241 +    all_packages=razor_package_iterator_create(system);
   7.242 +    while (razor_package_iterator_next(all_packages,&package,
   7.243 +      RAZOR_DETAIL_NAME,&name,RAZOR_DETAIL_LAST))
   7.244 +	if (plover_vector_remove(package_names,name))
   7.245 +	    to_remove=g_list_prepend(to_remove,package);
   7.246 +    razor_package_iterator_destroy(all_packages);
   7.247 +    if (package_names->len)
   7.248 +    {
   7.249 +	g_set_error(error,PLOVER_GENERAL_ERROR,
   7.250 +	  PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",
   7.251 +	  package_names->strings[0],"Package not found");
   7.252 +	plover_vector_free(package_names);
   7.253 +	g_list_free(to_remove);
   7.254 +	return FALSE;
   7.255 +    }
   7.256 +    plover_vector_free(package_names);
   7.257 +    do
   7.258 +    {
   7.259 +	changed=FALSE;
   7.260 +	query=razor_package_query_create(system);
   7.261 +	for(lnk=to_remove;lnk;lnk=lnk->next)
   7.262 +	    razor_package_query_add_package(query,lnk->data);
   7.263 +	removed=razor_package_query_finish(query);
   7.264 +	while(razor_package_iterator_next(removed,&package,RAZOR_DETAIL_LAST))
   7.265 +	{
   7.266 +	    removed_props=razor_property_iterator_create(system,package);
   7.267 +	    while (razor_property_iterator_next(removed_props,&property,&name,
   7.268 +	      &flags,&version))
   7.269 +	    {
   7.270 +		if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=RAZOR_PROPERTY_REQUIRES)
   7.271 +		    continue;
   7.272 +		what_provides=plover_what_provides(system,name);
   7.273 +		for(lnk2=what_provides;lnk2;lnk2=lnk2->next)
   7.274 +		{
   7.275 +		    maybe_unused_package=lnk2->data;
   7.276 +		    if (g_list_find(to_remove,maybe_unused_package))
   7.277 +			continue;
   7.278 +		    is_leaf=TRUE;
   7.279 +		    razor_package_get_details(system,maybe_unused_package,
   7.280 +		      RAZOR_DETAIL_NAME,&maybe_unused_name,RAZOR_DETAIL_LAST);
   7.281 +		    what_requires=plover_what_requires(system,
   7.282 +		      maybe_unused_name);
   7.283 +		    for(lnk=what_requires;lnk;lnk=lnk->next)
   7.284 +			if (!g_list_find(to_remove,lnk->data))
   7.285 +			{
   7.286 +			    is_leaf=FALSE;
   7.287 +			    break;
   7.288 +			}
   7.289 +		    g_list_free(what_requires);
   7.290 +		    if (is_leaf)
   7.291 +		    {
   7.292 +			to_remove=g_list_prepend(to_remove,
   7.293 +			  maybe_unused_package);
   7.294 +			changed=TRUE;
   7.295 +		    }
   7.296 +		}
   7.297 +	    }
   7.298 +	    razor_property_iterator_destroy(removed_props);
   7.299 +	}
   7.300 +	razor_package_iterator_destroy(removed);
   7.301 +    } while(changed);
   7.302 +    transaction->trans=razor_transaction_create(system,upstream);
   7.303 +    for(lnk=to_remove;lnk;lnk=lnk->next)
   7.304 +	razor_transaction_remove_package(transaction->trans,lnk->data);
   7.305 +    return TRUE;
   7.306 +}
   7.307 +
   7.308 +gboolean plover_transaction_remove_with_dependants_and_leaves(
   7.309 +  PloverTransaction *transaction,char **pkgs,GError **error)
   7.310 +{
   7.311 +    int i;
   7.312 +    gboolean retval;
   7.313 +    GList *lnk,*what_requires;
   7.314 +    struct plover_vector *to_remove;
   7.315 +    struct razor_set *system;
   7.316 +    g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE);
   7.317 +    g_return_val_if_fail(transaction->upstream != NULL,FALSE);
   7.318 +    g_return_val_if_fail(transaction->trans == NULL,FALSE);
   7.319 +    if (!pkgs)
   7.320 +	return plover_transaction_remove(transaction,NULL,error);
   7.321 +    system=plover_transaction_get_system_set(transaction);
   7.322 +    to_remove=plover_vector_new();
   7.323 +    for(i=0;pkgs[i];i++)
   7.324 +	if (!plover_vector_contains(to_remove,pkgs[i]))
   7.325 +	    plover_vector_append(to_remove,pkgs[i]);
   7.326 +    for(i=0;to_remove->strings[i];i++)
   7.327 +    {
   7.328 +	what_requires=plover_what_requires(system,to_remove->strings[i]);
   7.329 +	for(lnk=what_requires;lnk;lnk=lnk->next)
   7.330 +	    if (!plover_vector_contains(to_remove,lnk->data))
   7.331 +		plover_vector_append(to_remove,lnk->data);
   7.332 +	g_list_free(what_requires);
   7.333 +    }
   7.334 +    retval=plover_transaction_remove_with_leaves(transaction,to_remove->strings,
   7.335 +      error);
   7.336 +    plover_vector_free(to_remove);
   7.337 +    return retval;
   7.338 +}
   7.339 +
   7.340  PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs,
   7.341    GError **error)
   7.342  {
     8.1 --- a/plover/transaction.h	Thu Jul 16 23:03:08 2020 +0100
     8.2 +++ b/plover/transaction.h	Mon Aug 31 07:07:40 2020 +0100
     8.3 @@ -59,6 +59,9 @@
     8.4    const char *base,GError **error);
     8.5  gboolean plover_transaction_install(PloverTransaction *transaction,
     8.6    char **pkgs,GError **error);
     8.7 +gboolean
     8.8 +  plover_transaction_install_with_update_all(PloverTransaction *transaction,
     8.9 +  char **pkgs,GError **error);
    8.10  PloverTransaction *plover_transaction_new_install_uri(const char *base_uri,
    8.11    const char *prefix,char **pkgs,GError **error);
    8.12  PloverTransaction *plover_transaction_new_install(const char *base,
    8.13 @@ -73,6 +76,13 @@
    8.14    char **pkgs,GError **error);
    8.15  PloverTransaction *plover_transaction_new_remove(char **pkgs,
    8.16    GError **error);
    8.17 +gboolean
    8.18 +  plover_transaction_remove_with_dependants(PloverTransaction *transaction,
    8.19 +  char **pkgs,GError **error);
    8.20 +gboolean plover_transaction_remove_with_leaves(
    8.21 +  PloverTransaction *transaction,char **pkgs,GError **error);
    8.22 +gboolean plover_transaction_remove_with_dependants_and_leaves(
    8.23 +  PloverTransaction *transaction,char **pkgs,GError **error);
    8.24  PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs,
    8.25    GError **error);
    8.26  gboolean plover_transaction_resolve(PloverTransaction *transaction,