diff --git a/app/Makefile.am.inc b/app/Makefile.am.inc
index 9caf641a..e3d811fd 100644
--- a/app/Makefile.am.inc
+++ b/app/Makefile.am.inc
@@ -20,6 +20,7 @@ flatpak_SOURCES = \
app/flatpak-builtins-uninstall.c \
app/flatpak-builtins-list.c \
app/flatpak-builtins-info.c \
+ app/flatpak-builtins-config.c \
app/flatpak-builtins-run.c \
app/flatpak-builtins-enter.c \
app/flatpak-builtins-build-init.c \
diff --git a/app/flatpak-builtins-config.c b/app/flatpak-builtins-config.c
new file mode 100644
index 00000000..397c42ee
--- /dev/null
+++ b/app/flatpak-builtins-config.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 2017 Red Hat, Inc
+ *
+ * This program 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, see .
+ *
+ * Authors:
+ * Alexander Larsson
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "libglnx/libglnx.h"
+
+#include "flatpak-builtins.h"
+#include "common/flatpak-dir.h"
+
+static gboolean opt_get;
+static gboolean opt_set;
+static gboolean opt_unset;
+static gboolean opt_list;
+
+static GOptionEntry options[] = {
+ { "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, N_("List configuration keys and values"), NULL },
+ { "get", 0, 0, G_OPTION_ARG_NONE, &opt_get, N_("Get configuration for KEY"), NULL },
+ { "set", 0, 0, G_OPTION_ARG_NONE, &opt_set, N_("Set configuration for KEY to VALUE"), NULL },
+ { "unset", 0, 0, G_OPTION_ARG_NONE, &opt_unset, N_("Unset configuration for KEY"), NULL },
+ { NULL }
+};
+
+static char *
+parse_lang (const char *value)
+{
+ if (strcmp (value, "*") == 0 ||
+ strcmp (value, "*all*") == 0)
+ return g_strdup ("");
+ return g_strdup (value);
+}
+
+static char *
+print_lang (const char *value)
+{
+ if (*value == 0)
+ return g_strdup ("*all*");
+ return g_strdup (value);
+}
+
+static char *
+get_lang_default (FlatpakDir *dir)
+{
+ g_auto(GStrv) langs = flatpak_dir_get_default_locale_languages (dir);
+
+ return g_strjoinv (";", langs);
+}
+
+typedef struct {
+ const char *name;
+ const char *ostree_name;
+ char *(*parse)(const char *value);
+ char *(*print)(const char *value);
+ char *(*get_default)(FlatpakDir *dir);
+} ConfigKey;
+
+ConfigKey keys[] = {
+ { "languages", "xa.languages", parse_lang, print_lang, get_lang_default },
+};
+
+static ConfigKey *
+get_config_key (const char *arg, GError **error)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (keys); i++)
+ {
+ if (strcmp (keys[i].name, arg) == 0)
+ return &keys[i];
+ }
+
+ flatpak_fail (error, _("Unknown configure key '%s'"), arg);
+ return NULL;
+}
+
+static char *
+print_config (FlatpakDir *dir, ConfigKey *key)
+{
+ GKeyFile *config = ostree_repo_get_config (flatpak_dir_get_repo (dir));
+ g_autofree char *value = NULL;
+
+ value = g_key_file_get_string (config, "core", key->ostree_name, NULL);
+ if (value == NULL)
+ return g_strdup ("*unset*");
+
+ return key->print (value);
+}
+
+static gboolean
+list_config (int argc, char **argv, FlatpakDir *dir, GCancellable *cancellable, GError **error)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (keys); i++)
+ {
+ const char *key = keys[i].name;
+ g_autofree char *value = print_config (dir, &keys[i]);
+ g_autofree char *default_value = NULL;
+
+ g_print ("%s: %s", key, value);
+
+ if (keys[i].get_default)
+ default_value = keys[i].get_default (dir);
+ if (default_value)
+ {
+ g_autofree char *printed = keys[i].print (default_value);
+ g_print (" (default: %s)", printed);
+ }
+ g_print ("\n");
+ }
+
+ return TRUE;
+}
+
+static gboolean
+get_config (int argc, char **argv, FlatpakDir *dir, GCancellable *cancellable, GError **error)
+{
+ ConfigKey *key;
+ g_autofree char *value = NULL;
+
+ if (argc != 2)
+ return flatpak_fail (error, _("You must specify key"));
+
+ key = get_config_key (argv[1], error);
+ if (key == NULL)
+ return FALSE;
+
+ value = print_config (dir, key);
+ if (value)
+ g_print ("%s\n", value);
+ else
+ g_print ("*unset*\n");
+
+ return TRUE;
+}
+
+static gboolean
+set_config (int argc, char **argv, FlatpakDir *dir, GCancellable *cancellable, GError **error)
+{
+ ConfigKey *key;
+ g_autofree char *parsed = NULL;
+
+ if (argc != 3)
+ return flatpak_fail (error, _("You must specify both key and value"));
+
+ key = get_config_key (argv[1], error);
+ if (key == NULL)
+ return FALSE;
+
+ parsed = key->parse (argv[2]);
+ if (!flatpak_dir_set_config (dir, key->ostree_name, parsed, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+unset_config (int argc, char **argv, FlatpakDir *dir, GCancellable *cancellable, GError **error)
+{
+ ConfigKey *key;
+
+ if (argc != 2)
+ return flatpak_fail (error, _("You must specify key"));
+
+ key = get_config_key (argv[1], error);
+ if (key == NULL)
+ return FALSE;
+
+ if (!flatpak_dir_set_config (dir, key->ostree_name, argv[2], error))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+flatpak_builtin_config (int argc, char **argv, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(GOptionContext) context = NULL;
+ g_autoptr(FlatpakDir) dir = NULL;
+
+ context = g_option_context_new (_("[KEY [VALUE]] - Manage configuration"));
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
+
+ if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
+ return FALSE;
+
+ if (opt_get)
+ return get_config (argc, argv, dir, cancellable, error);
+ else if (opt_set)
+ return set_config (argc, argv, dir, cancellable, error);
+ else if (opt_unset)
+ return unset_config (argc, argv, dir, cancellable, error);
+ else if (opt_list)
+ return list_config (argc, argv, dir, cancellable, error);
+ else
+ return flatpak_fail (error, _("Must specify one on --list, --get, --set or --unset"));
+
+ return TRUE;
+}
+
+gboolean
+flatpak_complete_config (FlatpakCompletion *completion)
+{
+ g_autoptr(GOptionContext) context = NULL;
+ g_autoptr(FlatpakDir) dir = NULL;
+
+ context = g_option_context_new ("");
+ if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, 0, &dir, NULL, NULL))
+ return FALSE;
+
+ switch (completion->argc)
+ {
+ case 0:
+ case 1: /* REMOTE */
+ flatpak_complete_options (completion, global_entries);
+ flatpak_complete_options (completion, options);
+ flatpak_complete_options (completion, user_entries);
+
+ if (opt_set || opt_get || opt_unset)
+ {
+ int i;
+ for (i = 0; i < G_N_ELEMENTS (keys); i++)
+ flatpak_complete_word (completion, "%s", keys[i].name);
+ }
+
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/app/flatpak-builtins.h b/app/flatpak-builtins.h
index aa2ccf53..2970140b 100644
--- a/app/flatpak-builtins.h
+++ b/app/flatpak-builtins.h
@@ -84,6 +84,7 @@ BUILTINPROTO (document_info)
BUILTINPROTO (document_list)
BUILTINPROTO (override)
BUILTINPROTO (repo)
+BUILTINPROTO (config)
#undef BUILTINPROTO
diff --git a/app/flatpak-main.c b/app/flatpak-main.c
index 97c480b3..a4756932 100644
--- a/app/flatpak-main.c
+++ b/app/flatpak-main.c
@@ -64,6 +64,7 @@ static FlatpakCommand commands[] = {
{ "uninstall", N_("Uninstall an installed application or runtime"), flatpak_builtin_uninstall, flatpak_complete_uninstall },
{ "list", N_("List installed apps and/or runtimes"), flatpak_builtin_list, flatpak_complete_list },
{ "info", N_("Show info for installed app or runtime"), flatpak_builtin_info, flatpak_complete_info },
+ { "config", N_("Configure flatpak"), flatpak_builtin_config, flatpak_complete_config },
/* translators: please keep the leading newline and space */
{ N_("\n Running applications") },
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index e7bf7434..c1c1e87c 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -1642,6 +1642,28 @@ flatpak_dir_ensure_repo (FlatpakDir *self,
return TRUE;
}
+gboolean
+flatpak_dir_set_config (FlatpakDir *self,
+ const char *key,
+ const char *value,
+ GError **error)
+{
+ GKeyFile *config = ostree_repo_copy_config (self->repo);
+
+ if (value == NULL)
+ g_key_file_remove_key (config, "core", key, NULL);
+ else
+ g_key_file_set_value (config, "core", key, value);
+
+ if (!ostree_repo_write_config (self->repo, config, error))
+ return FALSE;
+
+ if (!ostree_repo_reload_config (self->repo, NULL, error))
+ return FALSE;
+
+ return TRUE;
+}
+
gboolean
flatpak_dir_mark_changed (FlatpakDir *self,
GError **error)
diff --git a/common/flatpak-dir.h b/common/flatpak-dir.h
index 0ad27e06..edac361e 100644
--- a/common/flatpak-dir.h
+++ b/common/flatpak-dir.h
@@ -309,6 +309,10 @@ gboolean flatpak_dir_recreate_repo (FlatpakDir *self,
gboolean flatpak_dir_ensure_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
+gboolean flatpak_dir_set_config (FlatpakDir *self,
+ const char *key,
+ const char *value,
+ GError **error);
gboolean flatpak_dir_mark_changed (FlatpakDir *self,
GError **error);
gboolean flatpak_dir_remove_appstream (FlatpakDir *self,
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f9b7a674..cb026213 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -25,6 +25,7 @@ man1 = \
flatpak-remote-modify.1 \
flatpak-remote-ls.1 \
flatpak-install.1 \
+ flatpak-config.1 \
flatpak-update.1 \
flatpak-uninstall.1 \
flatpak-list.1 \
diff --git a/doc/flatpak-config.xml b/doc/flatpak-config.xml
new file mode 100644
index 00000000..725de549
--- /dev/null
+++ b/doc/flatpak-config.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+ flatpak config
+ flatpak
+
+
+
+ Developer
+ Alexander
+ Larsson
+ alexl@redhat.com
+
+
+
+
+
+ flatpak config
+ 1
+
+
+
+ flatpak-config
+ Manage configuration
+
+
+
+
+ flatpak config
+ OPTION
+ KEY
+ VALUE
+
+
+
+
+ Description
+
+
+ Show and modify current configuration
+
+
+
+
+
+ Options
+
+ The following options are understood:
+
+
+
+
+
+
+
+ Show help options and exit.
+
+
+
+
+
+
+
+ Print all keys and their values
+
+
+
+
+
+
+
+ Set key KEY to VALUE
+
+
+
+
+
+
+
+ Unset key KEY
+
+
+
+
+
+
+
+ Print value of KEY.
+
+
+
+
+
+
+
+ Configure per-user installation.
+
+
+
+
+
+
+
+ Configure system-wide installation.
+
+
+
+
+
+
+
+ Configure the system-wide installation
+ specified by NAME among those defined in
+ /etc/flatpak/installations.d/. Using
+ --installation=default is equivalent to using
+ --system.
+
+
+
+
+
+
+
+ Examples
+
+
+ $ flatpak config --set language sv;en;fi
+
+
+
+
+
+ See also
+
+
+ flatpak1,
+
+
+
+
+
diff --git a/doc/flatpak.xml b/doc/flatpak.xml
index babc501d..082d2d50 100644
--- a/doc/flatpak.xml
+++ b/doc/flatpak.xml
@@ -190,6 +190,13 @@
Show information for an installed application or runtime.
+
+ flatpak-config1
+
+
+ Manage flatpak configuration.
+
+