Skip to content

Commit

Permalink
Merge apps with overlapping IDs from the same pkgname
Browse files Browse the repository at this point in the history
This should work for a lot of fonts and also applications where there are things
like level editors and different runtime versions.
  • Loading branch information
hughsie committed Sep 10, 2014
1 parent bdd2e91 commit 19a8e06
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 44 deletions.
Binary file added data/tests/composite-1-1.fc21.x86_64.rpm
Binary file not shown.
24 changes: 24 additions & 0 deletions data/tests/composite.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Summary: A test application
Name: composite
Version: 1
Release: 1%{?dist}
URL: http://people.freedesktop.org/
License: GPLv2+
Source1: valid1.desktop
Source2: valid2.desktop

%description
This is a composite application shipping multiple valid apps in one package.

%install
install -Dp %{SOURCE1} $RPM_BUILD_ROOT/%{_datadir}/applications/valid1.desktop
install -Dp %{SOURCE2} $RPM_BUILD_ROOT/%{_datadir}/applications/valid2.desktop

%files
%defattr(-,root,root)
%{_datadir}/applications/valid1.desktop
%{_datadir}/applications/valid2.desktop

%changelog
* Tue Aug 12 2014 Richard Hughes <richard@hughsie.com> - 1-1
- Initial version
6 changes: 5 additions & 1 deletion data/tests/rpmbuild/build.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
msgfmt ru.po -o ru.mo
msgfmt en_GB.po -o en_GB.mo
gcc -o app.bin app.c `pkg-config --cflags --libs gtk+-3.0`
cp * ~/rpmbuild/SOURCES/ && rpmbuild -ba ../app.spec && cp ~/rpmbuild/RPMS/app*.rpm ../
cp * ~/rpmbuild/SOURCES/
rpmbuild -ba ../app.spec
rpmbuild -ba ../composite.spec
cp ~/rpmbuild/RPMS/app*.rpm ../
cp ~/rpmbuild/RPMS/composite*.rpm ../
8 changes: 8 additions & 0 deletions data/tests/rpmbuild/valid1.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Desktop Entry]
Name=Frobnicator
Comment=Frobnicator
Icon=computer
Exec=app
Terminal=false
Type=Application
Categories=Profiling;
8 changes: 8 additions & 0 deletions data/tests/rpmbuild/valid2.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Desktop Entry]
Name=Frobnicator Example
Comment=Frobnicator Example Program
Icon=computer
Exec=app --example
Terminal=false
Type=Application
Categories=Profiling;
106 changes: 63 additions & 43 deletions libappstream-builder/asb-self-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ asb_test_plugin_loader_func (void)

/* get the list of plugins */
plugins = asb_plugin_loader_get_plugins (loader);
g_assert_cmpint (plugins->len, ==, 17);
g_assert_cmpint (plugins->len, ==, 18);
plugin = g_ptr_array_index (plugins, 0);
g_assert (plugin != NULL);
g_assert (plugin->module != NULL);
Expand Down Expand Up @@ -232,11 +232,7 @@ asb_test_context_test_func (AsbTestContextMode mode)
GError *error = NULL;
const gchar *expected_xml;
gboolean ret;
_cleanup_free_ gchar *filename1 = NULL;
_cleanup_free_ gchar *filename2 = NULL;
_cleanup_free_ gchar *filename3 = NULL;
_cleanup_free_ gchar *filename4 = NULL;
_cleanup_free_ gchar *filename5 = NULL;
guint i;
_cleanup_object_unref_ AsbContext *ctx = NULL;
_cleanup_object_unref_ AsStore *store_failed = NULL;
_cleanup_object_unref_ AsStore *store_ignore = NULL;
Expand All @@ -247,6 +243,14 @@ asb_test_context_test_func (AsbTestContextMode mode)
_cleanup_string_free_ GString *xml = NULL;
_cleanup_string_free_ GString *xml_failed = NULL;
_cleanup_string_free_ GString *xml_ignore = NULL;
const gchar *filenames[] = {
"test-0.1-1.fc21.noarch.rpm", /* a console app */
"app-1-1.fc21.x86_64.rpm", /* a GUI app */
"app-extra-1-1.fc21.noarch.rpm", /* addons for a GUI app */
"app-console-1-1.fc21.noarch.rpm", /* app with no icon */
"app-1-1.fc21.i686.rpm", /* GUI multiarch app */
"composite-1-1.fc21.x86_64.rpm", /* multiple GUI apps */
NULL};

