Rewrite the <launchable> tag when using rename-desktop-file

This also changes the <id> rewriting to use the non-desktop suffixed version of
the application ID as this has been deprecated now the launchable tag exists.

Applications shipping an appdata file without a launchable set will have one
auto-added at runtime based on the appstream <id>.

This copies FlatpakXml from the flatpak project.

Fixes https://github.com/flatpak/flatpak-builder/issues/155

Closes: #164
Approved by: alexlarsson
auto
Richard Hughes 2018-06-13 12:25:11 +01:00 committed by Atomic Bot
parent d63d9ee5bb
commit a233e84c11
3 changed files with 342 additions and 21 deletions

View File

@ -2420,35 +2420,54 @@ builder_manifest_cleanup (BuilderManifest *self,
if (appdata_file != NULL)
{
g_autofree char *contents;
const char *to_replace;
const char *match;
g_autofree char *replace_src = NULL;
g_autofree char *replace_dst = NULL;
FlatpakXml *n_id;
FlatpakXml *n_root;
FlatpakXml *n_text;
g_autoptr(FlatpakXml) xml_root = NULL;
g_autoptr(GInputStream) in = NULL;
g_autoptr(GString) new_contents = NULL;
if (!g_file_load_contents (appdata_file, NULL, &contents, NULL, NULL, error))
in = (GInputStream *) g_file_read (appdata_file, NULL, error);
if (!in)
return FALSE;
xml_root = flatpak_xml_parse (in, FALSE, NULL, error);
if (!xml_root)
return FALSE;
new_contents = g_string_sized_new (strlen (contents));
to_replace = contents;
/* We only want to replace entire matches to id tag, so add the brackets
* and the end-tag. That way we don't do partial matches, or match
* other tags, while still handling e.g. <id type="desktop">foo.desktop</id> */
replace_src = g_strdup_printf (">%s</id", self->rename_desktop_file);
replace_dst = g_strdup_printf (">%s</id", desktop_basename);
while ((match = strstr (to_replace, replace_src)) != NULL)
/* replace component/id */
n_root = flatpak_xml_find (xml_root, "component", NULL);
if (!n_root)
n_root = flatpak_xml_find (xml_root, "application", NULL);
if (!n_root)
{
g_string_append_len (new_contents, to_replace, match - to_replace);
g_string_append (new_contents, replace_dst);
to_replace = match + strlen (replace_src);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "no <component> node");
return FALSE;
}
n_id = flatpak_xml_find (n_root, "id", NULL);
if (n_id)
{
n_text = n_id->first_child;
if (n_text && g_strcmp0 (n_text->text, self->rename_desktop_file) == 0)
{
g_free (n_text->text);
n_text->text = g_strdup (self->id);
}
}
g_string_append (new_contents, to_replace);
/* replace any optional launchable */
n_id = flatpak_xml_find (n_root, "launchable", NULL);
if (n_id)
{
n_text = n_id->first_child;
if (n_text && g_strcmp0 (n_text->text, self->rename_desktop_file) == 0)
{
g_free (n_text->text);
n_text->text = g_strdup (desktop_basename);
}
}
new_contents = g_string_new ("");
flatpak_xml_to_string (xml_root, new_contents);
if (!g_file_set_contents (flatpak_file_get_path_cached (appdata_file),
new_contents->str,
new_contents->len,

View File

@ -2035,3 +2035,272 @@ builder_set_term_title (const gchar *format,
g_print ("\033]2;flatpak-builder: %s\007", message);
}
typedef struct
{
FlatpakXml *current;
} XmlData;
FlatpakXml *
flatpak_xml_new (const gchar *element_name)
{
FlatpakXml *node = g_new0 (FlatpakXml, 1);
node->element_name = g_strdup (element_name);
return node;
}
FlatpakXml *
flatpak_xml_new_text (const gchar *text)
{
FlatpakXml *node = g_new0 (FlatpakXml, 1);
node->text = g_strdup (text);
return node;
}
void
flatpak_xml_add (FlatpakXml *parent, FlatpakXml *node)
{
node->parent = parent;
if (parent->first_child == NULL)
parent->first_child = node;
else
parent->last_child->next_sibling = node;
parent->last_child = node;
}
static void
xml_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
XmlData *data = user_data;
FlatpakXml *node;
node = flatpak_xml_new (element_name);
node->attribute_names = g_strdupv ((char **) attribute_names);
node->attribute_values = g_strdupv ((char **) attribute_values);
flatpak_xml_add (data->current, node);
data->current = node;
}
static void
xml_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
XmlData *data = user_data;
data->current = data->current->parent;
}
static void
xml_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
XmlData *data = user_data;
FlatpakXml *node;
node = flatpak_xml_new (NULL);
node->text = g_strndup (text, text_len);
flatpak_xml_add (data->current, node);
}
static void
xml_passthrough (GMarkupParseContext *context,
const gchar *passthrough_text,
gsize text_len,
gpointer user_data,
GError **error)
{
}
static GMarkupParser xml_parser = {
xml_start_element,
xml_end_element,
xml_text,
xml_passthrough,
NULL
};
void
flatpak_xml_free (FlatpakXml *node)
{
FlatpakXml *child;
if (node == NULL)
return;
child = node->first_child;
while (child != NULL)
{
FlatpakXml *next = child->next_sibling;
flatpak_xml_free (child);
child = next;
}
g_free (node->element_name);
g_free (node->text);
g_strfreev (node->attribute_names);
g_strfreev (node->attribute_values);
g_free (node);
}
void
flatpak_xml_to_string (FlatpakXml *node, GString *res)
{
int i;
FlatpakXml *child;
if (node->parent == NULL)
g_string_append (res, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
if (node->element_name)
{
if (node->parent != NULL)
{
g_string_append (res, "<");
g_string_append (res, node->element_name);
if (node->attribute_names)
{
for (i = 0; node->attribute_names[i] != NULL; i++)
{
g_string_append_printf (res, " %s=\"%s\"",
node->attribute_names[i],
node->attribute_values[i]);
}
}
if (node->first_child == NULL)
g_string_append (res, "/>");
else
g_string_append (res, ">");
}
child = node->first_child;
while (child != NULL)
{
flatpak_xml_to_string (child, res);
child = child->next_sibling;
}
if (node->parent != NULL)
{
if (node->first_child != NULL)
g_string_append_printf (res, "</%s>", node->element_name);
}
}
else if (node->text)
{
g_autofree char *escaped = g_markup_escape_text (node->text, -1);
g_string_append (res, escaped);
}
}
FlatpakXml *
flatpak_xml_unlink (FlatpakXml *node,
FlatpakXml *prev_sibling)
{
FlatpakXml *parent = node->parent;
if (parent == NULL)
return node;
if (parent->first_child == node)
parent->first_child = node->next_sibling;
if (parent->last_child == node)
parent->last_child = prev_sibling;
if (prev_sibling)
prev_sibling->next_sibling = node->next_sibling;
node->parent = NULL;
node->next_sibling = NULL;
return node;
}
FlatpakXml *
flatpak_xml_find (FlatpakXml *node,
const char *type,
FlatpakXml **prev_child_out)
{
FlatpakXml *child = NULL;
FlatpakXml *prev_child = NULL;
child = node->first_child;
prev_child = NULL;
while (child != NULL)
{
FlatpakXml *next = child->next_sibling;
if (g_strcmp0 (child->element_name, type) == 0)
{
if (prev_child_out)
*prev_child_out = prev_child;
return child;
}
prev_child = child;
child = next;
}
return NULL;
}
FlatpakXml *
flatpak_xml_parse (GInputStream *in,
gboolean compressed,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GInputStream) real_in = NULL;
g_autoptr(FlatpakXml) xml_root = NULL;
XmlData data = { 0 };
char buffer[32 * 1024];
gssize len;
g_autoptr(GMarkupParseContext) ctx = NULL;
if (compressed)
{
g_autoptr(GZlibDecompressor) decompressor = NULL;
decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
real_in = g_converter_input_stream_new (in, G_CONVERTER (decompressor));
}
else
{
real_in = g_object_ref (in);
}
xml_root = flatpak_xml_new ("root");
data.current = xml_root;
ctx = g_markup_parse_context_new (&xml_parser,
G_MARKUP_PREFIX_ERROR_POSITION,
&data,
NULL);
while ((len = g_input_stream_read (real_in, buffer, sizeof (buffer),
cancellable, error)) > 0)
{
if (!g_markup_parse_context_parse (ctx, buffer, len, error))
return NULL;
}
if (len < 0)
return NULL;
return g_steal_pointer (&xml_root);
}

