GSettings : utilisation en « local »

Date
Catégories
Tags

Depuis Gnome 3, le stockage de la configuration d'une application se fait par l'intermédiaire de GSettings, une API « agnostique » dont l'utilisation dans un plugin Gedit ou une extension Gnome-shell pose de petits problèmes car elle nécessite les droits administrateurs. Voici quelques pistes pour l'utiliser « en local ».

§Présentation

L'enregistrement de la configuration d'une application est un principe simple qui consiste à stocker une série de couples clé/valeur, soit le nom d'une propriété de configuration et sa valeur. L'utilisateur retrouve ensuite ces valeurs à chaque fois qu'il lance l'application.

Dans ce qui suit, nous allons essayer de doter un plugin Gedit d'une configuration ; celle-ci sera uniquement constituée d'une chaîne de caractère « foo ».

  • myplugin
    • __init__.py
  • myplugin.plugin
Organistaion de notre plugin Gedit « myplugin ».

§Configuration sous Gnome 2 : GConf

Sous Gnome 2 (et donc Gedit < 3), le stockage des informations de configuration se faisait avec GConf. Son utilisation était dés plus simple :

# Importer gconf
import gconf
# Chemin de stockage de la configuration du plugin Gedit
GCONF_DIR = '/apps/gedit-2/plugins/myplugin/'
# Récupérer la valeur de 'foo' => 'bar'
value = gconf.client_get_default().get_string(GCONF_DIR + 'foo')
# Assigner une nouvelle valeur à 'foo' => 'baz'
gconf.client_get_default().set_string(GCONF_DIR + 'foo', 'baz')
Exemple d'utilisation de GConf en python.

§Configuration sous Gnome 3 : GSettings

Avec Gnome 3, les choses se complexifient un (tout) petit peu. D'abord parce que GConf est remplacé par Dconf ; ensuite parce que les applications n'interagissent plus directement avec l'outil de stockage mais avec GSettings, une API générique qui est chargée d'aller dialoguer avec DConf.

L'avantage de cette technique est évident : en utilisant GSettings, on reste indépendant de la manière dont les données vont être stockées. Si le projet Gnome décide un jour d'abandonner DConf pour utiliser un autre système de stockage, le changement sera transparent.

Pour pouvoir utiliser GSettings, il nous faut d'abord déclarer les propriétés de configuration de notre application dans un fichier xml. Voici à quoi ressemblerait celui de notre plugin Gedit :

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
  <schema id="org.gnome.gedit.plugins.myplugin" path="/org/gnome/gedit/plugins/myplugin/">
    <key type="s" name="foo">
      <default>"bar"</default>
      <summary>Foo value</summary>
      <description>This is the Foo value</description>
    </key>
  </schema>
</schemalist>
Fichier de configuration org.gnome.gedit.plugins.myplugin.gschema.xml.

Ces fichiers de « schémas » doivent avoir un nom qui se termine par « gschema.xml ». Ils ne sont utilisés que sous forme compilée, compilation qui s'effectue grâce au programme glib-compile-schemas. Nous pouvons ensuite créer un objet de configuration correspondant à notre plugin :

# Importer Gio
from gi.repository import Gio

# Nom du schéma
SETTINGS_SCHEMA = "org.gnome.gedit.plugins.myplugin"

# Liste des schémas disponibles
schemas = Gio.Settings.list_schemas()
# Notre schéma est dans la liste globale des schémas
if SETTINGS_SCHEMA in schemas:
    # Récupérer la configuration
    settings = Gio.Settings.new(SETTINGS_SCHEMA)
    # Récupérer la valeur de 'foo' => 'bar'
    value = settings.get_string('foo')
    # Assigner une nouvelle valeur à 'foo' => 'baz'
    settings.set_string('foo', 'baz')
Exemple d'utilisation de GSettings en python.

