# HG changeset patch # User J. Ali Harlow # Date 1682440860 -3600 # Node ID 2947214c450e48042b5bb7e9be0fcd7bbdd2712f # Parent b3d8e196dac848b1b999ebe2cb77f56106d9d78e Partial fix for #5537 diff -r b3d8e196dac8 -r 2947214c450e app-manager/Makefile.am --- a/app-manager/Makefile.am Tue Jun 29 10:09:34 2021 +0100 +++ b/app-manager/Makefile.am Tue Apr 25 17:41:00 2023 +0100 @@ -3,14 +3,15 @@ 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 default_action.c + localmedia.c localmedia.h setup.c update.c default_action.c \ + localdistributions.c localdistributions.h fetch_SOURCES=fetch.c fetch_LDADD=$(LDADD) $(FETCH_LIBS) if HAVE_WINDRES app_manager_SOURCES+=resources.rc app-manager.exe.manifest endif if PLOVER_MINGW -app_manager_LDFLAGS=-mwindows +#app_manager_LDFLAGS=-mwindows endif uidir=$(pkgdatadir) ui_DATA=app-manager.ui diff -r b3d8e196dac8 -r 2947214c450e app-manager/app-manager.c --- a/app-manager/app-manager.c Tue Jun 29 10:09:34 2021 +0100 +++ b/app-manager/app-manager.c Tue Apr 25 17:41:00 2023 +0100 @@ -32,6 +32,7 @@ #include #include "app-manager.h" #include "localmedia.h" +#include "localdistributions.h" LUALIB_API int luaopen_posix(lua_State *L); @@ -302,6 +303,17 @@ #ifdef WIN32 prefix=g_win32_get_package_installation_directory_of_module(NULL); #endif + if (prefix) + { + /* + * Note that this won't generally work if the application is stored + * on a removable device. If you need the logfile, copy it to the + * harddisk first. + */ + s=g_strconcat(prefix,"/var/log/init",NULL); + plover_log_open(s); + g_free(s); + } install_icons(); ui=gtk_builder_new(); if (!g_file_get_contents("app-manager.ui",&contents,&len,&err) && @@ -384,15 +396,21 @@ w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles")); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),TRUE); } + g_clear_object(&set); applications=plover_applications_model_new(installed); set_package_model(applications); w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow")); + if (prefix) + { + s=g_strconcat(prefix,"/var/log/interactive",NULL); + plover_log_open(s); + g_free(s); + } gtk_widget_show(w); started=TRUE; } if (started) gtk_main(); - g_clear_object(&set); objects=gtk_builder_get_objects(ui); for(lnk=objects;lnk;lnk=lnk->next) if (GTK_IS_WIDGET(lnk->data) && @@ -454,6 +472,108 @@ set_package_model(location); } +gboolean open_database(const char *uri,const char *destination,GError **err) +{ + gboolean retval; + GSList *sets,*lnk; + GtkWidget *w; + PloverPackageSet *set; + if (!g_strcmp0(uri,razor_get_database_uri())) + return TRUE; + if (relocations) + { + razor_relocations_destroy(relocations); + relocations=NULL; + } + razor_set_database_uri(uri); + if (destination) + { + relocations=razor_relocations_create(); + razor_relocations_add(relocations,"/usr",destination); + } + sets=plover_package_store_get_sets(PLOVER_PACKAGE_STORE(installed)); + sets=g_slist_copy(sets); + for(lnk=sets;lnk;lnk=lnk->next) + { + set=lnk->data; + plover_package_store_remove_set(PLOVER_PACKAGE_STORE(installed),set); + } + g_slist_free(sets); + set=plover_package_set_new(); + retval=plover_package_set_open(set,"",TRUE,err); + plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set); + g_object_unref(set); + w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles")); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), + !!plover_package_set_get_no_details(set)); + return retval; +} + +G_MODULE_EXPORT void on_open_database(GtkWidget *widget) +{ + gboolean have_local_distributions; + const char *database_uri; + gchar *uri,*s; + GList *cells; + GtkWidget *w,*radio_global,*radio_local,*combo,*dialog; + GtkCellRenderer *cell; + GtkTreeModel *local; + GtkTreeIter iter; + dialog=GTK_WIDGET(gtk_builder_get_object(ui,"OpenDatabase")); + local=GTK_TREE_MODEL(plover_local_distributions_new()); + have_local_distributions=!!gtk_tree_model_iter_n_children(local,NULL); + radio_global=GTK_WIDGET(gtk_builder_get_object(ui,"distribution_global")); + radio_local=GTK_WIDGET(gtk_builder_get_object(ui,"distribution_local")); + gtk_widget_set_sensitive(radio_local,have_local_distributions); + w=GTK_WIDGET(gtk_builder_get_object(ui,"local_databases_label")); + gtk_widget_set_sensitive(w,have_local_distributions); + combo=GTK_WIDGET(gtk_builder_get_object(ui,"local_databases")); + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),local); + gtk_widget_set_sensitive(w,have_local_distributions); + database_uri=razor_get_database_uri(); + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),NULL); + if (gtk_tree_model_get_iter_first(local,&iter)) + do + { + gtk_tree_model_get(local,&iter, + PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN,&s,-1); + if (!g_strcmp0(s,database_uri)) + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),&iter); + g_free(s); + } while(gtk_tree_model_iter_next(local,&iter)); + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter)) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_local),TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_global),TRUE); + cells=gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(combo)); + if (cells) + g_list_free(cells); + else + { + cell=gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),cell,TRUE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),cell,"text", + PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN); + } + if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT) + { + show_busy_cursor(TRUE); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_global))) + open_database(NULL,prefix,NULL); + else if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter)) + { + gtk_tree_model_get(local,&iter, + PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN,&uri, + PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN,&s,-1); + open_database(uri,s,NULL); + g_free(uri); + g_free(s); + } + show_busy_cursor(FALSE); + } + gtk_widget_hide(dialog); +} + G_MODULE_EXPORT void on_open_location(GtkWidget *widget) { GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow")); @@ -546,6 +666,86 @@ show_busy_cursor(FALSE); } +G_MODULE_EXPORT void on_open_archive(GtkWidget *widget) +{ + GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow")); + GtkWidget *dialog; + GFile *file,*parent; + GFileInfo *fi; + GMount *mount; + gchar *path,*name; + PloverPackageSet *set; + GSList *sets; + GError *err=NULL; + dialog=gtk_file_chooser_dialog_new("Open Achive",GTK_WINDOW(w), + GTK_FILE_CHOOSER_ACTION_OPEN,GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN,GTK_RESPONSE_ACCEPT,NULL); + if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT) + { + show_busy_cursor(TRUE); + path=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + set=plover_package_set_new_from_yum(path,relocations,&err); + if (set) + { + if (!location) + location=GTK_TREE_MODEL(plover_package_store_new()); + while((sets= + plover_package_store_get_sets(PLOVER_PACKAGE_STORE(location)))) + plover_package_store_remove_set(PLOVER_PACKAGE_STORE(location), + PLOVER_PACKAGE_SET(sets->data)); + plover_package_store_add_set(PLOVER_PACKAGE_STORE(location),set); + g_object_unref(set); + w=GTK_WIDGET(gtk_builder_get_object(ui,"LocationButton")); + file=g_file_new_for_path(path); + parent=g_file_get_parent(file); + if (parent) + { + g_object_unref(parent); + mount=NULL; + } + else + mount=g_file_find_enclosing_mount(file,NULL,NULL); + if (mount) + { + name=g_mount_get_name(mount); + g_object_unref(mount); + } + else + { + fi=g_file_query_info(file, + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,NULL,NULL); + if (fi) + { + name=g_strdup(g_file_info_get_display_name(fi)); + g_object_unref(fi); + } + else + name=g_filename_display_basename(path); + g_object_unref(file); + } + gtk_tool_button_set_label(GTK_TOOL_BUTTON(w),name); + g_free(name); + gtk_widget_show(w); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w),TRUE); + } + else + { + gtk_widget_destroy(dialog); + dialog=gtk_message_dialog_new(GTK_WINDOW(w), + GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE,"Error loading repository '%s'",path); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), + "%s",err->message); + gtk_dialog_run(GTK_DIALOG(dialog)); + g_error_free(err); + } + g_free(path); + show_busy_cursor(FALSE); + } + gtk_widget_destroy(dialog); +} + G_MODULE_EXPORT void on_help_about(GtkWidget *widget) { GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow")); diff -r b3d8e196dac8 -r 2947214c450e app-manager/app-manager.ui --- a/app-manager/app-manager.ui Tue Jun 29 10:09:34 2021 +0100 +++ b/app-manager/app-manager.ui Tue Apr 25 17:41:00 2023 +0100 @@ -1,61 +1,76 @@ - + + + + True + False + gtk-open + + + True + False + gtk-cdrom + + + True + False + gtk-file + + + True + False + gtk-open + + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Application Manager 600 400 - + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical 6 True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Package + _Database True - + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - Open _Location... + + _Open... True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Open a package repository at a known location + Open an existing package database True - image1 + image4 False - - - - - - - _Scan local media - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Scan local media for package repositories - True - image2 - False - + + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -63,12 +78,70 @@ gtk-quit True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Quit the application manager True True - + + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Repository + True + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + Open _Location... + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Open a package repository at a known location + True + image1 + False + + + + + + + _Scan local media + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Scan local media for package repositories + True + image2 + False + + + + + + Open _Archive... + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Open an archived package repository + True + image3 + False + + @@ -78,34 +151,38 @@ True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK _View True True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Show a list of files owned by the selected package _File list True True - + True + False Show the description etc., of the selected package Package _details True True True ViewFiles - + @@ -115,22 +192,25 @@ True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK _Help True True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-about True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Display details about the application manager True True - + @@ -140,6 +220,7 @@ False + True 0 @@ -147,12 +228,12 @@ True True - vertical 215 True True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 6 @@ -165,12 +246,13 @@ True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical 6 True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 @@ -178,12 +260,18 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True 10 False + False + False + True + True + True + True 0 @@ -197,7 +285,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + False @@ -215,31 +303,35 @@ True + False True - vertical + False False + True 0 True + False vertical 2 True True + False Show installed applications _Applications True plover-applications True - + False @@ -249,12 +341,13 @@ True + False Show all installed packages A_ll Packages True gtk-index toolbutton1 - + False @@ -264,6 +357,7 @@ True + False False @@ -273,12 +367,13 @@ True + False Show packages in repositories on local media Local _Media True gtk-cdrom toolbutton1 - + False @@ -287,11 +382,12 @@ + False Location True gtk-directory toolbutton1 - + False @@ -300,6 +396,7 @@ + False Show updates available for installed packages _Updates True @@ -313,21 +410,26 @@ + True + True 1 True - vertical + False False + True 2 + True + True 1 @@ -369,11 +471,13 @@ True + False 6 6 True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 @@ -391,6 +495,8 @@ + True + True 0 @@ -417,27 +523,33 @@ + True + True 1 True - vertical + False True + False 0 0 True + False True + False gtk-home + True False 0 @@ -453,6 +565,7 @@ http://www.city-occupational.co.uk/ + True False 1 @@ -462,6 +575,7 @@ False + True 0 @@ -474,15 +588,18 @@ True + False queue True + False 0 0 True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 2 @@ -492,6 +609,7 @@ True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 Architecture: @@ -499,12 +617,13 @@ GTK_FILL - + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 i386 @@ -515,12 +634,13 @@ 1 2 GTK_FILL - + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 License: @@ -530,12 +650,13 @@ 1 2 GTK_FILL - + True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 LGPL @@ -548,7 +669,7 @@ 1 2 GTK_FILL - + @@ -559,12 +680,15 @@ + True + True 1 False + True end 2 @@ -579,30 +703,194 @@ + True + True 1 True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 False + True 2 - - - True - gtk-open - - - True - gtk-cdrom + + False + 5 + Open Database + dialog + MainWindow + + + True + False + 2 + + + True + False + end + + + gtk-cancel + True + True + True + True + + + False + False + 0 + + + + + gtk-open + True + True + True + True + + + False + False + 1 + + + + + True + True + 0 + + + + + True + False + 6 + + + True + False + 0 + The primary package database for a system is known as the global +database. If a system needs to contain multiple package sets, then +additional ones may be configured as distribution-local databases. +This allows packages within each package set to be independent of +each other. + +If there are no distribution-local databases (or no global one), then +this option will not be available: + + + True + True + 0 + + + + + True + False + 6 + + + Global + True + True + False + True + True + + + True + True + 0 + + + + + Distribution-local + True + True + False + True + True + distribution_global + + + True + True + 1 + + + + + True + True + 1 + + + + + True + False + 0 + Each distribution-local database has an associated name and vendor: + + + True + True + 2 + + + + + True + False + 6 + + + True + False + + + True + True + 0 + + + + + True + True + 3 + + + + + True + True + 1 + + + + + + button2 + button3 + diff -r b3d8e196dac8 -r 2947214c450e app-manager/localdistributions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app-manager/localdistributions.c Tue Apr 25 17:41:00 2023 +0100 @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford + * Copyright (C) 2023 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 "localdistributions.h" + +#define VALID_ITER(iter,local) ((iter) && (iter)->user_data && \ + PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local)->stamp==(iter)->stamp) + +static GType column_types[PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS]; + +static void + plover_local_distributions_tree_model_init(GtkTreeModelIface *iface); + +G_DEFINE_TYPE_WITH_CODE(PloverLocalDistributions,plover_local_distributions, + G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, + plover_local_distributions_tree_model_init)); + +typedef struct _PloverLocalDistribution { + gchar *vendor,*distribution,*prefix,*user_friendly,*database_uri; +} PloverLocalDistribution; + +typedef struct _PloverLocalDistributionsPrivate { + GList *distributions; + int stamp; +} PloverLocalDistributionsPrivate; + +#define PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj)\ + G_TYPE_INSTANCE_GET_PRIVATE(obj,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\ + PloverLocalDistributionsPrivate) + +PloverLocalDistribution *plover_local_distribution_new(const char *vendor, + const char *distribution) +{ + gchar *s; + struct comps *comps; + PloverLocalDistribution *ld; + ld=g_new0(PloverLocalDistribution,1); + ld->vendor=g_strdup(vendor); + if (distribution) + { + ld->distribution=g_strdup(distribution); + ld->user_friendly=g_strdup_printf("%s (%s)",distribution,vendor); + } + else + ld->user_friendly=g_strdup(vendor); + comps=plover_comps_new(); + plover_comps_set_vendor(comps,vendor); + if (distribution) + plover_comps_set_distribution(comps,distribution); + ld->prefix=plover_comps_get_default_prefix(comps); + plover_comps_free(comps); + s=g_build_filename(ld->prefix,"var","lib","razor",NULL); + ld->database_uri=razor_path_to_uri(s); + g_free(s); + return ld; +} + +void plover_local_distribution_free(PloverLocalDistribution *ld) +{ + if (ld) + { + g_free(ld->vendor); + g_free(ld->distribution); + g_free(ld->prefix); + g_free(ld->user_friendly); + g_free(ld->database_uri); + g_free(ld); + } +} + +static void plover_local_distributions_finalize(GObject *obj) +{ + PloverLocalDistributionsPrivate *priv; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj); + g_list_foreach(priv->distributions,(GFunc)plover_local_distribution_free, + NULL); + g_list_free(priv->distributions); + if (G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize) + G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize(obj); +} + +static void + plover_local_distributions_class_init(PloverLocalDistributionsClass *klass) +{ + GObjectClass *oclass=G_OBJECT_CLASS(klass); + oclass->finalize=plover_local_distributions_finalize; + g_type_class_add_private(klass,sizeof(PloverLocalDistributionsPrivate)); + column_types[PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN]=G_TYPE_STRING; + column_types[PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN]=G_TYPE_STRING; + column_types[PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN]=G_TYPE_STRING; + column_types[PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN]=G_TYPE_STRING; + column_types[PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN]=G_TYPE_STRING; +} + +static GtkTreeModelFlags +plover_local_distributions_get_flags(GtkTreeModel *tree_model) +{ + return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY; +} + +static gint plover_local_distributions_get_n_columns(GtkTreeModel *tree_model) +{ + return PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS; +} + +static GType + plover_local_distributions_get_column_type(GtkTreeModel *tree_model,gint indx) +{ + g_return_val_if_fail(indx>=0 && indxdistributions,i); + if (!ld) + return FALSE; + iter->stamp=priv->stamp; + iter->user_data=ld; + return TRUE; +} + +static GtkTreePath * + plover_local_distributions_get_path(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + PloverLocalDistributionsPrivate *priv; + PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model; + g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL); + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local); + path=gtk_tree_path_new(); + gtk_tree_path_append_index(path, + g_list_index(priv->distributions,iter->user_data)); + return path; +} + +static void plover_local_distributions_get_value(GtkTreeModel *tree_model, + GtkTreeIter *iter,gint column,GValue *value) +{ + gchar *s; + PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model; + PloverLocalDistribution *ld; + g_return_if_fail(column>=0 && columnuser_data; + g_value_init(value,column_types[column]); + switch((PloverLocalDistributionsColumn)column) + { + case PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN: + g_value_set_string(value,ld->vendor); + break; + case PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN: + g_value_set_string(value,ld->distribution); + break; + case PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN: + g_value_set_string(value,ld->prefix); + break; + case PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN: + g_value_set_string(value,ld->user_friendly); + break; + case PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN: + g_value_set_string(value,ld->database_uri); + break; + case PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS: + /* Quieten compiler warning */ + break; + } +} + +static gboolean + plover_local_distributions_iter_next(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GList *lnk; + PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model; + PloverLocalDistributionsPrivate *priv; + g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE); + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local); + lnk=g_list_find(priv->distributions,iter->user_data); + iter->user_data=lnk->next?lnk->next->data:NULL; + return !!iter->user_data; +} + +static gboolean + plover_local_distributions_iter_children(GtkTreeModel *tree_model, + GtkTreeIter *iter,GtkTreeIter *parent) +{ + PloverLocalDistributionsPrivate *priv; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model); + /* this is a list, nodes have no children */ + if (parent) + return FALSE; + if (priv->distributions) + { + iter->stamp=priv->stamp; + iter->user_data=priv->distributions->data; + return TRUE; + } + else + return FALSE; +} + +static gboolean + plover_local_distributions_iter_has_child(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + PloverLocalDistributionsPrivate *priv; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model); + return !!priv->distributions; +} + +static gint plover_local_distributions_iter_n_children(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + PloverLocalDistributionsPrivate *priv; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model); + if (!iter) + return g_list_length(priv->distributions); + g_return_val_if_fail(VALID_ITER(iter,tree_model),-1); + return 0; +} + +static gboolean + plover_local_distributions_iter_nth_child(GtkTreeModel *tree_model, + GtkTreeIter *iter,GtkTreeIter *parent,gint n) +{ + GList *lnk; + PloverLocalDistributionsPrivate *priv; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model); + if (parent) + return FALSE; + lnk=g_list_nth(priv->distributions,n); + if (!lnk) + return FALSE; + iter->stamp=priv->stamp; + iter->user_data=lnk->data; + return TRUE; +} + +static gboolean plover_local_distributions_iter_parent(GtkTreeModel *tree_model, + GtkTreeIter *iter,GtkTreeIter *child) +{ + return FALSE; +} + +static void plover_local_distributions_tree_model_init(GtkTreeModelIface *iface) +{ + iface->get_flags=plover_local_distributions_get_flags; + iface->get_n_columns=plover_local_distributions_get_n_columns; + iface->get_column_type=plover_local_distributions_get_column_type; + iface->get_iter=plover_local_distributions_get_iter; + iface->get_path=plover_local_distributions_get_path; + iface->get_value=plover_local_distributions_get_value; + iface->iter_next=plover_local_distributions_iter_next; + iface->iter_children=plover_local_distributions_iter_children; + iface->iter_has_child=plover_local_distributions_iter_has_child; + iface->iter_n_children=plover_local_distributions_iter_n_children; + iface->iter_nth_child=plover_local_distributions_iter_nth_child; + iface->iter_parent=plover_local_distributions_iter_parent; +} + +static void plover_local_distributions_init(PloverLocalDistributions *store) +{ + gchar *s; + const char *vendor_prefix,*vendor,*distribution; + GDir *vendor_dir,*distribution_dir,*database_dir; + PloverLocalDistributionsPrivate *priv; + PloverLocalDistribution *ld; + priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(store); + /* + * local distribution databases may be found in + * /$VENDOR/$DISTRIBUTION/var/lib/razor and + * /$VENDOR/var/lib/razor + */ + vendor_prefix=plover_get_vendor_prefix(); + g_message("Vendor prefix is %s",vendor_prefix); + vendor_dir=g_dir_open(vendor_prefix,0,NULL); + if (!vendor_dir) + { + g_warning("Failed to open %s",vendor_prefix); + return; + } + while((vendor=g_dir_read_name(vendor_dir))) + { + g_message("Candidate for vendor is %s",vendor); + s=g_build_filename(vendor_prefix,vendor,NULL); + distribution_dir=g_dir_open(s,0,NULL); + g_free(s); + if (!distribution_dir) + { + g_warning("Failed to open %s/%s",vendor_prefix,vendor); + continue; + } + while((distribution=g_dir_read_name(distribution_dir))) + { + g_message("Candidate for distribution is %s",distribution); + if (!strcmp(distribution,"var")) + { + s=g_build_filename(vendor_prefix,vendor,"var","lib","razor", + NULL); + database_dir=g_dir_open(s,0,NULL); + g_free(s); + if (database_dir) + { + ld=plover_local_distribution_new(vendor,NULL); + g_message("Found vendor-specific razor database at %s", + ld->database_uri); + priv->distributions=g_list_prepend(priv->distributions,ld); + g_dir_close(database_dir); + } + else + g_warning("Failed to open %s/%s/var/lib/razor", + vendor_prefix,vendor); + } + s=g_build_filename(vendor_prefix,vendor,distribution, + "var","lib","razor",NULL); + database_dir=g_dir_open(s,0,NULL); + g_free(s); + if (database_dir) + { + ld=plover_local_distribution_new(vendor,distribution); + g_message("Found local-distribution razor database at %s", + ld->database_uri); + priv->distributions=g_list_prepend(priv->distributions,ld); + g_dir_close(database_dir); + } + else + g_warning("Failed to open %s/%s/%s/var/lib/razor", + vendor_prefix,vendor,distribution); + } + g_dir_close(distribution_dir); + } + g_dir_close(vendor_dir); + priv->stamp=g_random_int(); +} + +PloverLocalDistributions *plover_local_distributions_new(void) +{ + return g_object_new(PLOVER_TYPE_LOCAL_DISTRIBUTIONS,NULL); +} diff -r b3d8e196dac8 -r 2947214c450e app-manager/localdistributions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app-manager/localdistributions.h Tue Apr 25 17:41:00 2023 +0100 @@ -0,0 +1,52 @@ +#ifndef __PLOVER_LOCAL_DISTRIBUTIONS_H__ +#define __PLOVER_LOCAL_DISTRIBUTIONS_H__ + +#include + +G_BEGIN_DECLS + +#define PLOVER_TYPE_LOCAL_DISTRIBUTIONS\ + plover_local_distributions_get_type() +#define PLOVER_LOCAL_DISTRIBUTIONS(obj)\ + G_TYPE_CHECK_INSTANCE_CAST(obj,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\ + PloverLocalDistributions) +#define PLOVER_LOCAL_DISTRIBUTIONS_CLASS(klass)\ + G_TYPE_CHECK_CLASS_CAST(klass,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\ + PloverLocalDistributionsClass) +#define PLOVER_IS_LOCAL_DISTRIBUTIONS(obj)\ + G_TYPE_CHECK_INSTANCE_TYPE(obj,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS) +#define PLOVER_IS_LOCAL_DISTRIBUTIONS_CLASS(klass)\ + G_TYPE_CHECK_CLASS_TYPE(obj,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS) +#define PLOVER_LOCAL_DISTRIBUTIONS_GET_CLASS(obj)\ + G_TYPE_INSTANCE_GET_CLASS(obj,\ + PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\ + PloverLocalDistributionsClass) + +typedef enum +{ + PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN, + PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN, + PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN, + PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN, + PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN, + PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS +} PloverLocalDistributionsColumn; + +typedef struct _PloverLocalDistributions { + GObject parent_instance; +} PloverLocalDistributions; + +typedef struct _PloverLocalDistributionsClass { + GObjectClass parent_class; +} PloverLocalDistributionsClass; + +GType plover_local_distributions_get_type(void) G_GNUC_CONST; +PloverLocalDistributions *plover_local_distributions_new(void); + +G_END_DECLS + +#endif /* __PLOVER_LOCAL_DISTRIBUTIONS_H__ */ diff -r b3d8e196dac8 -r 2947214c450e app-manager/packagelist.c --- a/app-manager/packagelist.c Tue Jun 29 10:09:34 2021 +0100 +++ b/app-manager/packagelist.c Tue Apr 25 17:41:00 2023 +0100 @@ -20,8 +20,10 @@ #include #include #include +#include #include #include +#include #include #include #include "app-manager.h" @@ -32,11 +34,18 @@ void package_present(PloverPackage *package) { - gchar *s; + gchar *s,*prefix,*prefix_path; const char *text,*t; + char *multiple_prefixes="multiple"; + GError *tmp_err=NULL; + GSList *sets,*repositories,*lnk; GtkWidget *w; GtkTextBuffer *buf; + GtkTreeModel *model; + struct comps *comps; + PloverPackageSet *set; PloverPackageFileStore *store; + PloverRepository *repository; buf=GTK_TEXT_BUFFER(gtk_builder_get_object(ui,"description")); if (package) { @@ -44,7 +53,99 @@ g_strdelimit(s,"\t\n",' '); } else - s=g_strdup(""); + { + model=gtk_tree_view_get_model(view); + while(model && + (GTK_IS_TREE_MODEL_FILTER(model) || GTK_IS_TREE_MODEL_SORT(model))) + { + if (GTK_IS_TREE_MODEL_FILTER(model)) + model= + gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model)); + else + model=gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + } + repositories=NULL; + prefix=NULL; + if (model && PLOVER_IS_PACKAGE_STORE(model)) + { + sets=plover_package_store_get_sets(PLOVER_PACKAGE_STORE(model)); + for(lnk=sets;lnk;lnk=lnk->next) + { + set=lnk->data; + repository=plover_package_set_get_repository(set); + if (repository && !g_slist_find(repositories,repository)) + repositories=g_slist_prepend(repositories,repository); + t=plover_package_set_guess_prefix(set,tmp_err?NULL:&tmp_err); + if (!t) + continue; + if (!prefix) + prefix=g_strdup(t); + else if (prefix!=multiple_prefixes && strcmp(prefix,t)) + { + g_free(prefix); + prefix=multiple_prefixes; + } + } + if (prefix==multiple_prefixes) + s=g_strdup("Multiple install prefixes"); + else if (repositories) + { + if (prefix!=multiple_prefixes) + g_free(prefix); + prefix=NULL; + for(lnk=repositories;lnk;lnk=lnk->next) + { + repository=lnk->data; + if (PLOVER_IS_YUM_REPOSITORY(repository)) + { + comps=plover_yum_repository_get_comps( + PLOVER_YUM_REPOSITORY(repository),NULL); + t=plover_comps_get_default_prefix(comps); + if (!prefix) + prefix=g_strdup(t); + else if (prefix!=multiple_prefixes && strcmp(prefix,t)) + { + g_free(prefix); + prefix=multiple_prefixes; + } + } + } + if (prefix==multiple_prefixes) + s=g_strdup("Repositories intended to be installed to " + "multiple destinations"); + else if (prefix) + { + prefix_path=razor_path_from_uri(prefix,NULL); + s=g_strdup_printf("Repository intended to be installed to: " + "%s",prefix_path?prefix_path:prefix); + g_free(prefix_path); + } + else + s=g_strdup("Repository with no default " + "install destination"); + } + else if (prefix) + { + prefix_path=razor_path_from_uri(prefix,NULL); + s=g_strdup_printf("Installed in: %s", + prefix_path?prefix_path:prefix); + g_free(prefix_path); + } + else if (sets) + s=g_strdup("No common installation destination found"); + else + s=g_strdup("Empty package store"); + if (prefix!=multiple_prefixes) + g_free(prefix); + g_slist_free(repositories); + g_clear_error(&tmp_err); + } + else if (model) + s=g_strdup_printf("Unsupported package list container (%s)", + G_OBJECT_TYPE_NAME(model)); + else + s=g_strdup("No Package list container"); + } gtk_text_buffer_set_text(buf,s,-1); g_free(s); w=GTK_WIDGET(gtk_builder_get_object(ui,"PackageDetails")); @@ -149,6 +250,33 @@ } } +static void package_inserted(GtkTreeModel *tree_model,GtkTreePath *path, + GtkTreeIter *iter,gpointer data) +{ + gchar *s; + s=gtk_tree_path_to_string(path); + g_message("package_inserted(%s): %sactive package", + s,active?"":"no "); + g_free(s); + if (!active) + package_present(NULL); +} + +static void package_deleted(GtkTreeModel *tree_model,GtkTreePath *path, + gpointer data) +{ + /* + * If the deleted package was the active one, then selection-changed + * will be emitted which will handle that case. + */ + gchar *s; + s=gtk_tree_path_to_string(path); + g_message("package_deleted(%s): %sactive package",s,active?"":"no "); + g_free(s); + if (!active) + package_present(NULL); +} + static void package_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cell,GtkTreeModel *model,GtkTreeIter *iter,gpointer data) { @@ -169,9 +297,21 @@ void set_package_model(GtkTreeModel *model) { GtkWidget *w; + GtkTreeModel *old_model; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; + if (view) + { + old_model=gtk_tree_view_get_model(view); + if (old_model) + { + g_signal_handlers_disconnect_by_func(old_model, + G_CALLBACK(package_inserted),NULL); + g_signal_handlers_disconnect_by_func(old_model, + G_CALLBACK(package_deleted),NULL); + } + } if (!view) { w=GTK_WIDGET(gtk_builder_get_object(ui,"Packages")); @@ -218,9 +358,18 @@ } if (view) { + g_warning("set_package_model: Calling gtk_tree_view_set_model()"); gtk_tree_view_set_model(view,model); + g_warning("set_package_model: gtk_tree_view_set_model() returns"); gtk_tree_view_set_search_column(view, PLOVER_PACKAGE_STORE_NAME_COLUMN); + if (model) + { + g_signal_connect(model,"row-inserted",G_CALLBACK(package_inserted), + NULL); + g_signal_connect(model,"row-deleted",G_CALLBACK(package_deleted), + NULL); + } } package_present(NULL); } diff -r b3d8e196dac8 -r 2947214c450e app-manager/resources.rc.in --- a/app-manager/resources.rc.in Tue Jun 29 10:09:34 2021 +0100 +++ b/app-manager/resources.rc.in Tue Apr 25 17:41:00 2023 +0100 @@ -22,7 +22,7 @@ VALUE "FileVersion","@PACKAGE_VERSION@" VALUE "InternalName","app-manager" VALUE "LegalCopyright", - "Copyright © 2010 J. Ali Harlow et al" + "Copyright © 2010, 2023 J. Ali Harlow et al" VALUE "OriginalFilename","app-manager.exe" VALUE "ProductName","plover" VALUE "ProductVersion","@PACKAGE_VERSION@" diff -r b3d8e196dac8 -r 2947214c450e configure.ac --- a/configure.ac Tue Jun 29 10:09:34 2021 +0100 +++ b/configure.ac Tue Apr 25 17:41:00 2023 +0100 @@ -65,9 +65,9 @@ # increment CURRENT and set AGE and REVISION to 0. # - If the interface is the same as the previous version, increment REVISION. # -lt_current=5 +lt_current=6 lt_revision=0 -lt_age=2 +lt_age=3 LIBPLOVER_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age" AC_SUBST(LIBPLOVER_LT_VERSION_INFO) @@ -142,8 +142,10 @@ PKG_CHECK_MODULES(GMODULE_EXPORT,[gmodule-export-2.0]) LIBPLOVER_CFLAGS="$RAZOR_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $GIO_CFLAGS" LIBPLOVER_LIBS="$RAZOR_LIBS $EXPAT_LIBS $ZLIB_LIBS $GIO_LIBS" +LIBPLOVER_REQUIREMENTS="razor expat zlib glib2" AC_SUBST(LIBPLOVER_CFLAGS) AC_SUBST(LIBPLOVER_LIBS) +AC_SUBST(LIBPLOVER_REQUIREMENTS) PLOVER_GTK_CFLAGS="$GTK_CFLAGS $RAZOR_CFLAGS" PLOVER_GTK_LIBS="$GTK_LIBS $RAZOR_LIBS" AC_SUBST(PLOVER_GTK_CFLAGS) @@ -155,12 +157,6 @@ LIBS="$save_LIBS" AC_SUBST(LUA_POSIX_CFLAGS) AC_SUBST(LUA_POSIX_LIBS) -GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $WHELK_CFLAGS $PLOVER_GTK_CFLAGS \ - $LIBPLOVER_CFLAGS $LUA_POSIX_CFLAGS" -GUI_LIBS="$GMODULE_EXPORT_LIBS $WHELK_LIBS $PLOVER_GTK_LIBS \ - $LIBPLOVER_LIBS $LUA_POSIX_LIBS" -AC_SUBST(GUI_CFLAGS) -AC_SUBST(GUI_LIBS) save_PKG_CONFIG="$PKG_CONFIG" PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES(SETUP,[whelk razor >= 0.5.4 expat >= 2.2 zlib gio-2.0],[:], @@ -201,13 +197,28 @@ [have_breakpad="yes";REQUIREMENTS="$REQUIREMENTS x11"],[have_breakpad="no"]) if test "$have_breakpad" = yes; then AC_DEFINE([HAVE_BREAKPAD],[1],[Define if breakpad is available.]) + LIBPLOVER_PRIVATE_REQUIREMENTS="breakpad-client" + # breakpad-client uses C++. This should probably go into + # Libs.private in breakpad-client.pc + AS_IF([test -n "$host_mingw"],[ + static_stdcxx=`$CXX --print-file-name=libstdc++.a` + LIBPLOVER_PRIVATE_LIBS="-lversion -lgcc_eh $static_stdcxx" + ]) elif test "$with_breakpad" = yes; then AC_MSG_ERROR([$BREAKPAD_PKG_ERRORS]) fi else have_breakpad="no" fi +AC_SUBST(LIBPLOVER_PRIVATE_REQUIREMENTS) +AC_SUBST(LIBPLOVER_PRIVATE_LIBS) AM_CONDITIONAL([HAVE_BREAKPAD],[test $have_breakpad = yes]) +GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $WHELK_CFLAGS $PLOVER_GTK_CFLAGS \ + $LIBPLOVER_CFLAGS $LUA_POSIX_CFLAGS" +GUI_LIBS="$GMODULE_EXPORT_LIBS $WHELK_LIBS $PLOVER_GTK_LIBS \ + $LIBPLOVER_LIBS $LIBPLOVER_PRIVATE_LIBS $LUA_POSIX_LIBS" +AC_SUBST(GUI_CFLAGS) +AC_SUBST(GUI_LIBS) ################################################## # Checks for library functions. diff -r b3d8e196dac8 -r 2947214c450e plover-gtk/packagestore.c --- a/plover-gtk/packagestore.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover-gtk/packagestore.c Tue Apr 25 17:41:00 2023 +0100 @@ -298,35 +298,64 @@ return strcmp(plover_package_get_name(pa),plover_package_get_name(pb)); } +static gint + plover__sequence_iter_compar(gconstpointer a,gconstpointer b) +{ + GSequenceIter *sia=(GSequenceIter *)a; + GSequenceIter *sib=(GSequenceIter *)b; + return g_sequence_iter_get_position(sia)-g_sequence_iter_get_position(sib); +} + void plover_package_store_add_set(PloverPackageStore *store, PloverPackageSet *set) { - GSList *packages,*link; + GSList *packages,*lnk; GSequenceIter *si; GtkTreeIter ti; GtkTreePath *path; - gint *indices; PloverPackageStorePrivate *priv; g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store)); g_return_if_fail(PLOVER_IS_PACKAGE_SET(set)); priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store); g_return_if_fail(g_slist_find(priv->sets,set) == NULL); g_object_ref(set); + /* + * This is a little complicated because we don't want to + * emit row-inserted until we have actually added set to + * the list of sets. On the other hand, we don't want to + * add set to the list of sets until all the packages it + * contains have been added to the sequence. + * Thus, this two phase implementation. + * However, this introduces an addition complication in + * that the original row numbers are no longer valid as + * we keep inserting rows. GSequenceIter should deal with + * this, but it seems to be giving us problems. Just go + * with the simple solution. + * Finally, the positions of the result have to be + * published in increasing order to avoid confusing + * subscribers. + */ + packages=plover_package_set_get_packages(set); + for(lnk=packages;lnk;lnk=lnk->next) + g_sequence_insert_sorted(priv->seq,lnk->data, + plover__package_compar,NULL); + priv->sets=g_slist_prepend(priv->sets,set); + priv->stamp++; path=gtk_tree_path_new(); gtk_tree_path_append_index(path,0); - indices=gtk_tree_path_get_indices(path); - packages=plover_package_set_get_packages(set); - for(link=packages;link;link=link->next) + si=g_sequence_get_begin_iter(priv->seq); + while(!g_sequence_iter_is_end(si)) { - si=g_sequence_insert_sorted(priv->seq,link->data, - plover__package_compar,NULL); - *indices=g_sequence_iter_get_position(si); - ti.stamp=priv->stamp; - ti.user_data=si; - gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti); + if (g_slist_find(packages,g_sequence_get(si))) + { + ti.stamp=priv->stamp; + ti.user_data=si; + gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti); + } + si=g_sequence_iter_next(si); + gtk_tree_path_next(path); } gtk_tree_path_free(path); - priv->sets=g_slist_prepend(priv->sets,set); } void plover_package_store_remove_set(PloverPackageStore *store, diff -r b3d8e196dac8 -r 2947214c450e plover/Makefile.am --- a/plover/Makefile.am Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/Makefile.am Tue Apr 25 17:41:00 2023 +0100 @@ -1,18 +1,18 @@ -AM_CFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) -AM_CXXFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) -LIBS=$(LIBPLOVER_LIBS) +AM_CFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) $(BREAKPAD_CFLAGS) +AM_CXXFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) $(BREAKPAD_CFLAGS) +LIBS=$(LIBPLOVER_LIBS) $(BREAKPAD_LIBS) INCLUDES=-I$(top_srcdir) AM_LDFLAGS=-no-undefined -version-info $(LIBPLOVER_LT_VERSION_INFO) \ $(CODE_COVERAGE_LDFLAGS) -export-symbols-regex '^plover_[^_]' pkginclude_HEADERS=plover.h transaction.h package.h packageset.h repository.h \ - inputstream.h + yumrepository.h inputstream.h lib_LTLIBRARIES=libplover.la libplover_la_SOURCES=$(pkginclude_HEADERS) util.c import-yum.c razor.c comps.c \ log.c vector.c transaction.c package.c packageset.c repository.c \ - uri-handler.c uri-handler.h inputstream.c exception-handler.cpp \ - ascii-ctype.h + yumrepository.c uri-handler.c uri-handler.h inputstream.c \ + exception-handler.cpp ascii-ctype.h pkgconfigdir=$(libdir)/pkgconfig pkgconfig_DATA=plover.pc diff -r b3d8e196dac8 -r 2947214c450e plover/exception-handler.cpp --- a/plover/exception-handler.cpp Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/exception-handler.cpp Tue Apr 25 17:41:00 2023 +0100 @@ -17,6 +17,7 @@ */ #include +#include "config.h" #include "plover/plover.h" #if defined(HAVE_BREAKPAD) && defined(WIN32) #include @@ -42,7 +43,7 @@ plover_exception_handler=new google_breakpad::ExceptionHandler(dump_path,NULL,NULL,NULL, google_breakpad::ExceptionHandler::HANDLER_ALL,MiniDumpWithDataSegs, - NULL,NULL); + (WCHAR *)NULL,NULL); g_free(dump_path); } #endif /* HAVE_BREAKPAD && WIN32 */ diff -r b3d8e196dac8 -r 2947214c450e plover/import-yum.c --- a/plover/import-yum.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/import-yum.c Tue Apr 25 17:41:00 2023 +0100 @@ -18,454 +18,25 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include #include -#include "plover/plover.h" -#include "plover/uri-handler.h" -#include "plover/inputstream.h" +#include +#include +#include "plover/yumrepository.h" /* Import a yum filelist as a razor package set. */ -enum { - YUM_STATE_BEGIN, - YUM_STATE_PACKAGE_NAME, - YUM_STATE_PACKAGE_ARCH, - YUM_STATE_SUMMARY, - YUM_STATE_DESCRIPTION, - YUM_STATE_URL, - YUM_STATE_LICENSE, - YUM_STATE_CHECKSUM, - YUM_STATE_REQUIRES, - YUM_STATE_PROVIDES, - YUM_STATE_OBSOLETES, - YUM_STATE_CONFLICTS, - YUM_STATE_SKIPPING_PACKAGE, - YUM_STATE_FILE -}; - -struct yum_context { - XML_Parser primary_parser; - XML_Parser filelists_parser; - XML_Parser current_parser; - - struct razor_importer *importer; - struct import_property_context *current_property_context; - const char *base_uri; - GTree *uris; - char name[256], arch[64], summary[512], description[4096]; - char url[256], license[64], buffer[512], *p; - char pkgid[128], evr[128]; - uint32_t property_type; - int state; - - int total, current; -}; - -static uint32_t -yum_to_razor_relation (const char *flags) -{ - if (flags[0] == 'L') { - if (flags[1] == 'T') - return RAZOR_PROPERTY_LESS; - else - return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL; - } else if (flags[0] == 'G') { - if (flags[1] == 'T') - return RAZOR_PROPERTY_GREATER; - else - return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL; - } else - return RAZOR_PROPERTY_EQUAL; -} - -static void -yum_primary_start_element(void *data, const char *name, const char **atts) -{ - struct yum_context *ctx = data; - const char *n, *epoch, *version, *release; - char buffer[128]; - char *s; - gchar *nevra; - uint32_t pre, relation, flags; - int i; - - if (ctx->state == YUM_STATE_SKIPPING_PACKAGE) - return; - - if (strcmp(name, "metadata") == 0) { - for (i = 0; atts[i]; i += 2) { - if (strcmp(atts[i], "packages") == 0) - ctx->total = atoi(atts[i + 1]); - } - } else if (strcmp(name, "package") == 0) { - *ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0'; - *ctx->url=*ctx->license='\0'; - } else if (strcmp(name, "name") == 0) { - ctx->state = YUM_STATE_PACKAGE_NAME; - ctx->p = ctx->name; - } else if (strcmp(name, "arch") == 0) { - ctx->state = YUM_STATE_PACKAGE_ARCH; - ctx->p = ctx->arch; - } else if (strcmp(name, "version") == 0) { - epoch = NULL; - version = NULL; - release = NULL; - for (i = 0; atts[i]; i += 2) { - if (strcmp(atts[i], "epoch") == 0) - epoch = atts[i + 1]; - else if (strcmp(atts[i], "ver") == 0) - version = atts[i + 1]; - else if (strcmp(atts[i], "rel") == 0) - release = atts[i + 1]; - } - if (version == NULL || release == NULL) { - fprintf(stderr, "invalid version tag, " - "missing version or release attribute\n"); - return; - } - - razor_build_evr(ctx->evr, sizeof ctx->evr, epoch, version, - release); - if (!strcmp(ctx->arch, "noarch") || - !strcmp(ctx->arch, razor_system_arch())) { - razor_importer_begin_package(ctx->importer, ctx->name, - ctx->evr, ctx->arch); - } else - ctx->state = YUM_STATE_SKIPPING_PACKAGE; - } else if (strcmp(name, "summary") == 0) { - ctx->p = ctx->summary; - ctx->state = YUM_STATE_SUMMARY; - } else if (strcmp(name, "description") == 0) { - ctx->p = ctx->description; - ctx->state = YUM_STATE_DESCRIPTION; - } else if (strcmp(name, "url") == 0) { - ctx->p = ctx->url; - ctx->state = YUM_STATE_URL; - } else if (strcmp(name, "checksum") == 0) { - ctx->p = ctx->pkgid; - ctx->state = YUM_STATE_CHECKSUM; - } else if (strcmp(name, "location") == 0) { - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) { - for (i = 0; atts[i]; i += 2) - if (strcmp(atts[i], "href") == 0) { - nevra=g_strconcat(ctx->name,"-",ctx->evr,".", - ctx->arch,NULL); - s=razor_path_relative_to_uri(ctx->base_uri, - atts[i + 1],NULL); - g_tree_insert(ctx->uris,nevra,g_strdup(s)); - free(s); - break; - } - } - } else if (strcmp(name, "rpm:license") == 0) { - ctx->p = ctx->license; - ctx->state = YUM_STATE_LICENSE; - } else if (strcmp(name, "rpm:requires") == 0) { - ctx->state = YUM_STATE_REQUIRES; - ctx->property_type = RAZOR_PROPERTY_REQUIRES; - } else if (strcmp(name, "rpm:provides") == 0) { - ctx->state = YUM_STATE_PROVIDES; - ctx->property_type = RAZOR_PROPERTY_PROVIDES; - } else if (strcmp(name, "rpm:obsoletes") == 0) { - ctx->state = YUM_STATE_OBSOLETES; - ctx->property_type = RAZOR_PROPERTY_OBSOLETES; - } else if (strcmp(name, "rpm:conflicts") == 0) { - ctx->state = YUM_STATE_CONFLICTS; - ctx->property_type = RAZOR_PROPERTY_CONFLICTS; - } else if (strcmp(name, "rpm:entry") == 0 && - ctx->state != YUM_STATE_BEGIN) { - n = NULL; - epoch = NULL; - version = NULL; - release = NULL; - relation = RAZOR_PROPERTY_EQUAL; - pre = 0; - for (i = 0; atts[i]; i += 2) { - if (strcmp(atts[i], "name") == 0) - n = atts[i + 1]; - else if (strcmp(atts[i], "epoch") == 0) - epoch = atts[i + 1]; - else if (strcmp(atts[i], "ver") == 0) - version = atts[i + 1]; - else if (strcmp(atts[i], "rel") == 0) - release = atts[i + 1]; - else if (strcmp(atts[i], "flags") == 0) - relation = yum_to_razor_relation(atts[i + 1]); - else if (strcmp(atts[i], "pre") == 0) - pre = RAZOR_PROPERTY_PRE; - } - - if (n == NULL) { - fprintf(stderr, "invalid rpm:entry, " - "missing name or version attributes\n"); - return; - } - - razor_build_evr(buffer, sizeof buffer, epoch, version, release); - flags = ctx->property_type | relation | pre; - razor_importer_add_property(ctx->importer, n, flags, buffer); - } -} - -static void -yum_primary_end_element (void *data, const char *name) -{ - struct yum_context *ctx = data; - - switch (ctx->state) { - case YUM_STATE_PACKAGE_NAME: - case YUM_STATE_PACKAGE_ARCH: - case YUM_STATE_SUMMARY: - case YUM_STATE_DESCRIPTION: - case YUM_STATE_URL: - case YUM_STATE_LICENSE: - case YUM_STATE_CHECKSUM: - case YUM_STATE_FILE: - ctx->state = YUM_STATE_BEGIN; - break; - } - - if (strcmp(name, "package") == 0) { - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) - razor_importer_add_details(ctx->importer, ctx->summary, - ctx->description, ctx->url, - ctx->license); - - XML_StopParser(ctx->current_parser, XML_TRUE); - ctx->current_parser = ctx->filelists_parser; - } -} - -static void -yum_character_data (void *data, const XML_Char *s, int len) -{ - struct yum_context *ctx = data; - - switch (ctx->state) { - case YUM_STATE_PACKAGE_NAME: - case YUM_STATE_PACKAGE_ARCH: - case YUM_STATE_SUMMARY: - case YUM_STATE_DESCRIPTION: - case YUM_STATE_URL: - case YUM_STATE_LICENSE: - case YUM_STATE_CHECKSUM: - case YUM_STATE_FILE: - memcpy(ctx->p, s, len); - ctx->p += len; - *ctx->p = '\0'; - break; - } -} - -static void -yum_filelists_start_element(void *data, const char *name, const char **atts) -{ - struct yum_context *ctx = data; - const char *pkg, *pkgid; - int i; - - if (strcmp(name, "package") == 0 && - ctx->state != YUM_STATE_SKIPPING_PACKAGE) { - pkg = NULL; - pkgid = NULL; - for (i = 0; atts[i]; i += 2) { - if (strcmp(atts[i], "name") == 0) - pkg = atts[i + 1]; - else if (strcmp(atts[i], "pkgid") == 0) - pkgid = atts[i + 1]; - } - if (strcmp(pkgid, ctx->pkgid) != 0) - fprintf(stderr, "primary.xml and filelists.xml " - "mismatch for %s: %s vs %s", - pkg, pkgid, ctx->pkgid); - } else if (strcmp(name, "file") == 0) { - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) - ctx->state = YUM_STATE_FILE; - ctx->p = ctx->buffer; - } -} - -static void -yum_filelists_end_element (void *data, const char *name) -{ - struct yum_context *ctx = data; - - if (strcmp(name, "package") == 0) { - XML_StopParser(ctx->current_parser, XML_TRUE); - ctx->current_parser = ctx->primary_parser; - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) - razor_importer_finish_package(ctx->importer); - ctx->state = YUM_STATE_BEGIN; - } else if (strcmp(name, "file") == 0) { - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) - razor_importer_add_file(ctx->importer, ctx->buffer); - } - if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) - ctx->state = YUM_STATE_BEGIN; -} - -static int plover_system_arch_is_x86(void) -{ - const char *arch=razor_system_arch(); - if (!arch || arch[0]!='i' || arch[1]<'3' || arch[1]>'6') - return 0; - else - return !strcmp(arch+2,"86"); -} - -#define XML_BUFFER_SIZE 4096 - -PloverRepository *plover_repository_new_from_yum_uri(const char *base_uri, - GError **error) -{ - struct yum_context ctx; - gchar *s,**rpm_uris; - GPtrArray *uris; - char *uri; - const char *name,*version,*arch; - void *buf; - gssize len; - GInputStream *stream; - GInputStream *primary,*filelists; - GZlibDecompressor *decompressor; - XML_ParsingStatus status; - struct razor_set *razor; - struct razor_package_iterator *iter; - struct razor_package *pkg; - PloverPackageSet *set; - PloverRepository *repository; - g_return_val_if_fail(plover__uri_validate(base_uri),NULL); - plover__uri_handler_init(); - ctx.importer=razor_importer_create(); - ctx.state=YUM_STATE_BEGIN; - ctx.base_uri=base_uri; - ctx.primary_parser=XML_ParserCreate(NULL); - XML_SetUserData(ctx.primary_parser,&ctx); - XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element, - yum_primary_end_element); - XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data); - ctx.filelists_parser=XML_ParserCreate(NULL); - XML_SetUserData(ctx.filelists_parser,&ctx); - XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element, - yum_filelists_end_element); - XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data); - uri=razor_path_relative_to_uri(base_uri,"repodata/primary.xml.gz",NULL); - stream=plover_razor_input_stream_new(uri,error); - free(uri); - if (!stream) { - XML_ParserFree(ctx.primary_parser); - XML_ParserFree(ctx.filelists_parser); - return NULL; - } - decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP); - primary=g_converter_input_stream_new(G_INPUT_STREAM(stream), - G_CONVERTER(decompressor)); - g_object_unref(stream); - g_object_unref(decompressor); - uri=razor_path_relative_to_uri(base_uri,"repodata/filelists.xml.gz",NULL); - stream=plover_razor_input_stream_new(uri,error); - free(uri); - if (!stream) { - g_object_unref(primary); - XML_ParserFree(ctx.primary_parser); - XML_ParserFree(ctx.filelists_parser); - return NULL; - } - decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP); - filelists=g_converter_input_stream_new(G_INPUT_STREAM(stream), - G_CONVERTER(decompressor)); - g_object_unref(stream); - g_object_unref(decompressor); - ctx.current_parser=ctx.primary_parser; - ctx.uris=g_tree_new_full((GCompareDataFunc)strcmp,NULL,g_free,NULL); - ctx.current=0; - do - { - XML_GetParsingStatus(ctx.current_parser,&status); - switch (status.parsing) - { - case XML_SUSPENDED: - XML_ResumeParser(ctx.current_parser); - break; - case XML_PARSING: - case XML_INITIALIZED: - buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE); - if (ctx.current_parser==ctx.primary_parser) - len=g_input_stream_read(G_INPUT_STREAM(primary),buf, - XML_BUFFER_SIZE,NULL,error); - else - len=g_input_stream_read(G_INPUT_STREAM(filelists),buf, - XML_BUFFER_SIZE,NULL,error); - if (len<0) - return NULL; - XML_ParseBuffer(ctx.current_parser,len,!len); - break; - case XML_FINISHED: - break; - } - } while (status.parsing!=XML_FINISHED); - XML_ParserFree(ctx.primary_parser); - XML_ParserFree(ctx.filelists_parser); - g_object_unref(primary); - g_object_unref(filelists); - razor=razor_importer_finish(ctx.importer); -#if RAZOR_HEADER_VERSION_MIN<=1 - /* - * Header version 1 is supported by plover v0.3 and is used on - * 32-bit intel machines which allows the setup and update - * applications from v0.3 to work. On other machines, we don't - * want these old applications to work (since they would do - * the wrong thing) and so we use the current header version - * which they don't support. - */ - if (plover_system_arch_is_x86()) - razor_set_set_header_version(razor,1); -#endif - uris=g_ptr_array_new(); - iter=razor_package_iterator_create(razor); - while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_NAME,&name, - RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST)) - { - s=g_strconcat(name,"-",version,".",arch,NULL); - g_ptr_array_add(uris,g_tree_lookup(ctx.uris,s)); - g_free(s); - } - razor_package_iterator_destroy(iter); - g_ptr_array_add(uris,NULL); - g_tree_unref(ctx.uris); - rpm_uris=(gchar **)g_ptr_array_free(uris,FALSE); - set=plover_package_set_new_from_razor(razor); - razor_set_unref(razor); - repository=plover_repository_new_from_package_set(set, - (const char **)rpm_uris); - g_object_unref(set); - g_strfreev(rpm_uris); - return repository; -} - struct razor_set *plover_razor_set_create_from_yum_uri(const char *base_uri, GError **error) { - PloverRepository *repository; + PloverYumRepository *repository; PloverPackageSet *set; struct razor_set *razor; g_return_val_if_fail(plover__uri_validate(base_uri),NULL); - repository=plover_repository_new_from_yum_uri(base_uri,error); + repository=plover_yum_repository_new_from_uri(base_uri,error); if (!repository) return NULL; - set=plover_repository_get_package_set(repository); + set=plover_repository_get_package_set(PLOVER_REPOSITORY(repository)); razor=plover_package_set_get_razor(set); razor_set_ref(razor); g_object_unref(repository); diff -r b3d8e196dac8 -r 2947214c450e plover/log.c --- a/plover/log.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/log.c Tue Apr 25 17:41:00 2023 +0100 @@ -288,6 +288,7 @@ int plover_log_open(const char *path) { + static gchar *logfile=NULL; int retval; char *root; gchar *filename,*uri; @@ -367,7 +368,8 @@ g_free(filename); return -1; } - g_free(filename); + if (logfile) + printf("Switching logging to %s on %s",filename,ctime(&t)); #ifdef WIN32 /* * The situation under MS-Windows is a little complicated. If standard @@ -402,7 +404,17 @@ SetStdHandle(STD_ERROR_HANDLE,(HANDLE)_get_osfhandle(2)); #endif time(&t); - printf("Run started on %s",ctime(&t)); + if (logfile) + { + printf("Logging switched from %s on %s",logfile,ctime(&t)); + g_free(logfile); + logfile=filename; + } + else + { + printf("Run started on %s",ctime(&t)); + logfile=filename; + } fflush(stdout); return 0; } diff -r b3d8e196dac8 -r 2947214c450e plover/packageset.c --- a/plover/packageset.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/packageset.c Tue Apr 25 17:41:00 2023 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012, 2014 J. Ali Harlow + * Copyright (C) 2010-2012, 2014, 2023 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 @@ -38,6 +38,7 @@ GSList *packages; int no_details; gchar *guessed_prefix; + PloverRepository *repository; } PloverPackageSetPrivate; #define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\ @@ -118,6 +119,7 @@ g_free(priv->root_uri); priv->root_uri=NULL; } + g_clear_object(&priv->repository); } gboolean plover_package_set_open(PloverPackageSet *set,const char *root_uri, @@ -354,9 +356,18 @@ priv->set=plover_package_set_get_razor(unrelocated); razor_set_ref(priv->set); } + priv->repository=g_object_ref(repository); return set; } +PloverRepository *plover_package_set_get_repository(PloverPackageSet *set) +{ + PloverPackageSetPrivate *priv; + g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL); + priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set); + return priv->repository; +} + PloverPackageSet *plover_package_set_new_from_yum(const char *base, struct razor_relocations *relocations,GError **error) { @@ -700,6 +711,9 @@ priv->guessed_prefix=plover_comps_get_default_prefix(comps); plover_comps_free(comps); } + if (!priv->guessed_prefix) + g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, + "No popular prefixes and no default prefix either"); return priv->guessed_prefix; } diff -r b3d8e196dac8 -r 2947214c450e plover/packageset.h --- a/plover/packageset.h Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/packageset.h Tue Apr 25 17:41:00 2023 +0100 @@ -49,6 +49,7 @@ PloverPackageSet * plover_package_set_new_from_repository(PloverRepository *repository, struct razor_relocations *relocations,GError **err); +PloverRepository *plover_package_set_get_repository(PloverPackageSet *set); PloverPackageSet *plover_package_set_new_from_yum(const char *base, struct razor_relocations *relocations,GError **err); PloverPackageSet *plover_package_set_new_from_rpms(const char **filenames, diff -r b3d8e196dac8 -r 2947214c450e plover/plover.h --- a/plover/plover.h Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/plover.h Tue Apr 25 17:41:00 2023 +0100 @@ -112,6 +112,7 @@ void plover_comps_set_vendor(struct comps *comps,const char *vendor); void plover_comps_set_distribution(struct comps *comps, const char *distribution); +const char *plover_get_vendor_prefix(void); gchar *plover_comps_get_default_prefix(struct comps *comps); int plover_log_open(const char *path); diff -r b3d8e196dac8 -r 2947214c450e plover/plover.pc.in --- a/plover/plover.pc.in Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/plover.pc.in Tue Apr 25 17:41:00 2023 +0100 @@ -6,6 +6,8 @@ Name: plover Description: Plover packaging system Version: @VERSION@ -Requires: razor expat zlib glib2 +Requires: @LIBPLOVER_REQUIREMENTS@ +Requires.private: @LIBPLOVER_PRIVATE_REQUIREMENTS@ Libs: -L${libdir} -lplover +Libs.private: @LIBPLOVER_PRIVATE_LIBS@ Cflags: -I${includedir} diff -r b3d8e196dac8 -r 2947214c450e plover/repository.c --- a/plover/repository.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/repository.c Tue Apr 25 17:41:00 2023 +0100 @@ -19,12 +19,22 @@ #include "config.h" #include #include +#include #include #include #include #include #include "plover/uri-handler.h" +enum { + PROP_0, + PROP_PACKAGE_SET, + PROP_RPM_URIS, + LAST_PROP +}; + +static GParamSpec *properties[LAST_PROP]={0}; + G_DEFINE_TYPE(PloverRepository,plover_repository,G_TYPE_OBJECT); typedef struct _PloverRepositoryPrivate { @@ -53,12 +63,60 @@ G_OBJECT_CLASS(plover_repository_parent_class)->dispose(obj); } +static void plover_repository_set_property(GObject *obj,guint property_id, + const GValue *value,GParamSpec *pspec) +{ + PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj); + switch (property_id) + { + case PROP_PACKAGE_SET: + g_clear_object(&priv->set); + priv->set=g_value_dup_object(value); + break; + case PROP_RPM_URIS: + g_strfreev(priv->uris); + priv->uris=g_value_dup_boxed(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj,property_id,pspec); + break; + } +} + +static void plover_repository_get_property(GObject *obj,guint property_id, + GValue *value,GParamSpec *pspec) +{ + PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj); + switch (property_id) + { + case PROP_PACKAGE_SET: + g_value_set_object(value,priv->set); + break; + case PROP_RPM_URIS: + g_value_set_boxed(value,priv->uris); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj,property_id,pspec); + break; + } +} + static void plover_repository_class_init(PloverRepositoryClass *klass) { GObjectClass *oclass=G_OBJECT_CLASS(klass); plover__uri_handler_init(); oclass->finalize=plover_repository_finalize; oclass->dispose=plover_repository_dispose; + oclass->set_property=plover_repository_set_property; + oclass->get_property=plover_repository_get_property; + g_object_class_install_property(oclass,PROP_PACKAGE_SET, + g_param_spec_object("package-set",_("Package set"), + _("The package set helper object"),PLOVER_TYPE_PACKAGE_SET, + G_PARAM_STATIC_STRINGS|G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property(oclass,PROP_RPM_URIS, + g_param_spec_boxed("rpm-uris",_("RPM URIs"), + _("List of URIs, one for each RPM"),G_TYPE_STRV, + G_PARAM_STATIC_STRINGS|G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private(klass,sizeof(PloverRepositoryPrivate)); } @@ -69,15 +127,10 @@ PloverRepository *plover_repository_new_from_package_set(PloverPackageSet *set, const char **rpm_uris) { - PloverRepository *repository; - PloverRepositoryPrivate *priv; g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL); g_return_val_if_fail(rpm_uris != NULL,NULL); - repository=g_object_new(PLOVER_TYPE_REPOSITORY,NULL); - priv=PLOVER_REPOSITORY_GET_PRIVATE(repository); - priv->uris=g_strdupv((char **)rpm_uris); - priv->set=g_object_ref(set); - return repository; + return g_object_new(PLOVER_TYPE_REPOSITORY,"package-set",set, + "rpm-uris",rpm_uris,NULL); } PloverRepository *plover_repository_new_from_files(const char **filenames, @@ -105,20 +158,6 @@ return repository; } -PloverRepository *plover_repository_new_from_yum(const char *base, - GError **error) -{ - PloverRepository *repository; - gchar *base_uri; - GFile *file; - file=g_file_new_for_path(base); - base_uri=g_file_get_uri(file); - g_object_unref(file); - repository=plover_repository_new_from_yum_uri(base_uri,error); - g_free(base_uri); - return repository; -} - PloverPackageSet * plover_repository_get_package_set(PloverRepository *repository) { diff -r b3d8e196dac8 -r 2947214c450e plover/util.c --- a/plover/util.c Tue Jun 29 10:09:34 2021 +0100 +++ b/plover/util.c Tue Apr 25 17:41:00 2023 +0100 @@ -30,37 +30,49 @@ #include "plover.h" #include "ascii-ctype.h" -gchar *plover_comps_get_default_prefix(struct comps *comps) +const char *plover_get_vendor_prefix(void) { - const char *vendor_prefix; + static gchar *vendor_prefix=NULL; /* Leaked */ #ifdef WIN32 - /* - * We want to sidestep any redirecting that MS-Windows may - * introduce since this will be based on the architecture - * of the installer whereas the architecture that actually - * matters is of the packages (checked elsewhere). - */ BOOL is_wow64=FALSE; typedef BOOL (WINAPI *is_wow64_process_t)(HANDLE,PBOOL); is_wow64_process_t is_wow64_process; char *program_files=NULL; char buf[PATH_MAX]; - is_wow64_process=(is_wow64_process_t) - GetProcAddress(GetModuleHandleA("kernel32"),"IsWow64Process"); - if (is_wow64_process) - is_wow64_process(GetCurrentProcess(),&is_wow64); - if (is_wow64) - program_files=getenv("ProgramW6432"); - if (!program_files) +#endif + if (!vendor_prefix) { - SHGetFolderPath(NULL,CSIDL_PROGRAM_FILES|CSIDL_FLAG_DONT_VERIFY,NULL,0, - buf); - program_files=buf; +#ifdef WIN32 + /* + * We want to sidestep any redirecting that MS-Windows may + * introduce since this will be based on the architecture + * of the installer whereas the architecture that actually + * matters is of the packages (checked elsewhere). + */ + is_wow64_process=(is_wow64_process_t) + GetProcAddress(GetModuleHandleA("kernel32"),"IsWow64Process"); + if (is_wow64_process) + is_wow64_process(GetCurrentProcess(),&is_wow64); + if (is_wow64) + program_files=getenv("ProgramW6432"); + if (!program_files) + { + SHGetFolderPath(NULL,CSIDL_PROGRAM_FILES|CSIDL_FLAG_DONT_VERIFY, + NULL,0,buf); + program_files=buf; + } + vendor_prefix=g_strdup(program_files); +#else + vendor_prefix=g_strdup(g_getenv("PLOVER_VENDOR_PREFIX")); +#endif } - vendor_prefix=program_files; -#else - vendor_prefix=g_getenv("PLOVER_VENDOR_PREFIX"); -#endif + return vendor_prefix; +} + +gchar *plover_comps_get_default_prefix(struct comps *comps) +{ + const char *vendor_prefix; + vendor_prefix=plover_get_vendor_prefix(); if (!vendor_prefix) return NULL; else if (!comps) @@ -156,13 +168,25 @@ if (!d) { if (g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT)) - g_mkdir_with_parents(path,0777); + { + if (g_mkdir_with_parents(path,0777)) + g_warning("Failed to create reports directory: %s: %s",path, + g_strerror(errno)); + else + g_message("0 reports found in %s",path); + } + else + g_warning("Failed to open reports directory: %s: %s",path, + err->message); + g_clear_error(&err); return; } while(count<=MAX_REPORTS && g_dir_read_name(d)) count++; if (count>MAX_REPORTS) { + g_message("Purging %d report%s from %s",count-MAX_REPORTS, + count-MAX_REPORTS==1?"":"s",path); g_dir_rewind(d); while((name=g_dir_read_name(d))) { @@ -188,6 +212,8 @@ files=g_list_delete_link(files,files); } } + else + g_message("%d report%s found in %s",count,count==1?"":"s",path); g_dir_close(d); } diff -r b3d8e196dac8 -r 2947214c450e plover/yumrepository.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plover/yumrepository.c Tue Apr 25 17:41:00 2023 +0100 @@ -0,0 +1,554 @@ + +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * Copyright (C) 2009, 2011, 2014, 2016, 2023 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. + */ + +#define _GNU_SOURCE + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_DEFINE_TYPE(PloverYumRepository,plover_yum_repository,PLOVER_TYPE_REPOSITORY); + +typedef struct _PloverYumRepositoryPrivate { + gchar *base_uri; + struct comps *comps; +} PloverYumRepositoryPrivate; + +#define PLOVER_YUM_REPOSITORY_GET_PRIVATE(obj)\ + G_TYPE_INSTANCE_GET_PRIVATE(obj,\ + PLOVER_TYPE_YUM_REPOSITORY,\ + PloverYumRepositoryPrivate) + +enum { + YUM_STATE_BEGIN, + YUM_STATE_PACKAGE_NAME, + YUM_STATE_PACKAGE_ARCH, + YUM_STATE_SUMMARY, + YUM_STATE_DESCRIPTION, + YUM_STATE_URL, + YUM_STATE_LICENSE, + YUM_STATE_CHECKSUM, + YUM_STATE_REQUIRES, + YUM_STATE_PROVIDES, + YUM_STATE_OBSOLETES, + YUM_STATE_CONFLICTS, + YUM_STATE_SKIPPING_PACKAGE, + YUM_STATE_FILE +}; + +struct yum_context { + XML_Parser primary_parser; + XML_Parser filelists_parser; + XML_Parser current_parser; + + struct razor_importer *importer; + struct import_property_context *current_property_context; + const char *base_uri; + GTree *uris; + char name[256], arch[64], summary[512], description[4096]; + char url[256], license[64], buffer[512], *p; + char pkgid[128], evr[128]; + uint32_t property_type; + int state; + + int total, current; +}; + +static void plover_yum_repository_finalize(GObject *obj) +{ + PloverYumRepositoryPrivate *priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(obj); + plover_comps_free(priv->comps); + g_free(priv->base_uri); + if (G_OBJECT_CLASS(plover_yum_repository_parent_class)->finalize) + G_OBJECT_CLASS(plover_yum_repository_parent_class)->finalize(obj); +} + +static void plover_yum_repository_class_init(PloverYumRepositoryClass *klass) +{ + GObjectClass *oclass=G_OBJECT_CLASS(klass); + plover__uri_handler_init(); + oclass->finalize=plover_yum_repository_finalize; + g_type_class_add_private(klass,sizeof(PloverYumRepositoryPrivate)); +} + +static void plover_yum_repository_init(PloverYumRepository *repository) +{ +} + +static uint32_t +yum_to_razor_relation (const char *flags) +{ + if (flags[0] == 'L') { + if (flags[1] == 'T') + return RAZOR_PROPERTY_LESS; + else + return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL; + } else if (flags[0] == 'G') { + if (flags[1] == 'T') + return RAZOR_PROPERTY_GREATER; + else + return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL; + } else + return RAZOR_PROPERTY_EQUAL; +} + +static void +yum_primary_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *n, *epoch, *version, *release; + char buffer[128]; + char *s; + gchar *nevra; + uint32_t pre, relation, flags; + int i; + + if (ctx->state == YUM_STATE_SKIPPING_PACKAGE) + return; + + if (strcmp(name, "metadata") == 0) { + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "packages") == 0) + ctx->total = atoi(atts[i + 1]); + } + } else if (strcmp(name, "package") == 0) { + *ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0'; + *ctx->url=*ctx->license='\0'; + } else if (strcmp(name, "name") == 0) { + ctx->state = YUM_STATE_PACKAGE_NAME; + ctx->p = ctx->name; + } else if (strcmp(name, "arch") == 0) { + ctx->state = YUM_STATE_PACKAGE_ARCH; + ctx->p = ctx->arch; + } else if (strcmp(name, "version") == 0) { + epoch = NULL; + version = NULL; + release = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + } + if (version == NULL || release == NULL) { + fprintf(stderr, "invalid version tag, " + "missing version or release attribute\n"); + return; + } + + razor_build_evr(ctx->evr, sizeof ctx->evr, epoch, version, + release); + if (!strcmp(ctx->arch, "noarch") || + !strcmp(ctx->arch, razor_system_arch())) { + razor_importer_begin_package(ctx->importer, ctx->name, + ctx->evr, ctx->arch); + } else + ctx->state = YUM_STATE_SKIPPING_PACKAGE; + } else if (strcmp(name, "summary") == 0) { + ctx->p = ctx->summary; + ctx->state = YUM_STATE_SUMMARY; + } else if (strcmp(name, "description") == 0) { + ctx->p = ctx->description; + ctx->state = YUM_STATE_DESCRIPTION; + } else if (strcmp(name, "url") == 0) { + ctx->p = ctx->url; + ctx->state = YUM_STATE_URL; + } else if (strcmp(name, "checksum") == 0) { + ctx->p = ctx->pkgid; + ctx->state = YUM_STATE_CHECKSUM; + } else if (strcmp(name, "location") == 0) { + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) { + for (i = 0; atts[i]; i += 2) + if (strcmp(atts[i], "href") == 0) { + nevra=g_strconcat(ctx->name,"-",ctx->evr,".", + ctx->arch,NULL); + s=razor_path_relative_to_uri(ctx->base_uri, + atts[i + 1],NULL); + g_tree_insert(ctx->uris,nevra,g_strdup(s)); + free(s); + break; + } + } + } else if (strcmp(name, "rpm:license") == 0) { + ctx->p = ctx->license; + ctx->state = YUM_STATE_LICENSE; + } else if (strcmp(name, "rpm:requires") == 0) { + ctx->state = YUM_STATE_REQUIRES; + ctx->property_type = RAZOR_PROPERTY_REQUIRES; + } else if (strcmp(name, "rpm:provides") == 0) { + ctx->state = YUM_STATE_PROVIDES; + ctx->property_type = RAZOR_PROPERTY_PROVIDES; + } else if (strcmp(name, "rpm:obsoletes") == 0) { + ctx->state = YUM_STATE_OBSOLETES; + ctx->property_type = RAZOR_PROPERTY_OBSOLETES; + } else if (strcmp(name, "rpm:conflicts") == 0) { + ctx->state = YUM_STATE_CONFLICTS; + ctx->property_type = RAZOR_PROPERTY_CONFLICTS; + } else if (strcmp(name, "rpm:entry") == 0 && + ctx->state != YUM_STATE_BEGIN) { + n = NULL; + epoch = NULL; + version = NULL; + release = NULL; + relation = RAZOR_PROPERTY_EQUAL; + pre = 0; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + n = atts[i + 1]; + else if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + else if (strcmp(atts[i], "flags") == 0) + relation = yum_to_razor_relation(atts[i + 1]); + else if (strcmp(atts[i], "pre") == 0) + pre = RAZOR_PROPERTY_PRE; + } + + if (n == NULL) { + fprintf(stderr, "invalid rpm:entry, " + "missing name or version attributes\n"); + return; + } + + razor_build_evr(buffer, sizeof buffer, epoch, version, release); + flags = ctx->property_type | relation | pre; + razor_importer_add_property(ctx->importer, n, flags, buffer); + } +} + +static void +yum_primary_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_SUMMARY: + case YUM_STATE_DESCRIPTION: + case YUM_STATE_URL: + case YUM_STATE_LICENSE: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + ctx->state = YUM_STATE_BEGIN; + break; + } + + if (strcmp(name, "package") == 0) { + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) + razor_importer_add_details(ctx->importer, ctx->summary, + ctx->description, ctx->url, + ctx->license); + + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->filelists_parser; + } +} + +static void +yum_character_data (void *data, const XML_Char *s, int len) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_SUMMARY: + case YUM_STATE_DESCRIPTION: + case YUM_STATE_URL: + case YUM_STATE_LICENSE: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + memcpy(ctx->p, s, len); + ctx->p += len; + *ctx->p = '\0'; + break; + } +} + +static void +yum_filelists_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *pkg, *pkgid; + int i; + + if (strcmp(name, "package") == 0 && + ctx->state != YUM_STATE_SKIPPING_PACKAGE) { + pkg = NULL; + pkgid = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + pkg = atts[i + 1]; + else if (strcmp(atts[i], "pkgid") == 0) + pkgid = atts[i + 1]; + } + if (strcmp(pkgid, ctx->pkgid) != 0) + fprintf(stderr, "primary.xml and filelists.xml " + "mismatch for %s: %s vs %s", + pkg, pkgid, ctx->pkgid); + } else if (strcmp(name, "file") == 0) { + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) + ctx->state = YUM_STATE_FILE; + ctx->p = ctx->buffer; + } +} + +static void +yum_filelists_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + if (strcmp(name, "package") == 0) { + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->primary_parser; + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) + razor_importer_finish_package(ctx->importer); + ctx->state = YUM_STATE_BEGIN; + } else if (strcmp(name, "file") == 0) { + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) + razor_importer_add_file(ctx->importer, ctx->buffer); + } + if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) + ctx->state = YUM_STATE_BEGIN; +} + +static int plover_system_arch_is_x86(void) +{ + const char *arch=razor_system_arch(); + if (!arch || arch[0]!='i' || arch[1]<'3' || arch[1]>'6') + return 0; + else + return !strcmp(arch+2,"86"); +} + +#define XML_BUFFER_SIZE 4096 + +PloverYumRepository *plover_yum_repository_new_from_uri(const char *base_uri, + GError **error) +{ + struct yum_context ctx; + gchar *s,**rpm_uris; + GPtrArray *uris; + char *uri; + const char *name,*version,*arch; + void *buf; + gssize len; + GInputStream *stream; + GInputStream *primary,*filelists; + GZlibDecompressor *decompressor; + XML_ParsingStatus status; + struct razor_set *razor; + struct razor_package_iterator *iter; + struct razor_package *pkg; + PloverPackageSet *set; + PloverYumRepository *repository; + PloverYumRepositoryPrivate *priv; + g_return_val_if_fail(plover__uri_validate(base_uri),NULL); + ctx.importer=razor_importer_create(); + ctx.state=YUM_STATE_BEGIN; + ctx.base_uri=base_uri; + ctx.primary_parser=XML_ParserCreate(NULL); + XML_SetUserData(ctx.primary_parser,&ctx); + XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element, + yum_primary_end_element); + XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data); + ctx.filelists_parser=XML_ParserCreate(NULL); + XML_SetUserData(ctx.filelists_parser,&ctx); + XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element, + yum_filelists_end_element); + XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data); + uri=razor_path_relative_to_uri(base_uri,"repodata/primary.xml.gz",NULL); + stream=plover_razor_input_stream_new(uri,error); + free(uri); + if (!stream) { + XML_ParserFree(ctx.primary_parser); + XML_ParserFree(ctx.filelists_parser); + return NULL; + } + decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP); + primary=g_converter_input_stream_new(G_INPUT_STREAM(stream), + G_CONVERTER(decompressor)); + g_object_unref(stream); + g_object_unref(decompressor); + uri=razor_path_relative_to_uri(base_uri,"repodata/filelists.xml.gz",NULL); + stream=plover_razor_input_stream_new(uri,error); + free(uri); + if (!stream) { + g_object_unref(primary); + XML_ParserFree(ctx.primary_parser); + XML_ParserFree(ctx.filelists_parser); + return NULL; + } + decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP); + filelists=g_converter_input_stream_new(G_INPUT_STREAM(stream), + G_CONVERTER(decompressor)); + g_object_unref(stream); + g_object_unref(decompressor); + ctx.current_parser=ctx.primary_parser; + ctx.uris=g_tree_new_full((GCompareDataFunc)strcmp,NULL,g_free,NULL); + ctx.current=0; + do + { + XML_GetParsingStatus(ctx.current_parser,&status); + switch (status.parsing) + { + case XML_SUSPENDED: + XML_ResumeParser(ctx.current_parser); + break; + case XML_PARSING: + case XML_INITIALIZED: + buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE); + if (ctx.current_parser==ctx.primary_parser) + len=g_input_stream_read(G_INPUT_STREAM(primary),buf, + XML_BUFFER_SIZE,NULL,error); + else + len=g_input_stream_read(G_INPUT_STREAM(filelists),buf, + XML_BUFFER_SIZE,NULL,error); + if (len<0) + return NULL; + XML_ParseBuffer(ctx.current_parser,len,!len); + break; + case XML_FINISHED: + break; + } + } while (status.parsing!=XML_FINISHED); + XML_ParserFree(ctx.primary_parser); + XML_ParserFree(ctx.filelists_parser); + g_object_unref(primary); + g_object_unref(filelists); + razor=razor_importer_finish(ctx.importer); +#if RAZOR_HEADER_VERSION_MIN<=1 + /* + * Header version 1 is supported by plover v0.3 and is used on + * 32-bit intel machines which allows the setup and update + * applications from v0.3 to work. On other machines, we don't + * want these old applications to work (since they would do + * the wrong thing) and so we use the current header version + * which they don't support. + */ + if (plover_system_arch_is_x86()) + razor_set_set_header_version(razor,1); +#endif + uris=g_ptr_array_new(); + iter=razor_package_iterator_create(razor); + while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_NAME,&name, + RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST)) + { + s=g_strconcat(name,"-",version,".",arch,NULL); + g_ptr_array_add(uris,g_tree_lookup(ctx.uris,s)); + g_free(s); + } + razor_package_iterator_destroy(iter); + g_ptr_array_add(uris,NULL); + g_tree_unref(ctx.uris); + rpm_uris=(gchar **)g_ptr_array_free(uris,FALSE); + set=plover_package_set_new_from_razor(razor); + razor_set_unref(razor); + repository=g_object_new(PLOVER_TYPE_YUM_REPOSITORY,"package-set",set, + "rpm-uris",rpm_uris,NULL); + g_object_unref(set); + g_strfreev(rpm_uris); + priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(repository); + priv->base_uri=g_strdup(base_uri); + return repository; +} + +PloverYumRepository *plover_yum_repository_new_from_path(const char *base, + GError **error) +{ + PloverYumRepository *repository; + gchar *base_uri; + GFile *file; + file=g_file_new_for_path(base); + base_uri=g_file_get_uri(file); + g_object_unref(file); + repository=plover_yum_repository_new_from_uri(base_uri,error); + g_free(base_uri); + return repository; +} + +/* Compatibility function: Depreciated in favour of + * plover_yum_repository_new_from_uri() + */ + +PloverRepository *plover_repository_new_from_yum_uri(const char *base_uri, + GError **error) +{ + PloverYumRepository *repository; + repository=plover_yum_repository_new_from_uri(base_uri,error); + return repository?PLOVER_REPOSITORY(repository):NULL; +} + +/* Compatibility function: Depreciated in favour of + * plover_yum_repository_new_from_path() + */ + +PloverRepository *plover_repository_new_from_yum(const char *base, + GError **error) +{ + PloverYumRepository *repository; + repository=plover_yum_repository_new_from_path(base,error); + return repository?PLOVER_REPOSITORY(repository):NULL; +} + +struct comps *plover_yum_repository_get_comps(PloverYumRepository *repository, + GError **error) +{ + gchar *uri; + PloverYumRepositoryPrivate *priv; + g_return_val_if_fail(PLOVER_IS_YUM_REPOSITORY(repository),NULL); + priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(repository); + if (!priv->base_uri) + { + g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, + "No base URI set"); + return NULL; + } + if (!priv->comps) + { + uri=razor_path_relative_to_uri(priv->base_uri,"repodata/comps.xml", + NULL); + priv->comps=plover_comps_new_from_uri(uri,error); + free(uri); + } + return priv->comps; +} diff -r b3d8e196dac8 -r 2947214c450e plover/yumrepository.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plover/yumrepository.h Tue Apr 25 17:41:00 2023 +0100 @@ -0,0 +1,46 @@ +#ifndef __PLOVER_YUM_REPOSITORY_H__ +#define __PLOVER_YUM_REPOSITORY_H__ + +#include + +G_BEGIN_DECLS + +#define PLOVER_TYPE_YUM_REPOSITORY \ + plover_yum_repository_get_type() +#define PLOVER_YUM_REPOSITORY(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,\ + PLOVER_TYPE_YUM_REPOSITORY,\ + PloverYumRepository) +#define PLOVER_YUM_REPOSITORY_CLASS(klass)\ + G_TYPE_CHECK_CLASS_CAST(klass,\ + PLOVER_TYPE_YUM_REPOSITORY,\ + PloverYumRepositoryClass) +#define PLOVER_IS_YUM_REPOSITORY(obj)\ + G_TYPE_CHECK_INSTANCE_TYPE(obj,\ + PLOVER_TYPE_YUM_REPOSITORY) +#define PLOVER_IS_YUM_REPOSITORY_CLASS(klass)\ + G_TYPE_CHECK_CLASS_TYPE(obj,\ + PLOVER_TYPE_YUM_REPOSITORY) +#define PLOVER_YUM_REPOSITORY_GET_CLASS(obj)\ + G_TYPE_INSTANCE_GET_CLASS(obj,\ + PLOVER_TYPE_YUM_REPOSITORY,\ + PloverYumRepositoryClass) + +typedef struct _PloverYumRepository { + PloverRepository parent_instance; +} PloverYumRepository; + +typedef struct _PloverYumRepositoryClass { + PloverRepositoryClass parent_class; +} PloverYumRepositoryClass; + +GType plover_yum_repository_get_type(void) G_GNUC_CONST; +PloverYumRepository *plover_yum_repository_new_from_uri(const char *base_uri, + GError **error); +PloverYumRepository *plover_yum_repository_new_from_path(const char *base, + GError **error); +struct comps *plover_yum_repository_get_comps(PloverYumRepository *repository, + GError **error); + +G_END_DECLS + +#endif /* __PLOVER_YUM_REPOSITORY_H__ */ diff -r b3d8e196dac8 -r 2947214c450e pre-inst/pre-inst.c --- a/pre-inst/pre-inst.c Tue Jun 29 10:09:34 2021 +0100 +++ b/pre-inst/pre-inst.c Tue Apr 25 17:41:00 2023 +0100 @@ -48,12 +48,13 @@ #endif /* WIN32 */ #include "post.h" -#ifdef WIN32 -/* Under WIN32, g_spawn requires a helper program which we'd rather avoid */ -#undef USE_G_SPAWN -#else +/* + * Under WIN32, g_spawn may require a helper program which we'd rather avoid. + * At least with glib 2.58, this isn't needed if g_spawn_sync() is used (or + * G_SPAWN_DO_NOT_REAP_CHILD is specified), so we can now define USE_G_SPAWN + * unconditionally. + */ #define USE_G_SPAWN -#endif LUALIB_API int luaopen_posix(lua_State *L); @@ -376,6 +377,7 @@ "Post command exited with code %ld",(long)rc); return FALSE; } + fprintf(stderr,"post command exited normally\n"); return TRUE; } @@ -422,6 +424,29 @@ return TRUE; } +print_arguments(int argc,char **argv) +{ + int i,j; + for(i=0;iargc>0) + { + printf("Running post command: "); + print_arguments(post->argc,post->argv); + putchar('\n'); pre_install_spawn_sync(post->argv,&error); + } else if (argv) run_post(argc,argv,success,repository,&error); if (post)