Add --show-changelog flag to flatpak-info

This shows the latest changelog entry from the appstream data for
a given app.
This commit is contained in:
Patrick Griffis
2024-01-07 21:18:01 -06:00
parent 65bc369a9f
commit 00c52abb69
3 changed files with 153 additions and 1 deletions

View File

@@ -47,6 +47,7 @@ static gboolean opt_show_sdk;
static gboolean opt_show_permissions;
static gboolean opt_show_extensions;
static gboolean opt_show_location;
static gboolean opt_show_changelog;
static char *opt_arch;
static char **opt_installations;
static char *opt_file_access;
@@ -67,6 +68,7 @@ static GOptionEntry options[] = {
{ "file-access", 0, 0, G_OPTION_ARG_FILENAME, &opt_file_access, N_("Query file access"), N_("PATH") },
{ "show-extensions", 'e', 0, G_OPTION_ARG_NONE, &opt_show_extensions, N_("Show extensions"), NULL },
{ "show-location", 'l', 0, G_OPTION_ARG_NONE, &opt_show_location, N_("Show location"), NULL },
{ "show-changelog", 0, 0, G_OPTION_ARG_NONE, &opt_show_changelog, N_("Show changelog"), NULL },
{ NULL }
};
@@ -166,7 +168,7 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
metakey = flatpak_deploy_get_metadata (deploy);
if (opt_show_ref || opt_show_origin || opt_show_commit || opt_show_size || opt_show_metadata || opt_show_permissions ||
opt_file_access || opt_show_location || opt_show_runtime || opt_show_sdk)
opt_file_access || opt_show_location || opt_show_runtime || opt_show_sdk || opt_show_changelog)
friendly = FALSE;
if (friendly)
@@ -443,6 +445,38 @@ flatpak_builtin_info (int argc, char **argv, GCancellable *cancellable, GError *
g_print ("read-write\n");
}
}
if (opt_show_changelog)
{
#if AS_CHECK_VERSION(1, 0, 0)
g_autoptr(AsMetadata) mdata = as_metadata_new ();
g_autofree char *remote = g_strdup ("flathub"); // FIXME: Returns NULL: flatpak_decomposed_dup_remote(ref);
g_autofree char *arch = flatpak_decomposed_dup_arch (ref);
g_autoptr(GError) appstream_error = NULL;
g_autoptr(GPtrArray) dirs = g_ptr_array_new ();
AsComponent *component;
g_ptr_array_add(dirs, dir);
update_appstream (dirs, remote, arch, FLATPAK_APPSTREAM_TTL, TRUE, cancellable, NULL);
flatpak_dir_load_appstream_data (dir, remote, arch, mdata, cancellable, &appstream_error);
component = metadata_find_component (mdata, flatpak_decomposed_get_ref(ref));
if (component)
{
AsReleaseList *releases = as_component_get_releases_plain(component);
AsRelease *release = as_release_list_index_safe (releases, 0);
if (releases)
flatpak_print_appstream_release_description_markup (as_release_get_description (release));
else
g_print ("No changelog\n");
}
else
g_print ("Failed to find app, missing appstream data?\n");
#else
g_warning ("Listing changelogs is not supported with this version of libappstream");
#endif
}
}
if (opt_show_extensions)

View File

@@ -83,3 +83,5 @@ void flatpak_format_choices (const char **choices,
void flatpak_print_escaped_string (const char *s,
FlatpakEscapeFlags flags);
void flatpak_print_appstream_release_description_markup (const char *s);

View File

@@ -521,3 +521,119 @@ flatpak_print_escaped_string (const char *s,
g_autofree char *escaped = flatpak_escape_string (s, flags);
g_print ("%s", escaped);
}
/* Markup format documented here: https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-description */
typedef struct {
GString *formatted;
guint current_list_index;
gboolean in_list;
gboolean in_paragraph;
} DescriptionParserData;
static void
start_element (GMarkupParseContext *context,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
gpointer user_data,
GError **error)
{
DescriptionParserData *data = user_data;
if (g_str_equal (element_name, "p"))
{
if (data->formatted->len != 0)
g_string_append_c (data->formatted, '\n');
data->in_paragraph = TRUE;
}
else if (!data->in_list && g_str_equal (element_name, "ol"))
{
data->in_list = TRUE;
data->current_list_index = 1;
}
else if (!data->in_list && g_str_equal (element_name, "ul"))
{
data->in_list = TRUE;
}
else if (data->in_list && g_str_equal (element_name, "li"))
{
if (data->formatted->len != 0)
g_string_append_c (data->formatted, '\n');
if (data->current_list_index)
g_string_append_printf(data->formatted, " %u. ", data->current_list_index++);
else
g_string_append(data->formatted, " - ");
}
else if ((data->in_list || data->in_paragraph) && g_str_equal (element_name, "em"))
{
g_string_append (data->formatted, "\033[3m");
}
}
static void
end_element (GMarkupParseContext *context,
const char *element_name,
gpointer user_data,
GError **error)
{
DescriptionParserData *data = user_data;
if (g_str_equal (element_name, "p"))
{
data->in_paragraph = FALSE;
}
else if (data->in_list && g_str_equal (element_name, "ol"))
{
data->in_list = FALSE;
data->current_list_index = 0;
}
else if (data->in_list && g_str_equal (element_name, "ul"))
{
data->in_list = FALSE;
}
else if ((data->in_list || data->in_paragraph) && g_str_equal (element_name, "em"))
{
g_string_append (data->formatted, "\e[0m");
}
}
static void
text (GMarkupParseContext *context,
const char *text,
gsize text_len,
gpointer user_data,
GError **error)
{
DescriptionParserData *data = user_data;
g_string_append_len (data->formatted, text, text_len);
}
void
flatpak_print_appstream_release_description_markup (const char *s)
{
g_autoptr(GString) formatted = g_string_new_len(NULL, strlen (s));
g_autoptr(GError) error = NULL;
g_autoptr(GMarkupParseContext) context = NULL;
GMarkupParser parser = {
start_element,
end_element,
text,
NULL,
NULL
};
g_autofree DescriptionParserData *data = g_new0 (DescriptionParserData, 1);
data->formatted = formatted;
context = g_markup_parse_context_new (&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, data, NULL);
if (!g_markup_parse_context_parse (context, s, -1, &error))
{
g_warning ("Failed to release description: %s", error->message);
return;
}
g_string_append_c (formatted, '\n');
g_print ("%s", formatted->str);
}