Skip to content

Commit 923d52a

Browse files
committed
feat(config): implement config lexicon
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
1 parent 097f04c commit 923d52a

File tree

9 files changed

+542
-0
lines changed

9 files changed

+542
-0
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216
'OCP\\Comments\\MessageTooLongException' => $baseDir . '/lib/public/Comments/MessageTooLongException.php',
217217
'OCP\\Comments\\NotFoundException' => $baseDir . '/lib/public/Comments/NotFoundException.php',
218218
'OCP\\Common\\Exception\\NotFoundException' => $baseDir . '/lib/public/Common/Exception/NotFoundException.php',
219+
'OCP\\ConfigLexicon\\IConfigLexicon' => $baseDir . '/lib/public/ConfigLexicon/IConfigLexicon.php',
220+
'OCP\\ConfigLexicon\\IConfigLexiconEntry' => $baseDir . '/lib/public/ConfigLexicon/IConfigLexiconEntry.php',
219221
'OCP\\Config\\BeforePreferenceDeletedEvent' => $baseDir . '/lib/public/Config/BeforePreferenceDeletedEvent.php',
220222
'OCP\\Config\\BeforePreferenceSetEvent' => $baseDir . '/lib/public/Config/BeforePreferenceSetEvent.php',
221223
'OCP\\Console\\ConsoleEvent' => $baseDir . '/lib/public/Console/ConsoleEvent.php',
@@ -1025,6 +1027,7 @@
10251027
'OC\\Comments\\Manager' => $baseDir . '/lib/private/Comments/Manager.php',
10261028
'OC\\Comments\\ManagerFactory' => $baseDir . '/lib/private/Comments/ManagerFactory.php',
10271029
'OC\\Config' => $baseDir . '/lib/private/Config.php',
1030+
'OC\\ConfigLexicon\\ConfigLexiconEntry' => $baseDir . '/lib/private/ConfigLexicon/ConfigLexiconEntry.php',
10281031
'OC\\Console\\Application' => $baseDir . '/lib/private/Console/Application.php',
10291032
'OC\\Console\\TimestampFormatter' => $baseDir . '/lib/private/Console/TimestampFormatter.php',
10301033
'OC\\ContactsManager' => $baseDir . '/lib/private/ContactsManager.php',

lib/composer/composer/autoload_static.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
249249
'OCP\\Comments\\MessageTooLongException' => __DIR__ . '/../../..' . '/lib/public/Comments/MessageTooLongException.php',
250250
'OCP\\Comments\\NotFoundException' => __DIR__ . '/../../..' . '/lib/public/Comments/NotFoundException.php',
251251
'OCP\\Common\\Exception\\NotFoundException' => __DIR__ . '/../../..' . '/lib/public/Common/Exception/NotFoundException.php',
252+
'OCP\\ConfigLexicon\\IConfigLexicon' => __DIR__ . '/../../..' . '/lib/public/ConfigLexicon/IConfigLexicon.php',
253+
'OCP\\ConfigLexicon\\IConfigLexiconEntry' => __DIR__ . '/../../..' . '/lib/public/ConfigLexicon/IConfigLexiconEntry.php',
252254
'OCP\\Config\\BeforePreferenceDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceDeletedEvent.php',
253255
'OCP\\Config\\BeforePreferenceSetEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceSetEvent.php',
254256
'OCP\\Console\\ConsoleEvent' => __DIR__ . '/../../..' . '/lib/public/Console/ConsoleEvent.php',
@@ -1058,6 +1060,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
10581060
'OC\\Comments\\Manager' => __DIR__ . '/../../..' . '/lib/private/Comments/Manager.php',
10591061
'OC\\Comments\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Comments/ManagerFactory.php',
10601062
'OC\\Config' => __DIR__ . '/../../..' . '/lib/private/Config.php',
1063+
'OC\\ConfigLexicon\\ConfigLexiconEntry' => __DIR__ . '/../../..' . '/lib/private/ConfigLexicon/ConfigLexiconEntry.php',
10611064
'OC\\Console\\Application' => __DIR__ . '/../../..' . '/lib/private/Console/Application.php',
10621065
'OC\\Console\\TimestampFormatter' => __DIR__ . '/../../..' . '/lib/private/Console/TimestampFormatter.php',
10631066
'OC\\ContactsManager' => __DIR__ . '/../../..' . '/lib/private/ContactsManager.php',

