Skip to content

Commit

Permalink
compose: Allow setting a custom icon-policy on the command-line
Browse files Browse the repository at this point in the history
This was exposed by the API before, but we now also make it available on
the CLI. Users have to keep in mind that this change will significantly
increase the amount of generated data (that also might have to be
downloaded constantly).

Resolves: #602
  • Loading branch information
ximion committed Feb 24, 2024
1 parent d2b688a commit ddd3ec2
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 25 deletions.
174 changes: 174 additions & 0 deletions compose/asc-icon-policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,48 @@ asc_icon_policy_class_init (AscIconPolicyClass *klass)
object_class->finalize = asc_icon_policy_finalize;
}

/**
* asc_icon_state_to_string:
* @istate: the #AscIconState.
*
* Converts the enumerated value to an text representation.
*
* Returns: string version of @istate
**/
const gchar *
asc_icon_state_to_string (AscIconState istate)
{
if (istate == ASC_ICON_STATE_CACHED_REMOTE)
return "cached-remote";
if (istate == ASC_ICON_STATE_CACHED_ONLY)
return "cached";
if (istate == ASC_ICON_STATE_REMOTE_ONLY)
return "remote";

return "ignored";
}

/**
* asc_icon_state_from_string:
* @state_str: the string.
*
* Converts the text representation to an enumerated value.
*
* Returns: a #AscIconState
**/
AscIconState
asc_icon_state_from_string (const gchar *state_str)
{
if (as_str_equal0 (state_str, "cached-remote"))
return ASC_ICON_STATE_CACHED_REMOTE;
if (as_str_equal0 (state_str, "cached"))
return ASC_ICON_STATE_CACHED_ONLY;
if (as_str_equal0 (state_str, "remote"))
return ASC_ICON_STATE_REMOTE_ONLY;

return ASC_ICON_STATE_IGNORED;
}

/**
* asc_icon_policy_set_policy:
* @ipolicy: an #AscIconPolicy instance.
Expand Down Expand Up @@ -230,6 +272,138 @@ asc_icon_policy_iter_next (AscIconPolicyIter *iter, guint *size, guint *scale, A
return TRUE;
}

/**
* asc_icon_policy_to_string:
* @ipolicy: an #AscIconPolicy instance.
*
* Converts the current icon policy into a textual representation.
*
* Returns: The icon policy serialized into a string. Free with g_free()
**/
gchar *
asc_icon_policy_to_string (AscIconPolicy *ipolicy)
{
AscIconPolicyPrivate *priv = GET_PRIVATE (ipolicy);
GString *result = g_string_new ("");

for (guint i = 0; i < priv->entries->len; i++) {
AscIconPolicyEntry *e = g_ptr_array_index (priv->entries, i);
if (e->scale > 1)
g_string_append_printf (result,
"%dx%d@%d=%s,",
e->size,
e->size,
e->scale,
asc_icon_state_to_string (e->state));
else
g_string_append_printf (result,
"%dx%d=%s,",
e->size,
e->size,
asc_icon_state_to_string (e->state));
}

/* trim trailing comma */
if (result->len > 0)
g_string_truncate (result, result->len - 1);

return g_string_free (result, FALSE);
}