Bien. Il n'y a là rien de vraiment compliqué ni de fondamentalement différent par rapport à ce qui se faisait sous Gnome 2. Nous sommes cependant passé un peu trop rapidement sur la notion de compilation des schémas, car c'est-là que nous allons avoir des problèmes. Pas dans la compilation elle-même mais plutôt sur le lieu où elle doit avoir lieu.

§Un problème de compilation

En effet, GSettings ne lit que les schémas compilés présents dans les répertoires système de données ($XDG_DATA_DIRS dans les spécifications des répertoires de base), soit /usr/local/share/glib-2.0/schemas/ et /usr/share/glib-2.0/schemas/ par défaut, et pas dans le répertoire local de données propre à l'utilisateur ($XDG_DATA_HOME), soit ~/.local/share/glib-2.0/schemas/.

On devine dés lors le soucis : pour utiliser un schéma de configuration GSettings dans un plugin Gedit qu'un utilisateur installe, il va falloir copier le fichier xml et le compiler dans un répertoire système avec les droits administrateurs :

su -c "cp path/to/org.gnome.gedit.plugins.myplugin.gschema.xml /usr/share/glib-2.0/schemas/"
su -c "glib-compile-schemas /usr/share/glib-2.0/schemas/"
Copie et compilation de notre schéma dans /usr/share/glib-2.0/schemas/.

Un peu rude comme manipulation pour permettre la configuration d'un plugin Gedit, alors même que celui-ci peut être installer par l'utilisateur dans son répertoire local de données (~/.local/share/gedit/plugins/). C'est une véritable régression par rapport à GConf.

§Compilation embarquée dans le plugin

Heureusement, nous pouvons nous passer de cette étape et utiliser un schéma compilé localement, au sein même du plugin. Pour ce faire, nous organisons d'abord le plugin pour y placer le fichier xml de schémas dans un dossier dédié :

  • myplugin
    • schemas
      • org.gnome.gedit.plugins.myplugin.gschema.xml
    • __init__.py
  • myplugin.plugin
Organisation du plugin Gedit avec le schéma de configuration.

Nous compilons ensuite le schéma dans ce répertoire :

glib-compile-schemas path/to/myplugin/schemas/
Compilation du schéma de configuration de notre plugin.

La commande glib-compile-schemas va créer un fichier de compilation nommé « gschemas.compiled ».

  • myplugin
    • schemas
      • gschemas.compiled
      • org.gnome.gedit.plugins.myplugin.gschema.xml
    • __init__.py
  • myplugin.plugin
Apparition du fichier gschemas.compiled après compilation du schéma.

Nous allons maintenant utiliser cette source de schémas compilés :

# Importer Gio
from gi.repository import Gio

# Répertoire des schémas
SCHEMAS_DIR = "path/to/myplugin/schemas/"
# Nom du schéma
SETTINGS_SCHEMA = "org.gnome.gedit.plugins.myplugin"

# Liste des schémas disponibles
schemas = Gio.Settings.list_schemas()
# Notre schéma est dans la liste globale des schémas
if SETTINGS_SCHEMA in schemas:
    # Récupérer la configuration
    settings = Gio.Settings.new(SETTINGS_SCHEMA)
# Sinon, charger le schéma "embarqué"
else:
    # Créer une nouvelle source de schémas
    schema_source = Gio.SettingsSchemaSource.new_from_directory(
        SCHEMAS_DIR, 
        Gio.SettingsSchemaSource.get_default(), 
        False
    )
    # Chercher le schéma du plugin
    schema = schema_source.lookup(SETTINGS_SCHEMA, False)
    # Récupérer la configuration
    settings = Gio.Settings.new_full(schema, None, None)

# Récupérer la valeur de 'foo' => 'bar'
value = settings.get_string('foo')
# Assigner une nouvelle valeur à 'foo' => 'baz'
settings.set_string('foo', 'baz')
Code python pour utiliser une compilation de schémas embaqruée dans le plugin.

§Compilation en local

