/** * gs_plugin_refine_item_metadata: */ static gboolean gs_plugin_refine_item_metadata (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(XdgAppRef) xref = NULL; /* already set */ if (gs_app_get_metadata_item (app, "xdg-app::kind") != NULL) return TRUE; /* AppStream sets the source to appname/arch/branch, if this isn't set * we can't break out the fields */ if (gs_app_get_source_default (app) == NULL) { g_warning ("no source set by appstream for %s", gs_plugin_get_name (plugin)); return TRUE; } /* parse the ref */ xref = xdg_app_ref_parse (gs_app_get_source_default (app), error); if (xref == NULL) { g_prefix_error (error, "failed to parse '%s': ", gs_app_get_source_default (app)); return FALSE; } gs_plugin_xdg_app_set_metadata (app, xref); /* success */ return TRUE; }
/** * gs_plugin_refine_app: */ static gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GError **error) { LiPkgInfo *pki; g_autoptr(GError) error_local = NULL; /* sanity check */ if (gs_app_get_source_default (app) == NULL) return TRUE; pki = li_manager_get_software_by_pkid (plugin->priv->mgr, gs_app_get_source_default (app), &error_local); if (error_local != NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Unable to refine metadata: %s", error_local->message); return FALSE; } if (pki == NULL) return TRUE; if (li_pkg_info_has_flag (pki, LI_PACKAGE_FLAG_INSTALLED)) gs_app_set_state (app, AS_APP_STATE_INSTALLED); else gs_app_set_state (app, AS_APP_STATE_AVAILABLE); gs_app_set_version (app, li_pkg_info_get_version (pki)); return TRUE; }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); LiPkgInfo *pki; g_autoptr(GError) error_local = NULL; g_autoptr(AsProfileTask) ptask = NULL; /* not us */ if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) return TRUE; /* profile */ ptask = as_profile_start (gs_plugin_get_profile (plugin), "limba::refine{%s}", gs_app_get_id (app)); /* sanity check */ if (gs_app_get_source_default (app) == NULL) return TRUE; pki = li_manager_get_software_by_pkid (priv->mgr, gs_app_get_source_default (app), &error_local); if (error_local != NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Unable to refine metadata: %s", error_local->message); return FALSE; } if (pki == NULL) return TRUE; if (li_pkg_info_has_flag (pki, LI_PACKAGE_FLAG_INSTALLED)) gs_app_set_state (app, AS_APP_STATE_INSTALLED); else gs_app_set_state (app, AS_APP_STATE_AVAILABLE); gs_app_set_version (app, li_pkg_info_get_version (pki)); return TRUE; }
/** * gs_plugin_refine: */ gboolean gs_plugin_refine (GsPlugin *plugin, GList **list, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GList *l; GPtrArray *sources; GsApp *app; const gchar *pkgname; gboolean ret; gint rating; gint confidence; guint i; /* nothing to do here */ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING) == 0) return TRUE; /* already loaded */ if (g_once_init_enter (&plugin->priv->loaded)) { ret = gs_plugin_fedora_tagger_load_db (plugin, error); g_once_init_leave (&plugin->priv->loaded, TRUE); if (!ret) return FALSE; } /* add any missing ratings data */ for (l = *list; l != NULL; l = l->next) { app = GS_APP (l->data); if (gs_app_get_rating (app) != -1) continue; sources = gs_app_get_sources (app); for (i = 0; i < sources->len; i++) { pkgname = g_ptr_array_index (sources, i); ret = gs_plugin_resolve_app (plugin, pkgname, &rating, &confidence, error); if (!ret) return FALSE; if (rating != -1) { g_debug ("fedora-tagger setting rating on %s to %i%% [%i]", pkgname, rating, confidence); gs_app_set_rating (app, rating); gs_app_set_rating_confidence (app, confidence); gs_app_set_rating_kind (app, GS_APP_RATING_KIND_SYSTEM); if (confidence > 50 && rating > 80) { g_debug ("%s is popular [confidence %i]", gs_app_get_source_default (app), confidence); gs_app_add_kudo (app, GS_APP_KUDO_POPULAR); } } } } return TRUE; }
static gboolean gs_plugin_add_sources_related (GsPlugin *plugin, GHashTable *hash, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); guint i; GsApp *app; GsApp *app_tmp; PkBitfield filter; ProgressData data; const gchar *id; gboolean ret = TRUE; g_autoptr(GsAppList) installed = gs_app_list_new (); g_autoptr(PkResults) results = NULL; g_autoptr(AsProfileTask) ptask = NULL; data.app = NULL; data.plugin = plugin; data.ptask = NULL; ptask = as_profile_start_literal (gs_plugin_get_profile (plugin), "packagekit::add-sources-related"); g_assert (ptask != NULL); filter = pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, PK_FILTER_ENUM_NEWEST, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NOT_COLLECTIONS, -1); results = pk_client_get_packages (PK_CLIENT(priv->task), filter, cancellable, gs_plugin_packagekit_progress_cb, &data, error); if (!gs_plugin_packagekit_results_valid (results, error)) return FALSE; ret = gs_plugin_packagekit_add_results (plugin, installed, results, error); if (!ret) return FALSE; for (i = 0; i < gs_app_list_length (installed); i++) { g_auto(GStrv) split = NULL; app = gs_app_list_index (installed, i); split = pk_package_id_split (gs_app_get_source_id_default (app)); if (g_str_has_prefix (split[PK_PACKAGE_ID_DATA], "installed:")) { id = split[PK_PACKAGE_ID_DATA] + 10; app_tmp = g_hash_table_lookup (hash, id); if (app_tmp != NULL) { g_debug ("found package %s from %s", gs_app_get_source_default (app), id); gs_app_add_related (app_tmp, app); } } } return TRUE; }
gboolean gs_plugin_app_install (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(LiInstaller) inst = NULL; GsPluginHelper helper; g_autoptr(GError) error_local = NULL; /* not us */ if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) return TRUE; /* create new installer and select remote package */ inst = li_installer_new (); li_installer_open_remote (inst, gs_app_get_source_default (app), &error_local); if (error_local != NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to install software: %s", error_local->message); return FALSE; } /* set up progress forwarding */ helper.app = app; helper.plugin = plugin; g_signal_connect (inst, "progress", G_CALLBACK (gs_plugin_installer_progress_cb), &helper); /* install software */ gs_app_set_state (app, AS_APP_STATE_INSTALLING); li_installer_install (inst, &error_local); if (error_local != NULL) { gs_app_set_state (app, AS_APP_STATE_AVAILABLE); g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to install software: %s", error_local->message); return FALSE; } gs_app_set_state (app, AS_APP_STATE_INSTALLED); return TRUE; }
gboolean gs_plugin_app_remove (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(LiManager) mgr = NULL; GsPluginHelper helper; g_autoptr(GError) error_local = NULL; /* not us */ if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) return TRUE; mgr = li_manager_new (); /* set up progress forwarding */ helper.app = app; helper.plugin = plugin; g_signal_connect (mgr, "progress", G_CALLBACK (gs_plugin_manager_progress_cb), &helper); gs_app_set_state (app, AS_APP_STATE_REMOVING); li_manager_remove_software (mgr, gs_app_get_source_default (app), &error_local); if (error_local != NULL) { gs_app_set_state (app, AS_APP_STATE_INSTALLED); g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to remove software: %s", error_local->message); return FALSE; } gs_app_set_state (app, AS_APP_STATE_AVAILABLE); return TRUE; }
gboolean gs_plugin_refine (GsPlugin *plugin, GsAppList *list, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { g_autoptr(GsApp) app = NULL; g_autoptr(GsAppList) os_updates = gs_app_list_new (); /* not from get_updates() */ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS) == 0) return TRUE; /* do we have any packages left that are not apps? */ for (guint i = 0; i < gs_app_list_length (list); i++) { GsApp *app_tmp = gs_app_list_index (list, i); if (gs_plugin_generic_updates_merge_os_update (app_tmp)) gs_app_list_add (os_updates, app_tmp); } if (gs_app_list_length (os_updates) == 0) return TRUE; /* create new meta object */ app = gs_plugin_generic_updates_get_os_update (plugin); for (guint i = 0; i < gs_app_list_length (os_updates); i++) { GsApp *app_tmp = gs_app_list_index (os_updates, i); const gchar *id = gs_app_get_unique_id (app_tmp); if (id == NULL) id = gs_app_get_source_default (app_tmp); g_debug ("moving %s to parent %s", id, gs_app_get_unique_id (app)); gs_app_add_related (app, app_tmp); gs_app_list_remove (list, app_tmp); } gs_app_list_add (list, app); return TRUE; }
/** * gs_plugin_app_install: */ gboolean gs_plugin_app_install (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); g_autoptr(XdgAppInstalledRef) xref = NULL; /* only process this app if was created by this plugin */ if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) return TRUE; /* ensure we have metadata and state */ if (!gs_plugin_xdg_app_refine_app (plugin, app, 0, cancellable, error)) return FALSE; /* install */ gs_app_set_state (app, AS_APP_STATE_INSTALLING); /* install required runtime if not already installed */ if (gs_app_get_kind (app) == AS_APP_KIND_DESKTOP) { GsApp *runtime; runtime = gs_app_get_runtime (app); /* the runtime could come from a different remote to the app */ if (!gs_plugin_refine_item_metadata (plugin, runtime, cancellable, error)) return FALSE; if (!gs_plugin_refine_item_origin (plugin, runtime, cancellable, error)) return FALSE; if (!gs_plugin_refine_item_state (plugin, runtime, cancellable, error)) return FALSE; if (gs_app_get_state (runtime) == AS_APP_STATE_UNKNOWN) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED, "Failed to find runtime %s", gs_app_get_source_default (runtime)); return FALSE; } /* not installed */ if (gs_app_get_state (runtime) == AS_APP_STATE_AVAILABLE) { g_debug ("%s is not already installed, so installing", gs_app_get_id (runtime)); gs_app_set_state (runtime, AS_APP_STATE_INSTALLING); xref = xdg_app_installation_install (priv->installation, gs_app_get_origin (runtime), gs_app_get_xdgapp_kind (runtime), gs_app_get_xdgapp_name (runtime), gs_app_get_xdgapp_arch (runtime), gs_app_get_xdgapp_branch (runtime), gs_plugin_xdg_app_progress_cb, app, cancellable, error); if (xref == NULL) { gs_app_set_state_recover (runtime); return FALSE; } gs_app_set_state (runtime, AS_APP_STATE_INSTALLED); } else { g_debug ("%s is already installed, so skipping", gs_app_get_id (runtime)); } } /* use the source for local apps */ if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE_LOCAL) { xref = xdg_app_installation_install_bundle (priv->installation, gs_app_get_local_file (app), gs_plugin_xdg_app_progress_cb, app, cancellable, error); } else { g_debug ("installing %s", gs_app_get_id (app)); xref = xdg_app_installation_install (priv->installation, gs_app_get_origin (app), gs_app_get_xdgapp_kind (app), gs_app_get_xdgapp_name (app), gs_app_get_xdgapp_arch (app), gs_app_get_xdgapp_branch (app), gs_plugin_xdg_app_progress_cb, app, cancellable, error); } if (xref == NULL) { gs_app_set_state_recover (app); return FALSE; } /* state is known */ gs_app_set_state (app, AS_APP_STATE_INSTALLED); return TRUE; }
gboolean gs_plugin_update_app (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { GsPluginHelper helper; g_autoptr(LiManager) mgr = NULL; LiUpdateItem *uitem; g_autoptr(GError) error_local = NULL; /* sanity check */ if (gs_app_get_source_default (app) == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to run update: Default source was NULL."); return FALSE; } mgr = li_manager_new (); /* set up progress forwarding */ helper.app = app; helper.plugin = plugin; g_signal_connect (mgr, "progress", G_CALLBACK (gs_plugin_manager_progress_cb), &helper); /* find update which matches the ID we have */ uitem = li_manager_get_update_for_id (mgr, gs_app_get_source_default (app), &error_local); if (error_local != NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to find update: %s", error_local->message); return FALSE; } if (uitem == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Could not find update for '%s'.", gs_app_get_source_default (app)); return FALSE; } gs_app_set_state (app, AS_APP_STATE_INSTALLING); li_manager_update (mgr, uitem, &error_local); if (error_local != NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Software update failed: %s", error_local->message); gs_app_set_state (app, AS_APP_STATE_UPDATABLE_LIVE); return FALSE; } gs_app_set_state (app, AS_APP_STATE_INSTALLED); return TRUE; }
/** * gs_plugin_refine_app: */ gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { Header h; const gchar *fn; gint rc; g_auto(rpmdbMatchIterator) mi = NULL; g_auto(rpmts) ts = NULL; /* not required */ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) == 0) return TRUE; /* no need to run the plugin */ if (gs_app_get_source_default (app) != NULL && gs_app_get_source_id_default (app) != NULL) return TRUE; /* open db readonly */ ts = rpmtsCreate(); rpmtsSetRootDir (ts, NULL); rc = rpmtsOpenDB (ts, O_RDONLY); if (rc != 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to open rpmdb: %i", rc); return FALSE; } /* look for a specific file */ fn = gs_app_get_metadata_item (app, "appstream::source-file"); if (fn == NULL) return TRUE; if (!g_str_has_prefix (fn, "/usr")) return TRUE; mi = rpmtsInitIterator (ts, RPMDBI_INSTFILENAMES, fn, 0); if (mi == NULL) { g_debug ("rpm: no search results for %s", fn); return TRUE; } /* on rpm-ostree this package cannot be removed 'live' */ gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY); /* process any results */ g_debug ("rpm: querying for %s with %s", gs_app_get_id (app), fn); while ((h = rpmdbNextIterator (mi)) != NULL) { guint64 epoch; const gchar *name; const gchar *version; const gchar *arch; const gchar *release; const gchar *license; /* add default source */ name = headerGetString (h, RPMTAG_NAME); if (gs_app_get_source_default (app) == NULL) { g_debug ("rpm: setting source to %s", name); gs_app_add_source (app, name); } /* set size */ if (gs_app_get_size_download (app) == 0) gs_app_set_size_download (app, 0); if (gs_app_get_size_installed (app) == 0) { guint64 tmp; tmp = headerGetNumber (h, RPMTAG_SIZE); gs_app_set_size_installed (app, tmp); } /* set license */ license = headerGetString (h, RPMTAG_LICENSE); if (gs_app_get_license (app) == NULL && license != NULL) { g_autofree gchar *tmp = NULL; tmp = as_utils_license_to_spdx (license); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, tmp); } /* add version */ version = headerGetString (h, RPMTAG_VERSION); if (gs_app_get_version (app) == NULL) { g_debug ("rpm: setting version to %s", version); gs_app_set_version (app, version); } /* add source-id */ if (gs_app_get_source_id_default (app) == NULL) { g_autofree gchar *tmp = NULL; release = headerGetString (h, RPMTAG_RELEASE); arch = headerGetString (h, RPMTAG_ARCH); epoch = headerGetNumber (h, RPMTAG_EPOCH); if (epoch > 0) { tmp = g_strdup_printf ("%s;%" G_GUINT64_FORMAT ":%s-%s;%s;installed", name, epoch, version, release, arch); } else { tmp = g_strdup_printf ("%s;%s-%s;%s;installed", name, version, release, arch); } g_debug ("rpm: setting source-id to %s", tmp); gs_app_add_source_id (app, tmp); } } return TRUE; }
gboolean gs_plugin_review_submit (GsPlugin *plugin, GsApp *app, AsReview *review, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); GsAuth *auth; const gchar *consumer_key = NULL; const gchar *language; gint rating; gint n_stars; g_autofree gchar *architecture = NULL; g_autoptr(JsonBuilder) request = NULL; guint status_code; g_autoptr(JsonParser) result = NULL; /* Ubuntu reviews require a summary and description - just make one up for now */ rating = as_review_get_rating (review); if (rating > 80) n_stars = 5; else if (rating > 60) n_stars = 4; else if (rating > 40) n_stars = 3; else if (rating > 20) n_stars = 2; else n_stars = 1; language = gs_plugin_get_language (plugin); // FIXME: Need to get Apt::Architecture configuration value from APT architecture = g_strdup ("amd64"); /* Create message for reviews.ubuntu.com */ request = json_builder_new (); json_builder_begin_object (request); add_string_member (request, "package_name", gs_app_get_source_default (app)); add_string_member (request, "summary", as_review_get_summary (review)); add_string_member (request, "review_text", as_review_get_description (review)); add_string_member (request, "language", language); add_string_member (request, "origin", priv->origin); add_string_member (request, "distroseries", priv->distroseries); add_string_member (request, "version", as_review_get_version (review)); add_int_member (request, "rating", n_stars); add_string_member (request, "arch_tag", architecture); json_builder_end_object (request); if (!send_review_request (plugin, SOUP_METHOD_POST, "/api/1.0/reviews/", request, TRUE, &status_code, &result, cancellable, error)) return FALSE; if (status_code != SOUP_STATUS_OK) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to submit review, server returned status code %u", status_code); return FALSE; } // Extract new fields from posted review auth = gs_plugin_get_auth_by_id (plugin, "ubuntuone"); if (auth != NULL) consumer_key = gs_auth_get_metadata_item (auth, "consumer-key"); parse_review (review, consumer_key, json_parser_get_root (result)); return TRUE; }