Development/Tools/Using kconf update: Difference between revisions
(update debugging section to reflect today's reality) |
m (typos) |
||
(10 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
== Introduction == | |||
'''kconf_update''' is a tool designed to update KConfig configuration files. | |||
See [[Development/Tutorials/Updating_KConfig_Files]] for a tutorial. | |||
__TOC__ | |||
== | === What it does === | ||
Applications sometimes need to rearrange the way configuration options are stored. | |||
To avoid losing the old configuration, the application can look up both the old and the new configuration, and then decide which one to use. | |||
But this means that the application contains additional code, which deals only with configuration of the past, and is only used once. | |||
kconf_update addresses this problem by offering a framework to update configuration files, without adding complexity to the application itself. | |||
kconf_update is primarily used to move configuration entries from one place to another, but can also be used to modify the configuration data itself. | |||
=== How to use === | |||
To use kconf_update in your application, you only need to write an update file and install it in {{path|${KDE_INSTALL_KCONFUPDATEDIR}}}. | |||
An example update file is in the section [[#Example update file]]. | |||
If your application depends on KDED, kconf_update will be started automatically when the update file is installed. | |||
Otherwise, you can start it manually using <code>KConfig::checkUpdate()</code>. | |||
Note that kconf_update might process your update multiple times simultaneously in this case. | |||
This can cause problems if your update file uses the <code>Script=</code> command. | |||
See the [[#Note on side effects]] section for more details. | |||
{{Warning| | |||
Before you deploy update files to your users, you should verify that they do what you want. Otherwise you will probably get bug reports, but you already missed your change to fix them. | |||
See the [[#Testing update files]] section. | |||
}} | |||
== Testing update files == | |||
You can run kconf_update manually on a specific update file, to see how it will process it. | |||
If your update file is called {{path|myUpdate.upd}}, you would run this command: | |||
{{Input|<nowiki> | |||
/usr/lib/kf5/kconf_update --debug --testmode path/to/myUpdate.upd | |||
</nowiki>}} | |||
<code>--testmode</code> activates <code>QStandardPaths::setTestModeEnabled()</code>, so kconf_update will not update your actual configuration files, but files you have placed in a certain test directory. | |||
See the <code>QStandardPaths::GenericConfigLocation</code> documentation for your platform. | |||
See [[Development/Tutorials/Updating_KConfig_Files#Testing_update_files]] for more information on testing update files. | |||
== File format of the update file == | |||
Each line of the update file can contain a command (like <code>File=okularpartrc</code>) or a comment (like <code># Hello!</code>). | |||
Commands are processed sequentially from top to bottom. | |||
=== Update file structure === | |||
Update files are structured as follows: | |||
* ''Version=5'' (required) | |||
* any number of update sections, each started by an ''Id='' command | |||
* | ** any number of ''Script='' and ''ScriptArguments='' commands | ||
** or any number of ''File='' commands, followed by: | |||
*** any number of ''Group='', ''Key='', ''AllKeys'', ''RemoveGroup='', ''RemoveKey='', ''Options='', ''Script='', ''ScriptArguments='' commands | |||
*** ''AllGroups'' (optional) | |||
=== Update file command reference === | |||
All commands are case-sensitive. | |||
Commas are used to separate parameters, and may not occur as part of any parameter. | |||
Parameters in square brackets are optional. | |||
Parameters are referenced in angle brackets, sometimes parameters of preceding commands are referenced. | |||
(Square brackets and angle brackets are not written in the actual update file.) | |||
: | The following commands are available: | ||
:Specifies that <oldkey> is | ; Version=5 | ||
: This must be the first command in any update file. | |||
: Specifies which KDE Frameworks version this update file targets. At the time of writing the only valid value is 5, meaning modern (KDE Frameworks 5) kconf_update binaries will process the file. A file with ''Version=5'' may still be run on older kconf_updates! | |||
; Id=<id> | |||
: Starts a new update section. All commands until the next ''Id='' command are processed as part of this section. If ''<id>'' is stored in {{path|kconf_updaterc}}, this section will be skipped. When this section has been processed, ''<id>'' will be stored in {{path|kconf_updaterc}}. | |||
: ''<id>'' has to be unique. You should give your section a name that describes why this update necessary. You can also include the year of your changes, like in ''Id=annotation-toolbar-2020''. | |||
; File=<oldfile>[,<newfile>] | |||
: Specifies that configuration information is read from ''<oldfile>'' and written to ''<newfile>''. If you only specify ''<oldfile>'', the information is read from as well as written to <oldfile>. | |||
: If ''<oldfile>'' contains the ''<id>'' of the current section, the current section will be skipped. Otherwise, ''<id>'' is stored in ''<oldfile>'' and ''<newfile>''. | |||
: If ''<oldfile>'' does not exist at the time kconf_update first checks, the current section will be skipped. | |||
: Also note the [[#Updating multiple files per section]] section. | |||
; Group=<oldgroup>[,<newgroup>] | |||
: Specifies that configuration information is read from the group ''<oldgroup>'' and written to ''<newgroup>''. If you only specify ''<oldgroup>'', the information is read from as well as written to ''<oldgroup>''. | |||
: You can use <code><default></code> to select the top-level group. | |||
; Key=<oldkey>[,<newkey>] | |||
: Moves the configuration entry ''<oldkey>'' from ''<oldfile>/<oldgroup>'' to ''<newfile>/<newgroup>''. | |||
: If you specify ''<newkey>'', the entry is additionally renamed. | |||
: If you did not specify ''<newfile>'' nor ''<newgroup>'' nor ''Options=copy'', the entry is only renamed. | |||
; AllGroups | |||
: Moves all groups (including all entries) from ''<oldfile>'' to ''<newfile>''. | |||
: Note that the top-level group is not included. To include the top-level group, you need to use the ''AllKeys'' command additionally. | |||
; AllKeys | |||
: Moves all entries from ''<oldgroup>'' to ''<newgroup>''. | |||
; RemoveGroup=<oldgroup> | |||
: Removes ''<oldgroup>'' from ''<oldfile>''. | |||
: This can be used to remove obsolete entries or to force a revert to default values. | |||
; RemoveKey=<oldkey> | |||
: Removes ''<oldkey>'' from ''<oldfile>/<oldgroup>''. | |||
: This can be used to remove an obsolete entry or to force a revert to default values. | |||
; Options=<option1>, <option2>, ... | |||
: With this entry you can specify options that apply to the next ''Script='', ''Key='', ''AllKeys'', or ''AllGroups'' command (only to the first). Note that ''Script='' probably ignores the options, see the [[#Script output format]] section. | |||
: Possible options are: | |||
:; copy | |||
:: Copy the configuration item instead of moving it. This means that the configuration item will not be deleted from ''<oldfile>'' or ''<oldgroup>''. | |||
:; overwrite | |||
:: Normally, configuration entries are not moved if an entry with the new name already exists. When this option is specified, any existing entries are overwritten. | |||
; Script=<_script>[,<interpreter>] | |||
; ScriptArguments=<arguments> | |||
: See the [[#Update script commands]] section. | |||
== Using external update scripts == | |||
kconf_update provides commands to move configuration information around, but it can not manipulate the configuration data itself. | |||
Using external, so called ''update scripts'', configuration data can be manipulated through kconf_update. | |||
The concept is that old configuration entries are piped into a script. | |||
The output of the script is then interpreted as new configuration entries, which are merged to ''<newfile>'' or ''<newgroup>''. | |||
It is also possible to use scripts outside the context of a ''File='' command, then it will not get any input, and the output is ignored. | |||
See the section [[#Note on side effects]] about this. | |||
=== Update script commands === | |||
The following two commands are available to run update scripts: | |||
; Script=<_script>[,<interpreter>] | |||
: Executes the script file ''<_script>'' using the command ''<interpreter>''. If ''<interpreter>'' is not given, executes the compiled script file ''<_script>'' directly. You can not pass arguments with this command. | |||
: If in the context of a ''File='' command, all groups of ''<oldfile>'' (excluding the top-level group) will be piped into the script. If in the context of a ''Group='' command, all entries of ''<oldgroup>'' will be piped into the script. You can use <code>Group=<default></code> to process top-level entries. | |||
: The output of <_script> is merged into ''<newfile>'' or ''<newgroup>''. | |||
; ScriptArguments=<arguments> | |||
: ''<arguments>'' is passed to ''<_script>'' of the next ''Script='' command (only to the first). | |||
: ''<arguments>'' is everything from the <code>=</code> sign to the end of the line. Escape sequences are not possible. | |||
: Note that you must specify ''ScriptArguments='' before ''Script=''. | |||
=== Script output format === | |||
The output of the script is parsed as configuration file, and merged to ''<newfile>'' or ''<newgroup>''. If in the context of ''File='', script output is merged to the top-level group of ''<newfile>''. If in the context of ''Group='', the group context is initialized to ''<newgroup>''. | |||
These lines in the script output are recognized by kconf_update: | |||
; [<groupname>] | |||
: Sets the group context to ''<groupname>''. This will not create a subgroup, even in the context of ''Group=''. | |||
: You can use <code>[<default>]</code> to select the top-level group. However, this will not work in context of ''Group=''. | |||
; <key>=<value> | |||
: Creates a new entry in the current group context. | |||
: Note that existing entries will probably not be overridden, even with ''Options=override'' specified. | |||
; # DELETE <key> | |||
: Deletes the entry ''<key>'' in the current group context, but from ''<oldfile>''. | |||
; # DELETE [<group>]<key> | |||
: Deletes the entry ''<key>'' from the group ''<oldfile>/<group>''. | |||
: Note that this can change the group context, you should explicitly set the group context afterwards. | |||
; # DELETEGROUP <group> | |||
: Deletes the whole group ''<group>'' (not a subgroup) from ''<oldfile>''. | |||
: Note that this can change the group context, you should explicitly set the group context afterwards. | |||
=== Providing the script files === | |||
Script files should be installed in {{path|${KDE_INSTALL_KCONFUPDATEDIR}}}. You should install only actual scripts here, not binary executables. | |||
You should choose a script language whose interpreter will be available on your target platform. | |||
E. g. if your target platforms include Windows, you should not use shell scripts. | |||
Alternatively, you can use “compiled scripts”, which are executable binaries installed in {{path|${KDE_INSTALL_LIBDIR}/kconf_update_bin/}}. You can e. g. write your update script in C++ and use all the Qt API and other libraries you need, and compile and install the binary together with your application. | |||
=== Note on side effects === | |||
External update scripts can cause side effects. | |||
(E. g. rebuilding the database of another service.) | |||
This is an intended use case; you can use ''Script='' in the context of ''Id='', then no script input or output is processed. | |||
Nevertheless, you should be careful if you use update scripts for side effects. | |||
If your update scripts cause side effects, you probably want these side effects to happen at most once. | |||
KDED will run the update only once, but if <code>KConfig::checkUpdate()</code> is involved, this is not guaranteed. | |||
Consider separating updates into two update files, where one update file performs only deterministic configuration file updates, and the other update file causes only side effects. | |||
This way, you can safely call <code>KConfig::checkUpdate()</code> to guarantee configuration file updates, while the other update file is processed at most once by KDED. | |||
== Updating multiple files per section == | |||
You can use multiple ''File='' commands in the context of one ''Id='' command, then this update section will sequentially update multiple files. | |||
This can be used to split a single configuration file into multiple configuration files, or to join multiple configuration files into a single configuration file. | |||
However, in the latter case you will have different ''<oldfile>'' parameters. | |||
You should be aware that kconf_update will stop processing a section, when it encounters an ''<oldfile>'' which already has this update applied. | |||
In most cases, this shouldn’t be a problem. | |||
If it is a problem, you should consider to use multiple sections with only one ''File='' command each. | |||
== Example update file == | == Example update file == | ||
<syntaxhighlight lang="ini"> | <syntaxhighlight lang="ini"> | ||
Version=5 | |||
Id=kde2.2 | Id=kde2.2 | ||
File=kioslaverc,kio_httprc | File=kioslaverc,kio_httprc | ||
Group=Proxy Settings | Group=Proxy Settings | ||
Key=NoProxyFor | Key=NoProxyFor | ||
Key=UseProxy | Key=UseProxy | ||
Key=httpProxy,Proxy | Key=httpProxy,Proxy | ||
Group=Cache Settings,Cache | Group=Cache Settings,Cache | ||
Key=MaxCacheSize | Key=MaxCacheSize | ||
Key=UseCache | Key=UseCache | ||
Group=UserAgent | Group=UserAgent | ||
AllKeys | AllKeys | ||
RemoveGroup=KDE | RemoveGroup=KDE | ||
</syntaxhighlight> | </syntaxhighlight> | ||
The above update file extracts config information from the file {{path|kioslaverc}} and stores it into the file {{path|kio_httprc}}. | The above update file extracts config information from the file {{path|kioslaverc}} and stores it into the file {{path|kio_httprc}}. | ||
It reads the keys ''NoProxyFor'', ''UseProxy'' and ''httpProxy'' from the group ''Proxy Settings'' in the {{path|kioslaverc}} file. | |||
If any of these options are present they are written to the keys ''NoProxyFor'', ''UseProxy'' and ''Proxy'' (!) in the group ''Proxy Settings'' in the {{path|kio_httprc}} file. | |||
It also reads the keys ''MaxCacheSize'' and ''UseCache'' from the group ''Cache Settings'' in the {{path|kioslaverc}} file and writes this information to the group ''Cache'' (!) in the {{path|kio_httprc}} file. | |||
Then it takes all keys in the ''UserAgent'' group of the file {{path|kioslaverc}} and moves then to the ''UserAgent'' group in the {{path|kio_httprc}} file. | |||
Finally it removes the entire ''KDE'' group from the {{path|kioslaverc}} file. | |||
== Common Problems == | |||
If you change the value of an entry without changing the key or file, make sure to tell kconf_update that it should overwrite the old entry by adding | ; kconf_update refuses to update an entry | ||
: If you change the value of an entry without changing the key or file, make sure to tell kconf_update that it should overwrite the old entry by adding ''Options=overwrite''. |
Latest revision as of 21:10, 23 October 2021
Introduction
kconf_update is a tool designed to update KConfig configuration files.
See Development/Tutorials/Updating_KConfig_Files for a tutorial.
What it does
Applications sometimes need to rearrange the way configuration options are stored.
To avoid losing the old configuration, the application can look up both the old and the new configuration, and then decide which one to use. But this means that the application contains additional code, which deals only with configuration of the past, and is only used once.
kconf_update addresses this problem by offering a framework to update configuration files, without adding complexity to the application itself.
kconf_update is primarily used to move configuration entries from one place to another, but can also be used to modify the configuration data itself.
How to use
To use kconf_update in your application, you only need to write an update file and install it in ${KDE_INSTALL_KCONFUPDATEDIR}. An example update file is in the section #Example update file.
If your application depends on KDED, kconf_update will be started automatically when the update file is installed.
Otherwise, you can start it manually using KConfig::checkUpdate()
.
Note that kconf_update might process your update multiple times simultaneously in this case.
This can cause problems if your update file uses the Script=
command.
See the #Note on side effects section for more details.
Testing update files
You can run kconf_update manually on a specific update file, to see how it will process it. If your update file is called myUpdate.upd, you would run this command:
/usr/lib/kf5/kconf_update --debug --testmode path/to/myUpdate.upd
--testmode
activates QStandardPaths::setTestModeEnabled()
, so kconf_update will not update your actual configuration files, but files you have placed in a certain test directory.
See the QStandardPaths::GenericConfigLocation
documentation for your platform.
See Development/Tutorials/Updating_KConfig_Files#Testing_update_files for more information on testing update files.
File format of the update file
Each line of the update file can contain a command (like File=okularpartrc
) or a comment (like # Hello!
).
Commands are processed sequentially from top to bottom.
Update file structure
Update files are structured as follows:
- Version=5 (required)
- any number of update sections, each started by an Id= command
- any number of Script= and ScriptArguments= commands
- or any number of File= commands, followed by:
- any number of Group=, Key=, AllKeys, RemoveGroup=, RemoveKey=, Options=, Script=, ScriptArguments= commands
- AllGroups (optional)
Update file command reference
All commands are case-sensitive. Commas are used to separate parameters, and may not occur as part of any parameter. Parameters in square brackets are optional. Parameters are referenced in angle brackets, sometimes parameters of preceding commands are referenced. (Square brackets and angle brackets are not written in the actual update file.)
The following commands are available:
- Version=5
- This must be the first command in any update file.
- Specifies which KDE Frameworks version this update file targets. At the time of writing the only valid value is 5, meaning modern (KDE Frameworks 5) kconf_update binaries will process the file. A file with Version=5 may still be run on older kconf_updates!
- Id=<id>
- Starts a new update section. All commands until the next Id= command are processed as part of this section. If <id> is stored in kconf_updaterc, this section will be skipped. When this section has been processed, <id> will be stored in kconf_updaterc.
- <id> has to be unique. You should give your section a name that describes why this update necessary. You can also include the year of your changes, like in Id=annotation-toolbar-2020.
- File=<oldfile>[,<newfile>]
- Specifies that configuration information is read from <oldfile> and written to <newfile>. If you only specify <oldfile>, the information is read from as well as written to <oldfile>.
- If <oldfile> contains the <id> of the current section, the current section will be skipped. Otherwise, <id> is stored in <oldfile> and <newfile>.
- If <oldfile> does not exist at the time kconf_update first checks, the current section will be skipped.
- Also note the #Updating multiple files per section section.
- Group=<oldgroup>[,<newgroup>]
- Specifies that configuration information is read from the group <oldgroup> and written to <newgroup>. If you only specify <oldgroup>, the information is read from as well as written to <oldgroup>.
- You can use
<default>
to select the top-level group.
- Key=<oldkey>[,<newkey>]
- Moves the configuration entry <oldkey> from <oldfile>/<oldgroup> to <newfile>/<newgroup>.
- If you specify <newkey>, the entry is additionally renamed.
- If you did not specify <newfile> nor <newgroup> nor Options=copy, the entry is only renamed.
- AllGroups
- Moves all groups (including all entries) from <oldfile> to <newfile>.
- Note that the top-level group is not included. To include the top-level group, you need to use the AllKeys command additionally.
- AllKeys
- Moves all entries from <oldgroup> to <newgroup>.
- RemoveGroup=<oldgroup>
- Removes <oldgroup> from <oldfile>.
- This can be used to remove obsolete entries or to force a revert to default values.
- RemoveKey=<oldkey>
- Removes <oldkey> from <oldfile>/<oldgroup>.
- This can be used to remove an obsolete entry or to force a revert to default values.
- Options=<option1>, <option2>, ...
- With this entry you can specify options that apply to the next Script=, Key=, AllKeys, or AllGroups command (only to the first). Note that Script= probably ignores the options, see the #Script output format section.
- Possible options are:
- copy
- Copy the configuration item instead of moving it. This means that the configuration item will not be deleted from <oldfile> or <oldgroup>.
- overwrite
- Normally, configuration entries are not moved if an entry with the new name already exists. When this option is specified, any existing entries are overwritten.
- Script=<_script>[,<interpreter>]
- ScriptArguments=<arguments>
- See the #Update script commands section.
Using external update scripts
kconf_update provides commands to move configuration information around, but it can not manipulate the configuration data itself. Using external, so called update scripts, configuration data can be manipulated through kconf_update.
The concept is that old configuration entries are piped into a script. The output of the script is then interpreted as new configuration entries, which are merged to <newfile> or <newgroup>.
It is also possible to use scripts outside the context of a File= command, then it will not get any input, and the output is ignored. See the section #Note on side effects about this.
Update script commands
The following two commands are available to run update scripts:
- Script=<_script>[,<interpreter>]
- Executes the script file <_script> using the command <interpreter>. If <interpreter> is not given, executes the compiled script file <_script> directly. You can not pass arguments with this command.
- If in the context of a File= command, all groups of <oldfile> (excluding the top-level group) will be piped into the script. If in the context of a Group= command, all entries of <oldgroup> will be piped into the script. You can use
Group=<default>
to process top-level entries. - The output of <_script> is merged into <newfile> or <newgroup>.
- ScriptArguments=<arguments>
- <arguments> is passed to <_script> of the next Script= command (only to the first).
- <arguments> is everything from the
=
sign to the end of the line. Escape sequences are not possible. - Note that you must specify ScriptArguments= before Script=.
Script output format
The output of the script is parsed as configuration file, and merged to <newfile> or <newgroup>. If in the context of File=, script output is merged to the top-level group of <newfile>. If in the context of Group=, the group context is initialized to <newgroup>.
These lines in the script output are recognized by kconf_update:
- [<groupname>]
- Sets the group context to <groupname>. This will not create a subgroup, even in the context of Group=.
- You can use
[<default>]
to select the top-level group. However, this will not work in context of Group=.
- <key>=<value>
- Creates a new entry in the current group context.
- Note that existing entries will probably not be overridden, even with Options=override specified.
- # DELETE <key>
- Deletes the entry <key> in the current group context, but from <oldfile>.
- # DELETE [<group>]<key>
- Deletes the entry <key> from the group <oldfile>/<group>.
- Note that this can change the group context, you should explicitly set the group context afterwards.
- # DELETEGROUP <group>
- Deletes the whole group <group> (not a subgroup) from <oldfile>.
- Note that this can change the group context, you should explicitly set the group context afterwards.
Providing the script files
Script files should be installed in ${KDE_INSTALL_KCONFUPDATEDIR}. You should install only actual scripts here, not binary executables.
You should choose a script language whose interpreter will be available on your target platform. E. g. if your target platforms include Windows, you should not use shell scripts.
Alternatively, you can use “compiled scripts”, which are executable binaries installed in ${KDE_INSTALL_LIBDIR}/kconf_update_bin/. You can e. g. write your update script in C++ and use all the Qt API and other libraries you need, and compile and install the binary together with your application.
Note on side effects
External update scripts can cause side effects. (E. g. rebuilding the database of another service.) This is an intended use case; you can use Script= in the context of Id=, then no script input or output is processed.
Nevertheless, you should be careful if you use update scripts for side effects.
If your update scripts cause side effects, you probably want these side effects to happen at most once.
KDED will run the update only once, but if KConfig::checkUpdate()
is involved, this is not guaranteed.
Consider separating updates into two update files, where one update file performs only deterministic configuration file updates, and the other update file causes only side effects.
This way, you can safely call KConfig::checkUpdate()
to guarantee configuration file updates, while the other update file is processed at most once by KDED.
Updating multiple files per section
You can use multiple File= commands in the context of one Id= command, then this update section will sequentially update multiple files. This can be used to split a single configuration file into multiple configuration files, or to join multiple configuration files into a single configuration file.
However, in the latter case you will have different <oldfile> parameters. You should be aware that kconf_update will stop processing a section, when it encounters an <oldfile> which already has this update applied. In most cases, this shouldn’t be a problem. If it is a problem, you should consider to use multiple sections with only one File= command each.
Example update file
Version=5
Id=kde2.2
File=kioslaverc,kio_httprc
Group=Proxy Settings
Key=NoProxyFor
Key=UseProxy
Key=httpProxy,Proxy
Group=Cache Settings,Cache
Key=MaxCacheSize
Key=UseCache
Group=UserAgent
AllKeys
RemoveGroup=KDE
The above update file extracts config information from the file kioslaverc and stores it into the file kio_httprc.
It reads the keys NoProxyFor, UseProxy and httpProxy from the group Proxy Settings in the kioslaverc file. If any of these options are present they are written to the keys NoProxyFor, UseProxy and Proxy (!) in the group Proxy Settings in the kio_httprc file.
It also reads the keys MaxCacheSize and UseCache from the group Cache Settings in the kioslaverc file and writes this information to the group Cache (!) in the kio_httprc file.
Then it takes all keys in the UserAgent group of the file kioslaverc and moves then to the UserAgent group in the kio_httprc file.
Finally it removes the entire KDE group from the kioslaverc file.
Common Problems
- kconf_update refuses to update an entry
- If you change the value of an entry without changing the key or file, make sure to tell kconf_update that it should overwrite the old entry by adding Options=overwrite.