View File

@ -123,6 +123,39 @@ xml_autoptr_cleanup_generic_free (void *p)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (xmlDoc, xmlFreeDoc)
typedef struct FlatpakXml FlatpakXml;
struct FlatpakXml
{
gchar *element_name; /* NULL == text */
char **attribute_names;
char **attribute_values;
char *text;
FlatpakXml *parent;
FlatpakXml *first_child;
FlatpakXml *last_child;
FlatpakXml *next_sibling;
};
FlatpakXml *flatpak_xml_new (const gchar *element_name);
FlatpakXml *flatpak_xml_new_text (const gchar *text);
void flatpak_xml_add (FlatpakXml *parent,
FlatpakXml *node);
void flatpak_xml_free (FlatpakXml *node);
FlatpakXml *flatpak_xml_parse (GInputStream *in,
gboolean compressed,
GCancellable *cancellable,
GError **error);
void flatpak_xml_to_string (FlatpakXml *node,
GString *res);
FlatpakXml *flatpak_xml_unlink (FlatpakXml *node,
FlatpakXml *prev_sibling);
FlatpakXml *flatpak_xml_find (FlatpakXml *node,
const char *type,
FlatpakXml **prev_child_out);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakXml, flatpak_xml_free);
G_END_DECLS
#endif /* __BUILDER_UTILS_H__ */