diff --git a/app/src/main/kotlin/ch/addere/dga/app/App.kt b/app/src/main/kotlin/ch/addere/dga/app/App.kt index c346cd7..294c72b 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/App.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/App.kt @@ -3,7 +3,7 @@ package ch.addere.dga.app import ch.addere.dga.app.configuration.OutputOptions import ch.addere.dga.app.domain.model.CommandConfig import ch.addere.dga.app.domain.model.FilterConfig -import ch.addere.dga.app.domain.service.DependencyCommand +import ch.addere.dga.app.domain.service.DependencyCommandHandler import ch.addere.dga.app.infrastructure.factory.dgaModule import ch.addere.dga.app.infrastructure.factory.importerModule import ch.addere.dga.app.infrastructure.factory.userInputModule @@ -73,7 +73,7 @@ private class Dga : CliktCommand(help = "Analyse the module dependency graph of optionsFilter.transitiveModules ) val argument = CommandConfig(::echo, gradleProject, filterConfig, outputOption) - val command: DependencyCommand = get { parametersOf(argument) } + val command: DependencyCommandHandler = get { parametersOf(argument) } command.run() } diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/model/CommandConfig.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/model/CommandConfig.kt index 68ffc61..9574437 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/model/CommandConfig.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/model/CommandConfig.kt @@ -1,6 +1,7 @@ package ch.addere.dga.app.domain.model import ch.addere.dga.app.configuration.OutputOptions +import ch.addere.dga.app.configuration.OutputOptions.OutputOptionOverviewOnly import java.io.File data class CommandConfig( @@ -8,4 +9,12 @@ data class CommandConfig( val gradleProjectPath: File, val filterConfig: FilterConfig, val outputConfig: OutputOptions -) +) { + val hasActiveFilter: Boolean = + filterConfig.modules.isNotEmpty() || + filterConfig.originModules.isNotEmpty() || + filterConfig.destinationModules.isNotEmpty() || + filterConfig.configurations.isNotEmpty() || + filterConfig.includeTransitiveDependencies + val hasActiveOutput: Boolean = outputConfig != OutputOptionOverviewOnly +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/model/FilterConfig.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/model/FilterConfig.kt index 522284e..b4e0eda 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/model/FilterConfig.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/model/FilterConfig.kt @@ -8,5 +8,5 @@ data class FilterConfig( val originModules: List, val destinationModules: List, val configurations: List, - val isTransitiveModules: Boolean + val includeTransitiveDependencies: Boolean ) diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/model/OverviewData.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/model/OverviewData.kt deleted file mode 100644 index 7909c45..0000000 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/model/OverviewData.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ch.addere.dga.app.domain.model - -data class OverviewData( - val projectName: String, - val nofModules: Int, - val nofDependencies: Int, - val nofUniqueDependencies: Int -) diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommand.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommand.kt deleted file mode 100644 index 9c087f7..0000000 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommand.kt +++ /dev/null @@ -1,92 +0,0 @@ -package ch.addere.dga.app.domain.service - -import ch.addere.dga.app.configuration.OutputOptions.OutputOptionConfigurations -import ch.addere.dga.app.configuration.OutputOptions.OutputOptionMermaid -import ch.addere.dga.app.configuration.OutputOptions.OutputOptionModules -import ch.addere.dga.app.configuration.OutputOptions.OutputOptionOverviewOnly -import ch.addere.dga.app.domain.model.CommandConfig -import ch.addere.dga.app.domain.service.printer.ConsolePrinter -import ch.addere.dga.app.domain.service.printer.DependencyPrinter -import ch.addere.dga.app.domain.service.printer.MermaidPrinter -import ch.addere.dga.app.domain.service.printer.ModulePrinter -import ch.addere.dga.app.domain.service.printer.OverviewPrinter -import ch.addere.dga.core.domain.model.Dependency -import ch.addere.dga.core.domain.model.FilteredConfiguration -import ch.addere.dga.core.domain.model.FilteredModules -import ch.addere.dga.core.domain.service.ConfigurationService -import ch.addere.dga.core.domain.service.DependencyRelationService -import ch.addere.dga.core.domain.service.DependencyService -import ch.addere.dga.core.domain.service.ModuleService -import ch.addere.dga.importer.application.service.GradleProjectLoader - -class DependencyCommand( - private val config: CommandConfig, - private val dependencies: DependencyPrinter, - private val mermaid: MermaidPrinter, - private val modulePrinter: ModulePrinter, - private val overview: OverviewPrinter, - private val printer: ConsolePrinter, - private val dependencyService: DependencyService, - private val overviewService: OverviewService, - private val moduleService: ModuleService, - private val configurationService: ConfigurationService, - private val dependencyRelationService: DependencyRelationService, - private val gradleProjectLoader: GradleProjectLoader -) { - - fun run() { - - val projectName: String = gradleProjectLoader.loadGradleProject(config.gradleProjectPath) - - val overviewDataForOutput = overviewService.overviewData(projectName) - - val inputModules = config.filterConfig.modules - val inputOrigin = config.filterConfig.originModules - val inputDestination = config.filterConfig.destinationModules - val inputConfigurations = config.filterConfig.configurations - - val filteredModules = inputModules.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredOrigin = inputOrigin.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredDestination = - inputDestination.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredConfigurations = - inputConfigurations.flatMap(configurationService::resolvePartialConfigurationName) - .toList() - - var filteredDependencies: Set = - dependencyService.filteredDependencies( - FilteredModules(inputModules.isNotEmpty(), filteredModules), - FilteredModules(inputOrigin.isNotEmpty(), filteredOrigin), - FilteredModules(inputDestination.isNotEmpty(), filteredDestination), - FilteredConfiguration(inputConfigurations.isNotEmpty(), filteredConfigurations) - ) - - if (config.filterConfig.isTransitiveModules) { - val configurationSet = filteredDependencies.map { it.configuration }.toSet() - filteredDependencies = filteredDependencies.flatMap { dependency -> - dependencyRelationService.allDependenciesOf( - dependency.origin, - configurationSet - ) union - dependencyRelationService.allDependenciesOf( - dependency.destination, - configurationSet - ) - }.toSet() - } - - printer.println() - when (config.outputConfig) { - OutputOptionOverviewOnly -> overview.printToConsole(overviewDataForOutput) - OutputOptionModules -> modulePrinter.printToConsole(extractModules(filteredDependencies)) - OutputOptionConfigurations -> dependencies.printToConsole( - configurationAndCount( - filteredDependencies - ) - ) - - OutputOptionMermaid -> mermaid.printToConsole(filteredDependencies) - } - printer.println() - } -} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommandHandler.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommandHandler.kt new file mode 100644 index 0000000..235fd9d --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/DependencyCommandHandler.kt @@ -0,0 +1,35 @@ +package ch.addere.dga.app.domain.service + +import ch.addere.dga.app.domain.model.CommandConfig +import ch.addere.dga.app.domain.service.printer.ConsolePrinter +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.importer.application.service.GradleProjectLoader + +class DependencyCommandHandler( + private val config: CommandConfig, + private val printer: ConsolePrinter, + private val gradleProjectLoader: GradleProjectLoader, + private val projectOverviewPrinter: ProjectOverviewPrinter, + private val filterService: FilterService, + private val projectFilterPrinter: ProjectFilterPrinter, + private val projectOutputPrinter: ProjectOutputPrinter, +) { + + fun run() { + val projectName: String = gradleProjectLoader.loadGradleProject(config.gradleProjectPath) + projectOverviewPrinter.output(projectName) + + val relevantDependencies: Set = if (config.hasActiveFilter) { + val filteredDependencies: Set = filterService.filter(config.filterConfig) + projectFilterPrinter.output(filteredDependencies) + filteredDependencies + } else { + filterService.allDependencies() + } + + if (config.hasActiveOutput) { + projectOutputPrinter.output(config.outputConfig, relevantDependencies) + } + printer.println() + } +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt new file mode 100644 index 0000000..9bde2d8 --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt @@ -0,0 +1,68 @@ +package ch.addere.dga.app.domain.service + +import ch.addere.dga.app.domain.model.FilterConfig +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.core.domain.model.FilteredConfiguration +import ch.addere.dga.core.domain.model.FilteredModules +import ch.addere.dga.core.domain.service.ConfigurationService +import ch.addere.dga.core.domain.service.DependencyRelationService +import ch.addere.dga.core.domain.service.DependencyService +import ch.addere.dga.core.domain.service.ModuleService + +class FilterService( + private val dependencyService: DependencyService, + private val moduleService: ModuleService, + private val configurationService: ConfigurationService, + private val dependencyRelationService: DependencyRelationService, +) { + + + fun allDependencies(): Set { + return dependencyService.filteredDependencies( + FilteredModules(false, emptyList()), + FilteredModules(false, emptyList()), + FilteredModules(false, emptyList()), + FilteredConfiguration(false, emptyList()) + ) + } + + + fun filter(filterConfig: FilterConfig): Set { + val inputModules = filterConfig.modules + val inputOrigin = filterConfig.originModules + val inputDestination = filterConfig.destinationModules + val inputConfigurations = filterConfig.configurations + + val filteredModules = inputModules.flatMap(moduleService::resolvePartialModuleName).toList() + val filteredOrigin = inputOrigin.flatMap(moduleService::resolvePartialModuleName).toList() + val filteredDestination = + inputDestination.flatMap(moduleService::resolvePartialModuleName).toList() + val filteredConfigurations = + inputConfigurations.flatMap(configurationService::resolvePartialConfigurationName) + .toList() + + var filteredDependencies: Set = + dependencyService.filteredDependencies( + FilteredModules(inputModules.isNotEmpty(), filteredModules), + FilteredModules(inputOrigin.isNotEmpty(), filteredOrigin), + FilteredModules(inputDestination.isNotEmpty(), filteredDestination), + FilteredConfiguration(inputConfigurations.isNotEmpty(), filteredConfigurations) + ) + + if (filterConfig.includeTransitiveDependencies) { + val configurationSet = filteredDependencies.map { it.configuration }.toSet() + filteredDependencies = filteredDependencies.flatMap { dependency -> + dependencyRelationService.allDependenciesOf( + dependency.origin, + configurationSet + ) union + dependencyRelationService.allDependenciesOf( + dependency.destination, + configurationSet + ) + }.toSet() + } + + return filteredDependencies + } +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/OverviewService.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/OverviewService.kt deleted file mode 100644 index 2c0e3a7..0000000 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/service/OverviewService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package ch.addere.dga.app.domain.service - -import ch.addere.dga.app.domain.model.OverviewData -import ch.addere.dga.core.domain.service.DependencyService -import ch.addere.dga.core.domain.service.ModuleService - -class OverviewService( - private val moduleService: ModuleService, - private val dependencyService: DependencyService, -) { - - fun overviewData(projectName: String): OverviewData { - val nofModules = moduleService.nofModules() - val nofDependencies = dependencyService.nofProjectDependencies() - val nofUniqueDependencies = dependencyService.nofUniqueConfigurations() - return OverviewData(projectName, nofModules, nofDependencies, nofUniqueDependencies) - } -} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectFilterPrinter.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectFilterPrinter.kt new file mode 100644 index 0000000..1bf35e7 --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectFilterPrinter.kt @@ -0,0 +1,37 @@ +package ch.addere.dga.app.domain.service + +import ch.addere.dga.app.domain.service.printer.ConsolePrinter +import ch.addere.dga.core.domain.model.Dependency + +class ProjectFilterPrinter(private val printer: ConsolePrinter) { + + /** + * Print filtered module and configuration information. + */ + fun output(dependencies: Set) { + val overviewData = filteredData(dependencies) + printer.println() + printer.println("Applying filter on data results in:") + printer.println(String.format("%6d modules", overviewData.nofModules)) + printer.println( + String.format( + "%6d dependency configurations (%d unique dependency configurations)", + overviewData.nofDependencies, + overviewData.nofUniqueDependencies + ) + ) + } + + private fun filteredData(dependencies: Set): FilterData { + val nofModules = dependencies.flatMap { setOf(it.origin, it.destination) }.toSet().size + val nofDependencies = dependencies.map { it.configuration }.count() + val nofUniqueDependencies = dependencies.map { it.configuration }.toSet().size + return FilterData(nofModules, nofDependencies, nofUniqueDependencies) + } + + private data class FilterData( + val nofModules: Int, + val nofDependencies: Int, + val nofUniqueDependencies: Int + ) +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOutputPrinter.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOutputPrinter.kt new file mode 100644 index 0000000..f32a8c4 --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOutputPrinter.kt @@ -0,0 +1,35 @@ +package ch.addere.dga.app.domain.service + +import ch.addere.dga.app.configuration.OutputOptions +import ch.addere.dga.app.configuration.OutputOptions.OutputOptionConfigurations +import ch.addere.dga.app.configuration.OutputOptions.OutputOptionMermaid +import ch.addere.dga.app.configuration.OutputOptions.OutputOptionModules +import ch.addere.dga.app.configuration.OutputOptions.OutputOptionOverviewOnly +import ch.addere.dga.app.domain.service.printer.DependencyPrinter +import ch.addere.dga.app.domain.service.printer.MermaidPrinter +import ch.addere.dga.app.domain.service.printer.ModulePrinter +import ch.addere.dga.core.domain.model.Dependency + +class ProjectOutputPrinter( + private val dependencies: DependencyPrinter, + private val mermaid: MermaidPrinter, + private val modulePrinter: ModulePrinter, +) { + + /** + * Print analysed and filtered Gradle project according to the specified output option. + */ + fun output(outputConfig: OutputOptions, relevantDependencies: Set) { + when (outputConfig) { + OutputOptionOverviewOnly -> return + OutputOptionModules -> modulePrinter.printToConsole(extractModules(relevantDependencies)) + OutputOptionConfigurations -> dependencies.printToConsole( + configurationAndCount( + relevantDependencies + ) + ) + + OutputOptionMermaid -> mermaid.printToConsole(relevantDependencies) + } + } +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOverviewPrinter.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOverviewPrinter.kt new file mode 100644 index 0000000..79d26ed --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/ProjectOverviewPrinter.kt @@ -0,0 +1,43 @@ +package ch.addere.dga.app.domain.service + +import ch.addere.dga.app.domain.service.printer.ConsolePrinter +import ch.addere.dga.core.domain.service.DependencyService +import ch.addere.dga.core.domain.service.ModuleService + +class ProjectOverviewPrinter( + private val printer: ConsolePrinter, + private val moduleService: ModuleService, + private val dependencyService: DependencyService, +) { + + /** + * Print common information about the whole analysed Gradle project. + */ + fun output(projectName: String) { + val overviewData = overviewData(projectName) + printer.println() + printer.println("Analyse project \"${overviewData.projectName}\"") + printer.println(String.format("%6d modules", overviewData.nofModules)) + printer.println( + String.format( + "%6d dependency configurations (%d unique dependency configurations)", + overviewData.nofDependencies, + overviewData.nofUniqueDependencies + ) + ) + } + + private fun overviewData(projectName: String): OverviewData { + val nofModules = moduleService.nofModules() + val nofDependencies = dependencyService.nofProjectDependencies() + val nofUniqueDependencies = dependencyService.nofUniqueConfigurations() + return OverviewData(projectName, nofModules, nofDependencies, nofUniqueDependencies) + } + + private data class OverviewData( + val projectName: String, + val nofModules: Int, + val nofDependencies: Int, + val nofUniqueDependencies: Int + ) +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinter.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinter.kt deleted file mode 100644 index 0bba1d5..0000000 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package ch.addere.dga.app.domain.service.printer - -import ch.addere.dga.app.domain.model.OverviewData - -class OverviewPrinter(private val printer: ConsolePrinter) { - - fun printToConsole(overviewData: OverviewData) { - - printer.println("Analyse project \"${overviewData.projectName}\"") - printer.println(String.format("%6d modules", overviewData.nofModules)) - printer.println( - String.format( - "%6d dependencies (%d unique configurations)", - overviewData.nofDependencies, - overviewData.nofUniqueDependencies - ) - ) - } -} diff --git a/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt index f3cb9ba..394dae7 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt @@ -1,12 +1,14 @@ package ch.addere.dga.app.infrastructure.factory -import ch.addere.dga.app.domain.service.DependencyCommand -import ch.addere.dga.app.domain.service.OverviewService +import ch.addere.dga.app.domain.service.DependencyCommandHandler +import ch.addere.dga.app.domain.service.FilterService +import ch.addere.dga.app.domain.service.ProjectFilterPrinter +import ch.addere.dga.app.domain.service.ProjectOutputPrinter +import ch.addere.dga.app.domain.service.ProjectOverviewPrinter import ch.addere.dga.app.domain.service.printer.ConsolePrinter import ch.addere.dga.app.domain.service.printer.DependencyPrinter import ch.addere.dga.app.domain.service.printer.MermaidPrinter import ch.addere.dga.app.domain.service.printer.ModulePrinter -import ch.addere.dga.app.domain.service.printer.OverviewPrinter import ch.addere.dga.core.domain.model.graph.ModuleDependencyDag import ch.addere.dga.core.domain.service.ConfigurationService import ch.addere.dga.core.domain.service.ConfigurationServiceImpl @@ -25,7 +27,7 @@ import org.koin.dsl.module val dgaModule = module { singleOf(::ConfigurationServiceImpl) { bind() } singleOf(::ConsolePrinter) - singleOf(::DependencyCommand) + singleOf(::DependencyCommandHandler) singleOf(::DependencyPrinter) singleOf(::DependencyRelationServiceImpl) { bind() } singleOf(::DependencyRepository) @@ -35,6 +37,8 @@ val dgaModule = module { singleOf(::ModulePrinter) singleOf(::ModuleRepository) singleOf(::ModuleServiceImpl) { bind() } - singleOf(::OverviewPrinter) - singleOf(::OverviewService) + singleOf(::ProjectOverviewPrinter) + singleOf(::FilterService) + singleOf(::ProjectFilterPrinter) + singleOf(::ProjectOutputPrinter) } diff --git a/app/src/test/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinterTest.kt b/app/src/test/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinterTest.kt deleted file mode 100644 index 3393dee..0000000 --- a/app/src/test/kotlin/ch/addere/dga/app/domain/service/printer/OverviewPrinterTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package ch.addere.dga.app.domain.service.printer - -import assertk.assertThat -import assertk.assertions.containsExactly -import ch.addere.dga.app.domain.model.CommandConfig -import ch.addere.dga.app.domain.model.OverviewData -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Test -import org.mockito.Mockito -import org.mockito.kotlin.whenever - -class OverviewPrinterTest { - - private var log = mutableListOf() - - @AfterEach - fun `reset Log`() { - log = mutableListOf() - } - - @Test - fun `test prints project`() { - val printer = OverviewPrinter(consolePrinter()) - - printer.printToConsole(OverviewData("test Project", 1, 2, 3)) - - assertThat(log).containsExactly( - "Analyse project \"test Project\"", - " 1 modules", - " 2 dependencies (3 unique configurations)" - ) - } - - private fun consolePrinter(): ConsolePrinter { - val configMock: CommandConfig = Mockito.mock() - whenever(configMock.printer).thenReturn(::logPrinter) - return ConsolePrinter(configMock) - } - - private fun logPrinter(input: String) { - log.add(input) - } -}