lib/private/AppConfig.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838

3939
use InvalidArgumentException;
4040
use JsonException;
41+
use OC\AppFramework\Bootstrap\Coordinator;
42+
use OC\ConfigLexicon\ConfigLexiconEntry;
43+
use OCP\ConfigLexicon\IConfigLexiconEntry;
4144
use OCP\DB\Exception as DBException;
4245
use OCP\DB\QueryBuilder\IQueryBuilder;
4346
use OCP\Exceptions\AppConfigIncorrectTypeException;
@@ -82,6 +85,8 @@ class AppConfig implements IAppConfig {
8285
private array $valueTypes = []; // type for all config values
8386
private bool $fastLoaded = false;
8487
private bool $lazyLoaded = false;
88+
/** @var array<array-key, array{entries: array<array-key, IConfigLexiconEntry>, strict: bool}> ['app_id' => ['strict' => bool, 'entries' => ['config_key' => IConfigLexiconEntry[]]] */
89+
private array $configLexiconDetails = [];
8590

8691
/**
8792
* $migrationCompleted is only needed to manage the previous structure
@@ -457,6 +462,7 @@ private function getTypedValue(
457462
int $type
458463
): string {
459464
$this->assertParams($app, $key, valueType: $type);
465+
$this->compareRegisteredConfigValues($app, $key, $lazy, $type, $default);
460466
$this->loadConfig($lazy);
461467

462468
/**
@@ -748,6 +754,7 @@ private function setTypedValue(
748754
int $type
749755
): bool {
750756
$this->assertParams($app, $key);
757+
$this->compareRegisteredConfigValues($app, $key, $lazy, $type);
751758
$this->loadConfig($lazy);
752759

753760
$sensitive = $this->isTyped(self::VALUE_SENSITIVE, $type);
@@ -1567,4 +1574,74 @@ private function getSensitiveKeys(string $app): array {
15671574
public function clearCachedConfig(): void {
15681575
$this->clearCache();
15691576
}
1577+
1578+
/**
1579+
* verify and compare current use of config values with defined lexicon
1580+
*
1581+
* @throws AppConfigUnknownKeyException
1582+
* @throws AppConfigTypeConflictException
1583+
*/
1584+
private function compareRegisteredConfigValues(
1585+
string $app,
1586+
string $key,
1587+
bool &$lazy,
1588+
int &$type,
1589+
string &$default = '',
1590+
): void {
1591+
$configDetails = $this->getConfigDetailsFromLexicon($app);
1592+
if (!array_key_exists($key, $configDetails['entries'])) {
1593+
if ($configDetails['strict'] === true) {
1594+
throw new AppConfigUnknownKeyException('The key ' . $app . '/' . $key . ' is not defined in the config lexicon');
1595+
}
1596+
return;
1597+
}
1598+
1599+
/** @var ConfigLexiconEntry $configValue */
1600+
$configValue = $configDetails['entries'][$key];
1601+
$type &= ~self::VALUE_SENSITIVE;
1602+
1603+
if ($configValue->getValueType() !== match($type) {
1604+
self::VALUE_STRING => IConfigLexiconEntry::TYPE_STRING,
1605+
self::VALUE_INT => IConfigLexiconEntry::TYPE_INT,
1606+
self::VALUE_FLOAT => IConfigLexiconEntry::TYPE_FLOAT,
1607+
self::VALUE_BOOL => IConfigLexiconEntry::TYPE_BOOL,
1608+
self::VALUE_ARRAY => IConfigLexiconEntry::TYPE_ARRAY,
1609+
}) {
1610+
throw new AppConfigTypeConflictException('The key ' . $app . '/' . $key . ' is typed incorrectly in relation to the config lexicon');
1611+
}
1612+
1613+
$lazy = $configValue->isLazy();
1614+
$default = $configValue->getDefault() ?? $default;
1615+
if ($configValue->isSensitive()) {
1616+
$type |= self::VALUE_SENSITIVE;
1617+
}
1618+
if ($configValue->isDeprecated()) {
1619+
$this->logger->notice('config value ' . $app . '/' . $key . ' is set as deprecated.');
1620+
}
1621+
}
1622+
1623+
/**
1624+
* extract details from registered $appId's config lexicon
1625+
*
1626+
* @param string $appId
1627+
*
1628+
* @return array{entries: array<array-key, IConfigLexiconEntry>, strict: bool}
1629+
*/
1630+
private function getConfigDetailsFromLexicon(string $appId): array {
1631+
if (!array_key_exists($appId, $this->configLexiconDetails)) {
1632+
$entries = [];
1633+
$bootstrapCoordinator = \OCP\Server::get(Coordinator::class);
1634+
$configLexicon = $bootstrapCoordinator->getRegistrationContext()?->getConfigLexicon($appId);
1635+
foreach ($configLexicon?->getAppConfigs() ?? [] as $configEntry) {
1636+
$entries[$configEntry->getKey()] = $configEntry;
1637+
}
1638+
1639+
$this->configLexiconDetails[$appId] = [
1640+
'entries' => $entries,
1641+
'strict' => $configLexicon?->isStrict() ?? false
1642+
];
1643+
}
1644+
1645+
return $this->configLexiconDetails[$appId];
1646+
}
15701647
}

