mirror of
https://github.com/flatpak/flatpak.git
synced 2026-05-18 13:52:53 -04:00
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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user