/** * asb_context_write_xml: **/ static gboolean asb_context_write_xml (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; g_autofree gchar *filename = NULL; g_autoptr(AsStore) store = NULL; g_autoptr(GFile) file = NULL; /* convert any vetod applications into dummy components */ for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (!ASB_IS_APP (app)) continue; if (as_app_get_vetos(app)->len == 0) continue; asb_context_add_app_ignore (ctx, asb_app_get_package (ASB_APP (app))); } /* add any non-vetoed applications */ store = as_store_new (); for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_vetos(app)->len > 0) continue; as_store_add_app (store, app); as_store_remove_app (priv->store_failed, app); /* remove from the ignore list if the application was useful */ if (ASB_IS_APP (app)) { AsbPackage *pkg = asb_app_get_package (ASB_APP (app)); g_autofree gchar *name_arch = NULL; name_arch = g_strdup_printf ("%s.%s", asb_package_get_name (pkg), asb_package_get_arch (pkg)); as_store_remove_app_by_id (priv->store_ignore, name_arch); } } filename = g_strdup_printf ("%s/%s.xml.gz", priv->output_dir, priv->basename); file = g_file_new_for_path (filename); g_print ("Writing %s...\n", filename); as_store_set_origin (store, priv->origin); as_store_set_api_version (store, priv->api_version); if (priv->flags & ASB_CONTEXT_FLAG_ADD_CACHE_ID) { g_autofree gchar *builder_id = asb_utils_get_builder_id (); as_store_set_builder_id (store, builder_id); } return as_store_to_file (store, file, AS_NODE_TO_XML_FLAG_ADD_HEADER | AS_NODE_TO_XML_FLAG_FORMAT_INDENT | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, NULL, error); }
/** * asb_context_detect_missing_parents: **/ static gboolean asb_context_detect_missing_parents (AsbContext *ctx, GError **error) { AsApp *app; AsApp *found; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; const gchar *tmp; g_autoptr(GHashTable) hash = NULL; /* add all desktop apps to the hash */ hash = g_hash_table_new (g_str_hash, g_str_equal); for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (!ASB_IS_APP (app)) continue; if (as_app_get_pkgname_default (app) == NULL) continue; if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; g_hash_table_insert (hash, (gpointer) as_app_get_id (app), app); } /* look for the thing that an addon extends */ for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (!ASB_IS_APP (app)) continue; if (as_app_get_pkgname_default (app) == NULL) continue; if (as_app_get_id_kind (app) != AS_ID_KIND_ADDON) continue; if (as_app_get_extends(app)->len == 0) continue; tmp = g_ptr_array_index (as_app_get_extends(app), 0); found = g_hash_table_lookup (hash, tmp); if (found != NULL) continue; found = as_store_get_app_by_id (priv->store_old, tmp); if (found != NULL) continue; /* do not add the addon */ as_app_add_veto (app, "%s has no parent of '%s'", as_app_get_id (app), tmp); g_print ("WARNING: %s has no parent of '%s'\n", as_app_get_id (app), tmp); } return TRUE; }
/** * asb_context_write_app_xml: **/ static void asb_context_write_app_xml (AsbContext *ctx) { AsbApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; /* log the XML in the log file */ for (l = priv->apps; l != NULL; l = l->next) { g_autoptr(GString) xml = NULL; g_autoptr(AsStore) store = NULL; /* we have an open log file? */ if (!ASB_IS_APP (l->data)) continue; /* just log raw XML */ app = ASB_APP (l->data); store = as_store_new (); as_store_set_api_version (store, 1.0f); as_store_add_app (store, AS_APP (app)); xml = as_store_to_xml (store, AS_NODE_TO_XML_FLAG_FORMAT_INDENT | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE); asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_NONE, "%s", xml->str); } }
/** * asb_context_detect_pkgname_dups: **/ static gboolean asb_context_detect_pkgname_dups (AsbContext *ctx, GError **error) { AsApp *app; AsApp *found; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; const gchar *pkgname; g_autoptr(GHashTable) hash = NULL; hash = g_hash_table_new (g_str_hash, g_str_equal); for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); pkgname = as_app_get_pkgname_default (app); if (pkgname == NULL) continue; if (ASB_IS_APP (app) && as_app_get_vetos(app)->len > 0) continue; found = g_hash_table_lookup (hash, pkgname); if (found != NULL) { g_print ("WARNING: %s and %s share the package '%s'\n", as_app_get_id (app), as_app_get_id (found), pkgname); continue; } g_hash_table_insert (hash, (gpointer) pkgname, app); } return TRUE; }
/** * asb_plugin_merge: */ void asb_plugin_merge (AsbPlugin *plugin, GList **list) { AsApp *app; AsApp *found; GList *l; GList *list_new = NULL; _cleanup_hashtable_unref_ GHashTable *hash; /* make a hash table of ID->AsApp */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (l = *list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; g_hash_table_insert (hash, g_strdup (as_app_get_id_full (app)), g_object_ref (app)); } /* add addons where the pkgname is different from the * main package */ for (l = *list; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) { asb_plugin_add_app (&list_new, l->data); continue; } app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_ADDON) { asb_plugin_add_app (&list_new, l->data); continue; } found = g_hash_table_lookup (hash, as_app_get_id_full (app)); if (found == NULL) { asb_plugin_add_app (&list_new, l->data); continue; } if (g_strcmp0 (as_app_get_pkgname_default (app), as_app_get_pkgname_default (found)) == 0) { g_debug ("absorbing addon %s shipped in main package %s", as_app_get_id_full (app), as_app_get_pkgname_default (app)); as_app_subsume_full (found, app, AS_APP_SUBSUME_FLAG_PARTIAL); continue; } asb_plugin_add_app (&list_new, app); } /* success */ g_list_free_full (*list, (GDestroyNotify) g_object_unref); *list = list_new; }
/** * asb_plugin_composite_app: */ static void asb_plugin_composite_app (AsApp *app, AsApp *donor) { _cleanup_error_free_ GError *error = NULL; /* composite the app */ if (!_as_app_composite (app, donor, &error)) { if (ASB_IS_APP (app)) { asb_package_log (asb_app_get_package (ASB_APP (app)), ASB_PACKAGE_LOG_LEVEL_INFO, "%s", error->message); } else { g_warning ("%s", error->message); } return; } }
/** * asb_context_write_xml_fail: **/ static gboolean asb_context_write_xml_fail (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; g_autofree gchar *basename_failed = NULL; g_autofree gchar *filename = NULL; g_autoptr(GFile) file = NULL; /* no need to create */ if ((priv->flags & ASB_CONTEXT_FLAG_INCLUDE_FAILED) == 0) return TRUE; for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); if (!ASB_IS_APP (app)) continue; if (as_app_get_vetos(app)->len == 0) continue; if (as_store_get_app_by_id (priv->store_failed, as_app_get_id (app)) != NULL) continue; as_store_add_app (priv->store_failed, app); } filename = g_strdup_printf ("%s/%s-failed.xml.gz", priv->output_dir, priv->basename); file = g_file_new_for_path (filename); g_print ("Writing %s...\n", filename); basename_failed = g_strdup_printf ("%s-failed", priv->origin); as_store_set_origin (priv->store_failed, basename_failed); as_store_set_api_version (priv->store_failed, priv->api_version); if (priv->flags & ASB_CONTEXT_FLAG_ADD_CACHE_ID) { g_autofree gchar *builder_id = asb_utils_get_builder_id (); as_store_set_builder_id (priv->store_failed, builder_id); } return as_store_to_file (priv->store_failed, file, AS_NODE_TO_XML_FLAG_ADD_HEADER | AS_NODE_TO_XML_FLAG_FORMAT_INDENT | AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE, NULL, error); }
/** * asb_plugin_merge_prepare_deps: */ static void asb_plugin_merge_prepare_deps (GList *list) { AsApp *app; AsbPackage *pkg; GList *l; for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_id_kind (app) != AS_ID_KIND_DESKTOP) continue; if (!ASB_IS_APP (app)) continue; if (as_app_get_vetos(app)->len > 0) continue; pkg = asb_app_get_package (ASB_APP (app)); asb_plugin_absorb_parent_for_pkgname (list, app, asb_package_get_name (pkg)); } }
void asb_plugin_merge (AsbPlugin *plugin, GList *list) { AsApp *app; AsApp *found; GList *l; g_autoptr(GHashTable) hash = NULL; /* make a hash table of ID->AsApp */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (l = list; l != NULL; l = l->next) { app = AS_APP (l->data); if (as_app_get_kind (app) != AS_APP_KIND_DESKTOP) continue; g_hash_table_insert (hash, g_strdup (as_app_get_id (app)), g_object_ref (app)); } /* add addons where the pkgname is different from the * main package */ for (l = list; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = AS_APP (l->data); if (as_app_get_kind (app) != AS_APP_KIND_ADDON) continue; found = g_hash_table_lookup (hash, as_app_get_id (app)); if (found == NULL) continue; if (g_strcmp0 (as_app_get_pkgname_default (app), as_app_get_pkgname_default (found)) != 0) continue; as_app_add_veto (app, "absorbing addon %s shipped in " "main package %s", as_app_get_id (app), as_app_get_pkgname_default (app)); as_app_subsume_full (found, app, AS_APP_SUBSUME_FLAG_PARTIAL); } }
/** * asb_context_save_resources: **/ static gboolean asb_context_save_resources (AsbContext *ctx, GError **error) { AsApp *app; AsbContextPrivate *priv = GET_PRIVATE (ctx); GList *l; for (l = priv->apps; l != NULL; l = l->next) { app = AS_APP (l->data); /* save icon */ if (as_app_get_vetos(app)->len > 0) continue; if (!ASB_IS_APP (app)) continue; if (!asb_app_save_resources (ASB_APP (app), ASB_APP_SAVE_FLAG_ICONS, error)) return FALSE; } return TRUE; }
/** * asb_plugin_loader_merge: * @plugin_loader: A #AsbPluginLoader * @apps: (element-type AsbApp): a list of applications that need merging * * Merge the list of applications using the plugins. * * Since: 0.2.5 **/ void asb_plugin_loader_merge (AsbPluginLoader *plugin_loader, GList *apps) { AsbApp *app; AsbApp *found; AsbPluginLoaderPrivate *priv = GET_PRIVATE (plugin_loader); AsbPluginMergeFunc plugin_func = NULL; AsbPlugin *plugin; GList *l; const gchar *key; const gchar *tmp; gboolean ret; guint i; g_autoptr(GHashTable) hash = NULL; /* run each plugin */ for (i = 0; i < priv->plugins->len; i++) { plugin = g_ptr_array_index (priv->plugins, i); ret = g_module_symbol (plugin->module, "asb_plugin_merge", (gpointer *) &plugin_func); if (!ret) continue; plugin_func (plugin, apps); } /* FIXME: move to font plugin */ for (l = apps; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = ASB_APP (l->data); as_app_remove_metadata (AS_APP (app), "FontFamily"); as_app_remove_metadata (AS_APP (app), "FontFullName"); as_app_remove_metadata (AS_APP (app), "FontIconText"); as_app_remove_metadata (AS_APP (app), "FontParent"); as_app_remove_metadata (AS_APP (app), "FontSampleText"); as_app_remove_metadata (AS_APP (app), "FontSubFamily"); as_app_remove_metadata (AS_APP (app), "FontClassifier"); } /* deduplicate */ hash = g_hash_table_new (g_str_hash, g_str_equal); for (l = apps; l != NULL; l = l->next) { if (!ASB_IS_APP (l->data)) continue; app = ASB_APP (l->data); if (as_app_get_vetos(AS_APP(app))->len > 0) continue; key = as_app_get_id (AS_APP (app)); found = g_hash_table_lookup (hash, key); if (found == NULL) { g_hash_table_insert (hash, (gpointer) key, (gpointer) app); continue; } if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_FIRMWARE) { as_app_subsume_full (AS_APP (found), AS_APP (app), AS_APP_SUBSUME_FLAG_MERGE); } tmp = asb_package_get_nevr (asb_app_get_package (found)); as_app_add_veto (AS_APP (app), "duplicate of %s", tmp); asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_WARNING, "duplicate %s not included as added from %s", key, tmp); } }
/** * _as_app_composite: */ static gboolean _as_app_composite (AsApp *app, AsApp *donor, GError **error) { AsApp *tmp; gint rc; _cleanup_free_ gchar *id = NULL; /* check this makes sense */ if (as_app_get_id_kind (app) != as_app_get_id_kind (donor)) { g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_INVALID_TYPE, "Cannot composite %s:%s of different id kind", as_app_get_id (app), as_app_get_id (donor)); return FALSE; } /* the ID, name with the shortest length wins */ rc = strlen (as_app_get_id (app)) - strlen (as_app_get_id (donor)); if (rc == 0) { rc = strlen (as_app_get_name (app, "C")) - strlen (as_app_get_name (donor, "C")); } if (rc > 0) { tmp = app; app = donor; donor = tmp; } /* set the new composite string */ id = as_utils_get_string_overlap (as_app_get_id (app), as_app_get_id (donor)); if (id == NULL || !_as_app_is_id_valid (id)) { g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_INVALID_TYPE, "Cannot composite %s:%s as no ID overlap", as_app_get_id (app), as_app_get_id (donor)); return FALSE; } /* log */ if (ASB_IS_APP (app) && g_strcmp0 (as_app_get_id (app), id) != 0) { asb_package_log (asb_app_get_package (ASB_APP (app)), ASB_PACKAGE_LOG_LEVEL_INFO, "Renamed %s into %s so it could be " "composited with %s", as_app_get_id (app), id, as_app_get_id (donor)); } if (ASB_IS_APP (donor)) { asb_package_log (asb_app_get_package (ASB_APP (donor)), ASB_PACKAGE_LOG_LEVEL_INFO, "Composited %s into %s", as_app_get_id (donor), id); } /* set the new ID (on both apps?) */ as_app_set_id (app, id, -1); /* add some easily merged properties */ as_app_subsume_full (app, donor, AS_APP_SUBSUME_FLAG_PARTIAL); as_app_add_veto (donor, "absorbed into %s", as_app_get_id (app)); return TRUE; }