Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ logs/
*.log
*.db
*.wal.*
*.gz
*.gz

### Local Configuration ###
mcp-configs/
mcp-example.json
DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@

package io.github.alkoleft.mcp.application.actions.build

import io.github.alkoleft.mcp.application.actions.change.SourceSetChanges
import io.github.alkoleft.mcp.application.actions.common.BuildAction
import io.github.alkoleft.mcp.application.actions.common.BuildResult
import io.github.alkoleft.mcp.application.actions.exceptions.BuildException
import io.github.alkoleft.mcp.configuration.properties.ApplicationProperties
import io.github.alkoleft.mcp.configuration.properties.SourceSet
import io.github.alkoleft.mcp.infrastructure.platform.dsl.PlatformDsl
import io.github.alkoleft.mcp.infrastructure.platform.dsl.process.ProcessResult
import io.github.alkoleft.mcp.infrastructure.utility.PartialLoadListGenerator
import io.github.oshai.kotlinlogging.KotlinLogging
import java.nio.file.Path
import kotlin.time.TimeSource
Expand All @@ -36,10 +38,11 @@ private val logger = KotlinLogging.logger { }

/**
* Абстрактный базовый класс для BuildAction, предоставляющий общую функциональность
* для измерения времени выполнения, обработки ошибок и логирования
* для измерения времени выполнения, обработки ошибок, логирования и частичной загрузки.
*/
abstract class AbstractBuildAction(
protected val dsl: PlatformDsl,
protected val partialLoadListGenerator: PartialLoadListGenerator,
) : BuildAction {
/**
* Выполняет полную сборку проекта с измерением времени
Expand All @@ -49,6 +52,21 @@ abstract class AbstractBuildAction(
sourceSet: SourceSet,
): BuildResult = measureExecutionTime { executeBuildDsl(properties, sourceSet) }

/**
* Выполняет сборку проекта с поддержкой частичной загрузки.
*
* Автоматически определяет режим загрузки на основе:
* - Количества измененных файлов (порог из properties.build.partialLoadThreshold)
* - Наличия изменений в Configuration.xml
*/
override fun runPartial(
properties: ApplicationProperties,
sourceSet: SourceSet,
sourceSetChanges: Map<String, SourceSetChanges>,
): BuildResult = measureExecutionTime {
executeBuildDslPartial(properties, sourceSet, sourceSetChanges)
}

/**
* Измеряет время выполнения операции с обработкой ошибок
*/
Expand All @@ -67,13 +85,13 @@ abstract class AbstractBuildAction(
}

/**
* Метод для выполнения DSL сборки
* Метод для выполнения DSL сборки (полная загрузка)
*/
fun executeBuildDsl(
properties: ApplicationProperties,
sourceSet: SourceSet,
): BuildResult {
logger.debug { "Сборка проекта" }
logger.debug { "Сборка проекта (полная загрузка)" }

initDsl(properties)
val state = BuildActionState()
Expand Down Expand Up @@ -110,17 +128,125 @@ abstract class AbstractBuildAction(
return state.toResult("Сборка завершена").also { if (it.success) logger.info { it.message } }
}

/**
* Метод для выполнения DSL сборки с поддержкой частичной загрузки
*/
fun executeBuildDslPartial(
properties: ApplicationProperties,
sourceSet: SourceSet,
sourceSetChanges: Map<String, SourceSetChanges>,
): BuildResult {
logger.debug { "Сборка проекта с поддержкой частичной загрузки" }

initDsl(properties)
val state = BuildActionState()
val threshold = properties.build.partialLoadThreshold

// Загружаем основную конфигурацию
sourceSet.configuration?.also { configuration ->
val configPath = sourceSet.basePath.resolve(configuration.path)
val changes = sourceSetChanges[configuration.name]

val result = if (changes != null && shouldUsePartialLoad(changes, threshold, configPath)) {
logger.info { "Частичная загрузка конфигурации: ${changes.changedFiles.size} файлов" }
loadConfigurationPartial(configuration.name, configPath, changes.changedFiles)
} else {
logger.info { "Полная загрузка конфигурации" }
loadConfiguration(configuration.name, configPath)
}
state.addResult(configuration.name, result, "Загрузка конфигурации")
}

if (!state.success) {
return state.toResult("При загрузке исходников возникли ошибки")
}

// Загружаем расширения
val extensions = sourceSet.extensions
logger.info { "Загружаю ${extensions.size} расширений: ${extensions.joinToString(", ") { it.name }}" }
extensions.forEach { extension ->
val extensionPath = sourceSet.basePath.resolve(extension.path)
val changes = sourceSetChanges[extension.name]

val result = if (changes != null && shouldUsePartialLoad(changes, threshold, extensionPath)) {
logger.info { "Частичная загрузка расширения ${extension.name}: ${changes.changedFiles.size} файлов" }
loadExtensionPartial(extension.name, extensionPath, changes.changedFiles)
} else {
logger.info { "Полная загрузка расширения ${extension.name}" }
loadExtension(extension.name, extensionPath)
}
state.addResult(extension.name, result, "Загрузка расширения ${extension.name}")

if (!result.success) {
return@forEach
}
}

if (!state.success) {
return state.toResult("При загрузке исходников возникли ошибки")
}

updateDb()?.also(state::registerUpdateResult)

return state.toResult("Сборка завершена").also { if (it.success) logger.info { it.message } }
}

/**
* Определяет, следует ли использовать частичную загрузку для source set.
*/
private fun shouldUsePartialLoad(
changes: SourceSetChanges,
threshold: Int,
sourceSetPath: Path,
): Boolean {
return partialLoadListGenerator.shouldUsePartialLoad(
changedFiles = changes.changedFiles,
threshold = threshold,
sourceSetPath = sourceSetPath,
)
}

/**
* Инициализирует DSL для выполнения команд
*/
protected abstract fun initDsl(properties: ApplicationProperties): Unit

/**
* Загружает конфигурацию полностью
*/
protected abstract fun loadConfiguration(
name: String,
path: Path,
): ProcessResult

/**
* Загружает конфигурацию частично (только измененные файлы)
*/
protected abstract fun loadConfigurationPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult

/**
* Загружает расширение полностью
*/
protected abstract fun loadExtension(
name: String,
path: Path,
): ProcessResult

/**
* Загружает расширение частично (только измененные файлы)
*/
protected abstract fun loadExtensionPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult

/**
* Обновляет конфигурацию базы данных
*/
protected abstract fun updateDb(): ProcessResult?
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ package io.github.alkoleft.mcp.application.actions.build
import io.github.alkoleft.mcp.configuration.properties.ApplicationProperties
import io.github.alkoleft.mcp.infrastructure.platform.dsl.PlatformDsl
import io.github.alkoleft.mcp.infrastructure.platform.dsl.designer.DesignerDsl
import io.github.alkoleft.mcp.infrastructure.platform.dsl.process.ProcessResult
import io.github.alkoleft.mcp.infrastructure.utility.PartialLoadListGenerator
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Component
import java.nio.file.Path
Expand All @@ -35,7 +37,8 @@ import java.nio.file.Path
@ConditionalOnProperty(name = ["app.tools.builder"], havingValue = "DESIGNER")
class DesignerBuildAction(
dsl: PlatformDsl,
) : AbstractBuildAction(dsl) {
partialLoadListGenerator: PartialLoadListGenerator,
) : AbstractBuildAction(dsl, partialLoadListGenerator) {
private lateinit var actionDsl: DesignerDsl

override fun initDsl(properties: ApplicationProperties) {
Expand All @@ -55,6 +58,21 @@ class DesignerBuildAction(
updateDBCfg()
}

override fun loadConfigurationPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult {
val listFile = partialLoadListGenerator.generate(path, changedFiles)
return actionDsl.loadConfigFromFiles {
fromPath(path)
partial()
listFile(listFile)
updateConfigDumpInfo()
updateDBCfg()
}
}

override fun loadExtension(
name: String,
path: Path,
Expand All @@ -64,5 +82,21 @@ class DesignerBuildAction(
updateDBCfg()
}

override fun loadExtensionPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult {
val listFile = partialLoadListGenerator.generate(path, changedFiles)
return actionDsl.loadConfigFromFiles {
fromPath(path)
extension(name)
partial()
listFile(listFile)
updateConfigDumpInfo()
updateDBCfg()
}
}

override fun updateDb() = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import io.github.alkoleft.mcp.configuration.properties.ApplicationProperties
import io.github.alkoleft.mcp.infrastructure.platform.dsl.PlatformDsl
import io.github.alkoleft.mcp.infrastructure.platform.dsl.ibcmd.IbcmdDsl
import io.github.alkoleft.mcp.infrastructure.platform.dsl.process.ProcessResult
import io.github.alkoleft.mcp.infrastructure.utility.PartialLoadListGenerator
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Component
import java.nio.file.Path
Expand All @@ -36,7 +37,8 @@ import java.nio.file.Path
@ConditionalOnProperty(name = ["app.tools.builder"], havingValue = "IBCMD")
class IbcmdBuildAction(
dsl: PlatformDsl,
) : AbstractBuildAction(dsl) {
partialLoadListGenerator: PartialLoadListGenerator,
) : AbstractBuildAction(dsl, partialLoadListGenerator) {
private lateinit var actionDsl: IbcmdDsl

override fun initDsl(properties: ApplicationProperties) {
Expand All @@ -54,6 +56,24 @@ class IbcmdBuildAction(
return result
}

override fun loadConfigurationPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult {
// Для ibcmd используем подкоманду "files" и параметр --partial
// ibcmd infobase config import files --partial <path>
lateinit var result: ProcessResult
actionDsl.config {
result = import(path) {
importSubCommand = "files"
partial = true
baseDir = path.toString()
}
}
return result
}
Comment on lines +59 to +75
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Неиспользуемый параметр changedFiles

Оба метода loadConfigurationPartial() и loadExtensionPartial() принимают параметр changedFiles: Set<Path>, но не используют его. В отличие от DesignerBuildAction, здесь не вызывается partialLoadListGenerator.generate().

Возможные проблемы:

  1. Некорректная реализация: Если ibcmd не поддерживает файл списка (listFile), как DESIGNER, то частичная загрузка может не работать корректно
  2. Неполная реализация: Возможно, для ibcmd требуется другой механизм передачи списка изменённых файлов

Проверьте документацию ibcmd и уточните:

  • Поддерживает ли ibcmd config import files --partial автоматическое определение изменённых файлов?
  • Или требуется явная передача списка файлов?
ibcmd config import files --partial changed files list

Also applies to: 91-107

🤖 Prompt for AI Agents
In
src/main/kotlin/io/github/alkoleft/mcp/application/actions/build/IbcmdBuildAction.kt
around lines 59-75 and 91-107, the changedFiles parameter is accepted but never
used; verify ibcmd's behavior and either (A) if ibcmd supports passing an
explicit changed-files list for partial imports, call the
partialLoadListGenerator to generate the list from changedFiles and pass that
list path (e.g., set the import/listFile parameter or equivalent) into the
actionDsl.import call, or (B) if ibcmd auto-detects changed files or does not
support a list, remove the unused changedFiles parameter and/or add a clear
comment explaining why it is unused; implement the chosen path consistently in
both loadConfigurationPartial and loadExtensionPartial.


override fun loadExtension(
name: String,
path: Path,
Expand All @@ -68,6 +88,24 @@ class IbcmdBuildAction(
return result
}

override fun loadExtensionPartial(
name: String,
path: Path,
changedFiles: Set<Path>,
): ProcessResult {
// Для ibcmd используем подкоманду "files" и параметр --partial с расширением
lateinit var result: ProcessResult
actionDsl.config {
result = import(path) {
extension = name
importSubCommand = "files"
partial = true
baseDir = path.toString()
}
}
return result
}

override fun updateDb(): ProcessResult {
lateinit var result: ProcessResult
actionDsl.config { result = apply() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import kotlin.time.Duration
*/
interface BuildAction {
/**
* Выполняет сборку проекта
* Выполняет сборку проекта (полная загрузка)
*
* @param properties Свойства приложения с конфигурацией
* @param sourceSet Описание исходных файлов проекта
Expand All @@ -54,6 +54,24 @@ interface BuildAction {
properties: ApplicationProperties,
sourceSet: SourceSet,
): BuildResult

/**
* Выполняет сборку проекта с частичной загрузкой измененных файлов.
*
* Автоматически определяет режим загрузки (частичная или полная) на основе:
* - Количества измененных файлов (сравнение с порогом partialLoadThreshold)
* - Наличия изменений в Configuration.xml
*
* @param properties Свойства приложения с конфигурацией
* @param sourceSet Описание исходных файлов проекта
* @param sourceSetChanges Изменения, сгруппированные по source set
* @return Результат сборки
*/
fun runPartial(
properties: ApplicationProperties,
sourceSet: SourceSet,
sourceSetChanges: Map<String, SourceSetChanges>,
): BuildResult
}

/**
Expand Down
Loading