Skip to content

Commit 326a49f

Browse files
committed
feat: 添加 gsettings to dconfig 任务
gsettigns2dconfig 配置文件转换,信号转发等. Log:
1 parent fa372ad commit 326a49f

File tree

3 files changed

+868
-0
lines changed

3 files changed

+868
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
### 任务描述
2+
3+
`GSettings` 是一套可使用多个 `storage backends``API` ,默认使用 `dconf` 作为 `backend``GSettings` 的配置文件是 `xml` 格式的,文件需以 `.gschema.xml` 结尾,文件名通常与 `id` 相同。配置文件安装在 `/usr/share/glib-2.0/schemas/` 目录下,手动添加进去的文件需要执行 `glib-complie-schemas` 命令让其生效。
4+
5+
`DConfig` 配置策略是由 `UOS` 自主研发的一套存储规范,涉及主要包括配置描述文件(`meta`)、配置存储文件(`cache`)、覆盖机制配置文件(`override`), 应用需要配置的为 `meta``override`(可选)文件,它们均为 `json` 格式的文件。
6+
7+
基于 `DConfig``GSettings` 接口,完成一个配置转换小工具,此应用程序应当满足:
8+
9+
1. 项目使用 `cmake` 管理,基于 `dtkcore`
10+
2. 熟悉 `DConfig``GSettings` 相关概念及实现。
11+
3. 功能需求:
12+
- 支持解析 `GSettings``.gschema.xml` 配置文件转换 `DConfig` 配置需要的 `json` 文件
13+
```bash
14+
# 仅供参考
15+
gsettings2dconfig -i ./com.deepin.dde.dock.module.gschema.xml -o ./com.deepin.dde.dock.module.json
16+
```
17+
- 支持通过参数转发 `GSettings` 信号变化并同步到 `DConfig` 配置
18+
```bash
19+
# 仅供参考
20+
gsettings2dconfig --proxy -id com.deepin.dtk -path /dtk/deepin/deepin-terminal -appid dtk.deepin.deepin-terminal -resource com.deepin.dtk
21+
```
22+
23+
### 环境的准备
24+
25+
下载并安装最新 `deepin` 操作系统;
26+
27+
为方便起见,下述步骤假定您在使用 `deepin V20`
28+
- 检查 `gsetings` 是否安装正确,直接终端输入 `gsettings`,是否出现 `gsettings` 帮助文档;
29+
30+
- 安装 `libdtkcore-dev`, `libgsettings-qt-dev`
31+
```
32+
sudo apt install libdtkcore-dev libgsettings-qt-dev
33+
```
34+
35+
36+
### 验收标准
37+
38+
最终完成的应用程序应当能够提供下述功能:
39+
40+
- [ ] 能够恰当的运行和退出
41+
- [ ] 代码符合 deepin 编码风格
42+
- [ ] 项目用 CMake 管理,程序基于 DTK
43+
- [ ] 支持 `gschema` 文件转 `meta` 文件
44+
- [ ] 支持 `GSettings` 信号同步到 `DConfig`
45+
- [ ] 帮助文档提示友好
46+
47+
我们通过对上述各项标准的完成数量来评估任务的完成程度
48+
49+
### 涉及的项目/提交到何处
50+
51+
- 此项目需要您最终将代码提交到 `linuxdeepin/dde-app-services` 仓库之中
52+
- 在仓库中的 `dde-app-services/dconfig-center/` 目录下存储您的代码
53+
54+
### 预计工作量 116h
55+
56+
- 创建环境 4h
57+
- 熟悉需求 8h
58+
- 熟悉 `DConfig` 及 `GSettings` 相关资料 8h
59+
- 设计 10h
60+
- 代码编写 60 h
61+
- 自测 16h
62+
- 验收及沟通 8h
63+
64+
65+
### 参考文档
66+
67+
- [DConfig 规范](./%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A7%84%E8%8C%83.md)
68+
69+
- [dtkcore](https://github.com/linuxdeepin/dtkcore)
70+
- [dde-app-services](https://github.com/linuxdeepin/dde-app-services)
71+
72+
### 联系方式
73+
74+
此任务的任务对接人为: [email protected]
75+
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# 配置文件规范
2+
3+
> __警告!此规范内容是不稳定版本,可能会发生破坏兼容性的更新。当无法保障向下兼容时,将会升级此文档的主版本号,如从“1.0”更新到“2.0”。反之,普通更新只会升级次版本号,如“1.0”更新到“1.1”,其对“1.0”版本向下兼容。请在使用前确认此文档的版本号,并为将来可能发生的兼容性变化做好准备。__
4+
5+
* 维护者:zccrs <[email protected]>
6+
* 修改日期:2021.3.17
7+
* 版本:1.0
8+
* 议题:#3
9+
10+
## 引言
11+
12+
本文档规定了配置文件的存储格式和安装路径、配置文件的读写、配置中心的设计、开发库 API 接口等规范。
13+
14+
## 名词解释
15+
16+
* 配置描述文件:此类文件由安装包携带,类似于 gsettings 的 schemes 文件,用于描述配置项的元信息,以及携带配置项的默认值
17+
* 配置存储文件:对于一些可修改的配置项,本文件用于保存程序运行过程中的改动
18+
* $APP_ROOT:应用程序安装的根目录
19+
* $appid:应用程序的唯一ID
20+
21+
## 角色说明
22+
23+
* 应用程序:读写配置文件的实体,亦是配置文件的提供者,一个应用程序可提供多个配置文件
24+
* 配置文件:包含一系列配置项的集合,存储了配置项相关的信息
25+
* 配置中心:为程序提供读写配置项的 DBus 接口,实现配置项的 override 机制
26+
* DTK:应用程序开发基础库,提供统一的配置文件读写工具类
27+
28+
## 配置描述文件
29+
30+
配置描述文件使用 json 格式提供,以下将“配置描述文件”简称为“描述文件”。
31+
32+
* 文件名:$appid.json,如:foo.example.json
33+
* 安装路径:
34+
* $APP_ROOT/configs/:用于放置应用程序所携带的描述文件
35+
* $DSG\_DATA\_DIR/configs/:用于放置开发库所携带的描述文件,如 $DSG\_DATA\_DIR/configs/org.dtk.core.json,此目录下的配置描述文件为所有程序共享。如果安装到 $DSG\_DATA\_DIR/configs/ 下的配置文件与 $APP_ROOT/configs/ 中的同名(忽略子目录),则使用 $APP_ROOT/configs/ 下的文件
36+
* 子目录:描述文件安装可包含子路径。
37+
38+
假设 foo.example.json 安装到 “$APP_ROOT/configs/A/B”,当程序读取配置文件时,可额外传入 subpath 参数,假设传入的参数为 “/A/B/C”,则查找 foo.example.json 时的优先级顺序是:
39+
40+
1. $APP_ROOT/configs/A/B/C/foo.example.json
41+
2. $APP_ROOT/configs/A/B/foo.example.json
42+
3. $APP_ROOT/configs/A/foo.example.json
43+
4. $APP_ROOT/configs/foo.example.json
44+
45+
依次从上往下,直到找到一个存在的文件为止。当 subpath 为空时,直接读取 $APP_ROOT/configs/foo.example.json。安装到 $DSG\_DATA\_DIR/configs/ 下的配置文件同理。
46+
47+
* 描述文件包含下列属性:
48+
* magic:此 json 文件的标识性信息,所有描述文件均标记为 “dsg.config.meta”
49+
* version:此描述文件的内容格式的版本。版本号使用两位数字描述,首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。解析此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,并向使用者报告错误信息,如 “1.0” 和 “2.0” 版本之间不兼容,如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该报告错误,但是如果遇到 1.1 版本,则可以继续执行。
50+
* contents:配置项的内容,每一个配置项是一个 json 对象,配置项之间的相对顺序无意义,且不支持嵌套。每一项配置可包含下列属性:
51+
* value:配置项的默认值,可使用 json 支持的各种数据类型,如字符串、数字、数组、对象等
52+
* serial:单调递增的整数值,使用场景:假设程序 “A” 的配置项 “a” 记录其是否已经进行了初始化,之后 “A” 可能更改了初始化相关的代码,需要确保版本更新之后能重新进行初始化,则可以将配置项 “a” 的 “serial” 属性增加 1,则旧版 “A” 程序所记录的配置项 “a” 将失效,以此确保更新 “A” 之后能再次进行初始化工作。此配置项可以省略,无此项时读取配置存储文件将忽略 serial 字段。
53+
* name:配置项的可显示名称,需国际化(使用DTK工具为其生成 ts 文件,ts 编译后的 qm 文件需要与配置描述文件同名同路径放置)。此名称可用于展示到用户界面,如当程序 A 请求通过配置中心读取程序 B 的某个配置项时,将提示用户“程序 A 请求获取程序 B 的"允许退出"配置项的值,是否允许?”,用户可选择拒绝程序 A 的请求,名称在这里的作用是利于用户理解此配置项的含义。
54+
* description:描述此配置项的用途,需国际化(同 name)
55+
* permissions:配置项的权限
56+
* readonly:不允许修改,当程序读取此配置时,将直接使用默认值
57+
* readwrite:可读可写,如果此值被修改过,则不再使用此处定义的默认值
58+
* visibility:配置项的可见性
59+
* private 仅限程序内部使用,对外不可见。此类配置项完全由程序自己读写,可随意增删改写其含义,无需做兼容性考虑
60+
* public 外部程序可使用。__此类配置项一旦发布,在兼容性版本的升级中,要保障此配置项向下兼容,简而言之,只允许在程序/库的大版本升级时才允许删除或修改此类配置项,当配置项的 permissions、visibility、flags 任意一个属性被修改则认为此配置项被修改,除此之外修改 value、name、description 属性时则不需要考虑兼容性__
61+
* flags:配置项的一些特性
62+
* nooverride:存在此标记时,将表明则此配置项不可被覆盖(详见下述 [override 机制](#override))。反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项,如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口
63+
* global:当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据,写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志
64+
65+
$APP_ROOT/configs/foo.example.json 描述文件内容示例:
66+
67+
```json
68+
{
69+
"magic": "dsg.config.meta",
70+
"version": "1.0",
71+
"contents": {
72+
"key1": {
73+
"value": value1,
74+
"time": "2017-07-24T15:46:29",
75+
"name": "允许退出",
76+
"description": "xxxxxxxx",
77+
"permissions": "readwrite",
78+
"visibility": "private",
79+
"flags": ["nooverride"]
80+
}
81+
}
82+
}
83+
```
84+
85+
### override 机制<a name="override"></a>
86+
87+
以 foo.example.json 和 org.dtk.core.json 为例
88+
89+
* override 文件放置路径(按优先级排序):
90+
1. /etc/dsg/configs/overrides/$appid/foo.example/
91+
2. \$DSG\_DATA\_DIR/configs/overrides/$appid/foo.example/
92+
3. /etc/dsg/configs/overrides/org.dtk.core/
93+
4. \$DSG\_DATA\_DIR/configs/overrides/org.dtk.core/
94+
95+
* 同配置描述文件一样支持子目录机制,忽略其描述文件所对应的子目录,从头按规则顺序查找 override 目录
96+
* 对于第 2 和第 4 类路径,其省略了 $appid,放置在此目录下的文件对所有应用程序都生效,表示为所有应用程序提供对 org.dtk.core 配置的覆盖
97+
* `$DSG_XDG_DATA/configs` 下的路径用于放置安装包携带的文件
98+
* `/etc` 下的路径用于放置动态创建的文件,比如用户手动添加,或者域管等程序在运行时创建
99+
* 文件名只允许使用[拉丁字符](https://unicode-table.com/en/blocks/basic-latin/),后缀为 ".json"。使用[自然排序](http://www.naturalordersort.org/)(如“a2”在“a11”之前)规则,按文件名排序,越靠后的配置文件优先级越高。
100+
* 可以覆盖配置项的 "value"、"permissions" 属性
101+
102+
以 /etc/dsg/configs/overrides/foo.example/foo.example/oem1-override.json 为例,可包含以下属性:
103+
104+
* magic:此 json 文件的标识性信息,所有 override 文件均标记为 “dsg.config.override”
105+
* version:此文件的内容格式的版本。版本号使用两位数字描述,首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。解析此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件,并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容,如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析,但是如果遇到 1.1 版本,则可以继续执行。
106+
* contents:覆盖的配置项的内容,每一项是一个 json 对象,项之间的相对顺序无意义。每一项可包含下列属性:
107+
* value:覆盖配置项的默认值
108+
* serial:覆盖配置项对应的 serial 属性
109+
* comment:描述此 override 行为的注释内容
110+
* permissions:覆盖配置项的权限
111+
* readonly:将配置项覆盖为只读
112+
* readwrite:将配置项覆盖为可读可写
113+
114+
```json
115+
{
116+
"magic": "dsg.config.override",
117+
"version": "1.0",
118+
"contents": {
119+
"key1": {
120+
"value": value1,
121+
"comment": "xxxxxxxx",
122+
"permissions": "readonly"
123+
}
124+
}
125+
}
126+
```
127+
128+
## 配置存储文件
129+
130+
使用 json 作为配置文件的存储格式,以下称为“存储文件”。根据配置项是否携带 global 标志,将分开存储,以 foo.example.json 为例,分别存储在(下列路径用于存储程序的运行时修改的配置内容,请勿往此目录安装任何文件):
131+
132+
* 用户级别:\$HOME/.config/$appid/foo.example.json
133+
* global 级别:\$DSG\_APP_DATA/configs/foo.example.json
134+
135+
* 如果设置 subpath,则只从 subpath 中查找保存的配置文件,不 fallback 到上级目录
136+
137+
foo.example.json 文件格式如下:
138+
139+
* magic:此 json 文件的标识性信息,所有存储文件均标记为 “dsg.config.cache”
140+
* version:此文件的内容格式的版本。版本号使用两位数字描述,首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。读取此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件,并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容,如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析,但是如果遇到 1.1 版本,则可以继续执行。写入此描述文件时,遇到不兼容的版本时,需要先清空当前内容再写入,每次写入皆需更新此字段。
141+
* contents:保存的配置项的内容,每一项是一个 json 对象,项之间的相对顺序无意义。每一项可包含下列属性:
142+
* value:保存修改后的值
143+
* serial:在使用此配置项的存储值之前,应当先与配置描述文件中定义的 serial 属性做比较(需遵守 override 机制),如果此值不等于配置表述文件中记录的值,否则忽略此处存储的值
144+
* time:记录值的修改时间,使用 UTC 时间,采用 ISO 8601 表示方法
145+
* user:记录修改此项设置的用户名称
146+
* appid:记录修改此项设置的应用程序id,如无法正常获取程序id,需记录二进制文件路径
147+
148+
```json
149+
{
150+
"magic": "dsg.config.cache",
151+
"version": "1.0",
152+
"contents": {
153+
"key1": {
154+
"value": value1,
155+
"time": "2017-07-24T15:46:29",
156+
"user": "user name",
157+
"appid": "foo.example",
158+
"serial": 0
159+
}
160+
}
161+
}
162+
```
163+
164+
## 配置中心
165+
166+
配置中心为上述配置文件的管理服务,对外提供配置项的读写接口。基于 DBus 服务实现,关于 DBus 的规范请查看:<https://dbus.freedesktop.org/doc/dbus-specification.html>
167+
168+
配置中心需要监听`配置描述文件``配置override目录`的变化,当描述文件被修改或override目录新增、移除、修改文件时,需要重新解析对应的文件内容,但是不需要监听`配置存储文件`的变化。
169+
170+
### 与程序的关系
171+
172+
当配置中心的 DBus 服务存在时(需要注意,仅需要它存在,不要求它一定处于运行状态),所有配置项的读写皆要通过此服务进行。反之,可直接基于文件进行配置项的读写操作,无需考虑文件竞争的情况,且无需在修改配置项时通知其他进程。
173+
174+
### 配置中心的 DBus 接口
175+
176+
* 服务名:org.desktopspec.ConfigManager
177+
* 路 径:/org/desktopspec/ConfigManager
178+
179+
```xml
180+
<interface name='org.desktopspec.ConfigManager'>
181+
<method name='acquireManager'>
182+
<arg type='s' name='appid' direction='in'/>
183+
<arg type='s' name='name' direction='in'/>
184+
<arg type='s' name='subpath' direction='in'/>
185+
<arg type='o' name='path' direction='out'/>
186+
</method>
187+
</interface>
188+
<interface name='org.desktopspec.ConfigManager.Manager'>
189+
<property access="read" type="s" name="version"/>
190+
<property access="read" type="as" name="keyList"/>
191+
<property access="read" type="b" name="canRead"/>
192+
<property access="read" type="b" name="canWrite"/>
193+
<property access="read" type="b" name="canOverride"/>
194+
<!--为每个 key 提供一个只读属性,如:
195+
<property access="read" type="v" name="key1"/>
196+
...
197+
<property access="read" type="v" name="key2"/>
198+
-->
199+
<method name='value'>
200+
<arg type='s' name='key' direction='in'/>
201+
<arg type='v' name='value' direction='out'/>
202+
</method>
203+
<method name='setValue'>
204+
<arg type='s' name='key' direction='in'/>
205+
<arg type='v' name='value' direction='in'/>
206+
</method>
207+
<method name='name'>
208+
<arg type='s' name='key' direction='in'/>
209+
<arg type='s' name='language' direction='in'/>
210+
<arg type='s' name='name' direction='out'/>
211+
</method>
212+
<method name='description'>
213+
<arg type='s' name='key' direction='in'/>
214+
<arg type='s' name='language' direction='in'/>
215+
<arg type='s' name='description' direction='out'/>
216+
</method>
217+
<method name='visibility'>
218+
<arg type='s' name='key' direction='in'/>
219+
<arg type='s' name='visibility' direction='out'/>
220+
</method>
221+
<!--采用引用计数的方式,引用为 0 时才真正的销毁-->
222+
<method name='release'>
223+
</method>
224+
<signal name="valueChanged">
225+
<arg name="key" type="s" direction="out"/>'
226+
</signal>
227+
</interface>
228+
```
229+
230+
## API 接口规范
231+
232+
此接口规范定义了开发库所提供的关于配置文件读写的相关接口,如果应用程序所使用的开发库实现了此规范,则程序应当优先使用开发库提供的接口。
233+
234+
### 接口的伪代码
235+
236+
```cpp
237+
// 此规范实现自:https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/blob/master/unstable/配置文件规范.md
238+
class DConfig {
239+
DConfig(string name, string subpath);
240+
241+
property list<string> keyList;
242+
243+
signal valueChanged(string key);
244+
245+
variant value(string key);
246+
void setValue(string key, variant value);
247+
};
248+
249+
```

0 commit comments

Comments
 (0)