/* set up the context */
ctx = asb_context_new ();
Expand Down Expand Up @@ -279,46 +283,21 @@ asb_test_context_test_func (AsbTestContextMode mode)
g_assert_no_error (error);
g_assert (ret);

/* add a console application */
filename1 = asb_test_get_filename ("test-0.1-1.fc21.noarch.rpm");
g_assert (filename1 != NULL);
ret = asb_context_add_filename (ctx, filename1, &error);
g_assert_no_error (error);
g_assert (ret);

/* add another GUI application */
filename2 = asb_test_get_filename ("app-1-1.fc21.x86_64.rpm");
g_assert (filename2 != NULL);
ret = asb_context_add_filename (ctx, filename2, &error);
g_assert_no_error (error);
g_assert (ret);

/* add addons for the GUI application */
filename3 = asb_test_get_filename ("app-extra-1-1.fc21.noarch.rpm");
g_assert (filename3 != NULL);
ret = asb_context_add_filename (ctx, filename3, &error);
g_assert_no_error (error);
g_assert (ret);

/* add application with no icon */
filename4 = asb_test_get_filename ("app-console-1-1.fc21.noarch.rpm");
g_assert (filename4 != NULL);
ret = asb_context_add_filename (ctx, filename4, &error);
g_assert_no_error (error);
g_assert (ret);

/* the same GUI application in the different architecture */
filename5 = asb_test_get_filename ("app-1-1.fc21.i686.rpm");
g_assert (filename5 != NULL);
ret = asb_context_add_filename (ctx, filename5, &error);
g_assert_no_error (error);
g_assert (ret);
/* add packages */
for (i = 0; filenames[i] != NULL; i++) {
_cleanup_free_ gchar *filename = NULL;
filename = asb_test_get_filename (filenames[i]);
g_assert (filename != NULL);
ret = asb_context_add_filename (ctx, filename, &error);
g_assert_no_error (error);
g_assert (ret);
}

