From 48215f9ef164db106c210d6ac434ace69037b6d7 Mon Sep 17 00:00:00 2001 From: tangcent Date: Mon, 18 Mar 2024 06:57:15 +0800 Subject: [PATCH] feat: optimize configuration loading logic for enhanced efficiency and reliability (#1107) --- gradle.properties | 2 +- .../com/itangcent/idea/binder/DbBeanBinder.kt | 30 ++- .../idea/plugin/actions/ApiCallAction.kt | 6 - .../idea/plugin/actions/ApiDashBoardAction.kt | 14 +- .../idea/plugin/actions/ApiExportAction.kt | 5 +- .../plugin/actions/FieldsToMessageAction.kt | 7 - .../plugin/actions/MarkdownExportAction.kt | 15 +- .../plugin/actions/PostmanExportAction.kt | 11 +- .../plugin/actions/ScriptExecutorAction.kt | 11 +- .../idea/plugin/actions/SuvExportAction.kt | 10 +- .../plugin/actions/YapiDashBoardAction.kt | 7 +- .../idea/plugin/actions/YapiExportAction.kt | 6 +- .../api/export/core/EasyApiConfigProvider.kt | 17 ++ .../api/export/core/EasyApiConfigReader.kt | 20 -- .../generic/GenericRequestClassExporter.kt | 6 +- .../SimpleGenericRequestClassExporter.kt | 2 - .../export/postman/PostmanConfigProvider.kt | 26 +++ .../api/export/postman/PostmanConfigReader.kt | 24 -- .../plugin/api/export/suv/SuvApiExporter.kt | 27 +-- .../api/export/yapi/YapiConfigProvider.kt | 26 +++ .../api/export/yapi/YapiConfigReader.kt | 24 -- .../plugin/config/EnhancedConfigReader.kt | 221 ++++++++++++++++++ .../plugin/config/RecommendConfigReader.kt | 202 ---------------- .../AbstractEasyApiConfigurable.kt | 4 +- .../configurable/EasyApiConfigurable.kt | 6 - .../dialog/EasyApiSettingRemoteConfigGUI.kt | 4 +- .../helper/RemoteConfigSettingsHelper.kt | 36 ++- .../com/itangcent/utils/Initializable.kt | 2 +- .../com.itangcent.common.spi.SetupAble | 1 - ...m.itangcent.intellij.config.ConfigProvider | 6 + .../export/core/EasyApiConfigProviderTest.kt | 27 +++ .../export/core/EasyApiConfigReaderTest.kt | 27 --- .../postman/PostmanConfigProviderTest.kt | 52 +++++ .../export/postman/PostmanConfigReaderTest.kt | 51 ---- .../api/export/yapi/YapiConfigProviderTest.kt | 52 +++++ .../api/export/yapi/YapiConfigReaderTest.kt | 51 ---- ...derTest.kt => EnhancedConfigReaderTest.kt} | 82 ++----- .../helper/RemoteConfigSettingsHelperTest.kt | 6 +- ...figReaderTest.kt => ConfigProviderTest.kt} | 39 ++-- ...yRecommendEnhancedConfigReaderTest.log.txt | 7 + ...eEnhancedConfigReaderTest.foreach.api.txt} | 0 ...impleEnhancedConfigReaderTest.foreach.txt} | 4 +- ...st.SimpleEnhancedConfigReaderTest.log.txt} | 4 +- ...RecommendRecommendConfigReaderTest.log.txt | 8 - ...ImmutableRecommendConfigReaderTest.log.txt | 4 - 45 files changed, 564 insertions(+), 628 deletions(-) create mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProvider.kt delete mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReader.kt create mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProvider.kt delete mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReader.kt create mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProvider.kt delete mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReader.kt create mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReader.kt delete mode 100644 idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReader.kt create mode 100644 idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.config.ConfigProvider create mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProviderTest.kt delete mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReaderTest.kt create mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProviderTest.kt delete mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReaderTest.kt create mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProviderTest.kt delete mode 100644 idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReaderTest.kt rename idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/{RecommendConfigReaderTest.kt => EnhancedConfigReaderTest.kt} (56%) rename idea-plugin/src/test/kotlin/com/itangcent/intellij/config/{AutoSearchConfigReaderTest.kt => ConfigProviderTest.kt} (59%) create mode 100644 idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt rename idea-plugin/src/test/resources/result/{com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.api.txt => com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.api.txt} (100%) rename idea-plugin/src/test/resources/result/{com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.txt => com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.txt} (97%) rename idea-plugin/src/test/resources/result/{com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.log.txt => com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.log.txt} (50%) delete mode 100644 idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.EmptyRecommendRecommendConfigReaderTest.log.txt delete mode 100644 idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.ImmutableRecommendConfigReaderTest.log.txt diff --git a/gradle.properties b/gradle.properties index 0bc019051..95a803662 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ plugin_version=2.6.8.212.0 kotlin.code.style=official kotlin_version=1.8.0 junit_version=5.9.2 -itangcent_intellij_version=1.6.2 \ No newline at end of file +itangcent_intellij_version=1.6.3 \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/binder/DbBeanBinder.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/binder/DbBeanBinder.kt index df4181028..ee25d3a57 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/binder/DbBeanBinder.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/binder/DbBeanBinder.kt @@ -3,6 +3,9 @@ package com.itangcent.idea.binder import com.google.common.cache.Cache import com.google.common.cache.CacheBuilder import com.itangcent.idea.sqlite.SqliteDataResourceHelper +import com.itangcent.idea.sqlite.delete +import com.itangcent.idea.sqlite.get +import com.itangcent.idea.sqlite.set import com.itangcent.idea.utils.JacksonUtils import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.file.BeanBinder @@ -16,40 +19,35 @@ class DbBeanBinderFactory(private val file: String, protected var init: } private var dbBeanBinderCache: Cache> = CacheBuilder.newBuilder() - .maximumSize(20) - .build() + .maximumSize(20) + .build() fun getBeanBinder(beanBindName: String): BeanBinder { return dbBeanBinderCache.get(beanBindName) { DbBeanBinder(beanBindName) } } fun deleteBinder(beanBindName: String) { - dao.delete(beanBindName.toByteArray()) + dao.delete(beanBindName) } - inner class DbBeanBinder : BeanBinder { - private val beanBindName: String - - constructor(beanBindName: String) { - this.beanBindName = beanBindName - } + inner class DbBeanBinder(private val beanBindName: String) : BeanBinder { override fun tryRead(): T? { - return dao.get(beanBindName.toByteArray()) - ?.let { JacksonUtils.fromJson(String(it)) } + return dao.get(beanBindName) + ?.let { JacksonUtils.fromJson(it) } } override fun read(): T { - return dao.get(beanBindName.toByteArray()) - ?.let { JacksonUtils.fromJson(String(it)) } - ?: return init() + return dao.get(beanBindName) + ?.let { JacksonUtils.fromJson(it) } + ?: return init() } override fun save(t: T?) { if (t == null) { - dao.delete(beanBindName.toByteArray()) + dao.delete(beanBindName) } else { - dao.set(beanBindName.toByteArray(), JacksonUtils.toJson(t).toByteArray()) + dao.set(beanBindName, JacksonUtils.toJson(t)) } } } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiCallAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiCallAction.kt index fd1d6c24c..47b8ddea3 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiCallAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiCallAction.kt @@ -7,9 +7,6 @@ import com.itangcent.idea.plugin.api.call.ApiCaller import com.itangcent.idea.plugin.api.export.ExportDoc import com.itangcent.idea.plugin.api.export.core.ClassExporter import com.itangcent.idea.plugin.api.export.core.CompositeClassExporter -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -34,9 +31,6 @@ class ApiCallAction : ApiExportAction("Call Api") { builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(EasyApiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } builder.bind(ApiCaller::class) { it.singleton() } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiDashBoardAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiDashBoardAction.kt index 086470a4e..b8cb7aa7d 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiDashBoardAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiDashBoardAction.kt @@ -6,15 +6,14 @@ import com.itangcent.idea.plugin.api.cache.CachedRequestClassExporter import com.itangcent.idea.plugin.api.dashboard.ApiDashBoard import com.itangcent.idea.plugin.api.export.ExportChannel import com.itangcent.idea.plugin.api.export.ExportDoc -import com.itangcent.idea.plugin.api.export.core.* +import com.itangcent.idea.plugin.api.export.core.ClassExporter +import com.itangcent.idea.plugin.api.export.core.CompositeClassExporter +import com.itangcent.idea.plugin.api.export.core.CompositeRequestBuilderListener +import com.itangcent.idea.plugin.api.export.core.RequestBuilderListener import com.itangcent.idea.plugin.api.export.postman.PostmanApiHelper import com.itangcent.idea.plugin.api.export.postman.PostmanCachedApiHelper -import com.itangcent.idea.plugin.api.export.postman.PostmanConfigReader -import com.itangcent.idea.plugin.api.export.postman.PostmanRequestBuilderListener -import com.itangcent.idea.plugin.config.RecommendConfigReader import com.itangcent.idea.swing.ActiveWindowProvider import com.itangcent.idea.swing.SimpleActiveWindowProvider -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -37,11 +36,8 @@ class ApiDashBoardAction : ApiExportAction("ApiDashBoard") { builder.bindInstance(ExportChannel::class, ExportChannel.of("postman")) builder.bindInstance(ExportDoc::class, ExportDoc.of("request")) - - builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(PostmanConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } + builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() } builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } builder.bind(RequestBuilderListener::class) { it.with(CompositeRequestBuilderListener::class).singleton() } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiExportAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiExportAction.kt index f6210eb35..14e4c20df 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiExportAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ApiExportAction.kt @@ -7,9 +7,11 @@ import com.itangcent.idea.plugin.api.cache.FileApiCacheRepository import com.itangcent.idea.plugin.api.cache.ProjectCacheRepository import com.itangcent.idea.plugin.api.export.core.ClassExporter import com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporter +import com.itangcent.idea.plugin.config.EnhancedConfigReader import com.itangcent.idea.plugin.rule.SuvRuleParser import com.itangcent.idea.utils.CustomizedPsiClassHelper import com.itangcent.idea.utils.RuleComputeListenerRegistry +import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.config.rule.RuleComputeListener import com.itangcent.intellij.config.rule.RuleParser import com.itangcent.intellij.context.ActionContext @@ -18,7 +20,6 @@ import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with import com.itangcent.intellij.file.LocalFileRepository import com.itangcent.intellij.jvm.PsiClassHelper -import com.itangcent.intellij.util.ActionUtils abstract class ApiExportAction(text: String) : BasicAnAction(text) { @@ -35,6 +36,8 @@ abstract class ApiExportAction(text: String) : BasicAnAction(text) { builder.bind(LocalFileRepository::class, "projectCacheRepository") { it.with(ProjectCacheRepository::class).singleton() } + + builder.bind(ConfigReader::class) { it.with(EnhancedConfigReader::class).singleton() } } override fun actionPerformed(actionContext: ActionContext, project: Project?, anActionEvent: AnActionEvent) { diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToMessageAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToMessageAction.kt index 6543ac199..3cc153e62 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToMessageAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/FieldsToMessageAction.kt @@ -7,13 +7,9 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiType import com.itangcent.common.logger.traceError import com.itangcent.idea.plugin.api.cache.ProjectCacheRepository -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.idea.plugin.format.MessageFormatter import com.itangcent.idea.plugin.rule.SuvRuleParser import com.itangcent.idea.utils.CustomizedPsiClassHelper import com.itangcent.idea.utils.RuleComputeListenerRegistry -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.config.rule.RuleComputeListener import com.itangcent.intellij.config.rule.RuleParser import com.itangcent.intellij.context.ActionContext @@ -58,9 +54,6 @@ abstract class FieldsToMessageAction : BasicAnAction { it.with(ProjectCacheRepository::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(EasyApiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(RuleComputeListener::class) { it.with(RuleComputeListenerRegistry::class).singleton() } builder.bind(PsiClassHelper::class) { it.with(CustomizedPsiClassHelper::class).singleton() } } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/MarkdownExportAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/MarkdownExportAction.kt index e1e0d081f..9086db61e 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/MarkdownExportAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/MarkdownExportAction.kt @@ -4,14 +4,11 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project import com.itangcent.idea.plugin.api.export.ExportChannel import com.itangcent.idea.plugin.api.export.ExportDoc -import com.itangcent.idea.plugin.api.export.condition.ConditionOnSimple -import com.itangcent.idea.plugin.api.export.core.* -import com.itangcent.idea.plugin.api.export.generic.GenericMethodDocClassExporter -import com.itangcent.idea.plugin.api.export.generic.GenericRequestClassExporter +import com.itangcent.idea.plugin.api.export.core.ClassExporter +import com.itangcent.idea.plugin.api.export.core.CompositeClassExporter +import com.itangcent.idea.plugin.api.export.core.ConfigurableMethodFilter +import com.itangcent.idea.plugin.api.export.core.MethodFilter import com.itangcent.idea.plugin.api.export.markdown.MarkdownApiExporter -import com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporter -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -24,10 +21,6 @@ class MarkdownExportAction : ApiExportAction("Export Markdown") { super.afterBuildActionContext(event, builder) builder.bind(LocalFileRepository::class) { it.with(DefaultLocalFileRepository::class).singleton() } - - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(EasyApiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } builder.bindInstance(ExportChannel::class, ExportChannel.of("markdown")) diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/PostmanExportAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/PostmanExportAction.kt index 3c87710b4..bbd895c52 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/PostmanExportAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/PostmanExportAction.kt @@ -5,9 +5,10 @@ import com.intellij.openapi.project.Project import com.itangcent.idea.plugin.api.export.ExportChannel import com.itangcent.idea.plugin.api.export.ExportDoc import com.itangcent.idea.plugin.api.export.core.* -import com.itangcent.idea.plugin.api.export.postman.* -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.intellij.config.ConfigReader +import com.itangcent.idea.plugin.api.export.postman.PostmanApiExporter +import com.itangcent.idea.plugin.api.export.postman.PostmanApiHelper +import com.itangcent.idea.plugin.api.export.postman.PostmanCachedApiHelper +import com.itangcent.idea.plugin.api.export.postman.PostmanFormatFolderHelper import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -27,10 +28,6 @@ class PostmanExportAction : ApiExportAction("Export Postman") { builder.bind(PostmanApiHelper::class) { it.with(PostmanCachedApiHelper::class).singleton() } builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } - - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(PostmanConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } builder.bindInstance(ExportChannel::class, ExportChannel.of("postman")) diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ScriptExecutorAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ScriptExecutorAction.kt index 224515f68..3d6d4feda 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ScriptExecutorAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/ScriptExecutorAction.kt @@ -5,10 +5,7 @@ import com.intellij.openapi.project.Project import com.itangcent.idea.plugin.api.cache.CachedRequestClassExporter import com.itangcent.idea.plugin.api.debug.ScriptExecutor import com.itangcent.idea.plugin.api.export.core.ClassExporter -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader import com.itangcent.idea.plugin.api.export.spring.SpringRequestClassExporter -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -23,12 +20,10 @@ class ScriptExecutorAction : ApiExportAction("ScriptExecutor") { builder.bind(LocalFileRepository::class) { it.with(DefaultLocalFileRepository::class).singleton() } //allow cache api - builder.bind(ClassExporter::class, "delegate_classExporter") { it.with(SpringRequestClassExporter::class).singleton() } + builder.bind(ClassExporter::class, "delegate_classExporter") { + it.with(SpringRequestClassExporter::class).singleton() + } builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() } - - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(EasyApiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bindInstance("file.save.default", "script.txt") builder.bindInstance("file.save.last.location.key", "com.itangcent.debug.loadOrSave.path") diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/SuvExportAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/SuvExportAction.kt index f03ea4f6d..cd673f278 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/SuvExportAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/SuvExportAction.kt @@ -7,12 +7,13 @@ import com.intellij.openapi.project.Project import com.itangcent.idea.plugin.DataEventCollector import com.itangcent.idea.plugin.api.export.ExportDoc import com.itangcent.idea.plugin.api.export.condition.markAsSimple -import com.itangcent.idea.plugin.api.export.core.* +import com.itangcent.idea.plugin.api.export.core.ClassExporter +import com.itangcent.idea.plugin.api.export.core.CompositeClassExporter +import com.itangcent.idea.plugin.api.export.core.ConfigurableMethodFilter +import com.itangcent.idea.plugin.api.export.core.MethodFilter import com.itangcent.idea.plugin.api.export.postman.PostmanApiHelper import com.itangcent.idea.plugin.api.export.postman.PostmanCachedApiHelper import com.itangcent.idea.plugin.api.export.suv.SuvApiExporter -import com.itangcent.idea.plugin.config.RecommendConfigReader -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -47,9 +48,6 @@ class SuvExportAction : ApiExportAction("Export Api") { builder.bind(LocalFileRepository::class) { it.with(DefaultLocalFileRepository::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(EasyApiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(SuvApiExporter::class) { it.singleton() } builder.bind(MethodFilter::class) { it.with(ConfigurableMethodFilter::class).singleton() } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiDashBoardAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiDashBoardAction.kt index 7035de613..da7e6a7da 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiDashBoardAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiDashBoardAction.kt @@ -8,10 +8,8 @@ import com.itangcent.idea.plugin.api.export.ExportChannel import com.itangcent.idea.plugin.api.export.ExportDoc import com.itangcent.idea.plugin.api.export.core.* import com.itangcent.idea.plugin.api.export.yapi.* -import com.itangcent.idea.plugin.config.RecommendConfigReader import com.itangcent.idea.swing.ActiveWindowProvider import com.itangcent.idea.swing.SimpleActiveWindowProvider -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -27,9 +25,6 @@ class YapiDashBoardAction : ApiExportAction("YapiDashBoard") { builder.bind(LocalFileRepository::class) { it.with(DefaultLocalFileRepository::class).singleton() } builder.bind(LinkResolver::class) { it.with(YapiLinkResolver::class).singleton() } - - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(YapiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } builder.bind(YapiDashBoard::class) { it.singleton() } builder.bind(YapiApiDashBoardExporter::class) { it.singleton() } @@ -43,7 +38,7 @@ class YapiDashBoardAction : ApiExportAction("YapiDashBoard") { builder.bindInstance(ExportChannel::class, ExportChannel.of("yapi")) builder.bindInstance(ExportDoc::class, ExportDoc.of("request", "methodDoc")) - + builder.bind(ClassExporter::class) { it.with(CachedRequestClassExporter::class).singleton() } builder.bind(RequestBuilderListener::class) { it.with(CompositeRequestBuilderListener::class).singleton() } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiExportAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiExportAction.kt index 991f9b842..266a2e318 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiExportAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/YapiExportAction.kt @@ -6,9 +6,7 @@ import com.itangcent.idea.plugin.api.export.ExportChannel import com.itangcent.idea.plugin.api.export.ExportDoc import com.itangcent.idea.plugin.api.export.core.* import com.itangcent.idea.plugin.api.export.yapi.* -import com.itangcent.idea.plugin.config.RecommendConfigReader import com.itangcent.idea.plugin.settings.helper.YapiTokenChecker -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with @@ -28,15 +26,13 @@ class YapiExportAction : ApiExportAction("Export Yapi") { builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } builder.bind(LinkResolver::class) { it.with(YapiLinkResolver::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(YapiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } builder.bind(YapiApiHelper::class) { it.with(YapiCachedApiHelper::class).singleton() } builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } builder.bindInstance(ExportChannel::class, ExportChannel.of("yapi")) builder.bindInstance(ExportDoc::class, ExportDoc.of("request", "methodDoc")) - + builder.bind(RequestBuilderListener::class) { it.with(CompositeRequestBuilderListener::class).singleton() } builder.bind(MethodDocBuilderListener::class) { it.with(CompositeMethodDocBuilderListener::class).singleton() } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProvider.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProvider.kt new file mode 100644 index 000000000..86088b27b --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProvider.kt @@ -0,0 +1,17 @@ +package com.itangcent.idea.plugin.api.export.core + +import com.itangcent.intellij.config.LocalFileSearchConfigProvider +import com.itangcent.order.Order +import com.itangcent.order.Ordered + +@Order(Ordered.HIGHEST_PRECEDENCE) +class EasyApiConfigProvider : LocalFileSearchConfigProvider() { + + override fun configFileNames(): List { + return listOf( + ".easy.api.config", + ".easy.api.yml", + ".easy.api.yaml" + ) + } +} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReader.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReader.kt deleted file mode 100644 index 75899674d..000000000 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReader.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.itangcent.idea.plugin.api.export.core - -import com.itangcent.intellij.config.AutoSearchConfigReader -import com.itangcent.utils.Initializable - -class EasyApiConfigReader : AutoSearchConfigReader(), Initializable { - - // @PostConstruct - override fun init() { - loadConfigInfo() - } - - override fun configFileNames(): List { - return listOf( - ".easy.api.config", - ".easy.api.yml", - ".easy.api.yaml" - ) - } -} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/GenericRequestClassExporter.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/GenericRequestClassExporter.kt index 0ef088510..e3bbe4ec9 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/GenericRequestClassExporter.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/GenericRequestClassExporter.kt @@ -69,7 +69,8 @@ open class GenericRequestClassExporter : RequestClassExporter() { //RequestBody(json) if (isJsonBody(parameterExportContext.psi())) { if (request.method == "GET") { - logger.warn("Request Body is not supported for GET method, please check the rule [generic.param.as.json.body]") + logger.warn("Attempted to use a request body with a GET method in ${parameterExportContext.psi().containingFile.name} at ${parameterExportContext.psi().textOffset}." + + " Please ensure the HTTP method supports a body or adjust the rule [generic.param.as.json.body].") addParamAsQuery( parameterExportContext, request, parameterExportContext.defaultVal() ?: parameterExportContext.unbox(), getUltimateComment(paramDesc, parameterExportContext) @@ -102,7 +103,8 @@ open class GenericRequestClassExporter : RequestClassExporter() { val header = safe { additionalParseHelper.parseHeaderFromJson(headerStr) } when { header == null -> { - logger.error("error to parse additional header: $headerStr") + logger.error("Failed to parse additional header in ${parameterExportContext.psi().containingFile.name} at ${parameterExportContext.psi().textOffset}. Header content: '$headerStr'." + + " Verify the header format is correct.") return@cache null } header.name.isNullOrBlank() -> { diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/SimpleGenericRequestClassExporter.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/SimpleGenericRequestClassExporter.kt index 711edc414..c52b344f5 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/SimpleGenericRequestClassExporter.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/generic/SimpleGenericRequestClassExporter.kt @@ -7,7 +7,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.itangcent.common.logger.traceError import com.itangcent.common.model.Request -import com.itangcent.common.utils.stream import com.itangcent.idea.plugin.api.ClassApiExporterHelper import com.itangcent.idea.plugin.api.export.Orders import com.itangcent.idea.plugin.api.export.condition.ConditionOnDoc @@ -17,7 +16,6 @@ import com.itangcent.idea.plugin.condition.ConditionOnSetting import com.itangcent.idea.psi.PsiMethodResource import com.itangcent.intellij.config.rule.RuleComputer import com.itangcent.intellij.context.ActionContext -import com.itangcent.intellij.jvm.AnnotationHelper import com.itangcent.intellij.jvm.JvmClassHelper import com.itangcent.intellij.logger.Logger import com.itangcent.order.Order diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProvider.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProvider.kt new file mode 100644 index 000000000..6c289117d --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProvider.kt @@ -0,0 +1,26 @@ +package com.itangcent.idea.plugin.api.export.postman + +import com.itangcent.condition.Exclusion +import com.itangcent.idea.plugin.api.export.condition.ConditionOnChannel +import com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider +import com.itangcent.intellij.config.LocalFileSearchConfigProvider +import com.itangcent.order.Order +import com.itangcent.order.Ordered + +@ConditionOnChannel("postman") +@Exclusion(EasyApiConfigProvider::class) +@Order(Ordered.HIGHEST_PRECEDENCE) +class PostmanConfigProvider : LocalFileSearchConfigProvider() { + + override fun configFileNames(): List { + return listOf( + ".postman.config", + ".postman.yml", + ".postman.yaml", + + ".easy.api.config", + ".easy.api.yml", + ".easy.api.yaml" + ) + } +} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReader.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReader.kt deleted file mode 100644 index 34cd479c6..000000000 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReader.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.itangcent.idea.plugin.api.export.postman - -import com.itangcent.intellij.config.AutoSearchConfigReader -import com.itangcent.utils.Initializable - -class PostmanConfigReader : AutoSearchConfigReader(), Initializable { - - // @PostConstruct - override fun init() { - loadConfigInfo() - } - - override fun configFileNames(): List { - return listOf( - ".postman.config", - ".postman.yml", - ".postman.yaml", - - ".easy.api.config", - ".easy.api.yml", - ".easy.api.yaml" - ) - } -} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/suv/SuvApiExporter.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/suv/SuvApiExporter.kt index d681254bb..32488ef80 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/suv/SuvApiExporter.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/suv/SuvApiExporter.kt @@ -25,7 +25,7 @@ import com.itangcent.idea.plugin.api.export.http.HttpClientExporter import com.itangcent.idea.plugin.api.export.markdown.MarkdownFormatter import com.itangcent.idea.plugin.api.export.postman.* import com.itangcent.idea.plugin.api.export.yapi.* -import com.itangcent.idea.plugin.config.RecommendConfigReader +import com.itangcent.idea.plugin.config.EnhancedConfigReader import com.itangcent.idea.plugin.dialog.SuvApiExportDialog import com.itangcent.idea.plugin.rule.SuvRuleParser import com.itangcent.idea.plugin.settings.SettingBinder @@ -255,6 +255,8 @@ open class SuvApiExporter { it.with(ProjectCacheRepository::class).singleton() } + builder.bind(ConfigReader::class) { it.with(EnhancedConfigReader::class).singleton() } + afterBuildActionContext(actionContext, builder) } @@ -365,11 +367,6 @@ open class SuvApiExporter { builder.bind(FormatFolderHelper::class) { it.with(PostmanFormatFolderHelper::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { - it.with(PostmanConfigReader::class).singleton() - } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } builder.bindInstance(ExportChannel::class, ExportChannel.of("postman")) @@ -413,8 +410,6 @@ open class SuvApiExporter { builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } builder.bind(LinkResolver::class) { it.with(YapiLinkResolver::class).singleton() } - builder.bind(ConfigReader::class, "delegate_config_reader") { it.with(YapiConfigReader::class).singleton() } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } @@ -523,11 +518,6 @@ open class SuvApiExporter { builder.bindInstance(ExportChannel::class, ExportChannel.of("markdown")) builder.bindInstance(ExportDoc::class, ExportDoc.of("request", "methodDoc")) - builder.bind(ConfigReader::class, "delegate_config_reader") { - it.with(EasyApiConfigReader::class).singleton() - } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - //always not read api from cache builder.bindInstance("class.exporter.read.cache", false) @@ -586,11 +576,6 @@ open class SuvApiExporter { builder.bindInstance(ExportDoc::class, ExportDoc.of("request")) - builder.bind(ConfigReader::class, "delegate_config_reader") { - it.with(EasyApiConfigReader::class).singleton() - } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - //always not read api from cache builder.bindInstance("class.exporter.read.cache", false) @@ -633,12 +618,6 @@ open class SuvApiExporter { builder.bind(ClassExporter::class) { it.with(CompositeClassExporter::class).singleton() } builder.bindInstance(ExportDoc::class, ExportDoc.of("request")) - - builder.bind(ConfigReader::class, "delegate_config_reader") { - it.with(EasyApiConfigReader::class).singleton() - } - builder.bind(ConfigReader::class) { it.with(RecommendConfigReader::class).singleton() } - //always not read api from cache builder.bindInstance("class.exporter.read.cache", false) diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProvider.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProvider.kt new file mode 100644 index 000000000..58755fc92 --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProvider.kt @@ -0,0 +1,26 @@ +package com.itangcent.idea.plugin.api.export.yapi + +import com.itangcent.condition.Exclusion +import com.itangcent.idea.plugin.api.export.condition.ConditionOnChannel +import com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider +import com.itangcent.intellij.config.LocalFileSearchConfigProvider +import com.itangcent.order.Order +import com.itangcent.order.Ordered + +@ConditionOnChannel("yapi") +@Exclusion(EasyApiConfigProvider::class) +@Order(Ordered.HIGHEST_PRECEDENCE) +class YapiConfigProvider : LocalFileSearchConfigProvider() { + + override fun configFileNames(): List { + return listOf( + ".yapi.config", + ".yapi.yml", + ".yapi.yaml", + + ".easy.api.config", + ".easy.api.yml", + ".easy.api.yaml" + ) + } +} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReader.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReader.kt deleted file mode 100644 index 565de3f19..000000000 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReader.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.itangcent.idea.plugin.api.export.yapi - -import com.itangcent.intellij.config.AutoSearchConfigReader -import com.itangcent.utils.Initializable - -class YapiConfigReader : AutoSearchConfigReader(), Initializable { - - // @PostConstruct - override fun init() { - loadConfigInfo() - } - - override fun configFileNames(): List { - return listOf( - ".yapi.config", - ".yapi.yml", - ".yapi.yaml", - - ".easy.api.config", - ".easy.api.yml", - ".easy.api.yaml" - ) - } -} diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReader.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReader.kt new file mode 100644 index 000000000..ad6578a5e --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReader.kt @@ -0,0 +1,221 @@ +package com.itangcent.idea.plugin.config + +import com.google.inject.Inject +import com.itangcent.common.logger.traceError +import com.itangcent.idea.plugin.settings.helper.BuiltInConfigSettingsHelper +import com.itangcent.idea.plugin.settings.helper.RecommendConfigSettingsHelper +import com.itangcent.idea.plugin.settings.helper.RemoteConfigSettingsHelper +import com.itangcent.intellij.config.BaseConfigReader +import com.itangcent.intellij.config.ConfigContent +import com.itangcent.intellij.config.ConfigProvider +import com.itangcent.intellij.config.dev +import com.itangcent.intellij.context.ActionContext +import com.itangcent.intellij.jvm.dev.DevEnv +import com.itangcent.intellij.logger.Logger +import com.itangcent.intellij.psi.ContextSwitchListener +import com.itangcent.order.Order +import com.itangcent.spi.SpiCompositeLoader +import java.util.concurrent.TimeUnit + + +/** + * An enhanced configuration reader that extends a base configuration reader to include dynamic loading and initialization checks. + */ +class EnhancedConfigReader : BaseConfigReader() { + + private val configProviders: Array by lazy { + SpiCompositeLoader.load(ActionContext.getContext()!!) + } + + @Inject + private lateinit var contextSwitchListener: ContextSwitchListener + + @Volatile + private var loading: Thread? = null + + private var notInit = true + + override fun first(key: String): String? { + checkStatus() + return super.first(key) + } + + override fun foreach(keyFilter: (String) -> Boolean, action: (String, String) -> Unit) { + checkStatus() + super.foreach(keyFilter, action) + } + + override fun foreach(action: (String, String) -> Unit) { + checkStatus() + super.foreach(action) + } + + override fun read(key: String): Collection? { + checkStatus() + return super.read(key) + } + + override fun resolveProperty(property: String): String { + checkStatus() + return super.resolveProperty(property) + } + + /** + * Ensures the configuration is loaded and up to date before any read operation. + */ + private fun checkStatus() { + if (notInit) { + synchronized(this) { + if (notInit) { + try { + contextSwitchListener.onModuleChange { + loadConfigList() + } + } finally { + notInit = false + } + } + } + } + while (loading != null && loading != Thread.currentThread()) { + TimeUnit.MILLISECONDS.sleep(100) + } + } + + private var currentConfigContentHash: String? = null + + /** + * Collect configuration contents from all providers, handling any errors gracefully. + */ + private fun loadConfigList() { + synchronized(this) + { + if (loading != null && loading == Thread.currentThread()) { + return + } + try { + loading = Thread.currentThread() + val configContentList = collectConfigContentList() + val configContentHash = configContentList.joinToString { it.id }.let { "${it.length}x${it.hashCode()}" } + if (configContentHash == this.currentConfigContentHash) { + dev { + logger.debug("config not change. skip reload.") + } + return + } + this.currentConfigContentHash = configContentHash + super.reset() + configContentList.forEach { configContent -> + super.loadConfigInfoContent(configContent.content, configContent.type) + } + } finally { + loading = null + } + } + } + + private fun collectConfigContentList(): List { + val configContents = mutableListOf() + configProviders.forEach { configProvider -> + try { + configProvider.loadConfig().forEach { configContent -> + configContents.add(configContent) + } + } catch (e: Throwable) { + logger.traceError("failed to load config", e) + } + } + return configContents + } +} + +@Order(0) +class BuiltinConfigProvider : ConfigProvider { + + @Inject(optional = true) + private val builtInConfigSettingsHelper: BuiltInConfigSettingsHelper? = null + + @Inject + private lateinit var logger: Logger + + @Inject + private val devEnv: DevEnv? = null + + override fun loadConfig(): Sequence { + try { + val builtInConfig = builtInConfigSettingsHelper?.builtInConfig() ?: return emptySequence() + logger.debug("use built-in config") + devEnv!!.dev { + logger.debug("----------------\n$builtInConfig\n----------------") + } + return sequenceOf(ConfigContent(builtInConfig, "properties")) + } catch (e: Exception) { + logger.warn("failed to use built-in config") + return emptySequence() + } + } +} + +@Order(1) +class RecommendConfigProvider : ConfigProvider { + + @Inject(optional = true) + private val recommendConfigSettingsHelper: RecommendConfigSettingsHelper? = null + + @Inject + private lateinit var logger: Logger + + @Inject + private val devEnv: DevEnv? = null + + override fun loadConfig(): Sequence { + try { + if (recommendConfigSettingsHelper?.useRecommendConfig() == true) { + val recommendConfig = recommendConfigSettingsHelper.loadRecommendConfig() + logger.debug("use recommend config") + devEnv!!.dev { + logger.debug("----------------\n$recommendConfig\n----------------") + } + if (recommendConfig.isEmpty()) { + logger.debug( + "Even useRecommendConfig was true, but no recommend config be selected!\n" + + "\n" + + "If you need to enable the built-in recommended configuration." + + "Go to [Preference -> Other Setting -> EasyApi -> Recommend]" + ) + } + return sequenceOf(ConfigContent(recommendConfig, "properties")) + } + } catch (e: Exception) { + logger.warn("failed to use recommend config") + } + return emptySequence() + } +} + +@Order(2) +class RemoteConfigProvider : ConfigProvider { + + @Inject(optional = true) + private val remoteConfigSettingsHelper: RemoteConfigSettingsHelper? = null + + @Inject + private lateinit var logger: Logger + + @Inject + private val devEnv: DevEnv? = null + + override fun loadConfig(): Sequence { + try { + val remoteConfig = remoteConfigSettingsHelper?.remoteConfigContent() ?: return emptySequence() + logger.debug("load remote config") + devEnv!!.dev { + logger.debug("----------------\n$remoteConfig\n----------------") + } + return remoteConfig.asSequence() + } catch (e: Exception) { + logger.warn("failed to load remote config") + return emptySequence() + } + } +} \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReader.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReader.kt deleted file mode 100644 index c3f15ab3c..000000000 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReader.kt +++ /dev/null @@ -1,202 +0,0 @@ -package com.itangcent.idea.plugin.config - -import com.google.inject.Inject -import com.google.inject.name.Named -import com.itangcent.common.logger.traceError -import com.itangcent.common.utils.invokeMethod -import com.itangcent.common.utils.notNullOrBlank -import com.itangcent.idea.plugin.settings.helper.BuiltInConfigSettingsHelper -import com.itangcent.idea.plugin.settings.helper.RecommendConfigSettingsHelper -import com.itangcent.idea.plugin.settings.helper.RemoteConfigSettingsHelper -import com.itangcent.intellij.adaptor.ModuleAdaptor.filePath -import com.itangcent.intellij.config.ConfigReader -import com.itangcent.intellij.config.MutableConfigReader -import com.itangcent.intellij.extend.guice.PostConstruct -import com.itangcent.intellij.jvm.dev.DevEnv -import com.itangcent.intellij.logger.Logger -import com.itangcent.intellij.psi.ContextSwitchListener -import com.itangcent.utils.Initializable -import java.util.concurrent.TimeUnit - - -class RecommendConfigReader : ConfigReader, Initializable { - - @Inject - @Named("delegate_config_reader") - private val configReader: ConfigReader? = null - - @Inject(optional = true) - private val builtInConfigSettingsHelper: BuiltInConfigSettingsHelper? = null - - - @Inject(optional = true) - private val remoteConfigSettingsHelper: RemoteConfigSettingsHelper? = null - - @Inject(optional = true) - private val recommendConfigSettingsHelper: RecommendConfigSettingsHelper? = null - - @Inject - private lateinit var contextSwitchListener: ContextSwitchListener - - @Inject - private lateinit var logger: Logger - - @Inject - private val devEnv: DevEnv? = null - - @Volatile - private var loading: Thread? = null - - private var notInit = true - - override fun first(key: String): String? { - checkStatus() - return configReader!!.first(key) - } - - override fun foreach(keyFilter: (String) -> Boolean, action: (String, String) -> Unit) { - checkStatus() - configReader!!.foreach(keyFilter, action) - } - - override fun foreach(action: (String, String) -> Unit) { - checkStatus() - configReader!!.foreach(action) - } - - override fun read(key: String): Collection? { - checkStatus() - return configReader!!.read(key) - } - - override fun resolveProperty(property: String): String { - checkStatus() - return configReader!!.resolveProperty(property) - } - - private fun checkStatus() { - if (notInit) { - initDelegateAndRecommend() - } - while (loading != null && loading != Thread.currentThread()) { - TimeUnit.MILLISECONDS.sleep(100) - } - } - - @PostConstruct - override fun init() { - - if (configReader is MutableConfigReader) { - contextSwitchListener.onModuleChange { module -> - synchronized(this) - { - try { - configReader.reset() - module.filePath()?.let { configReader.put("module_path", it) } - initDelegateAndRecommend() - } finally { - loading = null - } - } - } - } else { - initDelegateAndRecommend() - } - } - - private fun initDelegateAndRecommend() { - synchronized(this) - { - try { - if (loading != null && loading == Thread.currentThread()) { - return - } - loading = Thread.currentThread() - try { - if (configReader is Initializable) { - configReader.init() - } else { - configReader?.invokeMethod("init") - } - } catch (e: Throwable) { - logger.traceError("failed init config", e) - } - try { - tryLoadRecommend() - } catch (e: Throwable) { - logger.traceError("failed load recommend config", e) - } - try { - tryLoadBuiltIn() - } catch (e: Throwable) { - logger.traceError("failed load built-in config", e) - } - try { - tryLoadRemote() - } catch (e: Throwable) { - logger.traceError("failed load remote config", e) - } - } finally { - loading = null - notInit = false - } - } - } - - private fun tryLoadRecommend() { - if (recommendConfigSettingsHelper?.useRecommendConfig() == true) { - if (configReader is MutableConfigReader) { - val recommendConfig = recommendConfigSettingsHelper.loadRecommendConfig() - - if (recommendConfig.isEmpty()) { - logger.info( - "Even useRecommendConfig was true, but no recommend config be selected!\n" + - "\n" + - "If you need to enable the built-in recommended configuration." + - "Go to [Preference -> Other Setting -> EasyApi -> Recommend]" - ) - - return - } - - configReader.loadConfigInfoContent(recommendConfig) - logger.debug("use recommend config") - devEnv!!.dev { - logger.debug("----------------\n$recommendConfig\n----------------") - } - } else { - logger.warn("failed to use recommend config") - } - } - } - - private fun tryLoadBuiltIn() { - val builtInConfig = builtInConfigSettingsHelper?.builtInConfig() - if (builtInConfig.notNullOrBlank()) { - if (configReader is MutableConfigReader) { - configReader.loadConfigInfoContent(builtInConfig!!) - logger.debug("use built-in config") - devEnv!!.dev { - logger.debug("----------------\n$builtInConfig\n----------------") - } - } else { - logger.warn("failed to use built-in config") - } - } - } - - private fun tryLoadRemote() { - val remoteConfig = remoteConfigSettingsHelper?.remoteConfigContent() - if (remoteConfig.notNullOrBlank()) { - if (configReader is MutableConfigReader) { - configReader.loadConfigInfoContent(remoteConfig!!) - logger.debug("load remote config") - devEnv!!.dev { - logger.debug("----------------\n$remoteConfig\n----------------") - } - } else { - logger.warn("failed to load remote config") - } - } - } -} \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/AbstractEasyApiConfigurable.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/AbstractEasyApiConfigurable.kt index 2bfe0cbf9..0828b112b 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/AbstractEasyApiConfigurable.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/AbstractEasyApiConfigurable.kt @@ -5,7 +5,7 @@ import com.intellij.openapi.options.SearchableConfigurable import com.intellij.openapi.project.Project import com.itangcent.common.kit.toJson import com.itangcent.common.logger.Log -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader +import com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider import com.itangcent.idea.plugin.settings.SettingBinder import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext @@ -18,7 +18,6 @@ import com.itangcent.intellij.logger.Logger import com.itangcent.intellij.logger.SystemLogger import com.itangcent.suv.http.ConfigurableHttpClientProvider import com.itangcent.suv.http.HttpClientProvider -import java.util.concurrent.TimeUnit import javax.swing.JComponent abstract class AbstractEasyApiConfigurable(private var myProject: Project?) : SearchableConfigurable { @@ -60,7 +59,6 @@ abstract class AbstractEasyApiConfigurable(private var myProject: Project?) : Se myProject?.let { builder.bindInstance(Project::class, it) } builder.bind(Logger::class) { it.with(SystemLogger::class).singleton() } builder.bind(HttpClientProvider::class) { it.with(ConfigurableHttpClientProvider::class).singleton() } - builder.bind(ConfigReader::class) { it.with(EasyApiConfigReader::class).singleton() } builder.bind(LocalFileRepository::class) { it.with(DefaultLocalFileRepository::class).singleton() } afterBuildActionContext(builder) diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiConfigurable.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiConfigurable.kt index 77b6a241e..32fbe5bac 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiConfigurable.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/configurable/EasyApiConfigurable.kt @@ -1,18 +1,12 @@ package com.itangcent.idea.plugin.configurable import com.intellij.openapi.project.Project -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader import com.itangcent.idea.plugin.dialog.EasyApiSettingGUI import com.itangcent.idea.plugin.settings.helper.MemoryPostmanSettingsHelper import com.itangcent.idea.plugin.settings.helper.PostmanSettingsHelper -import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with -import com.itangcent.intellij.file.DefaultLocalFileRepository -import com.itangcent.intellij.file.LocalFileRepository -import com.itangcent.suv.http.ConfigurableHttpClientProvider -import com.itangcent.suv.http.HttpClientProvider class EasyApiConfigurable(myProject: Project?) : AbstractEasyApiConfigurable(myProject) { diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/EasyApiSettingRemoteConfigGUI.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/EasyApiSettingRemoteConfigGUI.kt index bb3091eca..c04b8162a 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/EasyApiSettingRemoteConfigGUI.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/dialog/EasyApiSettingRemoteConfigGUI.kt @@ -3,6 +3,7 @@ package com.itangcent.idea.plugin.dialog import com.google.inject.Inject import com.intellij.openapi.ui.Messages import com.intellij.ui.CheckBoxList +import com.itangcent.common.utils.ResourceUtils import com.itangcent.idea.icons.EasyIcons import com.itangcent.idea.icons.iconOnly import com.itangcent.idea.plugin.configurable.AbstractEasyApiSettingGUI @@ -12,7 +13,6 @@ import com.itangcent.idea.swing.ActiveWindowProvider import com.itangcent.idea.swing.MessagesHelper import com.itangcent.idea.swing.MutableActiveWindowProvider import com.itangcent.intellij.context.ActionContext -import com.itangcent.common.utils.ResourceUtils import javax.swing.JButton import javax.swing.JComponent import javax.swing.JPanel @@ -95,7 +95,7 @@ class EasyApiSettingRemoteConfigGUI : AbstractEasyApiSettingGUI() { this.previewRemoteConfigTextArea.text = "Loading..." val config = remoteConfig[index].second actionContext.runAsync { - val content = remoteConfigSettingsHelper.loadConfig(config) + val content = remoteConfigSettingsHelper.loadConfig(config).content actionContext.runInSwingUI { if (this.configList.selectedIndex == index) { this.previewRemoteConfigTextArea.text = content diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelper.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelper.kt index a5d1ff0d9..5c6b93fa3 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelper.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelper.kt @@ -4,13 +4,19 @@ import com.google.inject.Inject import com.google.inject.Singleton import com.itangcent.idea.plugin.settings.SettingBinder import com.itangcent.idea.sqlite.SqliteDataResourceHelper +import com.itangcent.idea.sqlite.get +import com.itangcent.idea.sqlite.set +import com.itangcent.intellij.config.ConfigContent import com.itangcent.intellij.config.resource.ResourceResolver import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.file.LocalFileRepository +import com.itangcent.intellij.logger.Logger import java.util.* @Singleton class RemoteConfigSettingsHelper { + @Inject + private lateinit var logger: Logger @Inject private lateinit var settingBinder: SettingBinder @@ -31,23 +37,33 @@ class RemoteConfigSettingsHelper { ) } - fun remoteConfigContent(): String { + fun remoteConfigContent(): List { return settingBinder.read().remoteConfig .parse() .filter { it.first } - .map { it.second } - .distinct() - .joinToString("\n") { loadConfig(it) } + .map { loadConfig(it.second) } } - fun loadConfig(url: String): String { - val bytes = beanDAO.get(url.toByteArray()) ?: refreshConfig(url) - return bytes?.toString(Charsets.UTF_8) ?: "" + fun loadConfig(url: String): ConfigContent { + return ConfigContent( + content = beanDAO.get(url) ?: refreshConfig(url) ?: "", + type = getContentTypeFromUrl(url) + ) } - fun refreshConfig(url: String): ByteArray? { - return resourceResolver.resolve(url).bytes?.let { - beanDAO.set(url.toByteArray(), it) + private fun getContentTypeFromUrl(url: String): String { + return url.substringAfterLast('.').ifBlank { "properties" } + } + + fun refreshConfig(url: String): String? { + val resource = try { + resourceResolver.resolve(url) + } catch (e: Exception) { + logger.error("failed to load config: $url") + null + } + return resource?.content?.let { + beanDAO.set(url, it) it } } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/utils/Initializable.kt b/idea-plugin/src/main/kotlin/com/itangcent/utils/Initializable.kt index 800d69577..ad56cfef2 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/utils/Initializable.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/utils/Initializable.kt @@ -4,7 +4,7 @@ import com.itangcent.intellij.context.ActionContext /** * Interface to be implemented by beans that need to react once all their properties - * have been inject by [ActionContext]: e.g. to perform custom initialization, + * have been injected by [ActionContext]: e.g. to perform custom initialization, * or merely to check that all mandatory properties have been set. */ interface Initializable { diff --git a/idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble b/idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble index a3330b222..24f67fce5 100644 --- a/idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble +++ b/idea-plugin/src/main/resources/META-INF/services/com.itangcent.common.spi.SetupAble @@ -1,4 +1,3 @@ com.itangcent.intellij.spi.IdeaAutoInject com.itangcent.intellij.tip.OnlyOnceInContextTipSetup - com.itangcent.intellij.jvm.kotlin.KotlinAutoInject diff --git a/idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.config.ConfigProvider b/idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.config.ConfigProvider new file mode 100644 index 000000000..5b3166711 --- /dev/null +++ b/idea-plugin/src/main/resources/META-INF/services/com.itangcent.intellij.config.ConfigProvider @@ -0,0 +1,6 @@ +com.itangcent.idea.plugin.config.RecommendConfigProvider +com.itangcent.idea.plugin.config.BuiltinConfigProvider +com.itangcent.idea.plugin.config.RemoteConfigProvider +com.itangcent.idea.plugin.api.export.core.EasyApiConfigProvider +com.itangcent.idea.plugin.api.export.yapi.YapiConfigProvider +com.itangcent.idea.plugin.api.export.postman.PostmanConfigProvider \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProviderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProviderTest.kt new file mode 100644 index 000000000..82da250f4 --- /dev/null +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigProviderTest.kt @@ -0,0 +1,27 @@ +package com.itangcent.idea.plugin.api.export.core + +import com.itangcent.intellij.config.ConfigProvider +import com.itangcent.intellij.config.ConfigProviderTest +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.test.assertEquals + +/** + * Test case of [EasyApiConfigProvider] + */ +internal class EasyApiConfigProviderTest : ConfigProviderTest() { + override val configProviderClass: KClass + get() = EasyApiConfigProvider::class + + @Test + fun testConfig() { + assertEquals( + resourceId("config/a/.easy.api.config") + "\n" + + resourceId("config/a/.easy.api.yml") + "\n" + + resourceId("config/a/.easy.api.yaml") + "\n" + + resourceId("config/.easy.api.config") + "\n" + + resourceId("config/.easy.api.yml") + "\n" + + resourceId("config/.easy.api.yaml"), + configProvider.loadConfig().joinToString("\n") { it.id }) + } +} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReaderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReaderTest.kt deleted file mode 100644 index 109f1d759..000000000 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/core/EasyApiConfigReaderTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.itangcent.idea.plugin.api.export.core - -import com.itangcent.idea.plugin.api.export.core.EasyApiConfigReader -import com.itangcent.intellij.config.AutoSearchConfigReaderTest -import com.itangcent.intellij.config.ConfigReader -import org.junit.jupiter.api.Test -import kotlin.reflect.KClass -import kotlin.test.assertEquals - -/** - * Test case of [EasyApiConfigReader] - */ -internal class EasyApiConfigReaderTest : AutoSearchConfigReaderTest() { - override val configReaderClass: KClass - get() = EasyApiConfigReader::class - - @Test - fun testConfig() { - assertEquals("cc", configReader.first("config.c")) - assertEquals("ca", configReader.first("config.a")) - assertEquals("cy", configReader.first("config.y")) - assertEquals("cac", configReader.first("config.a.c")) - assertEquals("caa", configReader.first("config.a.a")) - assertEquals("cay", configReader.first("config.a.y")) - } - -} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProviderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProviderTest.kt new file mode 100644 index 000000000..8d19be39a --- /dev/null +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigProviderTest.kt @@ -0,0 +1,52 @@ +package com.itangcent.idea.plugin.api.export.postman + +import com.itangcent.intellij.config.ConfigProvider +import com.itangcent.intellij.config.ConfigProviderTest +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.test.assertEquals + +/** + * Test case of [PostmanConfigProvider] + */ +internal class PostmanConfigProviderTest : ConfigProviderTest() { + + override val configProviderClass: KClass + get() = PostmanConfigProvider::class + + override fun loadConfigs(): Array { + return arrayOf( + "config/.postman.config", + "config/.postman.yml", + "config/.postman.yaml", + "config/a/.postman.config", + "config/a/.postman.yml", + "config/a/.postman.yaml", + + "config/.easy.api.config", + "config/.easy.api.yml", + "config/.easy.api.yaml", + "config/a/.easy.api.config", + "config/a/.easy.api.yml", + "config/a/.easy.api.yaml", + ) + } + + @Test + fun testConfig() { + assertEquals( + resourceId("config/a/.postman.config") + "\n" + + resourceId("config/a/.postman.yml") + "\n" + + resourceId("config/a/.postman.yaml") + "\n" + + resourceId("config/a/.easy.api.config") + "\n" + + resourceId("config/a/.easy.api.yml") + "\n" + + resourceId("config/a/.easy.api.yaml") + "\n" + + resourceId("config/.postman.config") + "\n" + + resourceId("config/.postman.yml") + "\n" + + resourceId("config/.postman.yaml") + "\n" + + resourceId("config/.easy.api.config") + "\n" + + resourceId("config/.easy.api.yml") + "\n" + + resourceId("config/.easy.api.yaml"), + configProvider.loadConfig().joinToString("\n") { it.id }) + } +} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReaderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReaderTest.kt deleted file mode 100644 index a12e12147..000000000 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/postman/PostmanConfigReaderTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.itangcent.idea.plugin.api.export.postman - -import com.itangcent.intellij.config.AutoSearchConfigReaderTest -import com.itangcent.intellij.config.ConfigReader -import org.junit.jupiter.api.Test -import kotlin.reflect.KClass -import kotlin.test.assertEquals - -/** - * Test case of [PostmanConfigReader] - */ -internal class PostmanConfigReaderTest : AutoSearchConfigReaderTest() { - - override val configReaderClass: KClass - get() = PostmanConfigReader::class - - override fun loadConfigs(): Array { - return arrayOf( - "config/.postman.config", - "config/.postman.yml", - "config/.postman.yaml", - "config/a/.postman.config", - "config/a/.postman.yml", - "config/a/.postman.yaml", - - "config/.easy.api.config", - "config/.easy.api.yml", - "config/.easy.api.yaml", - "config/a/.easy.api.config", - "config/a/.easy.api.yml", - "config/a/.easy.api.yaml", - ) - } - - @Test - fun testConfig() { - assertEquals("cc", configReader.first("config.c")) - assertEquals("ca", configReader.first("config.a")) - assertEquals("cy", configReader.first("config.y")) - assertEquals("cac", configReader.first("config.a.c")) - assertEquals("caa", configReader.first("config.a.a")) - assertEquals("cay", configReader.first("config.a.y")) - - assertEquals("cc", configReader.first("postman.config.c")) - assertEquals("ca", configReader.first("postman.config.a")) - assertEquals("cy", configReader.first("postman.config.y")) - assertEquals("cac", configReader.first("postman.config.a.c")) - assertEquals("caa", configReader.first("postman.config.a.a")) - assertEquals("cay", configReader.first("postman.config.a.y")) - } -} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProviderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProviderTest.kt new file mode 100644 index 000000000..7d1d9a5ed --- /dev/null +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigProviderTest.kt @@ -0,0 +1,52 @@ +package com.itangcent.idea.plugin.api.export.yapi + +import com.itangcent.intellij.config.ConfigProvider +import com.itangcent.intellij.config.ConfigProviderTest +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.test.assertEquals + +/** + * Test case of [YapiConfigProvider] + */ +internal class YapiConfigProviderTest : ConfigProviderTest() { + + override val configProviderClass: KClass + get() = YapiConfigProvider::class + + override fun loadConfigs(): Array { + return arrayOf( + "config/.yapi.config", + "config/.yapi.yml", + "config/.yapi.yaml", + "config/a/.yapi.config", + "config/a/.yapi.yml", + "config/a/.yapi.yaml", + + "config/.easy.api.config", + "config/.easy.api.yml", + "config/.easy.api.yaml", + "config/a/.easy.api.config", + "config/a/.easy.api.yml", + "config/a/.easy.api.yaml", + ) + } + + @Test + fun testConfig() { + assertEquals( + resourceId("config/a/.yapi.config") + "\n" + + resourceId("config/a/.yapi.yml") + "\n" + + resourceId("config/a/.yapi.yaml") + "\n" + + resourceId("config/a/.easy.api.config") + "\n" + + resourceId("config/a/.easy.api.yml") + "\n" + + resourceId("config/a/.easy.api.yaml") + "\n" + + resourceId("config/.yapi.config") + "\n" + + resourceId("config/.yapi.yml") + "\n" + + resourceId("config/.yapi.yaml") + "\n" + + resourceId("config/.easy.api.config") + "\n" + + resourceId("config/.easy.api.yml") + "\n" + + resourceId("config/.easy.api.yaml"), + configProvider.loadConfig().joinToString("\n") { it.id }) + } +} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReaderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReaderTest.kt deleted file mode 100644 index 952e599bf..000000000 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/api/export/yapi/YapiConfigReaderTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.itangcent.idea.plugin.api.export.yapi - -import com.itangcent.intellij.config.AutoSearchConfigReaderTest -import com.itangcent.intellij.config.ConfigReader -import org.junit.jupiter.api.Test -import kotlin.reflect.KClass -import kotlin.test.assertEquals - -/** - * Test case of [YapiConfigReader] - */ -internal class YapiConfigReaderTest : AutoSearchConfigReaderTest() { - - override val configReaderClass: KClass - get() = YapiConfigReader::class - - override fun loadConfigs(): Array { - return arrayOf( - "config/.yapi.config", - "config/.yapi.yml", - "config/.yapi.yaml", - "config/a/.yapi.config", - "config/a/.yapi.yml", - "config/a/.yapi.yaml", - - "config/.easy.api.config", - "config/.easy.api.yml", - "config/.easy.api.yaml", - "config/a/.easy.api.config", - "config/a/.easy.api.yml", - "config/a/.easy.api.yaml", - ) - } - - @Test - fun testConfig() { - assertEquals("cc", configReader.first("config.c")) - assertEquals("ca", configReader.first("config.a")) - assertEquals("cy", configReader.first("config.y")) - assertEquals("cac", configReader.first("config.a.c")) - assertEquals("caa", configReader.first("config.a.a")) - assertEquals("cay", configReader.first("config.a.y")) - - assertEquals("cc", configReader.first("yapi.config.c")) - assertEquals("ca", configReader.first("yapi.config.a")) - assertEquals("cy", configReader.first("yapi.config.y")) - assertEquals("cac", configReader.first("yapi.config.a.c")) - assertEquals("caa", configReader.first("yapi.config.a.a")) - assertEquals("cay", configReader.first("yapi.config.a.y")) - } -} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReaderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReaderTest.kt similarity index 56% rename from idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReaderTest.kt rename to idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReaderTest.kt index 6a3ff7f3c..bc9aa65c6 100644 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/RecommendConfigReaderTest.kt +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/config/EnhancedConfigReaderTest.kt @@ -1,40 +1,34 @@ package com.itangcent.idea.plugin.config import com.google.inject.Inject +import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.module.Module import com.itangcent.common.kit.toJson import com.itangcent.debug.LoggerCollector import com.itangcent.idea.plugin.settings.SettingBinder import com.itangcent.idea.plugin.settings.Settings import com.itangcent.idea.plugin.settings.helper.RecommendConfigLoader -import com.itangcent.intellij.config.AbstractConfigReader import com.itangcent.intellij.config.ConfigReader import com.itangcent.intellij.context.ActionContext -import com.itangcent.intellij.extend.guice.PostConstruct import com.itangcent.intellij.extend.guice.singleton import com.itangcent.intellij.extend.guice.with import com.itangcent.intellij.logger.Logger import com.itangcent.intellij.psi.ContextSwitchListener -import com.itangcent.mock.AdvancedContextTest import com.itangcent.mock.SettingBinderAdaptor import com.itangcent.mock.toUnixString import com.itangcent.test.ResultLoader import com.itangcent.test.mock -import com.itangcent.utils.Initializable -import org.junit.jupiter.api.Test -import org.mockito.Mockito +import com.itangcent.testFramework.ContextLightCodeInsightFixtureTestCase import org.mockito.kotlin.any import org.mockito.kotlin.mock -import kotlin.test.assertEquals -import kotlin.test.assertNull /** - * Test case of [RecommendConfigReader] + * Test case of [EnhancedConfigReader] */ -internal abstract class RecommendConfigReaderTest : AdvancedContextTest() { +internal abstract class EnhancedConfigReaderTest : ContextLightCodeInsightFixtureTestCase() { @Inject - protected lateinit var recommendConfigReader: RecommendConfigReader + protected lateinit var enhancedConfigReader: EnhancedConfigReader override fun bind(builder: ActionContext.ActionContextBuilder) { super.bind(builder) @@ -49,35 +43,29 @@ internal abstract class RecommendConfigReaderTest : AdvancedContextTest() { })) } - builder.bind( - ConfigReader::class, - "delegate_config_reader" - ) { it.toInstance(ConfigReaderAdaptor(customConfig() ?: "")) } - builder.bind( ConfigReader::class - ) { it.with(RecommendConfigReader::class).singleton() } + ) { it.with(EnhancedConfigReader::class).singleton() } builder.mock { contextSwitchListener -> this.on(contextSwitchListener.onModuleChange(any())) .thenAnswer { it.getArgument<(Module) -> Unit>(0)(mock()) } } - } - override fun afterBind(actionContext: ActionContext) { - super.afterBind(actionContext) - recommendConfigReader.init() + builder.mock { dataContext -> + this.on(dataContext.getData(any())) + .thenAnswer { null } + } } - internal class SimpleRecommendConfigReaderTest : RecommendConfigReaderTest() { + internal class SimpleEnhancedConfigReaderTest : EnhancedConfigReaderTest() { - @Test - fun test() { + fun testLoadConfig() { + assertEquals("@Ignore", enhancedConfigReader.first("ignore")) assertEquals(ResultLoader.load("log"), LoggerCollector.getLog().toUnixString()) - assertEquals("#ignore", recommendConfigReader.first("ignore")) run { var configs = "" - recommendConfigReader.foreach { key, value -> + enhancedConfigReader.foreach { key, value -> if (configs.isNotEmpty()) { configs = "$configs\n" } @@ -87,7 +75,7 @@ internal abstract class RecommendConfigReaderTest : AdvancedContextTest() { } run { var configs = "" - recommendConfigReader.foreach({ it.startsWith("api.") }) { key, value -> + enhancedConfigReader.foreach({ it.startsWith("api.") }) { key, value -> if (configs.isNotEmpty()) { configs = "$configs\n" } @@ -95,12 +83,12 @@ internal abstract class RecommendConfigReaderTest : AdvancedContextTest() { } assertEquals(ResultLoader.load("foreach.api"), configs) } - assertEquals(listOf("#ignore", "@Ignore").toJson(), recommendConfigReader.read("ignore").toJson()) - assertEquals("#mock", recommendConfigReader.resolveProperty("\${field.mock}")) + assertEquals(listOf("@Ignore", "#ignore").toJson(), enhancedConfigReader.read("ignore").toJson()) + assertEquals("#mock", enhancedConfigReader.resolveProperty("\${field.mock}")) } } - internal class EmptyRecommendRecommendConfigReaderTest : RecommendConfigReaderTest() { + internal class EmptyRecommendEnhancedConfigReaderTest : EnhancedConfigReaderTest() { override fun bind(builder: ActionContext.ActionContextBuilder) { super.bind(builder) @@ -113,39 +101,9 @@ internal abstract class RecommendConfigReaderTest : AdvancedContextTest() { } } - @Test - fun test() { + fun testLoadConfig() { + assertEquals("@Ignore", enhancedConfigReader.first("ignore")) assertEquals(ResultLoader.load("log"), LoggerCollector.getLog().toUnixString()) - assertEquals("@Ignore", recommendConfigReader.first("ignore")) - } - } - - internal class ImmutableRecommendConfigReaderTest : RecommendConfigReaderTest() { - override fun bind(builder: ActionContext.ActionContextBuilder) { - super.bind(builder) - - builder.bind( - ConfigReader::class, - "delegate_config_reader" - ) { it.toInstance(mock(extraInterfaces = arrayOf(Initializable::class))) } - } - - @Test - fun test() { - assertEquals(ResultLoader.load("log"), LoggerCollector.getLog().toUnixString()) - assertNull(recommendConfigReader.first("ignore")) - } - } - - private inner class ConfigReaderAdaptor(val config: String) : AbstractConfigReader() { - - @PostConstruct - fun init() { - loadConfigInfoContent(config, "properties") - } - - override fun findConfigFiles(): List? { - return null } } } \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelperTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelperTest.kt index f60e4cb98..07e65c53e 100644 --- a/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelperTest.kt +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/settings/helper/RemoteConfigSettingsHelperTest.kt @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test import org.mockito.kotlin.eq import org.mockito.kotlin.mock import kotlin.test.assertEquals +import kotlin.test.assertTrue /** * Test case of [RemoteConfigSettingsHelper] @@ -52,7 +53,7 @@ internal class RemoteConfigSettingsHelperTest : SettingsHelperTest() { @Test fun remoteConfigContent() { - assertEquals("", remoteConfigSettingsHelper.remoteConfigContent()) + assertTrue(remoteConfigSettingsHelper.remoteConfigContent().isEmpty()) settings.remoteConfig = arrayOf( "https://github.com/tangcent/easy-yapi/raw/master/third/a.config", "!https://github.com/tangcent/easy-yapi/raw/master/third/b.config", @@ -60,7 +61,7 @@ internal class RemoteConfigSettingsHelperTest : SettingsHelperTest() { ) assertEquals( "a=1\n" + - "c=3", remoteConfigSettingsHelper.remoteConfigContent() + "c=3", remoteConfigSettingsHelper.remoteConfigContent().joinToString("\n") { it.content } ) } @@ -69,6 +70,7 @@ internal class RemoteConfigSettingsHelperTest : SettingsHelperTest() { assertEquals( "a=1", remoteConfigSettingsHelper.loadConfig("https://github.com/tangcent/easy-yapi/raw/master/third/a.config") + .content ) } diff --git a/idea-plugin/src/test/kotlin/com/itangcent/intellij/config/AutoSearchConfigReaderTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/intellij/config/ConfigProviderTest.kt similarity index 59% rename from idea-plugin/src/test/kotlin/com/itangcent/intellij/config/AutoSearchConfigReaderTest.kt rename to idea-plugin/src/test/kotlin/com/itangcent/intellij/config/ConfigProviderTest.kt index 1bb274487..faebb7171 100644 --- a/idea-plugin/src/test/kotlin/com/itangcent/intellij/config/AutoSearchConfigReaderTest.kt +++ b/idea-plugin/src/test/kotlin/com/itangcent/intellij/config/ConfigProviderTest.kt @@ -2,13 +2,14 @@ package com.itangcent.intellij.config import com.google.inject.Inject import com.intellij.openapi.module.Module +import com.itangcent.common.utils.ResourceUtils +import com.itangcent.common.utils.append import com.itangcent.common.utils.forceMkdirParent import com.itangcent.intellij.context.ActionContext import com.itangcent.intellij.extend.guice.with import com.itangcent.intellij.psi.ContextSwitchListener import com.itangcent.mock.AdvancedContextTest import com.itangcent.utils.Initializable -import com.itangcent.common.utils.ResourceUtils import org.mockito.Mockito import java.io.File import kotlin.reflect.KClass @@ -16,39 +17,39 @@ import kotlin.reflect.KClass /** * Test case of [AutoSearchConfigReader] */ -internal abstract class AutoSearchConfigReaderTest : AdvancedContextTest() { +internal abstract class ConfigProviderTest : AdvancedContextTest() { @Inject - protected lateinit var configReader: ConfigReader + protected lateinit var configProvider: ConfigProvider - protected abstract val configReaderClass: KClass + protected abstract val configProviderClass: KClass override fun afterBind(actionContext: ActionContext) { super.afterBind(actionContext) //load configs from resource to tempDir as files in module for (file in loadConfigs()) { File("$tempDir/$file") - .also { it.forceMkdirParent() } - .also { it.createNewFile() } - .writeBytes(ResourceUtils.findResource(file)!!.readBytes()) + .also { it.forceMkdirParent() } + .also { it.createNewFile() } + .writeBytes(ResourceUtils.findResource(file)!!.readBytes()) } - (configReader as? Initializable)?.init() + (configProvider as? Initializable)?.init() } protected open fun loadConfigs(): Array { return arrayOf( - "config/.easy.api.config", - "config/.easy.api.yml", - "config/.easy.api.yaml", - "config/a/.easy.api.config", - "config/a/.easy.api.yml", - "config/a/.easy.api.yaml", + "config/.easy.api.config", + "config/.easy.api.yml", + "config/.easy.api.yaml", + "config/a/.easy.api.config", + "config/a/.easy.api.yml", + "config/a/.easy.api.yaml", ) } override fun bind(builder: ActionContext.ActionContextBuilder) { super.bind(builder) - builder.bind(ConfigReader::class) { it.with(this.configReaderClass) } + builder.bind(ConfigProvider::class) { it.with(this.configProviderClass) } //mock mockContextSwitchListener val mockModule = Mockito.mock(Module::class.java) @@ -57,4 +58,12 @@ internal abstract class AutoSearchConfigReaderTest : AdvancedContextTest() { Mockito.`when`(mockContextSwitchListener.getModule()).thenReturn(mockModule) builder.bind(ContextSwitchListener::class.java) { it.toInstance(mockContextSwitchListener) } } + + fun resourceId(fileName: String): String { + var dir = tempDir.toString().replace(File.separator, "/") + if (!dir.startsWith('/')) { + dir = "/$dir" + } + return "Resource:file:$dir/$fileName" + } } \ No newline at end of file diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt new file mode 100644 index 000000000..13ada9de1 --- /dev/null +++ b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.EmptyRecommendEnhancedConfigReaderTest.log.txt @@ -0,0 +1,7 @@ +[TRACE] No config be found +[DEBUG] use built-in config +[DEBUG] use recommend config +[DEBUG] Even useRecommendConfig was true, but no recommend config be selected! + +If you need to enable the built-in recommended configuration.Go to [Preference -> Other Setting -> EasyApi -> Recommend] +[DEBUG] load remote config diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.api.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.api.txt similarity index 100% rename from idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.api.txt rename to idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.api.txt diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.txt similarity index 97% rename from idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.txt rename to idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.txt index d06dcafea..a472c5c55 100644 --- a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.foreach.txt +++ b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.foreach.txt @@ -1,3 +1,4 @@ +ignore=@Ignore module=#module ignore=#ignore field.name=@com.fasterxml.jackson.annotation.JsonProperty#value @@ -40,5 +41,4 @@ it.tokenize('.').inject([]) { acc, val -> acc << (acc ? "${acc.last()}.${val}" : def ignored = config.getValues("ignored.classes_or_packages").collect{ it.tokenize(',').collect { it.trim() }.findAll { it } }.flatten() -return !prefixList.intersect(ignored).isEmpty() -ignore=@Ignore \ No newline at end of file +return !prefixList.intersect(ignored).isEmpty() \ No newline at end of file diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.log.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.log.txt similarity index 50% rename from idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.log.txt rename to idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.log.txt index 4cb98fea7..098161e5a 100644 --- a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.SimpleRecommendConfigReaderTest.log.txt +++ b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.EnhancedConfigReaderTest.SimpleEnhancedConfigReaderTest.log.txt @@ -1,4 +1,4 @@ -[DEBUG] use recommend config +[TRACE] No config be found [DEBUG] use built-in config [DEBUG] use recommend config -[DEBUG] use built-in config +[DEBUG] load remote config diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.EmptyRecommendRecommendConfigReaderTest.log.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.EmptyRecommendRecommendConfigReaderTest.log.txt deleted file mode 100644 index acdce1184..000000000 --- a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.EmptyRecommendRecommendConfigReaderTest.log.txt +++ /dev/null @@ -1,8 +0,0 @@ -[INFO] Even useRecommendConfig was true, but no recommend config be selected! - -If you need to enable the built-in recommended configuration.Go to [Preference -> Other Setting -> EasyApi -> Recommend] -[DEBUG] use built-in config -[INFO] Even useRecommendConfig was true, but no recommend config be selected! - -If you need to enable the built-in recommended configuration.Go to [Preference -> Other Setting -> EasyApi -> Recommend] -[DEBUG] use built-in config diff --git a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.ImmutableRecommendConfigReaderTest.log.txt b/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.ImmutableRecommendConfigReaderTest.log.txt deleted file mode 100644 index a81ecb95a..000000000 --- a/idea-plugin/src/test/resources/result/com.itangcent.idea.plugin.config.RecommendConfigReaderTest.ImmutableRecommendConfigReaderTest.log.txt +++ /dev/null @@ -1,4 +0,0 @@ -[WARN] failed to use recommend config -[WARN] failed to use built-in config -[WARN] failed to use recommend config -[WARN] failed to use built-in config