예제 #1
0
gboolean
gs_plugin_refine_app (GsPlugin *plugin,
		      GsApp *app,
		      GsPluginRefineFlags flags,
		      GCancellable *cancellable,
		      GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	g_autoptr(SnapdClient) client = NULL;
	const gchar *name;
	g_autoptr(SnapdSnap) local_snap = NULL;
	g_autoptr(SnapdSnap) store_snap = NULL;
	SnapdSnap *snap;
	const gchar *developer_name;
	g_autofree gchar *description = NULL;

	/* not us */
	if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0)
		return TRUE;

	client = get_client (plugin, error);
	if (client == NULL)
		return FALSE;

	/* get information from local snaps and store */
	local_snap = snapd_client_get_snap_sync (client, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL);
	if (local_snap == NULL || (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) != 0)
		store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL);
	if (local_snap == NULL && store_snap == NULL)
		return TRUE;

	if (local_snap != NULL)
		gs_app_set_state (app, AS_APP_STATE_INSTALLED);
	else
		gs_app_set_state (app, AS_APP_STATE_AVAILABLE);

	/* use store information for basic metadata over local information */
	snap = store_snap != NULL ? store_snap : local_snap;
	name = snapd_snap_get_title (snap);
	if (name == NULL || g_strcmp0 (name, "") == 0)
		name = snapd_snap_get_name (snap);
	gs_app_set_name (app, GS_APP_QUALITY_NORMAL, name);
	gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_summary (snap));
	description = gs_plugin_snap_get_description_safe (snap);
	if (description != NULL)
		gs_app_set_description (app, GS_APP_QUALITY_NORMAL, description);
	gs_app_set_license (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_license (snap));
	developer_name = snapd_snap_get_publisher_display_name (snap);
	if (developer_name == NULL)
		developer_name = snapd_snap_get_publisher_username (snap);
	gs_app_set_developer_name (app, developer_name);
	if (snapd_snap_get_publisher_validation (snap) == SNAPD_PUBLISHER_VALIDATION_VERIFIED)
		gs_app_add_quirk (app, GS_APP_QUIRK_DEVELOPER_VERIFIED);

	snap = local_snap != NULL ? local_snap : store_snap;
	gs_app_set_version (app, snapd_snap_get_version (snap));

	switch (snapd_snap_get_snap_type (snap)) {
	case SNAPD_SNAP_TYPE_APP:
		gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
		break;
	case SNAPD_SNAP_TYPE_KERNEL:
	case SNAPD_SNAP_TYPE_GADGET:
	case SNAPD_SNAP_TYPE_OS:
		gs_app_set_kind (app, AS_APP_KIND_RUNTIME);
		break;
        default:
	case SNAPD_SNAP_TYPE_UNKNOWN:
		gs_app_set_kind (app, AS_APP_KIND_UNKNOWN);
		break;
	}

	/* add information specific to installed snaps */
	if (local_snap != NULL) {
		SnapdApp *snap_app;
		GDateTime *install_date;

		install_date = snapd_snap_get_install_date (local_snap);
		gs_app_set_size_installed (app, snapd_snap_get_installed_size (local_snap));
		gs_app_set_install_date (app, install_date != NULL ? g_date_time_to_unix (install_date) : GS_APP_INSTALL_DATE_UNKNOWN);

		snap_app = get_primary_app (local_snap);
		if (snap_app != NULL) {
			gs_app_set_metadata (app, "snap::launch-name", snapd_app_get_name (snap_app));
			gs_app_set_metadata (app, "snap::launch-desktop", snapd_app_get_desktop_file (snap_app));
		} else {
			gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE);
		}
	}

	/* add information specific to store snaps */
	if (store_snap != NULL) {
		gs_app_set_origin (app, priv->store_name);
		gs_app_set_size_download (app, snapd_snap_get_download_size (store_snap));

		if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS && gs_app_get_screenshots (app)->len == 0)
			refine_screenshots (app, store_snap);
	}

	/* load icon if requested */
	if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON && gs_app_get_pixbuf (app) == NULL)
		load_icon (plugin, client, app, gs_app_get_metadata_item (app, "snap::name"), local_snap, store_snap, cancellable);

	return TRUE;
}
예제 #2
0
static GsApp *
gs_editor_convert_app (GsEditor *self, AsApp *item)
{
	AsApp *item_global;
	AsAppState item_state;
	GsApp *app;
	const gchar *keys[] = {
		"GnomeSoftware::AppTile-css",
		"GnomeSoftware::FeatureTile-css",
		"GnomeSoftware::UpgradeBanner-css",
		NULL };

	/* copy name, summary and description */
	app = gs_app_new (as_app_get_id (item));
	item_global = as_store_get_app_by_id (self->store_global, as_app_get_id (item));
	if (item_global == NULL) {
		const gchar *tmp;
		g_autoptr(AsIcon) ic = NULL;
		g_debug ("no app found for %s, using fallback", as_app_get_id (item));

		/* copy from AsApp, falling back to something sane */
		tmp = as_app_get_name (item, NULL);
		if (tmp == NULL)
			tmp = "Application";
		gs_app_set_name (app, GS_APP_QUALITY_NORMAL, tmp);
		tmp = as_app_get_comment (item, NULL);
		if (tmp == NULL)
			tmp = "Description";
		gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, tmp);
		tmp = as_app_get_description (item, NULL);
		if (tmp == NULL)
			tmp = "A multiline description";
		gs_app_set_description (app, GS_APP_QUALITY_NORMAL, tmp);
		ic = as_icon_new ();
		as_icon_set_kind (ic, AS_ICON_KIND_STOCK);
		as_icon_set_name (ic, "application-x-executable");
		gs_app_add_icon (app, ic);
		item_state = as_app_get_state (item);
	} else {
		GPtrArray *icons;
		g_debug ("found global app for %s", as_app_get_id (item));
		gs_app_set_name (app, GS_APP_QUALITY_NORMAL,
				 as_app_get_name (item_global, NULL));
		gs_app_set_summary (app, GS_APP_QUALITY_NORMAL,
				    as_app_get_comment (item_global, NULL));
		gs_app_set_description (app, GS_APP_QUALITY_NORMAL,
					as_app_get_description (item_global, NULL));
		icons = as_app_get_icons (item_global);
		for (guint i = 0; i < icons->len; i++) {
			AsIcon *icon = g_ptr_array_index (icons, i);
			gs_app_add_icon (app, icon);
		}
		item_state = as_app_get_state (item_global);
	}

	/* copy state */
	if (item_state == AS_APP_STATE_UNKNOWN)
		item_state = AS_APP_STATE_AVAILABLE;
	gs_app_set_state (app, item_state);

	/* copy version */
	gs_app_set_version (app, "3.28");

	/* load pixbuf */
	gs_editor_refine_app_pixbuf (app);

	/* copy metadata */
	for (guint i = 0; keys[i] != NULL; i++) {
		g_autoptr(GError) error = NULL;
		const gchar *markup = as_app_get_metadata_item (item, keys[i]);
		if (markup != NULL) {
			g_autofree gchar *css_new = NULL;
			css_new = gs_editor_css_download_resources (self, markup, &error);
			if (css_new == NULL) {
				g_warning ("%s", error->message);
				gs_app_set_metadata (app, keys[i], markup);
			} else {
				gs_app_set_metadata (app, keys[i], css_new);
			}
		} else {
			gs_app_set_metadata (app, keys[i], NULL);
		}
	}
	return app;
}
예제 #3
0
static void
refine_app (GsPlugin *plugin, GsApp *app, JsonObject *package, gboolean from_search, GCancellable *cancellable)
{
	g_autofree gchar *macaroon = NULL;
	g_auto(GStrv) discharges = NULL;
	const gchar *status, *icon_url, *launch_name = NULL;
	g_autoptr(GdkPixbuf) icon_pixbuf = NULL;
	gint64 size = -1;

	get_macaroon (plugin, &macaroon, &discharges);

	status = json_object_get_string_member (package, "status");
	if (g_strcmp0 (status, "installed") == 0 || g_strcmp0 (status, "active") == 0) {
		const gchar *update_available;

		update_available = json_object_has_member (package, "update_available") ?
			json_object_get_string_member (package, "update_available") : NULL;
		if (update_available)
			gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
		else {
			if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE)
				gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
			gs_app_set_state (app, AS_APP_STATE_INSTALLED);
		}
	} else if (g_strcmp0 (status, "not installed") == 0 || g_strcmp0 (status, "available") == 0) {
		gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
	}
	gs_app_set_name (app, GS_APP_QUALITY_HIGHEST,
			 json_object_get_string_member (package, "summary"));
	gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST,
			    json_object_get_string_member (package, "summary"));
	gs_app_set_description (app, GS_APP_QUALITY_HIGHEST,
				json_object_get_string_member (package, "description"));
	gs_app_set_version (app, json_object_get_string_member (package, "version"));
	if (json_object_has_member (package, "installed-size")) {
		size = json_object_get_int_member (package, "installed-size");
		if (size > 0)
			gs_app_set_size_installed (app, (guint64) size);
	}
	if (json_object_has_member (package, "download-size")) {
		size = json_object_get_int_member (package, "download-size");
		if (size > 0)
			gs_app_set_size_download (app, (guint64) size);
	}
	gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE);
	icon_url = json_object_get_string_member (package, "icon");
	if (g_str_has_prefix (icon_url, "/")) {
		g_autofree gchar *icon_data = NULL;
		gsize icon_data_length;
		g_autoptr(GError) error = NULL;

		icon_data = gs_snapd_get_resource (macaroon, discharges, icon_url, &icon_data_length, cancellable, &error);
		if (icon_data != NULL) {
			g_autoptr(GdkPixbufLoader) loader = NULL;

			loader = gdk_pixbuf_loader_new ();
			gdk_pixbuf_loader_write (loader,
						 (guchar *) icon_data,
						 icon_data_length,
						 NULL);
			gdk_pixbuf_loader_close (loader, NULL);
			icon_pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
		}
		else
			g_printerr ("Failed to get icon: %s\n", error->message);
	}
	else {
		g_autoptr(SoupMessage) message = NULL;
		g_autoptr(GdkPixbufLoader) loader = NULL;

		message = soup_message_new (SOUP_METHOD_GET, icon_url);
		if (message != NULL) {
			soup_session_send_message (gs_plugin_get_soup_session (plugin), message);
			loader = gdk_pixbuf_loader_new ();
			gdk_pixbuf_loader_write (loader,
						 (guint8 *) message->response_body->data,
						 (gsize) message->response_body->length,
						 NULL);
			gdk_pixbuf_loader_close (loader, NULL);
			icon_pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
		}
	}

	if (icon_pixbuf) {
		gs_app_set_pixbuf (app, icon_pixbuf);
	} else {
		g_autoptr(AsIcon) icon = as_icon_new ();
		as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
		as_icon_set_name (icon, "package-x-generic");
		gs_app_add_icon (app, icon);
	}

	if (json_object_has_member (package, "screenshots") && gs_app_get_screenshots (app)->len <= 0) {
		JsonArray *screenshots;
		guint i;

		screenshots = json_object_get_array_member (package, "screenshots");
		for (i = 0; i < json_array_get_length (screenshots); i++) {
			JsonObject *screenshot = json_array_get_object_element (screenshots, i);
			g_autoptr(AsScreenshot) ss = NULL;
			g_autoptr(AsImage) image = NULL;

			ss = as_screenshot_new ();
			as_screenshot_set_kind (ss, AS_SCREENSHOT_KIND_NORMAL);
			image = as_image_new ();
			as_image_set_url (image, json_object_get_string_member (screenshot, "url"));
			as_image_set_kind (image, AS_IMAGE_KIND_SOURCE);
			as_screenshot_add_image (ss, image);
			gs_app_add_screenshot (app, ss);
		}
	}

	if (!from_search) {
		JsonArray *apps;

		apps = json_object_get_array_member (package, "apps");
		if (apps && json_array_get_length (apps) > 0)
			launch_name = json_object_get_string_member (json_array_get_object_element (apps, 0), "name");

		if (launch_name)
			gs_app_set_metadata (app, "snap::launch-name", launch_name);
		else
			gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
	}
}
예제 #4
0
/**
 * gs_plugin_add_updates:
 */
