# HG changeset patch # User J. Ali Harlow # Date 1598854060 -3600 # Node ID c4b0d5cc34bca37cf9493425ec54e4cb4c305ba9 # Parent fd3bee6d16374c05a45ccecf33c65c8af3a75997 Add support for --default-action in app-manager diff -r fd3bee6d1637 -r c4b0d5cc34bc app-manager/Makefile.am --- a/app-manager/Makefile.am Thu Jul 16 23:03:08 2020 +0100 +++ b/app-manager/Makefile.am Mon Aug 31 07:07:40 2020 +0100 @@ -3,7 +3,7 @@ bin_PROGRAMS=app-manager fetch app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \ - localmedia.c localmedia.h setup.c update.c + localmedia.c localmedia.h setup.c update.c default_action.c fetch_SOURCES=fetch.c fetch_LDADD=$(LDADD) $(FETCH_LIBS) if HAVE_WINDRES diff -r fd3bee6d1637 -r c4b0d5cc34bc app-manager/app-manager.c --- a/app-manager/app-manager.c Thu Jul 16 23:03:08 2020 +0100 +++ b/app-manager/app-manager.c Mon Aug 31 07:07:40 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 J. Ali Harlow + * Copyright (C) 2010, 2020 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -217,6 +217,7 @@ GtkWidget *w; gchar *s,*database_uri,*contents; gchar *database=NULL,*setup_base=NULL,*update_base=NULL; + gchar *default_action_base=NULL; gsize len; struct comps *comps; PloverPackageSet *set=NULL; @@ -229,6 +230,8 @@ "Setup from installation media","uri"}, {"update",0,0,G_OPTION_ARG_STRING,&update_base, "Update from upgrade media","uri"}, + {"default-action",0,0,G_OPTION_ARG_STRING,&default_action_base, + "Install, remove or update from repository","uri"}, {NULL} }; #ifdef WIN32 @@ -256,9 +259,10 @@ g_printerr("%s\n",err->message); exit(1); } - if (setup_base && update_base) + if (!!setup_base+!!update_base+!!default_action_base>1) { - g_printerr("--setup and --update are mutually exclusive\n"); + g_printerr( + "--setup, --update and --default_action are mutually exclusive\n"); exit(1); } #ifdef WIN32 @@ -294,6 +298,8 @@ started=setup(setup_base); else if (update_base) started=update(update_base); + else if (default_action_base) + started=default_action(default_action_base); else { if (database) @@ -357,6 +363,7 @@ g_free(prefix); g_free(setup_base); g_free(update_base); + g_free(default_action_base); g_free(database); exit(0); } diff -r fd3bee6d1637 -r c4b0d5cc34bc app-manager/app-manager.h --- a/app-manager/app-manager.h Thu Jul 16 23:03:08 2020 +0100 +++ b/app-manager/app-manager.h Mon Aug 31 07:07:40 2020 +0100 @@ -9,3 +9,4 @@ PloverPackage *get_active_package(void); gboolean setup(const char *base); gboolean update(const char *base); +gboolean default_action(const char *base); diff -r fd3bee6d1637 -r c4b0d5cc34bc app-manager/default_action.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app-manager/default_action.c Mon Aug 31 07:07:40 2020 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014, 2016, 2020 J. Ali Harlow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "app-manager.h" + +gboolean default_action(const char *base) +{ + gchar *s; + const char *prefix; + GError *error=NULL; + static PloverTransactionHelper *helper=NULL; + if (!helper) + { + helper=plover_transaction_helper_new(ui); + plover_transaction_helper_set_base_uri(helper,base); + prefix=plover_transaction_helper_get_prefix(helper,&error); + if (error) + g_clear_error(&error); + else + { + s=g_strconcat(prefix?prefix:"","/var/log/default-action",NULL); + plover_log_open(s); + g_free(s); + } + plover_transaction_helper_set_check_vendor(helper,TRUE); + g_signal_connect(helper,"close",G_CALLBACK(gtk_main_quit),NULL); + } + if (!plover_transaction_helper_get_visible(helper)) + { + if (!plover_transaction_helper_default_action_on_group(helper,"base", + &error)) + { + if (g_error_matches(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET)) + { + g_error_free(error); + error=g_error_new_literal(PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_REQUIREMENTS_NOT_MET, + "Software cannot be installed because of missing updates. " + "Installing all updates first should resolve this problem"); + plover_transaction_helper_set_error(helper,error, + "Software installation failed"); + } + else + plover_transaction_helper_set_error(helper,error, + "Software installation failed"); + g_error_free(error); + } + } + plover_transaction_helper_present(helper); + return TRUE; +} diff -r fd3bee6d1637 -r c4b0d5cc34bc plover-gtk/transactionhelper.c --- a/plover-gtk/transactionhelper.c Thu Jul 16 23:03:08 2020 +0100 +++ b/plover-gtk/transactionhelper.c Mon Aug 31 07:07:40 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014, 2016, 2018 J. Ali Harlow + * Copyright (C) 2014, 2016, 2018, 2020 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -903,7 +903,7 @@ { /* * If there are no reportable packages tasked for action there - * shouldn't by any packages at all, but let's be paranoid. + * shouldn't be any packages at all, but let's be paranoid. */ other_packages=FALSE; razor_install_iterator_rewind(ii); @@ -915,7 +915,9 @@ action=PLOVER_TRANSACTION_HELPER_REPORT_REMOVE; else continue; - if (action==report_action) + if (action==report_action || + razor_action==RAZOR_INSTALL_ACTION_ADD && + report_action==PLOVER_TRANSACTION_HELPER_REPORT_UPDATE) { razor_package_get_details(report_set,package,RAZOR_DETAIL_NAME, &name,RAZOR_DETAIL_LAST); @@ -1165,6 +1167,114 @@ } /* + * Returns TRUE if there is work to be done or FALSE if the group is + * empty or on error. + * + * The default action is to: + * - install (and update all) if any of the packages in @group are + * missing or out of date, + * - otherwise update all if any packages are out of date, + * - otherwise remove ALL packages for distribution-local comps, + * - otherwise remove all packages in @group, their dependants and leaves. + */ +gboolean plover_transaction_helper_default_action_on_group( + PloverTransactionHelper *helper,const char *group,GError **error) +{ + gboolean distribution_local=FALSE,retval; + GError *tmp_err=NULL; + struct comps *comps; + struct plover_vector *selected_packages; + PloverTransaction *transaction; + g_return_val_if_fail(PLOVER_IS_TRANSACTION_HELPER(helper),FALSE); + selected_packages=plover_transaction_helper_group_get_default_packages( + helper,group,error); + if (!selected_packages) + return FALSE; + if (!selected_packages->len) + { + g_set_error(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_FAILED,"%s: no default packages",group); + plover_vector_free(selected_packages); + return FALSE; + } + comps=plover_transaction_helper_get_comps(helper,NULL); + if (comps && comps->database==COMPS_DATABASE_DISTRIBUTION_LOCAL) + distribution_local=TRUE; + transaction=plover_transaction_helper_new_transaction(helper,error); + if (!transaction) + { + plover_vector_free(selected_packages); + return FALSE; + } + if (!plover_transaction_install_with_update_all(transaction, + selected_packages->strings,error)) + { + g_object_unref(transaction); + plover_vector_free(selected_packages); + return FALSE; + } + retval=plover_transaction_helper_add_transaction(helper,transaction, + selected_packages,PLOVER_TRANSACTION_HELPER_REPORT_INSTALL,&tmp_err); + g_object_unref(transaction); + if (!retval) + { + if (!g_error_matches(tmp_err,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_WORK)) + { + g_propagate_error(error,tmp_err); + plover_vector_free(selected_packages); + return FALSE; + } + g_clear_error(&tmp_err); + transaction=plover_transaction_helper_new_transaction(helper,error); + if (!transaction) + { + plover_vector_free(selected_packages); + return FALSE; + } + if (!plover_transaction_update(transaction,NULL,error)) + { + g_object_unref(transaction); + plover_vector_free(selected_packages); + return FALSE; + } + retval=plover_transaction_helper_add_transaction(helper,transaction, + selected_packages,PLOVER_TRANSACTION_HELPER_REPORT_UPDATE,&tmp_err); + g_object_unref(transaction); + if (!retval) + { + if (!g_error_matches(tmp_err,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_WORK)) + { + g_propagate_error(error,tmp_err); + plover_vector_free(selected_packages); + return FALSE; + } + g_clear_error(&tmp_err); + transaction=plover_transaction_helper_new_transaction(helper,error); + if (!transaction) + { + plover_vector_free(selected_packages); + return FALSE; + } + if (!plover_transaction_remove_with_dependants_and_leaves( + transaction,distribution_local?NULL:selected_packages->strings, + error)) + { + g_object_unref(transaction); + plover_vector_free(selected_packages); + return FALSE; + } + retval=plover_transaction_helper_add_transaction(helper,transaction, + NULL,PLOVER_TRANSACTION_HELPER_REPORT_REMOVE,error); + g_object_unref(transaction); + } + } + plover_vector_free(selected_packages); + return retval; +} + +/* * Returns TRUE if there is work to be done or FALSE if all updates have * already been applied or on error. */ diff -r fd3bee6d1637 -r c4b0d5cc34bc plover-gtk/transactionhelper.h --- a/plover-gtk/transactionhelper.h Thu Jul 16 23:03:08 2020 +0100 +++ b/plover-gtk/transactionhelper.h Mon Aug 31 07:07:40 2020 +0100 @@ -99,6 +99,8 @@ gboolean plover_transaction_helper_remove_group(PloverTransactionHelper *helper, const char *group,GError **error); +gboolean plover_transaction_helper_default_action_on_group( + PloverTransactionHelper *helper,const char *group,GError **error); gboolean plover_transaction_helper_update(PloverTransactionHelper *helper, GError **error); diff -r fd3bee6d1637 -r c4b0d5cc34bc plover/transaction.c --- a/plover/transaction.c Thu Jul 16 23:03:08 2020 +0100 +++ b/plover/transaction.c Mon Aug 31 07:07:40 2020 +0100 @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow + * Copyright (C) 2009, 2011, 2012, 2014, 2016, 2020 + * J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -580,6 +581,74 @@ return TRUE; } +/* + * Note that if the install is a NOP, no update all is done. + */ +gboolean + plover_transaction_install_with_update_all(PloverTransaction *transaction, + char **pkgs,GError **error) +{ + int i; + gboolean update_all=FALSE; + struct razor_set *system,*upstream; + struct razor_install_iterator *ii; + g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE); + g_return_val_if_fail(transaction->upstream != NULL,FALSE); + g_return_val_if_fail(transaction->trans == NULL,FALSE); + if (!plover_transaction_root_open(transaction,NULL,error)) + return FALSE; + system=plover_transaction_get_system_set(transaction); + if (!system) + { + /* Impossible */ + g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, + "Internal error: No system set"); + return FALSE; + } + upstream=plover_package_set_get_razor(transaction->relocated); + do + { + transaction->trans=razor_transaction_create(system,upstream); + for(i=0;pkgs[i];i++) + if (plover_mark_package_for_update(transaction->trans,system, + pkgs[i]) && + plover_mark_package_for_update(transaction->trans,upstream, + pkgs[i])) + { + g_set_error(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i], + "Package not found"); + razor_transaction_destroy(transaction->trans); + transaction->trans=NULL; + return FALSE; + break; + } + if (update_all) + { + razor_transaction_update_all(transaction->trans); + break; + } + if (plover_transaction_resolve(transaction,NULL)) + { + ii=plover_transaction_get_install_iterator(transaction,NULL); + if (ii && razor_install_iterator_seek(ii,1)) + update_all=TRUE; + transaction->flags&=~PLOVER_TRANSACTION_RESOLVED; + if (transaction->install_iterator) + { + razor_install_iterator_destroy(transaction->install_iterator); + transaction->install_iterator=NULL; + } + if (transaction->next) + { + razor_set_unref(transaction->next); + transaction->next=NULL; + } + } + } while(update_all); + return TRUE; +} + PloverTransaction *plover_transaction_new_install_uri(const char *base_uri, const char *prefix,char **pkgs,GError **error) { @@ -659,17 +728,20 @@ { struct razor_package_iterator *pi; struct razor_package *package; - const char *name; + const char *name,*version,*arch; + gchar *s; int retval=pkg?-1:0; pi=razor_package_iterator_create(set); while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name, - RAZOR_DETAIL_LAST)) + RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST)) { - if (!pkg || !strcmp(name,pkg)) + s=g_strconcat(name,"-",version,".",arch,NULL); + if (!pkg || !strcmp(name,pkg) || !strcmp(s,pkg)) { razor_transaction_remove_package(trans,package); retval=0; } + g_free(s); } razor_package_iterator_destroy(pi); return retval; @@ -725,6 +797,94 @@ return transaction; } +static void + plover_transaction_remove_with_dependants_callback(const char *requirement, + struct razor_package *package,const char *name,const char *version, + const char *arch,void *data) +{ + gchar *s; + struct plover_vector *dependants=data; + s=g_strdup_printf("%s-%s.%s",name,version,arch); + plover_vector_append(dependants,s); + g_free(s); +} + +/* + * Remove pkgs and any that depend on them (default behaviour of yum remove). + */ + +gboolean + plover_transaction_remove_with_dependants(PloverTransaction *transaction, + char **pkgs,GError **error) +{ + int i; + struct plover_vector *dependants=NULL; + struct razor_set *system,*empty; + g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE); + g_return_val_if_fail(transaction->trans == NULL,FALSE); + if (!pkgs) + return plover_transaction_remove(transaction,NULL,error); + if (!plover_transaction_root_open(transaction,NULL,error)) + return FALSE; + system=plover_transaction_get_system_set(transaction); + if (!system) + { + /* Impossible */ + g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, + "Internal error: No system set"); + return FALSE; + } + empty=razor_set_create_without_root(); + transaction->trans=razor_transaction_create(system,empty); + razor_set_unref(empty); + do + { + for(i=0;pkgs[i];i++) + { + if (plover_mark_packages_for_removal(transaction->trans,system, + pkgs[i])) + { + if (dependants) + { + /* + * Unfortunately we can't trivially work out which + * of the packages that we were originally asked to + * remove has caused this dependant package to be + * marked for removal, but this case should be + * impossible anyway. + */ + g_set_error(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i], + "Recorded as a dependant package but not found"); + plover_vector_free(dependants); + } + else + g_set_error(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s",pkgs[i], + "Package not found"); + razor_transaction_destroy(transaction->trans); + transaction->trans=NULL; + return FALSE; + break; + } + } + pkgs=NULL; + if (dependants) + { + plover_vector_free(dependants); + dependants=NULL; + } + razor_transaction_resolve(transaction->trans); + dependants=plover_vector_new(); + razor_transaction_unsatisfied(transaction->trans, + plover_transaction_remove_with_dependants_callback,dependants); + pkgs=dependants->strings; + } while(pkgs && pkgs[0]); + if (dependants) + plover_vector_free(dependants); + return TRUE; +} + static GList *plover_what_has_property(struct razor_set *set,uint32_t prop_type, const char *ref_name) { @@ -763,6 +923,137 @@ return plover_what_has_property(set,RAZOR_PROPERTY_REQUIRES,ref_name); } +gboolean plover_transaction_remove_with_leaves(PloverTransaction *transaction, + char **pkgs,GError **error) +{ + int i,changed,is_leaf; + uint32_t flags; + const char *name,*version,*maybe_unused_name; + struct razor_set *system,*upstream; + struct plover_vector *package_names; + GList *to_remove,*lnk,*lnk2,*what_requires,*what_provides; + struct razor_package *package,*maybe_unused_package; + struct razor_property *property; + struct razor_package_query *query; + struct razor_package_iterator *all_packages,*removed; + struct razor_property_iterator *removed_props; + g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE); + g_return_val_if_fail(transaction->upstream != NULL,FALSE); + g_return_val_if_fail(transaction->trans == NULL,FALSE); + if (!pkgs) + return plover_transaction_remove(transaction,NULL,error); + system=plover_transaction_get_system_set(transaction); + if (!system) + { + /* Impossible */ + g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, + "Internal error: No system set"); + return FALSE; + } + upstream=plover_package_set_get_razor(transaction->relocated); + package_names=plover_vector_new(); + for(i=0;pkgs[i];i++) + plover_vector_append(package_names,pkgs[i]); + to_remove=NULL; + all_packages=razor_package_iterator_create(system); + while (razor_package_iterator_next(all_packages,&package, + RAZOR_DETAIL_NAME,&name,RAZOR_DETAIL_LAST)) + if (plover_vector_remove(package_names,name)) + to_remove=g_list_prepend(to_remove,package); + razor_package_iterator_destroy(all_packages); + if (package_names->len) + { + g_set_error(error,PLOVER_GENERAL_ERROR, + PLOVER_GENERAL_ERROR_NO_SUCH_PACKAGE,"%s: %s", + package_names->strings[0],"Package not found"); + plover_vector_free(package_names); + g_list_free(to_remove); + return FALSE; + } + plover_vector_free(package_names); + do + { + changed=FALSE; + query=razor_package_query_create(system); + for(lnk=to_remove;lnk;lnk=lnk->next) + razor_package_query_add_package(query,lnk->data); + removed=razor_package_query_finish(query); + while(razor_package_iterator_next(removed,&package,RAZOR_DETAIL_LAST)) + { + removed_props=razor_property_iterator_create(system,package); + while (razor_property_iterator_next(removed_props,&property,&name, + &flags,&version)) + { + if ((flags&RAZOR_PROPERTY_TYPE_MASK)!=RAZOR_PROPERTY_REQUIRES) + continue; + what_provides=plover_what_provides(system,name); + for(lnk2=what_provides;lnk2;lnk2=lnk2->next) + { + maybe_unused_package=lnk2->data; + if (g_list_find(to_remove,maybe_unused_package)) + continue; + is_leaf=TRUE; + razor_package_get_details(system,maybe_unused_package, + RAZOR_DETAIL_NAME,&maybe_unused_name,RAZOR_DETAIL_LAST); + what_requires=plover_what_requires(system, + maybe_unused_name); + for(lnk=what_requires;lnk;lnk=lnk->next) + if (!g_list_find(to_remove,lnk->data)) + { + is_leaf=FALSE; + break; + } + g_list_free(what_requires); + if (is_leaf) + { + to_remove=g_list_prepend(to_remove, + maybe_unused_package); + changed=TRUE; + } + } + } + razor_property_iterator_destroy(removed_props); + } + razor_package_iterator_destroy(removed); + } while(changed); + transaction->trans=razor_transaction_create(system,upstream); + for(lnk=to_remove;lnk;lnk=lnk->next) + razor_transaction_remove_package(transaction->trans,lnk->data); + return TRUE; +} + +gboolean plover_transaction_remove_with_dependants_and_leaves( + PloverTransaction *transaction,char **pkgs,GError **error) +{ + int i; + gboolean retval; + GList *lnk,*what_requires; + struct plover_vector *to_remove; + struct razor_set *system; + g_return_val_if_fail(PLOVER_IS_TRANSACTION(transaction),FALSE); + g_return_val_if_fail(transaction->upstream != NULL,FALSE); + g_return_val_if_fail(transaction->trans == NULL,FALSE); + if (!pkgs) + return plover_transaction_remove(transaction,NULL,error); + system=plover_transaction_get_system_set(transaction); + to_remove=plover_vector_new(); + for(i=0;pkgs[i];i++) + if (!plover_vector_contains(to_remove,pkgs[i])) + plover_vector_append(to_remove,pkgs[i]); + for(i=0;to_remove->strings[i];i++) + { + what_requires=plover_what_requires(system,to_remove->strings[i]); + for(lnk=what_requires;lnk;lnk=lnk->next) + if (!plover_vector_contains(to_remove,lnk->data)) + plover_vector_append(to_remove,lnk->data); + g_list_free(what_requires); + } + retval=plover_transaction_remove_with_leaves(transaction,to_remove->strings, + error); + plover_vector_free(to_remove); + return retval; +} + PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs, GError **error) { diff -r fd3bee6d1637 -r c4b0d5cc34bc plover/transaction.h --- a/plover/transaction.h Thu Jul 16 23:03:08 2020 +0100 +++ b/plover/transaction.h Mon Aug 31 07:07:40 2020 +0100 @@ -59,6 +59,9 @@ const char *base,GError **error); gboolean plover_transaction_install(PloverTransaction *transaction, char **pkgs,GError **error); +gboolean + plover_transaction_install_with_update_all(PloverTransaction *transaction, + char **pkgs,GError **error); PloverTransaction *plover_transaction_new_install_uri(const char *base_uri, const char *prefix,char **pkgs,GError **error); PloverTransaction *plover_transaction_new_install(const char *base, @@ -73,6 +76,13 @@ char **pkgs,GError **error); PloverTransaction *plover_transaction_new_remove(char **pkgs, GError **error); +gboolean + plover_transaction_remove_with_dependants(PloverTransaction *transaction, + char **pkgs,GError **error); +gboolean plover_transaction_remove_with_leaves( + PloverTransaction *transaction,char **pkgs,GError **error); +gboolean plover_transaction_remove_with_dependants_and_leaves( + PloverTransaction *transaction,char **pkgs,GError **error); PloverTransaction *plover_transaction_new_remove_with_leaves(char **pkgs, GError **error); gboolean plover_transaction_resolve(PloverTransaction *transaction,