/** * asb_task_explode_extra_package: **/ static gboolean asb_task_explode_extra_package (AsbTask *task, const gchar *pkg_name, gboolean require_same_srpm, GError **error) { AsbTaskPrivate *priv = GET_PRIVATE (task); AsbPackage *pkg_extra; GPtrArray *deps; guint i; const gchar *dep; /* if not found, that's fine */ pkg_extra = asb_context_find_by_pkgname (priv->ctx, pkg_name); if (pkg_extra == NULL) return TRUE; /* check it's from the same source package */ if (!asb_package_ensure (pkg_extra, ASB_PACKAGE_ENSURE_SOURCE, error)) return FALSE; if (require_same_srpm && (g_strcmp0 (asb_package_get_source (pkg_extra), asb_package_get_source (priv->pkg)) != 0)) return TRUE; g_debug ("decompressing extra pkg %s", asb_package_get_name (pkg_extra)); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Adding extra package %s for %s", asb_package_get_name (pkg_extra), asb_package_get_name (priv->pkg)); if (!asb_package_ensure (pkg_extra, ASB_PACKAGE_ENSURE_FILES | ASB_PACKAGE_ENSURE_DEPS, error)) return FALSE; if (!asb_package_explode (pkg_extra, priv->tmpdir, asb_context_get_file_globs (priv->ctx), error)) return FALSE; /* copy all the extra package requires into the main package too */ deps = asb_package_get_deps (pkg_extra); for (i = 0; i < deps->len; i++) { dep = g_ptr_array_index (deps, i); asb_package_add_dep (priv->pkg, dep); } /* free resources */ if (!asb_package_close (pkg_extra, error)) return FALSE; asb_package_clear (pkg_extra, ASB_PACKAGE_ENSURE_DEPS | ASB_PACKAGE_ENSURE_FILES); return TRUE; }
/** * 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_add_app_ignore: **/ void asb_context_add_app_ignore (AsbContext *ctx, AsbPackage *pkg) { AsApp *app_tmp; AsbContextPrivate *priv = GET_PRIVATE (ctx); g_autofree gchar *name_arch = NULL; g_autoptr(AsApp) app = NULL; g_autoptr(GPtrArray) apps = NULL; /* only do this when we are using a cache-id */ if ((priv->flags & ASB_CONTEXT_FLAG_ADD_CACHE_ID) == 0) return; /* check not already added a dummy application for this package */ apps = as_store_get_apps_by_metadata (priv->store_ignore, "X-CacheID", asb_package_get_basename (pkg)); if (apps->len > 0) { g_debug ("already found CacheID of %s", asb_package_get_basename (pkg)); return; } /* package name already exists, but with a different CacheID */ name_arch = g_strdup_printf ("%s.%s", asb_package_get_name (pkg), asb_package_get_arch (pkg)); app_tmp = as_store_get_app_by_id (priv->store_ignore, name_arch); if (app_tmp != NULL) { as_app_add_metadata (AS_APP (app_tmp), "X-CacheID", asb_package_get_basename (pkg)); return; } /* never encountered before, so add */ app = as_app_new (); as_app_set_id (app, name_arch); as_app_add_pkgname (app, asb_package_get_name (pkg)); as_app_add_metadata (app, "X-CacheID", asb_package_get_basename (pkg)); as_store_add_app (priv->store_ignore, app); }
/** * asb_context_find_by_pkgname: * @ctx: A #AsbContext * @pkgname: a package name * * Find a package from its name. * * Returns: (transfer none): a #AsbPackage, or %NULL for not found. * * Since: 0.1.0 **/ AsbPackage * asb_context_find_by_pkgname (AsbContext *ctx, const gchar *pkgname) { AsbContextPrivate *priv = GET_PRIVATE (ctx); AsbPackage *pkg; guint i; for (i = 0; i < priv->packages->len; i++) { pkg = g_ptr_array_index (priv->packages, i); if (g_strcmp0 (asb_package_get_name (pkg), pkgname) == 0) return pkg; } return NULL; }
/** * asb_context_add_filename: * @ctx: A #AsbContext * @filename: package filename * @error: A #GError or %NULL * * Adds a filename to the list of packages to be processed * * Returns: %TRUE for success, %FALSE otherwise * * Since: 0.1.0 **/ gboolean asb_context_add_filename (AsbContext *ctx, const gchar *filename, GError **error) { g_autoptr(AsbPackage) pkg = NULL; /* can find in existing metadata */ if (asb_context_find_in_cache (ctx, filename)) { g_debug ("Found %s in old metadata", filename); return TRUE; } /* open */ #if HAVE_RPM if (g_str_has_suffix (filename, ".rpm")) pkg = asb_package_rpm_new (); #endif #if HAVE_ALPM if (g_str_has_suffix (filename, ".pkg.tar.xz")) pkg = asb_package_alpm_new (); #endif if (g_str_has_suffix (filename, ".cab")) pkg = asb_package_cab_new (); if (g_str_has_suffix (filename, ".deb")) pkg = asb_package_deb_new (); if (pkg == NULL) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "No idea how to handle %s", filename); return FALSE; } /* add to array */ asb_package_set_filename (pkg, filename); /* failed to guess the nevra */ if (asb_package_get_name (pkg) == NULL) { if (!asb_package_open (pkg, filename, error)) return FALSE; } asb_context_add_package (ctx, pkg); return TRUE; }
/** * 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)); } }
/** * asb_context_disable_older_pkgs: **/ static void asb_context_disable_older_pkgs (AsbContext *ctx) { AsbContextPrivate *priv = GET_PRIVATE (ctx); AsbPackage *found; AsbPackage *pkg; const gchar *key; guint i; g_autoptr(GHashTable) newest = NULL; newest = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); for (i = 0; i < priv->packages->len; i++) { pkg = ASB_PACKAGE (g_ptr_array_index (priv->packages, i)); if (!asb_package_get_enabled (pkg)) continue; key = asb_package_get_name (pkg); if (key == NULL) continue; switch (asb_package_get_kind (pkg)) { case ASB_PACKAGE_KIND_DEFAULT: case ASB_PACKAGE_KIND_BUNDLE: found = g_hash_table_lookup (newest, key); if (found != NULL) { if (asb_package_compare (pkg, found) <= 0) { asb_package_set_enabled (pkg, FALSE); continue; } asb_package_set_enabled (found, FALSE); } break; default: /* allow multiple versions */ break; } g_hash_table_insert (newest, g_strdup (key), g_object_ref (pkg)); } }
/** * asb_task_process: * @task: A #AsbTask * @error_not_used: A #GError or %NULL * * Processes the task. * * Returns: %TRUE for success, %FALSE otherwise * * Since: 0.1.0 **/ gboolean asb_task_process (AsbTask *task, GError **error_not_used) { AsRelease *release; AsbApp *app; AsbPlugin *plugin = NULL; AsbTaskPrivate *priv = GET_PRIVATE (task); GList *apps = NULL; GList *l; GPtrArray *array; gboolean ret; gchar *cache_id; guint i; guint nr_added = 0; g_autoptr(GError) error = NULL; g_autofree gchar *basename = NULL; /* reset the profile timer */ asb_package_log_start (priv->pkg); /* ensure nevra read */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_NEVRA, error_not_used)) return FALSE; g_debug ("starting: %s", asb_package_get_name (priv->pkg)); /* treat archive as a special case */ if (g_str_has_suffix (priv->filename, ".cab")) { AsApp *app_tmp; GPtrArray *apps_tmp; g_autoptr(AsStore) store = as_store_new (); g_autoptr(GFile) file = g_file_new_for_path (priv->filename); if (!as_store_from_file (store, file, NULL, NULL, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to parse %s: %s", asb_package_get_filename (priv->pkg), error->message); return TRUE; } apps_tmp = as_store_get_apps (store); for (i = 0; i < apps_tmp->len; i++) { g_autoptr(AsbApp) app2 = NULL; app_tmp = AS_APP (g_ptr_array_index (apps_tmp, i)); app2 = asb_app_new (priv->pkg, as_app_get_id (app_tmp)); as_app_subsume (AS_APP (app2), app_tmp); asb_context_add_app (priv->ctx, app2); /* set cache-id in case we want to use the metadata directly */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID)) { cache_id = asb_utils_get_cache_id_for_filename (priv->filename); as_app_add_metadata (AS_APP (app2), "X-CacheID", cache_id); g_free (cache_id); } nr_added++; } g_debug ("added %i apps from archive", apps_tmp->len); goto skip; } /* ensure file list read */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_FILES, error_not_used)) return FALSE; /* did we get a file match on any plugin */ basename = g_path_get_basename (priv->filename); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Getting filename match for %s", basename); asb_task_add_suitable_plugins (task); if (priv->plugins_to_run->len == 0) { asb_context_add_app_ignore (priv->ctx, priv->pkg); goto out; } /* delete old tree if it exists */ ret = asb_utils_ensure_exists_and_empty (priv->tmpdir, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to clear: %s", error->message); goto out; } /* explode tree */ g_debug ("decompressing files: %s", asb_package_get_name (priv->pkg)); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Exploding tree for %s", asb_package_get_name (priv->pkg)); ret = asb_package_explode (priv->pkg, priv->tmpdir, asb_context_get_file_globs (priv->ctx), &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to explode: %s", error->message); g_clear_error (&error); goto skip; } /* add extra packages */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_DEPS | ASB_PACKAGE_ENSURE_SOURCE, error_not_used)) return FALSE; ret = asb_task_explode_extra_packages (task, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to explode extra file: %s", error->message); goto skip; } /* run plugins */ g_debug ("examining: %s", asb_package_get_name (priv->pkg)); for (i = 0; i < priv->plugins_to_run->len; i++) { GList *apps_tmp = NULL; plugin = g_ptr_array_index (priv->plugins_to_run, i); asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "Processing %s with %s", basename, plugin->name); apps_tmp = asb_plugin_process (plugin, priv->pkg, priv->tmpdir, &error); if (apps_tmp == NULL) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to run process '%s': %s", plugin->name, error->message); g_clear_error (&error); } for (l = apps_tmp; l != NULL; l = l->next) { app = ASB_APP (l->data); asb_plugin_add_app (&apps, AS_APP (app)); } g_list_free_full (apps_tmp, g_object_unref); } if (apps == NULL) goto skip; /* print */ g_debug ("processing: %s", asb_package_get_name (priv->pkg)); for (l = apps; l != NULL; l = l->next) { app = l->data; /* never set */ if (as_app_get_id (AS_APP (app)) == NULL) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_INFO, "app id not set for %s", asb_package_get_name (priv->pkg)); continue; } /* copy data from pkg into app */ if (!asb_package_ensure (priv->pkg, ASB_PACKAGE_ENSURE_LICENSE | ASB_PACKAGE_ENSURE_RELEASES | ASB_PACKAGE_ENSURE_VCS | ASB_PACKAGE_ENSURE_URL, error_not_used)) return FALSE; if (asb_package_get_url (priv->pkg) != NULL && as_app_get_url_item (AS_APP (app), AS_URL_KIND_HOMEPAGE) == NULL) { as_app_add_url (AS_APP (app), AS_URL_KIND_HOMEPAGE, asb_package_get_url (priv->pkg)); } if (asb_package_get_license (priv->pkg) != NULL && as_app_get_project_license (AS_APP (app)) == NULL) { as_app_set_project_license (AS_APP (app), asb_package_get_license (priv->pkg)); } /* add the source name so we can suggest these together */ if (g_strcmp0 (asb_package_get_source_pkgname (priv->pkg), asb_package_get_name (priv->pkg)) != 0) { as_app_set_source_pkgname (AS_APP (app), asb_package_get_source_pkgname (priv->pkg)); } /* set all the releases on the app */ array = asb_package_get_releases (priv->pkg); for (i = 0; i < array->len; i++) { release = g_ptr_array_index (array, i); as_app_add_release (AS_APP (app), release); } /* run each refine plugin on each app */ ret = asb_plugin_loader_process_app (asb_context_get_plugin_loader (priv->ctx), priv->pkg, app, priv->tmpdir, &error); if (!ret) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to run process on %s: %s", as_app_get_id (AS_APP (app)), error->message); g_clear_error (&error); goto skip; } /* set cache-id in case we want to use the metadata directly */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID)) { cache_id = asb_utils_get_cache_id_for_filename (priv->filename); as_app_add_metadata (AS_APP (app), "X-CacheID", cache_id); g_free (cache_id); } /* set the VCS information into the metadata */ if (asb_package_get_vcs (priv->pkg) != NULL) { as_app_add_metadata (AS_APP (app), "VersionControlSystem", asb_package_get_vcs (priv->pkg)); } /* save any screenshots early */ if (array->len == 0) { if (!asb_app_save_resources (ASB_APP (app), ASB_APP_SAVE_FLAG_SCREENSHOTS, error_not_used)) return FALSE; } /* all okay */ asb_context_add_app (priv->ctx, app); nr_added++; } skip: /* add a dummy element to the AppStream metadata so that we don't keep * parsing this every time */ if (asb_context_get_flag (priv->ctx, ASB_CONTEXT_FLAG_ADD_CACHE_ID) && nr_added == 0) asb_context_add_app_ignore (priv->ctx, priv->pkg); /* delete tree */ g_debug ("deleting temp files: %s", asb_package_get_name (priv->pkg)); if (!asb_utils_rmtree (priv->tmpdir, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to delete tree: %s", error->message); goto out; } /* write log */ g_debug ("writing log: %s", asb_package_get_name (priv->pkg)); if (!asb_package_log_flush (priv->pkg, &error)) { asb_package_log (priv->pkg, ASB_PACKAGE_LOG_LEVEL_WARNING, "Failed to write package log: %s", error->message); goto out; } out: /* clear loaded resources */ asb_package_close (priv->pkg, NULL); asb_package_clear (priv->pkg, ASB_PACKAGE_ENSURE_DEPS | ASB_PACKAGE_ENSURE_FILES); g_list_free_full (apps, (GDestroyNotify) g_object_unref); return TRUE; }
/** * asb_task_explode_extra_packages: **/ static gboolean asb_task_explode_extra_packages (AsbTask *task, GError **error) { AsbTaskPrivate *priv = GET_PRIVATE (task); GPtrArray *deps; const gchar *ignore[] = { "rtld", NULL }; const gchar *tmp; guint i; g_autoptr(GHashTable) hash = NULL; g_autoptr(GPtrArray) array = NULL; g_autoptr(GPtrArray) icon_themes = NULL; /* anything the package requires */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; ignore[i] != NULL; i++) { g_hash_table_insert (hash, g_strdup (ignore[i]), GINT_TO_POINTER (1)); } array = g_ptr_array_new_with_free_func (g_free); icon_themes = g_ptr_array_new_with_free_func (g_free); deps = asb_package_get_deps (priv->pkg); for (i = 0; i < deps->len; i++) { tmp = g_ptr_array_index (deps, i); if (g_strstr_len (tmp, -1, " ") != NULL) continue; if (g_strstr_len (tmp, -1, ".so") != NULL) continue; if (g_str_has_prefix (tmp, "/")) continue; if (g_hash_table_lookup (hash, tmp) != NULL) continue; if (g_strcmp0 (tmp, asb_package_get_name (priv->pkg)) == 0) continue; /* libreoffice making things complicated */ if (g_strcmp0 (tmp, "libreoffice-core") == 0) g_ptr_array_add (array, g_strdup ("libreoffice-data")); /* if an app depends on kde-runtime, that means the * oxygen icon set is available to them */ if (g_strcmp0 (tmp, "oxygen-icon-theme") == 0 || g_strcmp0 (tmp, "kde-runtime") == 0) { g_hash_table_insert (hash, g_strdup ("oxygen-icon-theme"), GINT_TO_POINTER (1)); g_ptr_array_add (icon_themes, g_strdup ("oxygen-icon-theme")); } else { g_ptr_array_add (array, g_strdup (tmp)); } g_hash_table_insert (hash, g_strdup (tmp), GINT_TO_POINTER (1)); } /* explode any potential packages */ for (i = 0; i < array->len; i++) { tmp = g_ptr_array_index (array, i); if (!asb_task_explode_extra_package (task, tmp, TRUE, error)) return FALSE; } /* explode any icon themes */ for (i = 0; i < icon_themes->len; i++) { tmp = g_ptr_array_index (icon_themes, i); if (!asb_task_explode_extra_package (task, tmp, FALSE, error)) return FALSE; } return TRUE; }
/** * asb_plugin_process: */ GList * asb_plugin_process (AsbPlugin *plugin, AsbPackage *pkg, const gchar *tmpdir, GError **error) { const gchar *tmp; gchar **split; GList *apps = NULL; GPtrArray *keywords; guint i; guint j; _cleanup_free_ gchar *app_id = NULL; _cleanup_object_unref_ AsbApp *app = NULL; _cleanup_object_unref_ AsIcon *icon = NULL; _cleanup_string_free_ GString *str = NULL; /* use the pkgname suffix as the app-id */ tmp = asb_package_get_name (pkg); if (g_str_has_prefix (tmp, "gstreamer1-")) tmp += 11; if (g_str_has_prefix (tmp, "gstreamer-")) tmp += 10; if (g_str_has_prefix (tmp, "plugins-")) tmp += 8; app_id = g_strdup_printf ("gstreamer-%s", tmp); /* create app */ app = asb_app_new (pkg, app_id); as_app_set_id_kind (AS_APP (app), AS_ID_KIND_CODEC); as_app_set_name (AS_APP (app), "C", "GStreamer Multimedia Codecs", -1); asb_app_set_requires_appdata (app, TRUE); asb_app_set_hidpi_enabled (app, asb_context_get_hidpi_enabled (plugin->ctx)); as_app_add_category (AS_APP (app), "Addons", -1); as_app_add_category (AS_APP (app), "Codecs", -1); /* add icon */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "application-x-executable", -1); as_app_add_icon (AS_APP (app), icon); for (i = 0; data[i].path != NULL; i++) { if (!asb_utils_is_file_in_tmpdir (tmpdir, data[i].path)) continue; split = g_strsplit (data[i].text, "|", -1); for (j = 0; split[j] != NULL; j++) as_app_add_keyword (AS_APP (app), NULL, split[j], -1); g_strfreev (split); } /* no codecs we care about */ keywords = as_app_get_keywords (AS_APP (app), NULL); if (keywords == NULL) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "nothing interesting in %s", asb_package_get_basename (pkg)); return NULL; } /* sort categories by name */ g_ptr_array_sort (keywords, asb_utils_string_sort_cb); /* create a description */ str = g_string_new ("Multimedia playback for "); if (keywords->len > 1) { for (i = 0; i < keywords->len - 1; i++) { tmp = g_ptr_array_index (keywords, i); g_string_append_printf (str, "%s, ", tmp); } g_string_truncate (str, str->len - 2); tmp = g_ptr_array_index (keywords, keywords->len - 1); g_string_append_printf (str, " and %s", tmp); } else { g_string_append (str, g_ptr_array_index (keywords, 0)); } as_app_set_comment (AS_APP (app), "C", str->str, -1); /* add */ asb_plugin_add_app (&apps, AS_APP (app)); return apps; }