diff options
author | Guillaume Girol <symphorien+git@xlumurb.eu> | 2022-10-13 12:00:00 +0000 |
---|---|---|
committer | Guillaume Girol <symphorien+git@xlumurb.eu> | 2022-11-11 13:30:00 +0100 |
commit | e094494915761e7b4e6de47f5b9c87a301edb974 (patch) | |
tree | c69a625242a5140baa5bb40e400775c41174cff7 /pkgs/development/libraries/glib | |
parent | 0533be43f1ce89c51ce9720386258ea5c19fcb1d (diff) |
glib: add an update script combinator to patch gsettings schema paths
and use it in evolution-data-server and evolution-ews as a proof of concept
Diffstat (limited to 'pkgs/development/libraries/glib')
-rw-r--r-- | pkgs/development/libraries/glib/default.nix | 51 | ||||
-rw-r--r-- | pkgs/development/libraries/glib/hardcode-gsettings.cocci | 70 |
2 files changed, 121 insertions, 0 deletions
diff --git a/pkgs/development/libraries/glib/default.nix b/pkgs/development/libraries/glib/default.nix index 8e3d1a45dbe1c..b38ba682a76be 100644 --- a/pkgs/development/libraries/glib/default.nix +++ b/pkgs/development/libraries/glib/default.nix @@ -8,6 +8,8 @@ , coreutils, dbus, libxml2, tzdata , desktop-file-utils, shared-mime-info , darwin +# update script +, runCommand, git, coccinelle }: assert stdenv.isLinux -> util-linuxMinimal != null; @@ -246,6 +248,55 @@ stdenv.mkDerivation (finalAttrs: { packageName = "glib"; versionPolicy = "odd-unstable"; }; + /* + can be used as part of an update script to automatically create a patch + hardcoding the path of all gsettings schemas in C code. + For example: + passthru = { + hardcodeGsettingsPatch = glib.mkHardcodeGsettingsPatch { + inherit src; + glib-schema-to-var = { + ... + }; + }; + + updateScript = + let + updateSource = ...; + patch = _experimental-update-script-combinators.copyAttrOutputToFile "evolution-ews.hardcodeGsettingsPatch" ./hardcode-gsettings.patch; + in + _experimental-update-script-combinators.sequence [ + updateSource + patch + ]; + }; + } + takes as input a mapping from schema path to variable name. + For example `{ "org.gnome.evolution" = "EVOLUTION_SCHEMA_PATH"; }` + hardcodes looking for `org.gnome.evolution` into `@EVOLUTION_SCHEMA_PATH@`. + All schemas must be listed. + */ + mkHardcodeGsettingsPatch = { src, glib-schema-to-var }: + runCommand + "hardcode-gsettings.patch" + { + inherit src; + nativeBuildInputs = [ + git + coccinelle + python3 # For patch script + ]; + } + '' + unpackPhase + cd "''${sourceRoot:-.}" + set -x + cp ${builtins.toFile "glib-schema-to-var.json" (builtins.toJSON glib-schema-to-var)} ./glib-schema-to-var.json + git init + git add -A + spatch --sp-file "${./hardcode-gsettings.cocci}" --dir . --in-place + git diff > "$out" + ''; }; meta = with lib; { diff --git a/pkgs/development/libraries/glib/hardcode-gsettings.cocci b/pkgs/development/libraries/glib/hardcode-gsettings.cocci new file mode 100644 index 0000000000000..bedacf846bc49 --- /dev/null +++ b/pkgs/development/libraries/glib/hardcode-gsettings.cocci @@ -0,0 +1,70 @@ +/** + * Since Nix does not have a standard location like /usr/share, + * where GSettings system could look for schemas, we need to point the software to a correct location somehow. + * For executables, we handle this using wrappers but this is not an option for libraries like e-d-s. + * Instead, we hardcode the schema path when creating the settings. + * A schema path (ie org.gnome.evolution) can be replaced by @EVOLUTION_SCHEMA_PATH@ + * which is then replaced at build time by substituteAll. + * The mapping is provided in a json file ./glib-schema-to-var.json + */ + +@initialize:python@ +@@ +import json + +cpp_constants = {} + +def register_cpp_constant(const_name, val): + cpp_constants[const_name] = val.strip() + +def resolve_cpp_constant(const_name): + return cpp_constants.get(const_name, const_name) + +with open("./glib-schema-to-var.json") as mapping_file: + schema_to_var = json.load(mapping_file); + +def get_schema_directory(schema_path): + # Sometimes the schema id is referenced using C preprocessor #define constant in the same file + # let’s try to resolve it first. + schema_path = resolve_cpp_constant(schema_path.strip()).strip('"') + if schema_path in schema_to_var: + return f'"@{schema_to_var[schema_path]}@"' + raise Exception(f"Unknown schema path {schema_path!r}, please add it to ./glib-schema-to-var.json") + + +@find_cpp_constants@ +identifier const_name; +expression val; +@@ + +#define const_name val + +@script:python record_cpp_constants depends on find_cpp_constants@ +const_name << find_cpp_constants.const_name; +val << find_cpp_constants.val; +@@ + +register_cpp_constant(const_name, val) + + +@depends on ever record_cpp_constants || never record_cpp_constants@ +// We want to run after #define constants have been collected but even if there are no #defines. +expression SCHEMA_PATH; +expression settings; +// Coccinelle does not like autocleanup macros in + sections, +// let’s use fresh id with concatenation to produce the code as a string. +fresh identifier schema_source_decl = "g_autoptr(GSettingsSchemaSource) " ## "schema_source"; +fresh identifier schema_decl = "g_autoptr(GSettingsSchema) " ## "schema"; +fresh identifier SCHEMA_DIRECTORY = script:python(SCHEMA_PATH) { get_schema_directory(SCHEMA_PATH) }; +@@ +-settings = g_settings_new(SCHEMA_PATH); ++{ ++ schema_source_decl; ++ schema_decl; ++ schema_source = g_settings_schema_source_new_from_directory(SCHEMA_DIRECTORY, ++ g_settings_schema_source_get_default(), ++ TRUE, ++ NULL); ++ schema = g_settings_schema_source_lookup(schema_source, SCHEMA_PATH, FALSE); ++ settings = g_settings_new_full(schema, NULL, NULL); ++} |