gboolean
gs_plugin_add_updates (GsPlugin *plugin,
			GList **list,
			GCancellable *cancellable,
			GError **error)
{
	g_autoptr(GList) updates = NULL;
	GList *l;
	g_autoptr(GError) error_local = NULL;

	updates = li_manager_get_update_list (plugin->priv->mgr, &error_local);
	if (error_local != NULL) {
		g_set_error (error,
				GS_PLUGIN_ERROR,
				GS_PLUGIN_ERROR_FAILED,
				"Failed to list updates: %s",
				error_local->message);
		return FALSE;
	}

	for (l = updates; l != NULL; l = l->next) {
		LiPkgInfo *old_pki;
		LiPkgInfo *new_pki;
		const gchar *cptkind_str;
		g_autoptr(GsApp) app = NULL;
		LiUpdateItem *uitem = LI_UPDATE_ITEM (l->data);

		old_pki = li_update_item_get_installed_pkg (uitem);
		new_pki = li_update_item_get_available_pkg (uitem);

		cptkind_str = li_pkg_info_get_component_kind (old_pki);
		if ((cptkind_str != NULL) && (g_strcmp0 (cptkind_str, "desktop") == 0)) {
			g_autofree gchar *tmp = NULL;
			/* type=desktop AppStream components result in a Limba bundle name which has the .desktop stripped away.
			 * We need to re-add it for GNOME Software.
			 * In any other case, the Limba bundle name equals the AppStream ID of the component it contains */
			tmp = g_strdup_printf ("%s.desktop", li_pkg_info_get_name (old_pki));
			app = gs_app_new (tmp);
			gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
		} else {
			app = gs_app_new (li_pkg_info_get_name (old_pki));
		}

		gs_app_set_management_plugin (app, "Limba");
		gs_app_set_state (app, AS_APP_STATE_UPDATABLE_LIVE);
		gs_app_set_kind (app, AS_APP_KIND_GENERIC);
		gs_plugin_add_app (list, app);
		gs_app_set_name (app,
				 GS_APP_QUALITY_LOWEST,
				 li_pkg_info_get_name (old_pki));
		gs_app_set_summary (app,
				    GS_APP_QUALITY_LOWEST,
				    li_pkg_info_get_name (old_pki));
		gs_app_set_version (app,
				    li_pkg_info_get_version (old_pki));
		gs_app_set_update_version (app,
					   li_pkg_info_get_version (new_pki));
		gs_app_add_source (app,
				   li_pkg_info_get_id (old_pki));
		gs_plugin_add_app (list, app);
	}

	return TRUE;
}
예제 #5
0
gboolean
gs_plugin_file_to_app (GsPlugin *plugin,
		       GsAppList *list,
		       GFile *file,
		       GCancellable *cancellable,
		       GError **error)
{
	GsApp *app;
	guint i;
	g_autofree gchar *content_type = NULL;
	g_autofree gchar *output = NULL;
	g_auto(GStrv) argv = NULL;
	g_auto(GStrv) tokens = NULL;
	g_autoptr(GString) str = NULL;
	const gchar *mimetypes[] = {
		"application/vnd.debian.binary-package",
		NULL };

	/* does this match any of the mimetypes we support */
	content_type = gs_utils_get_content_type (file, cancellable, error);
	if (content_type == NULL)
		return FALSE;
	if (!g_strv_contains (mimetypes, content_type))
		return TRUE;

	/* exec sync */
	argv = g_new0 (gchar *, 5);
	argv[0] = g_strdup (DPKG_DEB_BINARY);
	argv[1] = g_strdup ("--showformat=${Package}\\n"
			    "${Version}\\n"
			    "${Installed-Size}\\n"
			    "${Homepage}\\n"
			    "${Description}");
	argv[2] = g_strdup ("-W");
	argv[3] = g_file_get_path (file);
	if (!g_spawn_sync (NULL, argv, NULL,
			   G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
			   NULL, NULL, &output, NULL, NULL, error)) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}

	/* parse output */
	tokens = g_strsplit (output, "\n", 0);
	if (g_strv_length (tokens) < 5) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "dpkg-deb output format incorrect:\n\"%s\"\n", output);
		return FALSE;
	}

	/* create app */
	app = gs_app_new (NULL);
	gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
	gs_app_add_source (app, tokens[0]);
	gs_app_set_name (app, GS_APP_QUALITY_LOWEST, tokens[0]);
	gs_app_set_version (app, tokens[1]);
	gs_app_set_size_installed (app, 1024 * g_ascii_strtoull (tokens[2], NULL, 10));
	gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, tokens[3]);
	gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, tokens[4]);
	gs_app_set_kind (app, AS_APP_KIND_GENERIC);
	gs_app_set_metadata (app, "GnomeSoftware::Creator",
			     gs_plugin_get_name (plugin));

	/* multiline text */
	str = g_string_new ("");
	for (i = 5; tokens[i] != NULL; i++) {
		if (g_strcmp0 (tokens[i], " .") == 0) {
			if (str->len > 0)
				g_string_truncate (str, str->len - 1);
			g_string_append (str, "\n");
			continue;
		}
		g_strstrip (tokens[i]);
		g_string_append_printf (str, "%s ", tokens[i]);
	}
	if (str->len > 0)
		g_string_truncate (str, str->len - 1);
	gs_app_set_description (app, GS_APP_QUALITY_LOWEST, str->str);

	/* success */
	gs_app_list_add (list, app);
	return TRUE;
}
예제 #6
0
gboolean
gs_plugin_add_distro_upgrades (GsPlugin *plugin,
			       GsAppList *list,
			       GCancellable *cancellable,
			       GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	gsize len;
	guint i;
	g_autofree gchar *data = NULL;
	g_autoptr(GPtrArray) distros = NULL;
	g_autoptr(GSettings) settings = NULL;

	/* just ensure there is any data, no matter how old */
	if (!gs_plugin_fedora_distro_upgrades_refresh (plugin,
						       G_MAXUINT,
						       cancellable,
						       error))
		return FALSE;

	/* get cached file */
	if (!g_file_get_contents (priv->cachefn, &data, &len, error)) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}

	/* parse data */
	settings = g_settings_new ("org.gnome.software");
	distros = parse_pkgdb_collections_data (data, (gssize) len, error);
	if (distros == NULL)
		return FALSE;
	g_ptr_array_sort (distros, sort_distros_cb);
	for (i = 0; i < distros->len; i++) {
		DistroInfo *distro_info = g_ptr_array_index (distros, i);
		g_autofree gchar *app_id = NULL;
		g_autofree gchar *app_version = NULL;
		g_autofree gchar *background = NULL;
		g_autofree gchar *cache_key = NULL;
		g_autofree gchar *url = NULL;
		g_autofree gchar *css = NULL;
		g_autoptr(GsApp) app = NULL;
		g_autoptr(AsIcon) ic = NULL;

		/* only interested in upgrades to the same distro */
		if (g_strcmp0 (distro_info->name, priv->os_name) != 0)
			continue;

		/* only interested in newer versions, but not more than N+2 */
		if (distro_info->version <= priv->os_version ||
		    distro_info->version > priv->os_version + 2)
			continue;

		/* only interested in non-devel distros */
		if (!g_settings_get_boolean (settings, "show-upgrade-prerelease")) {
			if (distro_info->status == DISTRO_STATUS_DEVEL)
				continue;
		}

		/* search in the cache */
		cache_key = g_strdup_printf ("release-%u", distro_info->version);
		app = gs_plugin_cache_lookup (plugin, cache_key);
		if (app != NULL) {
			gs_app_list_add (list, app);
			continue;
		}

		app_id = g_strdup_printf ("org.fedoraproject.release-%u.upgrade",
					  distro_info->version);
		app_version = g_strdup_printf ("%u", distro_info->version);

		/* icon from disk */
		ic = as_icon_new ();
		as_icon_set_kind (ic, AS_ICON_KIND_LOCAL);
		as_icon_set_filename (ic, "/usr/share/pixmaps/fedora-logo-sprite.png");

		/* create */
		app = gs_app_new (app_id);
		gs_app_set_kind (app, AS_APP_KIND_OS_UPGRADE);
		gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
		gs_app_set_name (app, GS_APP_QUALITY_LOWEST, distro_info->name);
		gs_app_set_summary (app, GS_APP_QUALITY_LOWEST,
		                    /* TRANSLATORS: this is a title for Fedora distro upgrades */
		                    _("A major upgrade, with new features and added polish."));
		gs_app_set_description (app, GS_APP_QUALITY_LOWEST,
		                        "Fedora Workstation is a polished, "
		                        "easy to use operating system for "
		                        "laptop and desktop computers, with a "
		                        "complete set of tools for developers "
		                        "and makers of all kinds.");
		gs_app_set_version (app, app_version);
		gs_app_set_size_installed (app, 1024 * 1024 * 1024); /* estimate */
		gs_app_set_size_download (app, 256 * 1024 * 1024); /* estimate */
		gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free");
		gs_app_add_quirk (app, AS_APP_QUIRK_NEEDS_REBOOT);
		gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE);
		gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE);
		gs_app_set_origin_ui (app, distro_info->name);
		gs_app_add_icon (app, ic);
		gs_app_set_management_plugin (app, "packagekit");

		/* show a Fedora magazine article for the release */
		url = g_strdup_printf ("https://fedoramagazine.org/whats-new-fedora-%u-workstation",
		                       distro_info->version);
		gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, url);

		/* use a fancy background */
		background = get_upgrade_css_background (distro_info->version);
		css = g_strdup_printf ("background: %s;"
				       "background-position: center;"
				       "background-size: cover;",
				       background);
		gs_app_set_metadata (app, "GnomeSoftware::UpgradeBanner-css", css);

		gs_app_list_add (list, app);

		/* save in the cache */
		gs_plugin_cache_add (plugin, cache_key, app);
	}

	return TRUE;
}