Comme expliqué plus haut, GSettings n'est pas capable de lire des schémas de configuration déployés en local, dans ~/.local/share/glib-2.0/schemas/. En fait, cela n'est pas tout à fait vrai, cela grâce à la variable d'environnement GSETTINGS_SCHEMA_DIR :

GSETTINGS_SCHEMA_DIR. This variable can be set to the name of a directory that is considered in addition to the glib-2.0/schemas subdirectories of the XDG system data dirs when looking for compiled schemas for GSettings.

Running GIO applications

Cependant, pour pouvoir utiliser GSETTINGS_SCHEMA_DIR, il faut que l'utilisateur la définisse lui-même car elle ne l'est pas par défaut - du moins sous Fedora 17, définition à effectuer dans son fichier .profile par exemple :

# GSettings local dir
GSETTINGS_SCHEMA_DIR=$HOME/.local/share/glib-2.0/schemas/
export GSETTINGS_SCHEMA_DIR
Définition de GSETTINGS_SCHEMA_DIR dans ~/.profile.

Il faudra ensuite copier le schéma de configuration dans ce répertoire et lancer sa compilation, avec un script d'installation du plugin par exemple :

import os
# Variable d'environnement
local_schema_dir = os.environ.get('GSETTINGS_SCHEMA_DIR')
# Si la variable d'environnement est définie:
if local_schema_dir is not None:
    cmd_copy = 'cp path/to/myplugin/schemas/org.gnome.gedit.plugins.myplugin.gschema.xml ' + local_schema_dir
    cmd_compil = 'glib-compile-schemas ' + local_schema_dir
    os.system(cmd_copy)
    os.system(cmd_compil)
else:
    print 'GSETTINGS_SCHEMA_DIR is not defined'
Copie et compilation du schéma dans le répertoire local (python).
if [[ $GSETTINGS_SCHEMA_DIR ]]; then
    cp path/to/myplugin/schemas/org.gnome.gedit.plugins.myplugin.gschema.xml $GSETTINGS_SCHEMA_DIR
    glib-compile-schemas $GSETTINGS_SCHEMA_DIR
else
    echo "GSETTINGS_SCHEMA_DIR is not defined"
fi
Copie et compilation du schéma dans le répertoire local (bash).

Obliger l'utilisateur à définir une variable d'environnement pour avoir à disposition la configuration d'un plugin est tout de même contraignant, moins que de devoir installer des fichiers avec des droits administrateurs mais contraignant tout de même. La compilation dans le plugin reste donc la solution la plus acceptable, en attendant que GSETTINGS_SCHEMA_DIR soit définie par les systèmes d'exploitation.

§Extensions Gnome-shell

A noter enfin qu'on peut aussi utiliser une compilation embarquée de schémas dans une extension Gnome-shell, le javascript remplaçant le python comme langage de programmation. L'API de l'objet Gio est sensiblement identique dans les 2 cas :

// Importer Gio
const Gio = imports.gi.Gio;

// Répertoire des schémas
let SCHEMAS_DIR = "path/to/myextension/schemas/";
// Nom du schéma
let SETTINGS_SCHEMA = "org.gnome.shell.extensions.myextension";

// Créer une nouvelle source de schémas
let schema_source = Gio.SettingsSchemaSource.new_from_directory(
    SCHEMAS_DIR,
    Gio.SettingsSchemaSource.get_default(),
    false
);
// Chercher le schéma de l'extension
let schema = schema_source.lookup(SETTINGS_SCHEMA, false);
// Récupérer la configuration
let settings = new Gio.Settings({ settings_schema: schema });
Utilisation d'une compilation de schémas embarquée dans une extension Gnome-shell.

§Ressources et références

GIO Reference Manual. Gnome Dev Center. GSettings

GIO Reference Manual. Gnome Dev Center. Running GIO applications

BASTIAN, Waldo ; LORTIE, Ryan ; POETTERING, Lennart. XDG Base Directory Specification. freedesktop.org

GConf Reference Manual. Gnome Dev Center

CARRICK, Micah. Using GSettings with Python/PyGObject. micahcarrick.com,