lib/private/AppFramework/Bootstrap/RegistrationContext.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class RegistrationContext {
160160
/** @var ServiceRegistration<IDeclarativeSettingsForm>[] */
161161
private array $declarativeSettings = [];
162162

163+
/** @var array<array-key, string> */
164+
private array $configLexiconClasses = [];
165+
163166
/** @var ServiceRegistration<ITeamResourceProvider>[] */
164167
private array $teamResourceProviders = [];
165168

@@ -411,6 +414,13 @@ public function registerDeclarativeSettings(string $declarativeSettingsClass): v
411414
$declarativeSettingsClass
412415
);
413416
}
417+
418+
public function registerConfigLexicon(string $configLexiconClass): void {
419+
$this->context->registerConfigLexicon(
420+
$this->appId,
421+
$configLexiconClass
422+
);
423+
}
414424
};
415425
}
416426

@@ -590,6 +600,13 @@ public function registerDeclarativeSettings(string $appId, string $declarativeSe
590600
$this->declarativeSettings[] = new ServiceRegistration($appId, $declarativeSettingsClass);
591601
}
592602

603+
/**
604+
* @psalm-param class-string<IConfigLexicon> $configLexiconClass
605+
*/
606+
public function registerConfigLexicon(string $appId, string $configLexiconClass): void {
607+
$this->configLexiconClasses[$appId] = $configLexiconClass;
608+
}
609+
593610
/**
594611
* @param App[] $apps
595612
*/
@@ -920,4 +937,20 @@ public function getTeamResourceProviders(): array {
920937
public function getDeclarativeSettings(): array {
921938
return $this->declarativeSettings;
922939
}
940+
941+
/**
942+
* returns IConfigLexicon registered by the app.
943+
* null if none registered.
944+
*
945+
* @param string $appId
946+
*
947+
* @return IConfigLexicon|null
948+
*/
949+
public function getConfigLexicon(string $appId): ?IConfigLexicon {
950+
if (!array_key_exists($appId, $this->configLexiconClasses)) {
951+
return null;
952+
}
953+
954+
return \OCP\Server::get($this->configLexiconClasses[$appId]);
955+
}
923956
}

0 commit comments

Comments
 (0)