app-manager/localdistributions.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Apr 25 17:41:00 2023 +0100 (2023-04-25)
changeset 109 2947214c450e
permissions -rw-r--r--
Partial fix for #5537
     1 /*
     2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
     3  * Copyright (C) 2023  J. Ali Harlow <ali@juiblex.co.uk>
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #include "config.h"
    21 #include <stdlib.h>
    22 #include <string.h>
    23 #include <glib-object.h>
    24 #include <gtk/gtk.h>
    25 #include <plover/plover.h>
    26 #include "localdistributions.h"
    27 
    28 #define VALID_ITER(iter,local) ((iter) && (iter)->user_data && \
    29 	PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local)->stamp==(iter)->stamp)
    30 
    31 static GType column_types[PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS];
    32 
    33 static void
    34   plover_local_distributions_tree_model_init(GtkTreeModelIface *iface);
    35 
    36 G_DEFINE_TYPE_WITH_CODE(PloverLocalDistributions,plover_local_distributions,
    37   G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
    38   plover_local_distributions_tree_model_init));
    39 
    40 typedef struct _PloverLocalDistribution {
    41     gchar *vendor,*distribution,*prefix,*user_friendly,*database_uri;
    42 } PloverLocalDistribution;
    43 
    44 typedef struct _PloverLocalDistributionsPrivate {
    45     GList *distributions;
    46     int stamp;
    47 } PloverLocalDistributionsPrivate;
    48 
    49 #define PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj)\
    50 				G_TYPE_INSTANCE_GET_PRIVATE(obj,\
    51 				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\
    52 				  PloverLocalDistributionsPrivate)
    53 
    54 PloverLocalDistribution *plover_local_distribution_new(const char *vendor,
    55   const char *distribution)
    56 {
    57     gchar *s;
    58     struct comps *comps;
    59     PloverLocalDistribution *ld;
    60     ld=g_new0(PloverLocalDistribution,1);
    61     ld->vendor=g_strdup(vendor);
    62     if (distribution)
    63     {
    64 	ld->distribution=g_strdup(distribution);
    65 	ld->user_friendly=g_strdup_printf("%s (%s)",distribution,vendor);
    66     }
    67     else
    68 	ld->user_friendly=g_strdup(vendor);
    69     comps=plover_comps_new();
    70     plover_comps_set_vendor(comps,vendor);
    71     if (distribution)
    72 	plover_comps_set_distribution(comps,distribution);
    73     ld->prefix=plover_comps_get_default_prefix(comps);
    74     plover_comps_free(comps);
    75     s=g_build_filename(ld->prefix,"var","lib","razor",NULL);
    76     ld->database_uri=razor_path_to_uri(s);
    77     g_free(s);
    78     return ld;
    79 }
    80 
    81 void plover_local_distribution_free(PloverLocalDistribution *ld)
    82 {
    83     if (ld)
    84     {
    85 	g_free(ld->vendor);
    86 	g_free(ld->distribution);
    87 	g_free(ld->prefix);
    88 	g_free(ld->user_friendly);
    89 	g_free(ld->database_uri);
    90 	g_free(ld);
    91     }
    92 }
    93 
    94 static void plover_local_distributions_finalize(GObject *obj)
    95 {
    96     PloverLocalDistributionsPrivate *priv;
    97     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj);
    98     g_list_foreach(priv->distributions,(GFunc)plover_local_distribution_free,
    99       NULL);
   100     g_list_free(priv->distributions);
   101     if (G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize)
   102 	G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize(obj);
   103 }
   104 
   105 static void
   106   plover_local_distributions_class_init(PloverLocalDistributionsClass *klass)
   107 {
   108     GObjectClass *oclass=G_OBJECT_CLASS(klass);
   109     oclass->finalize=plover_local_distributions_finalize;
   110     g_type_class_add_private(klass,sizeof(PloverLocalDistributionsPrivate));
   111     column_types[PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN]=G_TYPE_STRING;
   112     column_types[PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN]=G_TYPE_STRING;
   113     column_types[PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN]=G_TYPE_STRING;
   114     column_types[PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN]=G_TYPE_STRING;
   115     column_types[PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN]=G_TYPE_STRING;
   116 }
   117 
   118 static GtkTreeModelFlags
   119 plover_local_distributions_get_flags(GtkTreeModel *tree_model)
   120 {
   121     return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY;
   122 }
   123 
   124 static gint plover_local_distributions_get_n_columns(GtkTreeModel *tree_model)
   125 {
   126     return PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS;
   127 }
   128 
   129 static GType
   130   plover_local_distributions_get_column_type(GtkTreeModel *tree_model,gint indx)
   131 {
   132     g_return_val_if_fail(indx>=0 && indx<PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS,
   133       G_TYPE_INVALID);
   134     return column_types[indx];
   135 }
   136 
   137 static gboolean plover_local_distributions_get_iter(GtkTreeModel *tree_model,
   138   GtkTreeIter *iter,GtkTreePath *path)
   139 {
   140     int i;
   141     PloverLocalDistributionsPrivate *priv;
   142     PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   143     PloverLocalDistribution *ld;
   144     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   145     i=gtk_tree_path_get_indices(path)[0];
   146     ld=g_list_nth_data(priv->distributions,i);
   147     if (!ld)
   148 	return FALSE;
   149     iter->stamp=priv->stamp;
   150     iter->user_data=ld;
   151     return TRUE;
   152 }
   153 
   154 static GtkTreePath *
   155   plover_local_distributions_get_path(GtkTreeModel *tree_model,
   156   GtkTreeIter *iter)
   157 {
   158     GtkTreePath *path;
   159     PloverLocalDistributionsPrivate *priv;
   160     PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   161     g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL);
   162     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   163     path=gtk_tree_path_new();
   164     gtk_tree_path_append_index(path,
   165       g_list_index(priv->distributions,iter->user_data));
   166     return path;
   167 }
   168 
   169 static void plover_local_distributions_get_value(GtkTreeModel *tree_model,
   170   GtkTreeIter *iter,gint column,GValue *value)
   171 {
   172     gchar *s;
   173     PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   174     PloverLocalDistribution *ld;
   175     g_return_if_fail(column>=0 && column<PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS);
   176     g_return_if_fail(VALID_ITER(iter,local));
   177     ld=iter->user_data;
   178     g_value_init(value,column_types[column]);
   179     switch((PloverLocalDistributionsColumn)column)
   180     {
   181 	case PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN:
   182 	    g_value_set_string(value,ld->vendor);
   183 	    break;
   184 	case PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN:
   185 	    g_value_set_string(value,ld->distribution);
   186 	    break;
   187 	case PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN:
   188 	    g_value_set_string(value,ld->prefix);
   189 	    break;
   190 	case PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN:
   191 	    g_value_set_string(value,ld->user_friendly);
   192 	    break;
   193 	case PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN:
   194 	    g_value_set_string(value,ld->database_uri);
   195 	    break;
   196 	case PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS:
   197 	    /* Quieten compiler warning */
   198 	    break;
   199     }
   200 }
   201 
   202 static gboolean
   203   plover_local_distributions_iter_next(GtkTreeModel *tree_model,
   204   GtkTreeIter *iter)
   205 {
   206     GList *lnk;
   207     PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   208     PloverLocalDistributionsPrivate *priv;
   209     g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE);
   210     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   211     lnk=g_list_find(priv->distributions,iter->user_data);
   212     iter->user_data=lnk->next?lnk->next->data:NULL;
   213     return !!iter->user_data;
   214 }
   215 
   216 static gboolean
   217   plover_local_distributions_iter_children(GtkTreeModel *tree_model,
   218   GtkTreeIter *iter,GtkTreeIter *parent)
   219 {
   220     PloverLocalDistributionsPrivate *priv;
   221     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   222     /* this is a list, nodes have no children */
   223     if (parent)
   224 	return FALSE;
   225     if (priv->distributions)
   226     {
   227 	iter->stamp=priv->stamp;
   228 	iter->user_data=priv->distributions->data;
   229 	return TRUE;
   230     }
   231     else
   232 	return FALSE;
   233 }
   234 
   235 static gboolean
   236   plover_local_distributions_iter_has_child(GtkTreeModel *tree_model,
   237   GtkTreeIter *iter)
   238 {
   239     PloverLocalDistributionsPrivate *priv;
   240     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   241     return !!priv->distributions;
   242 }
   243 
   244 static gint plover_local_distributions_iter_n_children(GtkTreeModel *tree_model,
   245   GtkTreeIter *iter)
   246 {
   247     PloverLocalDistributionsPrivate *priv;
   248     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   249     if (!iter)
   250 	return g_list_length(priv->distributions);
   251     g_return_val_if_fail(VALID_ITER(iter,tree_model),-1);
   252     return 0;
   253 }
   254 
   255 static gboolean
   256   plover_local_distributions_iter_nth_child(GtkTreeModel *tree_model,
   257   GtkTreeIter *iter,GtkTreeIter *parent,gint n)
   258 {
   259     GList *lnk;
   260     PloverLocalDistributionsPrivate *priv;
   261     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   262     if (parent)
   263 	return FALSE;
   264     lnk=g_list_nth(priv->distributions,n);
   265     if (!lnk)
   266 	return FALSE;
   267     iter->stamp=priv->stamp;
   268     iter->user_data=lnk->data;
   269     return TRUE;
   270 }
   271 
   272 static gboolean plover_local_distributions_iter_parent(GtkTreeModel *tree_model,
   273   GtkTreeIter *iter,GtkTreeIter *child)
   274 {
   275     return FALSE;
   276 }
   277 
   278 static void plover_local_distributions_tree_model_init(GtkTreeModelIface *iface)
   279 {
   280     iface->get_flags=plover_local_distributions_get_flags;
   281     iface->get_n_columns=plover_local_distributions_get_n_columns;
   282     iface->get_column_type=plover_local_distributions_get_column_type;
   283     iface->get_iter=plover_local_distributions_get_iter;
   284     iface->get_path=plover_local_distributions_get_path;
   285     iface->get_value=plover_local_distributions_get_value;
   286     iface->iter_next=plover_local_distributions_iter_next;
   287     iface->iter_children=plover_local_distributions_iter_children;
   288     iface->iter_has_child=plover_local_distributions_iter_has_child;
   289     iface->iter_n_children=plover_local_distributions_iter_n_children;
   290     iface->iter_nth_child=plover_local_distributions_iter_nth_child;
   291     iface->iter_parent=plover_local_distributions_iter_parent;
   292 }
   293 
   294 static void plover_local_distributions_init(PloverLocalDistributions *store)
   295 {
   296     gchar *s;
   297     const char *vendor_prefix,*vendor,*distribution;
   298     GDir *vendor_dir,*distribution_dir,*database_dir;
   299     PloverLocalDistributionsPrivate *priv;
   300     PloverLocalDistribution *ld;
   301     priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(store);
   302     /*
   303      * local distribution databases may be found in
   304      * <vendor-prefix>/$VENDOR/$DISTRIBUTION/var/lib/razor and
   305      * <vendor-prefix>/$VENDOR/var/lib/razor
   306      */
   307     vendor_prefix=plover_get_vendor_prefix();
   308     g_message("Vendor prefix is %s",vendor_prefix);
   309     vendor_dir=g_dir_open(vendor_prefix,0,NULL);
   310     if (!vendor_dir)
   311     {
   312 	g_warning("Failed to open %s",vendor_prefix);
   313 	return;
   314     }
   315     while((vendor=g_dir_read_name(vendor_dir)))
   316     {
   317 	g_message("Candidate for vendor is %s",vendor);
   318 	s=g_build_filename(vendor_prefix,vendor,NULL);
   319 	distribution_dir=g_dir_open(s,0,NULL);
   320 	g_free(s);
   321 	if (!distribution_dir)
   322 	{
   323 	    g_warning("Failed to open %s/%s",vendor_prefix,vendor);
   324 	    continue;
   325 	}
   326 	while((distribution=g_dir_read_name(distribution_dir)))
   327 	{
   328 	    g_message("Candidate for distribution is %s",distribution);
   329 	    if (!strcmp(distribution,"var"))
   330 	    {
   331 		s=g_build_filename(vendor_prefix,vendor,"var","lib","razor",
   332 		  NULL);
   333 		database_dir=g_dir_open(s,0,NULL);
   334 		g_free(s);
   335 		if (database_dir)
   336 		{
   337 		    ld=plover_local_distribution_new(vendor,NULL);
   338 		    g_message("Found vendor-specific razor database at %s",
   339 		      ld->database_uri);
   340 		    priv->distributions=g_list_prepend(priv->distributions,ld);
   341 		    g_dir_close(database_dir);
   342 		}
   343 		else
   344 		    g_warning("Failed to open %s/%s/var/lib/razor",
   345 		      vendor_prefix,vendor);
   346 	    }
   347 	    s=g_build_filename(vendor_prefix,vendor,distribution,
   348 	      "var","lib","razor",NULL);
   349 	    database_dir=g_dir_open(s,0,NULL);
   350 	    g_free(s);
   351 	    if (database_dir)
   352 	    {
   353 		ld=plover_local_distribution_new(vendor,distribution);
   354 		g_message("Found local-distribution razor database at %s",
   355 		  ld->database_uri);
   356 		priv->distributions=g_list_prepend(priv->distributions,ld);
   357 		g_dir_close(database_dir);
   358 	    }
   359 	    else
   360 		g_warning("Failed to open %s/%s/%s/var/lib/razor",
   361 		  vendor_prefix,vendor,distribution);
   362 	}
   363 	g_dir_close(distribution_dir);
   364     }
   365     g_dir_close(vendor_dir);
   366     priv->stamp=g_random_int();
   367 }
   368 
   369 PloverLocalDistributions *plover_local_distributions_new(void)
   370 {
   371     return g_object_new(PLOVER_TYPE_LOCAL_DISTRIBUTIONS,NULL);
   372 }