/* verify queue size */
switch (mode) {
case ASB_TEST_CONTEXT_MODE_NO_CACHE:
case ASB_TEST_CONTEXT_MODE_WITH_OLD_CACHE:
g_assert_cmpint (asb_context_get_packages(ctx)->len, ==, 5);
g_assert_cmpint (asb_context_get_packages(ctx)->len, ==, 6);
break;
default:
/* no packages should need extracting */
Expand All @@ -343,7 +322,7 @@ asb_test_context_test_func (AsbTestContextMode mode)
ret = as_store_from_file (store, file, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (as_store_get_size (store), ==, 2);
g_assert_cmpint (as_store_get_size (store), ==, 3);
app = as_store_get_app_by_pkgname (store, "app");
g_assert (app != NULL);
app = as_store_get_app_by_id (store, "app.desktop");
Expand Down Expand Up @@ -411,6 +390,24 @@ asb_test_context_test_func (AsbTestContextMode mode)
"<value key=\"X-CacheID\">app-1-1.fc21.x86_64.rpm</value>\n"
"</metadata>\n"
"</component>\n"
"<component type=\"desktop\">\n"
"<id>valid.desktop</id>\n"
"<pkgname>composite</pkgname>\n"
"<name>Frobnicator</name>\n"
"<summary>Frobnicator</summary>\n"
"<icon type=\"stock\">computer</icon>\n"
"<categories>\n"
"<category>Profiling</category>\n"
"</categories>\n"
"<project_license>GPL-2.0+</project_license>\n"
"<url type=\"homepage\">http://people.freedesktop.org/</url>\n"
"<releases>\n"
"<release version=\"1\" timestamp=\"1407844800\"/>\n"
"</releases>\n"
"<metadata>\n"
"<value key=\"X-CacheID\">composite-1-1.fc21.x86_64.rpm</value>\n"
"</metadata>\n"
"</component>\n"
"</components>\n";
if (g_strcmp0 (xml->str, expected_xml) != 0)
g_warning ("Expected:\n%s\nGot:\n%s", expected_xml, xml->str);
Expand All @@ -422,11 +419,13 @@ asb_test_context_test_func (AsbTestContextMode mode)
ret = as_store_from_file (store_failed, file_failed, NULL, NULL, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (as_store_get_size (store_failed), ==, 2);
g_assert_cmpint (as_store_get_size (store_failed), ==, 3);
app = as_store_get_app_by_id (store_failed, "console1.desktop");
g_assert (app != NULL);
app = as_store_get_app_by_id (store_failed, "console2.desktop");
g_assert (app != NULL);
app = as_store_get_app_by_id (store_failed, "valid2.desktop");
g_assert (app != NULL);

/* check output */
xml_failed = as_store_to_xml (store_failed, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
Expand Down Expand Up @@ -484,6 +483,27 @@ asb_test_context_test_func (AsbTestContextMode mode)
"<value key=\"X-CacheID\">app-console-1-1.fc21.noarch.rpm</value>\n"
"</metadata>\n"
"</component>\n"
"<component type=\"desktop\">\n"
"<id>valid2.desktop</id>\n"
"<pkgname>composite</pkgname>\n"
"<name>Frobnicator Example</name>\n"
"<summary>Frobnicator Example Program</summary>\n"
"<icon type=\"stock\">computer</icon>\n"
"<categories>\n"
"<category>Profiling</category>\n"
"</categories>\n"
"<vetos>\n"
"<veto>absorbed into valid.desktop</veto>\n"
"</vetos>\n"
"<project_license>GPL-2.0+</project_license>\n"
"<url type=\"homepage\">http://people.freedesktop.org/</url>\n"
"<releases>\n"
"<release version=\"1\" timestamp=\"1407844800\"/>\n"
"</releases>\n"
"<metadata>\n"
"<value key=\"X-CacheID\">composite-1-1.fc21.x86_64.rpm</value>\n"
"</metadata>\n"
"</component>\n"
"</components>\n";
if (g_strcmp0 (xml_failed->str, expected_xml) != 0)
g_warning ("Expected:\n%s\nGot:\n%s", expected_xml, xml_failed->str);
Expand Down
6 changes: 6 additions & 0 deletions libappstream-builder/plugins/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ plugin_LTLIBRARIES = \
libasb_plugin_absorb.la \
libasb_plugin_appdata.la \
libasb_plugin_blacklist.la \
libasb_plugin_composite.la \
libasb_plugin_dbus.la \
libasb_plugin_desktop.la \
libasb_plugin_gir.la \
Expand Down Expand Up @@ -117,4 +118,9 @@ libasb_plugin_font_la_LIBADD = $(GLIB_LIBS) $(FREETYPE_LIBS) $(GDKPIXBUF_LIBS)
libasb_plugin_font_la_LDFLAGS = -module -avoid-version
libasb_plugin_font_la_CFLAGS = $(GLIB_CFLAGS) $(WARNINGFLAGS_C)

libasb_plugin_composite_la_SOURCES = asb-plugin-composite.c
libasb_plugin_composite_la_LIBADD = $(GLIB_LIBS) $(FREETYPE_LIBS) $(GDKPIXBUF_LIBS)
libasb_plugin_composite_la_LDFLAGS = -module -avoid-version
libasb_plugin_composite_la_CFLAGS = $(GLIB_CFLAGS) $(WARNINGFLAGS_C)

-include $(top_srcdir)/git.mk
121 changes: 121 additions & 0 deletions libappstream-builder/plugins/asb-plugin-composite.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2014 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <config.h>
#include <string.h>

#include <asb-plugin.h>

/**
* asb_plugin_get_name:
*/
const gchar *
asb_plugin_get_name (void)
{
return "composite";
}

/**
* asb_plugin_composite_app:
*/
static gboolean
asb_plugin_composite_app (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 apps %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 || strlen (id) < 12) {
g_set_error (error,
AS_APP_ERROR,
AS_APP_ERROR_INVALID_TYPE,
"Cannot composite apps %s:%s as no ID overlap",
as_app_get_id (app),
as_app_get_id (donor));
return FALSE;
}
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;
}

/**
* asb_plugin_merge:
*/
void
asb_plugin_merge (AsbPlugin *plugin, GList *list)
{
AsApp *app;
AsApp *found;
GList *l;
_cleanup_hashtable_unref_ GHashTable *hash = NULL;

/* add all packages to the hash */
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_vetos (app)->len > 0)
continue;
found = g_hash_table_lookup (hash, as_app_get_pkgname_default (app));
if (found != NULL) {
_cleanup_error_free_ GError *error = NULL;
if (!asb_plugin_composite_app (app, found, &error)) {
g_warning ("Failed to composite %s:%s",
as_app_get_id (app),
as_app_get_id (found));
continue;
}
continue;
}
g_hash_table_insert (hash,
g_strdup (as_app_get_pkgname_default (app)),
g_object_ref (app));
}
}

0 comments on commit 19a8e06

Please sign in to comment.