/**
* asc_icon_policy_from_string:
* @ipolicy: an #AscIconPolicy instance.
* @serialized_policy: A policy string as returned by %asc_icon_policy_to_string
* @error: A #GError
*
* Loads the icon policy from a textual representation.
*
**/
gboolean
asc_icon_policy_from_string (AscIconPolicy *ipolicy, const gchar *serialized_policy, GError **error)
{
AscIconPolicyPrivate *priv = GET_PRIVATE (ipolicy);
g_auto(GStrv) policy_blocks = NULL;
gboolean success = TRUE;
gboolean have_64x64_cached = FALSE;
g_return_val_if_fail (serialized_policy != NULL, FALSE);

policy_blocks = g_strsplit (serialized_policy, ",", -1);
if (policy_blocks == NULL) {
g_set_error_literal (error,
AS_UTILS_ERROR,
AS_UTILS_ERROR_FAILED,
"Unable to parse icon policy string representation.");
return FALSE;
}

/* delete existing entries */
g_ptr_array_set_size (priv->entries, 0);

/* parse data */
for (guint i = 0; policy_blocks[i] != NULL; i++) {
guint size = 0;
guint scale = 1;
gchar *scale_ptr;
g_auto(GStrv) size_scale = NULL;
g_auto(GStrv) parts = g_strsplit (policy_blocks[i], "=", 2);

if (parts == NULL || g_strv_length (parts) != 2) {
success = FALSE;
continue;
}
size_scale = g_strsplit (parts[0], "x", 2);
if (size_scale == NULL || g_strv_length (size_scale) != 2) {
success = FALSE;
continue;
}

size = g_ascii_strtoull (size_scale[0], NULL, 10);
scale_ptr = g_strrstr (size_scale[1], "@");
if (scale_ptr != NULL)
scale = g_ascii_strtoull (scale_ptr + 1, NULL, 10);

if (size == 0 || scale == 0) {
success = FALSE;
continue;
}

asc_icon_policy_set_policy (ipolicy,
size,
scale,
asc_icon_state_from_string (parts[1]));
}

/* we must have 64x64px icons cached, to satisfy policy */
for (guint i = 0; i < priv->entries->len; i++) {
AscIconPolicyEntry *e = g_ptr_array_index (priv->entries, i);
if (e->size == 64 && e->scale == 1) {
if (e->state == ASC_ICON_STATE_CACHED_REMOTE ||
e->state == ASC_ICON_STATE_CACHED_ONLY)
have_64x64_cached = TRUE;
break;
}
}

if (!have_64x64_cached) {
g_set_error_literal (
error,
AS_UTILS_ERROR,
AS_UTILS_ERROR_FAILED,
"64x64@1 icons were not selected for being cached, which is not permitted.");
asc_icon_policy_set_policy (ipolicy, 64, 1, ASC_ICON_STATE_CACHED_ONLY);
return FALSE;
}

if (!success)
g_set_error_literal (error,
AS_UTILS_ERROR,
AS_UTILS_ERROR_FAILED,
"Unable to parse icon policy string representation.");

return success;
}

/**
* asc_icon_policy_new:
*
Expand Down
8 changes: 8 additions & 0 deletions compose/asc-icon-policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ typedef enum {
ASC_ICON_STATE_REMOTE_ONLY
} AscIconState;

const gchar *asc_icon_state_to_string (AscIconState istate);
AscIconState asc_icon_state_from_string (const gchar *state_str);

AscIconPolicy *asc_icon_policy_new (void);

void asc_icon_policy_set_policy (AscIconPolicy *ipolicy,
Expand All @@ -79,4 +82,9 @@ gboolean asc_icon_policy_iter_next (AscIconPolicyIter *iter,
guint *scale,
AscIconState *state);

gchar *asc_icon_policy_to_string (AscIconPolicy *ipolicy);
gboolean asc_icon_policy_from_string (AscIconPolicy *ipolicy,
const gchar *serialized_policy,
GError **error);

G_END_DECLS
36 changes: 34 additions & 2 deletions docs/xml/man/appstreamcli-compose.1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<refentryinfo>
<title>appstreamcli compose</title>
<copyright>
<year>2020-2022</year>
<year>2020-2024</year>
<holder>Matthias Klumpp</holder>
</copyright>
<productname>AppStream</productname>
Expand Down Expand Up @@ -69,7 +69,7 @@
<variablelist>

<varlistentry>
<term><replaceable>SOURCE DIRECTORIES</replaceable></term>
<term><replaceable>SOURCE-DIRECTORIES</replaceable></term>
<listitem>
<para>
A list of directories to process needs to be provided as positional parameters.
Expand Down Expand Up @@ -184,6 +184,38 @@
</listitem>
</varlistentry>

<varlistentry>
<term><option>--no-partial-urls</option></term>
<listitem>
<para>
If set, all URLs in the generated data will be absolute and <code>media_baseurl</code> will not be used.
This makes changing the media mirror harder without regenerating all data and is generally not recommended,
to increase flexibility.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><option>--icon-policy <replaceable>POLICY-STRING</replaceable></option></term>
<listitem>
<para>
Override the existing icon policy with a custom one. The icon policy sets how icons of
different sizes should be dealt with. They can be in the icon cache only, be a remote icon in
the media location or be both cached and available in the remote location.
</para>
<para>
The icon-policy string is comprised of comma-separated <code>%{size}x%{size}@%{scale}=%{state}</code> statements.
The <code>size</code> and <code>scale</code> are that of the respective icon, with the scale being allowed to be
omitted if it is 1. The <code>state</code> can be one of <literal>remote</literal>, <literal>cached</literal> or
<literal>cached-remote</literal>.
</para>
<para>
By default, a policy of <code>48x48=cached,48x48@2=cached,64x64=cached,64x64@2=cached,128x128=cached-remote,128x128@2=cached-remote</code>
is selected.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><option>--components <replaceable>COMPONENT-IDs</replaceable></option></term>
<listitem>
Expand Down
2 changes: 1 addition & 1 deletion docs/xml/man/appstreamcli.1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<refentryinfo>
<title>appstreamcli</title>
<copyright>
<year>2012-2022</year>
<year>2012-2024</year>
<holder>Matthias Klumpp</holder>
</copyright>
<productname>AppStream</productname>
Expand Down
11 changes: 6 additions & 5 deletions src/as-relation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,11 +1912,12 @@ as_relation_is_satisfied (AsRelation *relation,
* AS_RELATION_ITEM_KIND_INTERNET
*/

