Skip to content

Commit 7125474

Browse files
authored
Support conditional rebuild (#90)
- Rebuild only if schema *after* pre-processing has changed. - Add support for conditional selection using dictionary values - Revert output directory to `out/ConfigDB`
1 parent 6b3605b commit 7125474

5 files changed

Lines changed: 219 additions & 48 deletions

File tree

README.rst

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -297,34 +297,32 @@ This example generates a `uint8_t` property value. A different type may be speci
297297
Calculated Values
298298
-----------------
299299

300-
With ConfigDB, if an attribute name is prefixed with ``@`` then it will be evaluated as a simple expression. See https://github.com/SmingHub/Sming/blob/develop/Tools/Python/evaluator/README.md for details.
301-
302-
Such expressions are parsed during loading of a schema. During the build process, copies are written to ``out/{SOC}/{build}/ConfigDB/schema`` to assist with debugging and development.
303-
304-
.. note::
305-
306-
Variable names correspond to environment variables.
307-
The build system is not aware of variable dependencies, so it may be necessary to perform a manual `clean` or `configdb-rebuild` to pick up any changed values.
300+
Within a ConfigDB schema, if an attribute name is prefixed with @ then the attribute value will be evaluated and the result used as the actual value.
301+
The expression must be given as a string, with variable names corresponding to environment variables.
302+
See :doc:`/_inc/Tools/Python/evaluator/README` for details.
308303

304+
The ``.cfgdb`` schema are pre-processed on every build and the source files regenerated automatically if there is a change.
305+
The pre-processed schema can be found in ``out/ConfigDB/schema/``, together with a *summary.txt* file.
309306

310307
An example is included in the test application:
311308

312309
.. code-block:: json
313310
314-
"properties": {
311+
"simple-string": {
312+
"type": "string",
315313
"@default": "SIMPLE_STRING"
316314
}
317315
318-
During loading, the attribute value is evaluated in python and the result stored in `default`. The value `SIMPLE_STRING` must be available in the environment - an error occurs if not found.
316+
The pre-processed schema will contain a ``default`` attribute with the contents of the environment variable ``SIMPLE_STRING``.
317+
An error will be given if named variable is not present in the environment.
319318

320319
To test this, build and run as follows:
321320

322321
.. code-block:: bash
323322
324-
make clean
325323
SIMPLE_STRING="donkey2" make -j run
326324
327-
The test application now fails as the value has changed - "donkey" is expected.
325+
The test application now fails as the schema default value has changed - "donkey" is expected.
328326

329327
.. note::
330328

@@ -338,21 +336,28 @@ JSON does not support extended number formats, such as `0x12`, so this mechanism
338336

339337
.. code-block:: json
340338
341-
"properties": {
339+
"simple-int": {
340+
"type": "integer",
342341
"@default": "8 + 27",
343342
"minimum": 0,
344343
"@maximum": "0xffff"
345344
}
346345
347346
348-
Array defaults
349-
~~~~~~~~~~~~~~
347+
Array values
348+
~~~~~~~~~~~~
349+
350+
If a calculated attribute value is an array, then each element is evaluated separately.
351+
Arrays may contain a mixture of types, but only string values will be evalulated: others will be passed through unchanged.
350352

351-
Array defaults may contain a mixture of types:
352353

353354
.. code-block:: json
354355
355-
"properties": {
356+
"simple-array": {
357+
"type": "array",
358+
"items": {
359+
"type": "integer"
360+
},
356361
"@default": [
357362
"0x12",
358363
5,
@@ -361,7 +366,34 @@ Array defaults may contain a mixture of types:
361366
]
362367
}
363368
364-
Only string values will be evalulated, the others will be passed through unchanged.
369+
370+
Dictionary values
371+
~~~~~~~~~~~~~~~~~
372+
373+
To conditionally select from one of a number of options, provide a dictionary as the calculated attribute value.
374+
The first key which evaluates as *True* is matched, and the corresponding value becomes the value for the property.
375+
If none of the entries matches, an error is raised.
376+
377+
In this example, the default contents of the *pin-list* array is determined by the targetted SOC.
378+
The final *"True": []* ensures a value is provided if nothing else is matched.
379+
380+
.. code-block:: json
381+
382+
"pin-list": {
383+
"type": "array",
384+
"items": {
385+
"type": "integer",
386+
"minimum": 0,
387+
"maximum": 255
388+
},
389+
"@default": {
390+
"SMING_SOC == 'esp8266'": [ 1, 2, 3, 4 ],
391+
"SMING_SOC == 'esp32c3'": [ 5, 6, 7, 8 ],
392+
"SMING_SOC == 'esp32s2'": [ 9, 10, 11, 12 ],
393+
"SMING_SOC in ['rp2040', 'rp2350']": [ 13, 14, 15, 16 ],
394+
"True": []
395+
}
396+
}
365397
366398
367399
Store loading / saving
@@ -375,11 +407,11 @@ This can be overridden to customise loading/saving behaviour.
375407
The :cpp:func:`ConfigDB::Database::getFormat` method is called to get the storage format for a given Store.
376408
A :cpp:class:`ConfigDB::Format` implementation provides various methods for serializing and de-serializing database and object content.
377409

378-
Currently only **json** is implemented - see :cpp:class:`ConfigDB::Json::format`.
410+
Currently only **json** is implemented - see :cpp:member:`ConfigDB::Json::format`.
379411
Each store is contained in a separate file.
380412
The name of the store forms the JSONPath prefix for any contained objects and values.
381413

382-
The :sample:`BasicConfig` sample demonstrates using the stream classes to read and write data from a web client.
414+
The :sample:`Basic_Config` sample demonstrates using the stream classes to read and write data from a web client.
383415

384416
.. important::
385417

component.mk

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,39 @@ ifneq (,$(COMPONENT_RULE))
99
CONFIGDB_GEN_CMDLINE := $(PYTHON) $(COMPONENT_PATH)/tools/dbgen.py
1010

1111
COMPONENT_VARS := APP_CONFIGDB_DIR
12-
APP_CONFIGDB_DIR ?= $(PROJECT_DIR)/$(OUT_BASE)/ConfigDB
12+
APP_CONFIGDB_DIR := $(PROJECT_DIR)/out/ConfigDB
1313
COMPONENT_INCDIRS += $(APP_CONFIGDB_DIR)
1414
COMPONENT_APPCODE := $(APP_CONFIGDB_DIR)
1515

1616
COMPONENT_VARS += CONFIGDB_SCHEMA
1717
CONFIGDB_SCHEMA := $(wildcard *.cfgdb)
1818

19+
CONFIGDB_JSON := $(patsubst %.cfgdb,$(APP_CONFIGDB_DIR)/schema/%.json,$(CONFIGDB_SCHEMA))
20+
21+
##@ConfigDB
22+
23+
.PHONY: configdb-preprocess
24+
configdb-preprocess: ##Pre-process .cfgdb into .json
25+
$(Q) $(CONFIGDB_GEN_CMDLINE) --preprocess --outdir $(APP_CONFIGDB_DIR) $(CONFIGDB_SCHEMA)
26+
1927
CONFIGDB_FILES := $(patsubst %.cfgdb,$(APP_CONFIGDB_DIR)/%.h,$(CONFIGDB_SCHEMA))
2028
CONFIGDB_FILES := $(CONFIGDB_FILES) $(CONFIGDB_FILES:.h=.cpp)
21-
COMPONENT_PREREQUISITES := $(CONFIGDB_FILES)
29+
COMPONENT_PREREQUISITES := configdb-preprocess $(CONFIGDB_FILES)
2230

23-
$(CONFIGDB_FILES): $(CONFIGDB_SCHEMA)
31+
$(CONFIGDB_FILES): $(CONFIGDB_JSON)
2432
$(MAKE) configdb-build
2533

2634
.PHONY: configdb-build
27-
configdb-build: $(CONFIGDB_SCHEMA)
35+
configdb-build: $(CONFIGDB_SCHEMA) ##Parse schema and generate source code
2836
$(vecho) "CFGDB $^"
2937
$(Q) $(CONFIGDB_GEN_CMDLINE) --outdir $(APP_CONFIGDB_DIR) $^
3038

3139
.PHONY: configdb-rebuild
32-
configdb-rebuild: configdb-clean configdb-build
40+
configdb-rebuild: configdb-clean configdb-build ##Force regeneration of source code
3341

3442
.PHONY: configdb-clean
35-
configdb-clean:
36-
$(Q) rm -f $(CONFIGDB_FILES)
43+
configdb-clean: ##Remove generated files
44+
$(Q) rm -rf $(APP_CONFIGDB_DIR)/*
3745

3846
clean: configdb-clean
3947

test/modules/Enum.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,44 @@ class EnumTest : public TestGroup
7676
REQUIRE(!range.contains(badColor));
7777
REQUIRE_EQ(range.clip(badColor), Color::blue);
7878
}
79+
80+
/*
81+
* RAW enums without ctype override
82+
*/
83+
TEST_CASE("Raw enums")
84+
{
85+
// These properties contain a value index, not the value itself
86+
auto numIndex = root.getNum();
87+
int num = TestConfigEnum::numType.values()[numIndex];
88+
#ifdef SMING_RELEASE
89+
REQUIRE_EQ(numIndex, 4);
90+
REQUIRE_EQ(num, 25);
91+
#else
92+
REQUIRE_EQ(numIndex, 5);
93+
REQUIRE_EQ(num, 45);
94+
#endif
95+
96+
auto wordIndex = root.getWord();
97+
String word = TestConfigEnum::wordType.values()[wordIndex];
98+
REQUIRE_EQ(wordIndex, 2);
99+
REQUIRE_EQ(word, "brown");
100+
}
101+
102+
TEST_CASE("Conditional enum")
103+
{
104+
String s;
105+
for(auto v : TestConfigEnum::pinType.values()) {
106+
s += v;
107+
s += ',';
108+
}
109+
#if defined(ARCH_ESP8266)
110+
REQUIRE_EQ(s, "1,2,3,4,");
111+
#elif defined(ARCH_HOST)
112+
REQUIRE_EQ(s, "50,51,52,55,");
113+
#else
114+
REQUIRE_EQ(s, "0,");
115+
#endif
116+
}
79117
}
80118
};
81119

test/test-config-enum.cfgdb

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
"color": {
66
"$ref": "#/$defs/Color"
77
},
8+
"pin": {
9+
"$ref": "#/$defs/Pin"
10+
},
811
"num": {
912
"type": "integer",
10-
"default": 25,
13+
"@default": "25 if SMING_RELEASE else 45",
1114
"enum": [
1215
15,
1316
37,
@@ -100,6 +103,43 @@
100103
"green",
101104
"blue"
102105
]
106+
},
107+
"TestMode": {
108+
"type": "string",
109+
"ctype": "Color",
110+
"@enum": {
111+
"SMING_RELEASE": [
112+
"silent",
113+
"error"
114+
],
115+
"1": [
116+
"silent",
117+
"error",
118+
"debug",
119+
"info"
120+
]
121+
}
122+
},
123+
"Pin": {
124+
"comment": "Valid pin numbers depend on selected SOC",
125+
"type": "integer",
126+
"@enum": {
127+
"SMING_SOC == 'esp8266'": [
128+
1,
129+
2,
130+
3,
131+
4
132+
],
133+
"SMING_ARCH == 'Host'": [
134+
50,
135+
51,
136+
52,
137+
55
138+
],
139+
"True": [
140+
0
141+
]
142+
}
103143
}
104144
}
105145
}

0 commit comments

Comments
 (0)