g_set_error (error,
AS_RELATION_ERROR,
AS_RELATION_ERROR_NOT_IMPLEMENTED,
_("Satisfiability check for relation items of type '%s' is not implemented yet."),
as_relation_item_kind_to_string (priv->item_kind));
g_set_error (
error,
AS_RELATION_ERROR,
AS_RELATION_ERROR_NOT_IMPLEMENTED,
_("Satisfiability check for relation items of type '%s' is not implemented yet."),
as_relation_item_kind_to_string (priv->item_kind));

return NULL;
}
Expand Down
38 changes: 38 additions & 0 deletions tests/test-compose.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,42 @@ test_compose_font (void)
asc_assert_no_hints_in_result (cres);
}

static void
test_compose_icon_policy_serialize (void)
{
g_autoptr(AscIconPolicy) ipolicy = NULL;
g_autofree gchar *tmp = NULL;
gboolean ret;
g_autoptr(GError) error = NULL;

ipolicy = asc_icon_policy_new ();
tmp = asc_icon_policy_to_string (ipolicy);
g_assert_cmpstr (tmp,
==,
"48x48=cached,48x48@2=cached,64x64=cached,64x64@2=cached,"
"128x128=cached-remote,128x128@2=cached-remote");
g_free (g_steal_pointer (&tmp));

ret = asc_icon_policy_from_string (
ipolicy,
"48x48@2=ignored,64x64=cached,64x64@2=cached-remote,128x128=remote,128x128@2=remote",
&error);
g_assert_no_error (error);
g_assert_true (ret);
g_clear_error (&error);

tmp = asc_icon_policy_to_string (ipolicy);
g_assert_cmpstr (
tmp,
==,
"48x48@2=ignored,64x64=cached,64x64@2=cached-remote,128x128=remote,128x128@2=remote");
g_free (g_steal_pointer (&tmp));

ret = asc_icon_policy_from_string (ipolicy, "48x48-2:ignored,64x64:cached", &error);
g_assert_error (error, AS_UTILS_ERROR, AS_UTILS_ERROR_FAILED);
g_assert_false (ret);
}

int
main (int argc, char **argv)
{
Expand Down Expand Up @@ -988,6 +1024,8 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/Compose/SourceLocale", test_compose_source_locale);
g_test_add_func ("/AppStream/Compose/VideoInfo", test_compose_video_info);
g_test_add_func ("/AppStream/Compose/Font", test_compose_font);
g_test_add_func ("/AppStream/Compose/IconPolicySerialize",
test_compose_icon_policy_serialize);

ret = g_test_run ();
g_free (datadir);
Expand Down
Loading

0 comments on commit ddd3ec2

Please sign in to comment.