From 725bf781b80a439257fba104b3ca49096aa0e6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martynas=20Petu=C5=A1ka?= Date: Wed, 7 Apr 2021 15:26:33 +0100 Subject: [PATCH] Migration to atlas --- .editorconfig | 9 +- .gitlab-ci.yml | 131 ------------ app/build.gradle.kts | 4 +- .../kotlin/app/domain/LibraryCount.kt | 2 +- .../kotlin/app/domain/PagedResponse.kt | 2 +- .../kotlin/app/service/LibraryService.kt | 15 +- .../app/util/{kodein.kt => DIModule.kt} | 6 +- app/src/jsMain/kotlin/app/config/di.kt | 30 +-- app/src/jsMain/kotlin/app/config/env.kt | 6 +- app/src/jsMain/kotlin/app/index.kt | 12 +- .../kotlin/app/service/LibraryService.kt | 30 +-- .../jsMain/kotlin/app/store/LibraryStore.kt | 22 +- .../jsMain/kotlin/app/store/thunk/appThunk.kt | 38 ++-- app/src/jsMain/kotlin/app/util/general.kt | 17 +- app/src/jsMain/kotlin/app/view/App.kt | 12 +- app/src/jsMain/kotlin/app/view/Content.kt | 15 +- app/src/jsMain/kotlin/app/view/Header.kt | 193 +++++++++++------- .../jsMain/kotlin/app/view/component/Badge.kt | 68 +++--- .../kotlin/app/view/component/GitHubIcon.kt | 12 +- .../kotlin/app/view/component/KampIcon.kt | 8 +- .../kotlin/app/view/component/LibraryCard.kt | 63 +++--- .../kotlin/app/view/component/NavAnchor.kt | 7 +- app/src/jvmMain/kotlin/app/config/di.kt | 27 ++- app/src/jvmMain/kotlin/app/config/features.kt | 20 +- app/src/jvmMain/kotlin/app/config/routing.kt | 76 ++++--- app/src/jvmMain/kotlin/app/index.kt | 11 +- .../kotlin/app/service/LibraryService.kt | 49 +++-- app/src/jvmMain/kotlin/app/util/env.kt | 3 +- app/src/jvmMain/kotlin/app/util/kodein.kt | 16 +- app/src/jvmMain/kotlin/app/util/paging.kt | 6 +- build.gradle.kts | 46 ++--- gradle.properties | 2 + gradle/wrapper/gradle-wrapper.properties | 2 +- scanner/build.gradle.kts | 6 +- .../kotlin/scanner/client/AnchorClient.kt | 14 +- .../scanner/client/ArtifactoryClient.kt | 12 +- .../main/kotlin/scanner/client/JBossClient.kt | 12 +- .../scanner/client/MavenRepositoryClient.kt | 100 ++++----- scanner/src/main/kotlin/scanner/config/di.kt | 87 ++++---- .../main/kotlin/scanner/domain/CLIOptions.kt | 45 ++-- .../kotlin/scanner/domain/GradleModule.kt | 59 +++--- .../main/kotlin/scanner/domain/Repository.kt | 57 +++--- scanner/src/main/kotlin/scanner/index.kt | 75 ++++--- .../processor/GradleModuleProcessor.kt | 36 ++-- .../kotlin/scanner/processor/PomProcessor.kt | 28 +-- .../scanner/service/MavenScannerService.kt | 76 ++++--- .../service/MavenScannerServiceImpl.kt | 55 ++--- .../kotlin/scanner/service/Orchestrator.kt | 48 +++-- .../kotlin/scanner/util/LoggerDelegate.kt | 14 +- .../scanner/util/{env.kt => PrivateEnv.kt} | 2 +- .../main/kotlin/scanner/util/coroutines.kt | 27 ++- .../src/main/kotlin/scanner/util/general.kt | 13 +- scanner/src/test/kotlin/scanner/Sandbox.kt | 2 +- .../processor/GradleModuleProcessorTest.kt | 110 +++++----- .../scanner/processor/PomProcessorTest.kt | 44 ++-- .../test/kotlin/scanner/testutil/resources.kt | 19 +- settings.gradle.kts | 2 +- .../kotlin/kamp/domain/KotlinMPPLibrary.kt | 3 +- .../kotlin/kamp/domain/KotlinTarget.kt | 2 +- .../kotlin/kamp/domain/MavenArtifact.kt | 3 +- src/jvmMain/kotlin/kamp/util/Env.kt | 7 +- versions.properties | 4 +- 62 files changed, 1001 insertions(+), 921 deletions(-) delete mode 100644 .gitlab-ci.yml rename app/src/commonMain/kotlin/app/util/{kodein.kt => DIModule.kt} (81%) rename scanner/src/main/kotlin/scanner/util/{env.kt => PrivateEnv.kt} (91%) diff --git a/.editorconfig b/.editorconfig index 0d58075..cdc2ca9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,6 @@ -[*.{kt,kts}] +root = true + +[*] indent_size = 2 -insert_final_newline = true -max_line_length = 280 -disabled_rules=no-wildcard-imports +continuation_indent_size = 4 +ij_kotlin_name_count_to_use_star_import = unset diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 356ffde..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,131 +0,0 @@ -image: gradle:6.5 - -variables: - # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled - DOCKER_HOST: tcp://docker:2376 - DOCKER_TLS_CERTDIR: "/certs" - GRADLE_OPTS: "-Dorg.gradle.daemon=false" - APP_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:$CI_PIPELINE_ID - SCANNER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE/scanner:$CI_PIPELINE_ID - -before_script: - - export GRADLE_USER_HOME=`pwd`/.gradle - -stages: - - build - - test - - publish - - release - -build: - stage: build - script: - - gradle --build-cache assemble - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull-push - paths: - - .gradle - - build - - app/build - - app/client/build - - scanner/build - -app:test: - stage: test - script: gradle :app:check - needs: - - build - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - app/build - - app/client/build - - .gradle - -app:publish: - stage: publish - image: docker:19.03.12 - services: - - docker:19.03.12-dind - needs: - - build - - app:test - before_script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - script: - - cd app - - docker build -t $APP_RELEASE_IMAGE . - - docker push $APP_RELEASE_IMAGE - artifacts: - name: app - paths: - - app/build/libs/*-all.jar - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - app/build - - app/client/build - - .gradle - -app:release: - stage: release - image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest - variables: - TF_ROOT: $CI_PROJECT_DIR/infra - TF_VAR_docker_registry_username: $CI_REGISTRY_USER - TF_VAR_docker_registry_password: $CI_REGISTRY_PASSWORD - needs: - - app:publish - only: - - master - script: - - cd $TF_ROOT - - export TF_VAR_docker_image_tag=$APP_RELEASE_IMAGE - - gitlab-terraform init - - gitlab-terraform validate - - gitlab-terraform plan - - gitlab-terraform apply - - wget https://kamp.azurewebsites.net - environment: - name: Azure App - url: https://kamp.azurewebsites.net - -scanner:test: - stage: test - script: gradle :scanner:check - needs: - - build - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - scanner/build - - .gradle - -scanner:publish: - stage: publish - image: docker:19.03.12 - services: - - docker:19.03.12-dind - needs: - - build - - scanner:test - before_script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - script: - - cd scanner - - docker build --pull -t $SCANNER_RELEASE_IMAGE . - - docker push $SCANNER_RELEASE_IMAGE - artifacts: - name: scanner - paths: - - scanner/build/libs/*-all.jar - cache: - key: "$CI_COMMIT_REF_NAME" - policy: pull - paths: - - scanner/build - - .gradle diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a5c16cf..c736118 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -96,7 +96,7 @@ afterEvaluate { exclude("META-INF/*.DSA") exclude("META-INF/*.RSA") } - + manifest { attributes( "Main-Class" to mainClassName, @@ -107,7 +107,7 @@ afterEvaluate { "Created-From" to Git.headCommitHash ) } - + inputs.property("mainClassName", mainClassName) inputs.files(classpath) inputs.files(jsBrowserDistribution.outputs) diff --git a/app/src/commonMain/kotlin/app/domain/LibraryCount.kt b/app/src/commonMain/kotlin/app/domain/LibraryCount.kt index 34bb658..8e04357 100644 --- a/app/src/commonMain/kotlin/app/domain/LibraryCount.kt +++ b/app/src/commonMain/kotlin/app/domain/LibraryCount.kt @@ -1,6 +1,6 @@ package app.domain -import kotlinx.serialization.* +import kotlinx.serialization.Serializable @Serializable data class LibraryCount(val count: Long) diff --git a/app/src/commonMain/kotlin/app/domain/PagedResponse.kt b/app/src/commonMain/kotlin/app/domain/PagedResponse.kt index b0be9a6..a748054 100644 --- a/app/src/commonMain/kotlin/app/domain/PagedResponse.kt +++ b/app/src/commonMain/kotlin/app/domain/PagedResponse.kt @@ -1,6 +1,6 @@ package app.domain -import kotlinx.serialization.* +import kotlinx.serialization.Serializable @Serializable data class PagedResponse( diff --git a/app/src/commonMain/kotlin/app/service/LibraryService.kt b/app/src/commonMain/kotlin/app/service/LibraryService.kt index 8db4377..3459ea6 100644 --- a/app/src/commonMain/kotlin/app/service/LibraryService.kt +++ b/app/src/commonMain/kotlin/app/service/LibraryService.kt @@ -1,12 +1,19 @@ package app.service -import app.domain.* -import kamp.domain.* +import app.domain.LibraryCount +import app.domain.PagedResponse +import kamp.domain.KotlinMPPLibrary expect class LibraryService { - suspend fun getAll(page: Int, size: Int = 20, search: String? = null, targets: Set? = null): PagedResponse + suspend fun getAll( + page: Int, + size: Int = 20, + search: String? = null, + targets: Set? = null, + ): PagedResponse + suspend fun getCount(search: String? = null, targets: Set? = null): LibraryCount - + companion object } diff --git a/app/src/commonMain/kotlin/app/util/kodein.kt b/app/src/commonMain/kotlin/app/util/DIModule.kt similarity index 81% rename from app/src/commonMain/kotlin/app/util/kodein.kt rename to app/src/commonMain/kotlin/app/util/DIModule.kt index 9524724..5f4150e 100644 --- a/app/src/commonMain/kotlin/app/util/kodein.kt +++ b/app/src/commonMain/kotlin/app/util/DIModule.kt @@ -1,8 +1,8 @@ package app.util -import org.kodein.di.* -import kotlin.properties.* -import kotlin.reflect.* +import org.kodein.di.DI +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty class DIModule( private val allowSilentOverride: Boolean = false, diff --git a/app/src/jsMain/kotlin/app/config/di.kt b/app/src/jsMain/kotlin/app/config/di.kt index f515ca9..52953be 100644 --- a/app/src/jsMain/kotlin/app/config/di.kt +++ b/app/src/jsMain/kotlin/app/config/di.kt @@ -1,23 +1,29 @@ package app.config -import app.service.* -import app.util.* -import io.ktor.client.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.http.* -import kotlinx.serialization.json.* -import org.kodein.di.* - +import app.service.LibraryService +import app.util.DIModule +import io.ktor.client.HttpClient +import io.ktor.client.features.defaultRequest +import io.ktor.client.features.json.JsonFeature +import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.http.ContentType +import io.ktor.http.contentType +import kotlinx.serialization.json.Json +import org.kodein.di.DI +import org.kodein.di.bind +import org.kodein.di.instance +import org.kodein.di.provider +import org.kodein.di.singleton private val services by DIModule { bind() with provider { LibraryService(instance()) } } val di = DI { - bind() from provider { - Json {} + bind { + provider { + Json {} + } } bind() with singleton { HttpClient { diff --git a/app/src/jsMain/kotlin/app/config/env.kt b/app/src/jsMain/kotlin/app/config/env.kt index 2a2c94c..7e4033a 100644 --- a/app/src/jsMain/kotlin/app/config/env.kt +++ b/app/src/jsMain/kotlin/app/config/env.kt @@ -1,8 +1,8 @@ package app.config -import kotlinx.browser.* -import kotlinx.coroutines.* -import org.w3c.dom.* +import kotlinx.browser.window +import kotlinx.coroutines.await +import org.w3c.dom.Window external interface AppEnv { val API_URL: String diff --git a/app/src/jsMain/kotlin/app/index.kt b/app/src/jsMain/kotlin/app/index.kt index 938adc8..1b57515 100644 --- a/app/src/jsMain/kotlin/app/index.kt +++ b/app/src/jsMain/kotlin/app/index.kt @@ -1,10 +1,12 @@ package app -import app.config.* -import app.store.thunk.* -import app.view.* -import dev.fritz2.dom.html.* -import kotlinx.coroutines.* +import app.config.loadEnv +import app.store.thunk.fetchLibraryCount +import app.store.thunk.fetchLibraryPage +import app.view.App +import dev.fritz2.dom.html.render +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch suspend fun main() = coroutineScope { loadEnv() diff --git a/app/src/jsMain/kotlin/app/service/LibraryService.kt b/app/src/jsMain/kotlin/app/service/LibraryService.kt index f95a0ce..dc4d5ac 100644 --- a/app/src/jsMain/kotlin/app/service/LibraryService.kt +++ b/app/src/jsMain/kotlin/app/service/LibraryService.kt @@ -1,30 +1,36 @@ package app.service -import app.domain.* -import app.util.* -import io.ktor.client.* -import io.ktor.client.request.* -import kamp.domain.* +import app.domain.LibraryCount +import app.domain.PagedResponse +import app.util.toApi +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import kamp.domain.KotlinMPPLibrary actual class LibraryService(private val client: HttpClient) { - actual suspend fun getAll(page: Int, size: Int, search: String?, targets: Set?): PagedResponse { + actual suspend fun getAll( + page: Int, + size: Int, + search: String?, + targets: Set?, + ): PagedResponse { val pagination = "page=$page&size=$size" val searchQuery = search?.let { "search=$it" } ?: "" val targetsQuery = targets?.joinToString(prefix = "target=", separator = "&target=") ?: "" - + return client.get("${path}${buildQuery(pagination, searchQuery, targetsQuery)}".toApi()) } - + actual suspend fun getCount(search: String?, targets: Set?): LibraryCount { val searchQuery = search?.let { "search=$it" } val targetsQuery = targets?.joinToString(prefix = "target=", separator = "&target=") - - return client.get("${path}/count${buildQuery(searchQuery, targetsQuery)}".toApi()) + + return client.get("$path/count${buildQuery(searchQuery, targetsQuery)}".toApi()) } - + private fun buildQuery(vararg query: String?): String { return query.toSet().filterNotNull().takeIf(List::isNotEmpty)?.joinToString("&", prefix = "?") ?: "" } - + actual companion object } diff --git a/app/src/jsMain/kotlin/app/store/LibraryStore.kt b/app/src/jsMain/kotlin/app/store/LibraryStore.kt index bee08f6..9857aa1 100644 --- a/app/src/jsMain/kotlin/app/store/LibraryStore.kt +++ b/app/src/jsMain/kotlin/app/store/LibraryStore.kt @@ -1,9 +1,8 @@ package app.store -import app.domain.* -import dev.fritz2.binding.* -import kamp.domain.* - +import app.domain.PagedResponse +import dev.fritz2.binding.RootStore +import kamp.domain.KotlinMPPLibrary object LibraryStore : RootStore(LibraryState()) { data class LibraryState( @@ -12,17 +11,18 @@ object LibraryStore : RootStore(LibraryState()) { val targets: Set? = null, val count: Long? = null, ) - - val setLibraries = handleAndEmit, PagedResponse> { state, libraries -> - emit(libraries) - state.copy(libraries = libraries) - } - + + val setLibraries = + handleAndEmit, PagedResponse> { state, libraries -> + emit(libraries) + state.copy(libraries = libraries) + } + val setSearch = handleAndEmit { state, search -> emit(search) state.copy(search = search) } - + val setCount = handleAndEmit { state, count -> emit(count) state.copy(count = count) diff --git a/app/src/jsMain/kotlin/app/store/thunk/appThunk.kt b/app/src/jsMain/kotlin/app/store/thunk/appThunk.kt index 39ef241..377d10b 100644 --- a/app/src/jsMain/kotlin/app/store/thunk/appThunk.kt +++ b/app/src/jsMain/kotlin/app/store/thunk/appThunk.kt @@ -1,30 +1,30 @@ package app.store.thunk -import app.config.* -import app.service.* -import app.store.* -import kotlinx.browser.* -import org.kodein.di.* +import app.config.di +import app.service.LibraryService +import app.store.LibraryStore +import kotlinx.browser.window +import org.kodein.di.instance +fun fetchLibraryPage(page: Int, size: Int = 12, search: String? = null, targets: Set? = null) = + LibraryStore.handle { state -> + val theSearch = (search ?: state.search)?.takeIf(String::isNotEmpty) + val theTargets = (targets ?: state.targets)?.takeIf(Set::isNotEmpty) -fun fetchLibraryPage(page: Int, size: Int = 12, search: String? = null, targets: Set? = null) = LibraryStore.handle { state -> - val theSearch = (search ?: state.search)?.takeIf(String::isNotEmpty) - val theTargets = (targets ?: state.targets)?.takeIf(Set::isNotEmpty) - - val service by di.instance() - val libraries = service.getAll(page, size, theSearch, theTargets) - window.scrollTo(0.0, 0.0) - state.copy( - libraries = libraries, - search = theSearch, - targets = theTargets, - ) -} + val service by di.instance() + val libraries = service.getAll(page, size, theSearch, theTargets) + window.scrollTo(0.0, 0.0) + state.copy( + libraries = libraries, + search = theSearch, + targets = theTargets, + ) + } fun fetchLibraryCount(search: String? = null, targets: Set? = null) = LibraryStore.handle { state -> val theSearch = (search ?: state.search)?.takeIf(String::isNotEmpty) val theTargets = (targets ?: state.targets)?.takeIf(Set::isNotEmpty) - + val service by di.instance() val count = service.getCount(theSearch, theTargets).count state.copy( diff --git a/app/src/jsMain/kotlin/app/util/general.kt b/app/src/jsMain/kotlin/app/util/general.kt index 049a997..28eeea3 100644 --- a/app/src/jsMain/kotlin/app/util/general.kt +++ b/app/src/jsMain/kotlin/app/util/general.kt @@ -1,11 +1,15 @@ package app.util -import app.config.* -import app.view.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.params.* -import kotlinx.browser.* -import kotlinx.coroutines.* +import app.config.env +import app.view.KampComponent +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.styling.params.BasicComponent +import dev.fritz2.styling.params.BoxParams +import dev.fritz2.styling.params.styled +import kotlinx.browser.window +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch external fun require(module: String): dynamic @@ -21,7 +25,6 @@ inline fun suspending(crossinline block: suspend CoroutineScope.() -> Unit) { fun String.toApi() = "${window.env.API_URL}/${this.removePrefix("/")}" - typealias StyledComponent = RenderContext.(style: BoxParams.() -> Unit, block: E.() -> Unit) -> E @KampComponent diff --git a/app/src/jsMain/kotlin/app/view/App.kt b/app/src/jsMain/kotlin/app/view/App.kt index 74108de..5a072e6 100644 --- a/app/src/jsMain/kotlin/app/view/App.kt +++ b/app/src/jsMain/kotlin/app/view/App.kt @@ -1,15 +1,16 @@ package app.view -import dev.fritz2.components.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.* +import dev.fritz2.components.stackUp +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.styling.staticStyle @DslMarker annotation class KampComponent @KampComponent fun RenderContext.App() { - staticStyle(""" + staticStyle( + """ /* width */ ::-webkit-scrollbar { width: 0.75rem; @@ -32,7 +33,8 @@ fun RenderContext.App() { ::-webkit-scrollbar-thumb:hover { background: gray; } - """.trimIndent()) + """.trimIndent() + ) stackUp({ height { "100%" } width { "100%" } diff --git a/app/src/jsMain/kotlin/app/view/Content.kt b/app/src/jsMain/kotlin/app/view/Content.kt index ecc6bde..f9bceed 100644 --- a/app/src/jsMain/kotlin/app/view/Content.kt +++ b/app/src/jsMain/kotlin/app/view/Content.kt @@ -1,12 +1,13 @@ package app.view -import app.store.* -import app.util.* -import app.view.component.* -import dev.fritz2.components.* -import dev.fritz2.dom.html.* -import kotlinx.coroutines.flow.* - +import app.store.LibraryStore +import app.util.styled +import app.view.component.LibraryCard +import dev.fritz2.components.gridBox +import dev.fritz2.components.spinner +import dev.fritz2.components.stackUp +import dev.fritz2.dom.html.RenderContext +import kotlinx.coroutines.flow.map @KampComponent fun RenderContext.Content() { diff --git a/app/src/jsMain/kotlin/app/view/Header.kt b/app/src/jsMain/kotlin/app/view/Header.kt index a59250c..52604bd 100644 --- a/app/src/jsMain/kotlin/app/view/Header.kt +++ b/app/src/jsMain/kotlin/app/view/Header.kt @@ -1,22 +1,37 @@ package app.view - -import app.store.* -import app.store.thunk.* -import app.util.* -import app.view.component.* -import dev.fritz2.binding.* -import dev.fritz2.components.* -import dev.fritz2.dom.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.params.* -import kotlinx.coroutines.flow.* +import app.store.LibraryStore +import app.store.thunk.fetchLibraryCount +import app.store.thunk.fetchLibraryPage +import app.util.styled +import app.view.component.Badge +import app.view.component.KampIcon +import app.view.component.Link +import dev.fritz2.binding.storeOf +import dev.fritz2.components.box +import dev.fritz2.components.checkbox +import dev.fritz2.components.clickButton +import dev.fritz2.components.gridBox +import dev.fritz2.components.inputField +import dev.fritz2.components.lineUp +import dev.fritz2.components.modal +import dev.fritz2.components.navBar +import dev.fritz2.components.spinner +import dev.fritz2.components.stackUp +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.dom.states +import dev.fritz2.styling.params.BasicParams +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach @KampComponent -private fun RenderContext.stackUpClose(style: BasicParams.() -> Unit = {}, children: RenderContext.() -> Unit) = stackUp(style) { - spacing { none } - items(children) -} +private fun RenderContext.stackUpClose(style: BasicParams.() -> Unit = {}, children: RenderContext.() -> Unit) = + stackUp(style) { + spacing { none } + items(children) + } @KampComponent private fun RenderContext.SearchModal() = modal({ @@ -25,7 +40,7 @@ private fun RenderContext.SearchModal() = modal({ }) { close -> val searchStore = storeOf("") val targetsStore = storeOf(setOf()) - + @KampComponent fun RenderContext.TargetCheckbox(values: Set, label: RenderContext.() -> Unit = {}) { checkbox { @@ -42,16 +57,19 @@ private fun RenderContext.SearchModal() = modal({ label(label) } } - + @KampComponent fun RenderContext.TargetCheckbox(values: Set, label: String) = TargetCheckbox(values) { label { sub { +label } } } - + @KampComponent - fun RenderContext.TargetCheckboxGroup(targets: kotlin.collections.Map, header: RenderContext.() -> Unit) = stackUpClose { + fun RenderContext.TargetCheckboxGroup( + targets: kotlin.collections.Map, + header: RenderContext.() -> Unit, + ) = stackUpClose { lineUp { spacing { none } items { @@ -62,7 +80,7 @@ private fun RenderContext.SearchModal() = modal({ TargetCheckbox(setOf(value), name) } } - + size { large } content { gridBox({ @@ -93,25 +111,31 @@ private fun RenderContext.SearchModal() = modal({ } }) { stackUpClose { - TargetCheckboxGroup(mapOf( - "common" to "common", - )) { + TargetCheckboxGroup( + mapOf( + "common" to "common", + ) + ) { h4 { +"Metadata" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "jvm" to "jvm", - "android" to "android", - )) { + TargetCheckboxGroup( + mapOf( + "jvm" to "jvm", + "android" to "android", + ) + ) { h4 { +"JVM" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "legacy" to "legacy", - "ir" to "ir", - )) { + TargetCheckboxGroup( + mapOf( + "legacy" to "legacy", + "ir" to "ir", + ) + ) { h4 { +"JS" } } } @@ -125,72 +149,88 @@ private fun RenderContext.SearchModal() = modal({ gap { small } }) { stackUpClose { - TargetCheckboxGroup(mapOf( - "linuxArm32Hfp" to "linux_arm32_hfp", - "linuxArm64" to "linux_arm64", - "linuxMips32" to "linux_mips32", - "linuxMipsel32" to "linux_mipsel32", - "linuxX64" to "linux_x64", - )) { + TargetCheckboxGroup( + mapOf( + "linuxArm32Hfp" to "linux_arm32_hfp", + "linuxArm64" to "linux_arm64", + "linuxMips32" to "linux_mips32", + "linuxMipsel32" to "linux_mipsel32", + "linuxX64" to "linux_x64", + ) + ) { h6 { +"Linux" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "mingwX64" to "mingw_x64", - "mingwX86" to "mingw_x86", - )) { + TargetCheckboxGroup( + mapOf( + "mingwX64" to "mingw_x64", + "mingwX86" to "mingw_x86", + ) + ) { h6 { +"Windows" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "androidNativeX64" to "android_x64", - "androidNativeX86" to "android_x86", - "androidNativeArm32" to "android_arm32", - "androidNativeArm64" to "android_arm64", - )) { + TargetCheckboxGroup( + mapOf( + "androidNativeX64" to "android_x64", + "androidNativeX86" to "android_x86", + "androidNativeArm32" to "android_arm32", + "androidNativeArm64" to "android_arm64", + ) + ) { h6 { +"Android NDK" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "tvosArm64" to "tvos_arm64", - "tvosX64" to "tvos_x64", - )) { + TargetCheckboxGroup( + mapOf( + "tvosArm64" to "tvos_arm64", + "tvosX64" to "tvos_x64", + ) + ) { h6 { +"tvOS" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "iosArm32" to "ios_arm32", - "iosArm64" to "ios_arm64", - "iosX64" to "ios_x64", - )) { + TargetCheckboxGroup( + mapOf( + "iosArm32" to "ios_arm32", + "iosArm64" to "ios_arm64", + "iosX64" to "ios_x64", + ) + ) { h6 { +"iOS" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "watchosArm32" to "watchos_arm32", - "watchosArm64" to "watchos_arm64", - "watchosX86" to "watchos_x86", - "watchosX64" to "watchos_x64", - )) { + TargetCheckboxGroup( + mapOf( + "watchosArm32" to "watchos_arm32", + "watchosArm64" to "watchos_arm64", + "watchosX86" to "watchos_x86", + "watchosX64" to "watchos_x64", + ) + ) { h6 { +"watchOS" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "macosX64" to "macos_x64", - )) { + TargetCheckboxGroup( + mapOf( + "macosX64" to "macos_x64", + ) + ) { h6 { +"macOS" } } } stackUpClose { - TargetCheckboxGroup(mapOf( - "wasm32" to "wasm32", - )) { + TargetCheckboxGroup( + mapOf( + "wasm32" to "wasm32", + ) + ) { h6 { +"WebAssembly" } } } @@ -273,7 +313,7 @@ fun RenderContext.Header() { display { inline } css("border-radius: 50%") } - + styled(::span)({ margins { left { smaller } } verticalAlign { sub } @@ -283,11 +323,14 @@ fun RenderContext.Header() { }) { +"KAMP" } } LibraryStore.data.map { it.count }.render { count -> - Badge({ success }, { - margins { - left { tiny } + Badge( + { success }, + { + margins { + left { tiny } + } } - }) { + ) { if (count != null) { +"$count Lib${if (count > 1) "s" else ""}" } else { @@ -298,7 +341,7 @@ fun RenderContext.Header() { } } } - + actions { lineUp({ display(sm = { none }, md = { flex }) diff --git a/app/src/jsMain/kotlin/app/view/component/Badge.kt b/app/src/jsMain/kotlin/app/view/component/Badge.kt index b5ae574..c3943de 100644 --- a/app/src/jsMain/kotlin/app/view/component/Badge.kt +++ b/app/src/jsMain/kotlin/app/view/component/Badge.kt @@ -1,40 +1,44 @@ package app.view.component -import app.util.* -import app.view.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.params.* -import dev.fritz2.styling.theme.* +import app.util.styled +import app.view.KampComponent +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.dom.html.Span +import dev.fritz2.styling.params.BoxParams +import dev.fritz2.styling.theme.Colors +import dev.fritz2.styling.theme.Property @KampComponent fun RenderContext.Badge( color: (Colors.() -> Property) = { primary.base }, style: BoxParams.() -> Unit = {}, content: Span.() -> Unit = {}, -) = styled(::span)({ - css("border-radius: 0.75rem") - css("background: none repeat scroll 0% 0%") - boxShadow { flat } - display { inlineFlex } - fontWeight { "500" } - minHeight { large } - minWidth { "1.5rem" } - alignItems { center } - justifyContent { spaceAround } - textAlign { center } - paddings { - horizontal { small } - vertical { tiny } - } - textShadow { flat } - fontSize( - sm = { smaller }, - md = { small } - ) - background { - color(color) - } - color { neutral } - style() -}, content) - +) = styled(::span)( + { + css("border-radius: 0.75rem") + css("background: none repeat scroll 0% 0%") + boxShadow { flat } + display { inlineFlex } + fontWeight { "500" } + minHeight { large } + minWidth { "1.5rem" } + alignItems { center } + justifyContent { spaceAround } + textAlign { center } + paddings { + horizontal { small } + vertical { tiny } + } + textShadow { flat } + fontSize( + sm = { smaller }, + md = { small } + ) + background { + color(color) + } + color { neutral } + style() + }, + content +) diff --git a/app/src/jsMain/kotlin/app/view/component/GitHubIcon.kt b/app/src/jsMain/kotlin/app/view/component/GitHubIcon.kt index 5e86b81..bf04a1d 100644 --- a/app/src/jsMain/kotlin/app/view/component/GitHubIcon.kt +++ b/app/src/jsMain/kotlin/app/view/component/GitHubIcon.kt @@ -1,10 +1,10 @@ package app.view.component -import app.view.* -import dev.fritz2.components.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.params.* -import dev.fritz2.styling.theme.* +import app.view.KampComponent +import dev.fritz2.components.icon +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.styling.params.BasicParams +import dev.fritz2.styling.theme.IconDefinition private val gitHubSvg = IconDefinition( displayName = "github", @@ -25,7 +25,7 @@ private val gitHubSvg = IconDefinition( 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z" /> - """.trimIndent() + """.trimIndent() ) @KampComponent diff --git a/app/src/jsMain/kotlin/app/view/component/KampIcon.kt b/app/src/jsMain/kotlin/app/view/component/KampIcon.kt index 437a74b..75cd491 100644 --- a/app/src/jsMain/kotlin/app/view/component/KampIcon.kt +++ b/app/src/jsMain/kotlin/app/view/component/KampIcon.kt @@ -1,9 +1,9 @@ package app.view.component -import app.util.* -import app.view.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.params.* +import app.util.styled +import app.view.KampComponent +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.styling.params.BoxParams @KampComponent fun RenderContext.KampIcon(style: BoxParams.() -> Unit = {}) { diff --git a/app/src/jsMain/kotlin/app/view/component/LibraryCard.kt b/app/src/jsMain/kotlin/app/view/component/LibraryCard.kt index 778c9d8..40bb100 100644 --- a/app/src/jsMain/kotlin/app/view/component/LibraryCard.kt +++ b/app/src/jsMain/kotlin/app/view/component/LibraryCard.kt @@ -1,16 +1,25 @@ package app.view.component -import app.util.* -import app.view.* -import dev.fritz2.binding.* -import dev.fritz2.components.* -import dev.fritz2.dom.html.* -import dev.fritz2.styling.theme.* -import io.ktor.http.* -import io.ktor.util.date.* -import kamp.domain.* -import kotlinx.coroutines.flow.* - +import app.util.styled +import app.view.KampComponent +import dev.fritz2.binding.RootStore +import dev.fritz2.binding.storeOf +import dev.fritz2.components.box +import dev.fritz2.components.clickButton +import dev.fritz2.components.flexBox +import dev.fritz2.components.icon +import dev.fritz2.components.lineUp +import dev.fritz2.components.popover +import dev.fritz2.components.stackUp +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.dom.html.Span +import dev.fritz2.styling.theme.Colors +import dev.fritz2.styling.theme.Property +import io.ktor.http.toHttpDate +import io.ktor.util.date.GMTDate +import kamp.domain.KotlinMPPLibrary +import kamp.domain.KotlinTarget +import kotlinx.coroutines.flow.map private val String.badgeColor: Colors.() -> Property get() = when (this) { @@ -33,16 +42,20 @@ private fun targetPriority(target: String) = when (target) { private fun RenderContext.TargetBadge(category: String, targets: List) { @KampComponent fun RenderContext.RenderBadge(content: Span.() -> Unit) { - Badge(category.badgeColor, { - css("cursor: pointer") - height { large } - margins { - left { tiny } - top { tiny } - } - }, content) + Badge( + category.badgeColor, + { + css("cursor: pointer") + height { large } + margins { + left { tiny } + top { tiny } + } + }, + content + ) } - + if (targets.size > 1) { popover({ width { minContent } @@ -58,7 +71,7 @@ private fun RenderContext.TargetBadge(category: String, targets: List targetPriority(keyA) - targetPriority(keyB) } - + box { box({ display { flex } @@ -215,7 +228,7 @@ private fun RenderContext.CardFooter(library: KotlinMPPLibrary, selectedVersion: margins { top { small } } }) { val selectedPackageManager = storeOf(PackageManager.GRADLE) - + spacing { none } items { lineUp { @@ -269,7 +282,7 @@ private fun RenderContext.CardFooter(library: KotlinMPPLibrary, selectedVersion: domNode.innerText = """| | ${library.group} | ${library.name} - | ${version} + | $version | """.trimMargin() } @@ -283,7 +296,7 @@ private fun RenderContext.CardFooter(library: KotlinMPPLibrary, selectedVersion: @KampComponent fun RenderContext.LibraryCard(library: KotlinMPPLibrary) { val selectedVersionStore = storeOf(library.version) - + box({ border { width { "1px" } diff --git a/app/src/jsMain/kotlin/app/view/component/NavAnchor.kt b/app/src/jsMain/kotlin/app/view/component/NavAnchor.kt index 35aadcd..d3826ef 100644 --- a/app/src/jsMain/kotlin/app/view/component/NavAnchor.kt +++ b/app/src/jsMain/kotlin/app/view/component/NavAnchor.kt @@ -1,8 +1,9 @@ package app.view.component -import app.util.* -import app.view.* -import dev.fritz2.dom.html.* +import app.util.styled +import app.view.KampComponent +import dev.fritz2.dom.html.A +import dev.fritz2.dom.html.RenderContext @KampComponent fun RenderContext.Link(href: String, target: String? = null, block: A.() -> Unit = {}) { diff --git a/app/src/jvmMain/kotlin/app/config/di.kt b/app/src/jvmMain/kotlin/app/config/di.kt index 8da0d06..26a1d50 100644 --- a/app/src/jvmMain/kotlin/app/config/di.kt +++ b/app/src/jvmMain/kotlin/app/config/di.kt @@ -1,13 +1,20 @@ package app.config -import app.service.* -import app.util.* -import io.ktor.application.* -import kamp.domain.* -import org.kodein.di.* -import org.kodein.di.ktor.* -import org.litote.kmongo.coroutine.* -import org.litote.kmongo.reactivestreams.* +import app.service.LibraryService +import app.util.DIModule +import app.util.PrivateEnv +import io.ktor.application.Application +import kamp.domain.KotlinMPPLibrary +import org.kodein.di.bind +import org.kodein.di.instance +import org.kodein.di.ktor.CallScope +import org.kodein.di.ktor.di +import org.kodein.di.scoped +import org.kodein.di.singleton +import org.litote.kmongo.coroutine.CoroutineClient +import org.litote.kmongo.coroutine.CoroutineCollection +import org.litote.kmongo.coroutine.coroutine +import org.litote.kmongo.reactivestreams.KMongo fun Application.diConfig() = di { import(services) @@ -15,6 +22,8 @@ fun Application.diConfig() = di { private val services by DIModule { bind() with singleton { KMongo.createClient(PrivateEnv.MONGO_STRING).coroutine } - bind>() with singleton { instance().getDatabase(PrivateEnv.MONGO_DATABASE).getCollection("libraries") } + bind>() with singleton { + instance().getDatabase(PrivateEnv.MONGO_DATABASE).getCollection("libraries") + } bind() with scoped(CallScope).singleton { LibraryService(context, instance()) } } diff --git a/app/src/jvmMain/kotlin/app/config/features.kt b/app/src/jvmMain/kotlin/app/config/features.kt index 8eabcde..3d1ee3d 100644 --- a/app/src/jvmMain/kotlin/app/config/features.kt +++ b/app/src/jvmMain/kotlin/app/config/features.kt @@ -1,11 +1,19 @@ package app.config -import app.util.* -import io.ktor.application.* -import io.ktor.auth.* -import io.ktor.features.* -import io.ktor.serialization.* -import org.slf4j.event.* +import app.util.PrivateEnv +import io.ktor.application.Application +import io.ktor.application.install +import io.ktor.auth.Authentication +import io.ktor.auth.UserIdPrincipal +import io.ktor.auth.basic +import io.ktor.features.CachingHeaders +import io.ktor.features.CallLogging +import io.ktor.features.Compression +import io.ktor.features.ContentNegotiation +import io.ktor.features.DefaultHeaders +import io.ktor.features.StatusPages +import io.ktor.serialization.json +import org.slf4j.event.Level fun Application.features() { install(CallLogging) { diff --git a/app/src/jvmMain/kotlin/app/config/routing.kt b/app/src/jvmMain/kotlin/app/config/routing.kt index d95facc..2ab62b6 100644 --- a/app/src/jvmMain/kotlin/app/config/routing.kt +++ b/app/src/jvmMain/kotlin/app/config/routing.kt @@ -1,14 +1,30 @@ package app.config -import app.service.* -import app.util.* -import io.ktor.application.* -import io.ktor.auth.* -import io.ktor.http.* -import io.ktor.http.content.* -import io.ktor.request.* -import io.ktor.response.* -import io.ktor.routing.* +import app.service.LibraryService +import app.service.path +import app.util.PublicEnv +import app.util.inject +import app.util.page +import app.util.pageSize +import app.util.search +import app.util.targets +import io.ktor.application.Application +import io.ktor.application.call +import io.ktor.auth.authenticate +import io.ktor.http.HttpStatusCode +import io.ktor.http.content.default +import io.ktor.http.content.defaultResource +import io.ktor.http.content.files +import io.ktor.http.content.resources +import io.ktor.http.content.static +import io.ktor.request.receive +import io.ktor.response.respond +import io.ktor.response.respondText +import io.ktor.routing.Routing +import io.ktor.routing.get +import io.ktor.routing.post +import io.ktor.routing.route +import io.ktor.routing.routing fun Application.routing() = routing { libraries() @@ -18,29 +34,31 @@ fun Application.routing() = routing { } private fun Routing.libraries() = - route(LibraryService.path) { - get { - val service by inject() - call.respond( - service.getAll( - call.request.page, - call.request.pageSize, - call.request.search, - call.request.targets)) - } - get("/count") { - val service by inject() - call.respond(service.getCount(call.request.search, call.request.targets)) - } + route(LibraryService.path) { + get { + val service by inject() + call.respond( + service.getAll( + call.request.page, + call.request.pageSize, + call.request.search, + call.request.targets + ) + ) + } + get("/count") { + val service by inject() + call.respond(service.getCount(call.request.search, call.request.targets)) + } - authenticate { - post { - val service by inject() - val entity = service.create(call.receive()) - call.respond(HttpStatusCode.Created, entity) - } + authenticate { + post { + val service by inject() + val entity = service.create(call.receive()) + call.respond(HttpStatusCode.Created, entity) } } + } private fun Routing.staticContent() = static { val folder = "WEB-INF" diff --git a/app/src/jvmMain/kotlin/app/index.kt b/app/src/jvmMain/kotlin/app/index.kt index 3b295e7..09f20e5 100644 --- a/app/src/jvmMain/kotlin/app/index.kt +++ b/app/src/jvmMain/kotlin/app/index.kt @@ -1,9 +1,12 @@ package app -import app.config.* -import app.util.* -import io.ktor.application.* -import io.ktor.server.cio.* +import app.config.diConfig +import app.config.features +import app.config.routing +import app.util.PublicEnv +import io.ktor.application.Application +import io.ktor.application.log +import io.ktor.server.cio.EngineMain fun main(args: Array) { System.setProperty("jdk.tls.client.protocols", "TLSv1.2") diff --git a/app/src/jvmMain/kotlin/app/service/LibraryService.kt b/app/src/jvmMain/kotlin/app/service/LibraryService.kt index 784e082..81facd2 100644 --- a/app/src/jvmMain/kotlin/app/service/LibraryService.kt +++ b/app/src/jvmMain/kotlin/app/service/LibraryService.kt @@ -1,29 +1,29 @@ package app.service -import app.domain.* -import app.util.* -import io.ktor.application.* -import kamp.domain.* -import org.litote.kmongo.* +import app.domain.LibraryCount +import app.domain.PagedResponse +import app.util.buildNextUrl +import app.util.buildPrevUrl +import io.ktor.application.ApplicationCall +import kamp.domain.KotlinMPPLibrary import org.litote.kmongo.MongoOperator.all import org.litote.kmongo.MongoOperator.and -import org.litote.kmongo.MongoOperator.or -import org.litote.kmongo.MongoOperator.regex -import org.litote.kmongo.coroutine.* +import org.litote.kmongo.MongoOperator.search +import org.litote.kmongo.MongoOperator.text +import org.litote.kmongo.ascending +import org.litote.kmongo.coroutine.CoroutineCollection actual class LibraryService( private val call: ApplicationCall, private val collection: CoroutineCollection, ) { - private fun buildQuery(search: String?, targets: Set?): String { - val searchQuery = search?.let { + private fun buildQuery(_search: String?, targets: Set?): String { + val searchQuery = _search?.let { """ { - $or: [ - {name: {$regex: /$search/i}}, - {group: {$regex: /$search/i}}, - {description: {$regex: /$search/i}}, - ] + $text: { + $search: "searchQuery" + } } """.trimIndent() } @@ -45,9 +45,16 @@ actual class LibraryService( } ?: "{}" return query } - - actual suspend fun getAll(page: Int, size: Int, search: String?, targets: Set?): PagedResponse { - val data = collection.find(buildQuery(search, targets)).sort(ascending(KotlinMPPLibrary::name)).skip(size * (page - 1)).limit(size).toList() + + actual suspend fun getAll( + page: Int, + size: Int, + search: String?, + targets: Set?, + ): PagedResponse { + val data = + collection.find(buildQuery(search, targets)).sort(ascending(KotlinMPPLibrary::name)).skip(size * (page - 1)) + .limit(size).toList() return PagedResponse( data = data, page = page, @@ -55,14 +62,14 @@ actual class LibraryService( prev = call.request.buildPrevUrl() ) } - + actual suspend fun getCount(search: String?, targets: Set?): LibraryCount { return LibraryCount(collection.countDocuments(buildQuery(search, targets))) } - + suspend fun create(library: KotlinMPPLibrary) { collection.save(library) } - + actual companion object } diff --git a/app/src/jvmMain/kotlin/app/util/env.kt b/app/src/jvmMain/kotlin/app/util/env.kt index 1c006c6..dd64881 100644 --- a/app/src/jvmMain/kotlin/app/util/env.kt +++ b/app/src/jvmMain/kotlin/app/util/env.kt @@ -1,7 +1,6 @@ package app.util -import kamp.util.* - +import kamp.util.Env object PrivateEnv : Env() { val MONGO_STRING by EnvDelegate { it ?: "mongodb://localhost:27017" } diff --git a/app/src/jvmMain/kotlin/app/util/kodein.kt b/app/src/jvmMain/kotlin/app/util/kodein.kt index 8ec390c..39bd693 100644 --- a/app/src/jvmMain/kotlin/app/util/kodein.kt +++ b/app/src/jvmMain/kotlin/app/util/kodein.kt @@ -1,13 +1,17 @@ package app.util -import io.ktor.application.* -import io.ktor.util.pipeline.* -import org.kodein.di.* -import org.kodein.di.bindings.* -import org.kodein.di.ktor.* +import io.ktor.application.ApplicationCall +import io.ktor.util.pipeline.PipelineContext +import org.kodein.di.DI +import org.kodein.di.bindings.NoArgBindingDI +import org.kodein.di.contexted +import org.kodein.di.instance +import org.kodein.di.ktor.closestDI +import org.kodein.di.on +import org.kodein.di.provider inline fun DI.Builder.callProvider(noinline creator: NoArgBindingDI.() -> T) = contexted().provider(creator) inline fun PipelineContext.inject(tag: Any? = null) = - di().on(context).instance(tag) + closestDI().on(context).instance(tag) diff --git a/app/src/jvmMain/kotlin/app/util/paging.kt b/app/src/jvmMain/kotlin/app/util/paging.kt index 55dd587..681accb 100644 --- a/app/src/jvmMain/kotlin/app/util/paging.kt +++ b/app/src/jvmMain/kotlin/app/util/paging.kt @@ -1,7 +1,9 @@ package app.util -import io.ktor.http.* -import io.ktor.request.* +import io.ktor.http.URLBuilder +import io.ktor.request.ApplicationRequest +import io.ktor.request.port +import io.ktor.request.uri fun ApplicationRequest.buildNextUrl(currentElementCount: Int): String? = if (currentElementCount == pageSize) { URLBuilder(call.request.uri).apply { diff --git a/build.gradle.kts b/build.gradle.kts index 46dfbc2..ff946ec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,30 +1,33 @@ -import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("multiplatform") id("org.jetbrains.kotlin.plugin.serialization") id("com.github.jakemarsden.git-hooks") - id("com.diffplug.spotless") + id("org.jlleitschuh.gradle.ktlint") idea } -allprojects { - group = "lt.petuska" - version = "0.0.1" - apply(plugin = "idea") - apply(plugin = "com.diffplug.spotless") - - spotless { - kotlin { - ktfmt("0.22") - } - } - idea { - module { - isDownloadSources = true - isDownloadJavadoc = true - } +gitHooks { + setHooks( + mapOf( + "post-checkout" to "ktlintApplyToIdea", + "pre-commit" to "ktlintFormat", + "pre-push" to "check" + ) + ) +} + +idea { + module { + isDownloadSources = true + isDownloadJavadoc = true } +} + +allprojects { + apply(plugin = "org.jlleitschuh.gradle.ktlint") + repositories { mavenCentral() maven("https://jitpack.io") @@ -35,7 +38,6 @@ allprojects { useJUnitPlatform() } withType { - kotlinOptions.jvmTarget = "15" kotlinOptions { useIR = true jvmTarget = "${JavaVersion.VERSION_11}" @@ -44,17 +46,13 @@ allprojects { } } -gitHooks { - setHooks(mapOf("pre-commit" to "spotlessApply", "pre-push" to "check")) -} - kotlin { explicitApi() jvm() js { browser() } - + sourceSets { named("commonMain") { dependencies { diff --git a/gradle.properties b/gradle.properties index b0c478e..48007bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,3 +5,5 @@ kotlin.js.generate.externals=false kotlin.js.compiler=ir kotlin.incremental.js=true org.gradle.project.sourceCompatibility=11 +version=0.0.0 +group=lt.petuska diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da9702f..442d913 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/scanner/build.gradle.kts b/scanner/build.gradle.kts index 2e37317..97b2a0d 100644 --- a/scanner/build.gradle.kts +++ b/scanner/build.gradle.kts @@ -13,7 +13,7 @@ kotlin { implementation("ch.qos.logback:logback-classic:_") implementation(kotlin("reflect")) implementation("org.jetbrains.kotlinx:kotlinx-cli:_") - + testImplementation("io.kotest:kotest-runner-junit5:_") } sourceSets.all { @@ -49,7 +49,7 @@ tasks { exclude("META-INF/*.DSA") exclude("META-INF/*.RSA") } - + manifest { attributes( "Main-Class" to mainClassName, @@ -60,7 +60,7 @@ tasks { "Created-From" to Git.headCommitHash ) } - + inputs.property("mainClassName", mainClassName) inputs.files(classpath) outputs.file(archiveFile) diff --git a/scanner/src/main/kotlin/scanner/client/AnchorClient.kt b/scanner/src/main/kotlin/scanner/client/AnchorClient.kt index babf775..a84a46a 100644 --- a/scanner/src/main/kotlin/scanner/client/AnchorClient.kt +++ b/scanner/src/main/kotlin/scanner/client/AnchorClient.kt @@ -1,16 +1,16 @@ package scanner.client -import kamp.domain.* -import org.jsoup.nodes.* +import kamp.domain.MavenArtifact +import org.jsoup.nodes.Document abstract class AnchorClient( - val url: String, + val url: String, ) : MavenRepositoryClient(url) { abstract fun String.isBackLink(): Boolean override fun parsePage(page: Document): List? = - page.getElementsByTag("a")?.mapNotNull { elm -> - val text = elm.text() - text.takeIf { it.isNotBlank() && !it.isBackLink() } - } + page.getElementsByTag("a")?.mapNotNull { elm -> + val text = elm.text() + text.takeIf { it.isNotBlank() && !it.isBackLink() } + } } diff --git a/scanner/src/main/kotlin/scanner/client/ArtifactoryClient.kt b/scanner/src/main/kotlin/scanner/client/ArtifactoryClient.kt index 441a1ba..68fa97f 100644 --- a/scanner/src/main/kotlin/scanner/client/ArtifactoryClient.kt +++ b/scanner/src/main/kotlin/scanner/client/ArtifactoryClient.kt @@ -1,13 +1,13 @@ package scanner.client -import io.ktor.client.* -import kamp.domain.* -import kotlinx.serialization.json.* +import io.ktor.client.HttpClient +import kamp.domain.MavenArtifactImpl +import kotlinx.serialization.json.Json class ArtifactoryClient( - url: String, - override val client: HttpClient, - override val json: Json, + url: String, + override val client: HttpClient, + override val json: Json, ) : AnchorClient(url) { override fun String.isBackLink(): Boolean = startsWith("..") } diff --git a/scanner/src/main/kotlin/scanner/client/JBossClient.kt b/scanner/src/main/kotlin/scanner/client/JBossClient.kt index 6638e90..c464a4b 100644 --- a/scanner/src/main/kotlin/scanner/client/JBossClient.kt +++ b/scanner/src/main/kotlin/scanner/client/JBossClient.kt @@ -1,13 +1,13 @@ package scanner.client -import io.ktor.client.* -import kamp.domain.* -import kotlinx.serialization.json.* +import io.ktor.client.HttpClient +import kamp.domain.MavenArtifactImpl +import kotlinx.serialization.json.Json class JBossClient( - url: String, - override val client: HttpClient, - override val json: Json, + url: String, + override val client: HttpClient, + override val json: Json, ) : AnchorClient(url) { override fun String.isBackLink(): Boolean = equals("Parent Directory", true) } diff --git a/scanner/src/main/kotlin/scanner/client/MavenRepositoryClient.kt b/scanner/src/main/kotlin/scanner/client/MavenRepositoryClient.kt index 124e954..f9a0904 100644 --- a/scanner/src/main/kotlin/scanner/client/MavenRepositoryClient.kt +++ b/scanner/src/main/kotlin/scanner/client/MavenRepositoryClient.kt @@ -1,19 +1,23 @@ package scanner.client -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.util.date.* -import io.ktor.utils.io.core.* -import kamp.domain.* -import kotlinx.coroutines.* -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import org.jsoup.nodes.* -import scanner.domain.* -import scanner.util.* +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.util.date.GMTDate +import io.ktor.util.date.Month +import io.ktor.utils.io.core.Closeable +import kamp.domain.MavenArtifact +import kamp.domain.MavenArtifactImpl +import kotlinx.coroutines.coroutineScope +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import org.jsoup.nodes.Document +import scanner.domain.GradleModule +import scanner.util.LoggerDelegate +import scanner.util.asDocument +import scanner.util.supervisedAsync abstract class MavenRepositoryClient( - private val defaultRepositoryRootUrl: String, + private val defaultRepositoryRootUrl: String, ) : Closeable { protected abstract fun parsePage(page: Document): List? protected abstract val client: HttpClient @@ -32,25 +36,25 @@ abstract class MavenRepositoryClient( val doc = pom.getElementsByTag("metadata").first() try { val lastUpdated = - doc.selectFirst("versioning>lastUpdated")?.text()?.let { - GMTDate( - year = it.substring(0 until 4).toInt(), - month = Month.from(it.substring(4 until 6).toInt() - 1), - dayOfMonth = it.substring(6 until 8).toInt(), - hours = it.substring(8 until 10).toInt(), - minutes = it.substring(10 until 12).toInt(), - seconds = it.substring(12 until 14).toInt(), - ) - .timestamp - } + doc.selectFirst("versioning>lastUpdated")?.text()?.let { + GMTDate( + year = it.substring(0 until 4).toInt(), + month = Month.from(it.substring(4 until 6).toInt() - 1), + dayOfMonth = it.substring(6 until 8).toInt(), + hours = it.substring(8 until 10).toInt(), + minutes = it.substring(10 until 12).toInt(), + seconds = it.substring(12 until 14).toInt(), + ) + .timestamp + } MavenArtifactImpl( - group = doc.selectFirst("groupId").text(), - name = doc.selectFirst("artifactId").text(), - latestVersion = doc.selectFirst("versioning>latest")?.text() - ?: doc.selectFirst("version").text(), - releaseVersion = doc.selectFirst("versioning>release")?.text(), - versions = doc.selectFirst("versioning>versions")?.children()?.map { v -> v.text() }, - lastUpdated = lastUpdated, + group = doc.selectFirst("groupId").text(), + name = doc.selectFirst("artifactId").text(), + latestVersion = doc.selectFirst("versioning>latest")?.text() + ?: doc.selectFirst("version").text(), + releaseVersion = doc.selectFirst("versioning>release")?.text(), + versions = doc.selectFirst("versioning>versions")?.children()?.map { v -> v.text() }, + lastUpdated = lastUpdated, ) } catch (e: Exception) { if (doc.selectFirst("plugins") == null) { @@ -65,31 +69,33 @@ abstract class MavenRepositoryClient( suspend fun getGradleModule(artifact: A): GradleModule? = coroutineScope { supervisedAsync { - val module = - client.get( - "${artifact.mavenModuleVersionUrl}/${artifact.name}-${artifact.releaseVersion}.module") - json.decodeFromString(module) - } - .await() + val module = + client.get( + "${artifact.mavenModuleVersionUrl}/${artifact.name}-${artifact.releaseVersion}.module" + ) + json.decodeFromString(module) + } + .await() } suspend fun getMavenPom(artifact: A): Document? = coroutineScope { supervisedAsync { - client - .get( - "${artifact.mavenModuleVersionUrl}/${artifact.name}-${artifact.releaseVersion}.pom") - .asDocument() - } - .await() + client + .get( + "${artifact.mavenModuleVersionUrl}/${artifact.name}-${artifact.releaseVersion}.pom" + ) + .asDocument() + } + .await() } suspend fun listRepositoryPath(path: String): List? = coroutineScope { supervisedAsync { - client.get("$defaultRepositoryRootUrl${path.removeSuffix("/")}/").let { str -> - parsePage(str.asDocument())?.map { RepoItem(it, path) } - } - } - .await() + client.get("$defaultRepositoryRootUrl${path.removeSuffix("/")}/").let { str -> + parsePage(str.asDocument())?.map { RepoItem(it, path) } + } + } + .await() } override fun close() = client.close() diff --git a/scanner/src/main/kotlin/scanner/config/di.kt b/scanner/src/main/kotlin/scanner/config/di.kt index 93d8d92..f0a99b0 100644 --- a/scanner/src/main/kotlin/scanner/config/di.kt +++ b/scanner/src/main/kotlin/scanner/config/di.kt @@ -1,22 +1,32 @@ package scanner.config -import io.ktor.client.* -import io.ktor.client.engine.cio.* -import io.ktor.client.features.* -import io.ktor.client.features.auth.* -import io.ktor.client.features.auth.providers.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.request.* -import io.ktor.http.* -import kotlin.time.* -import org.kodein.di.* -import scanner.client.* -import scanner.domain.* -import scanner.domain.Repository.* -import scanner.processor.* -import scanner.service.* -import scanner.util.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.cio.CIO +import io.ktor.client.engine.cio.CIOEngineConfig +import io.ktor.client.features.HttpTimeout +import io.ktor.client.features.auth.Auth +import io.ktor.client.features.auth.providers.basic +import io.ktor.client.features.defaultRequest +import io.ktor.client.features.json.JsonFeature +import io.ktor.client.features.json.serializer.KotlinxSerializer +import io.ktor.client.request.accept +import io.ktor.http.ContentType +import io.ktor.http.contentType +import kotlinx.serialization.json.Json +import org.kodein.di.DI +import org.kodein.di.bind +import org.kodein.di.instance +import org.kodein.di.provider +import org.kodein.di.singleton +import scanner.domain.Repository +import scanner.processor.GradleModuleProcessor +import scanner.processor.PomProcessor +import scanner.service.MavenScannerService +import scanner.service.MavenScannerServiceImpl +import scanner.util.PrivateEnv +import scanner.util.prettyJson +import kotlin.time.minutes fun HttpClientConfig.baseConfig() { val timeout = 2.5.minutes.inMilliseconds.toLong() @@ -36,32 +46,33 @@ fun HttpClientConfig.baseConfig() { val di = DI { Repository.values().forEach { repo -> - bind(repo.alias) from provider { with(repo) { client(url) } } + bind(repo.alias) { provider { with(repo) { client(url) } } } bind>(repo.alias) with - singleton { MavenScannerServiceImpl(instance(repo.alias), instance(), instance()) } + singleton { MavenScannerServiceImpl(instance(repo.alias), instance(), instance()) } } - bind() from - singleton { - kotlinx.serialization.json.Json { - prettyPrint = true - ignoreUnknownKeys = true - } + bind { + singleton { + Json { + prettyPrint = true + ignoreUnknownKeys = true } - bind() from singleton { PomProcessor() } - bind() from singleton { GradleModuleProcessor() } - - bind() from provider { HttpClient(CIO, HttpClientConfig::baseConfig) } - bind("kamp") from - provider { - HttpClient(CIO) { - baseConfig() - install(Auth) { - basic { - username = PrivateEnv.ADMIN_USER - password = PrivateEnv.ADMIN_PASSWORD - } + } + } + bind { singleton { PomProcessor() } } + bind { singleton { GradleModuleProcessor() } } + bind { provider { HttpClient(CIO, HttpClientConfig::baseConfig) } } + bind("kamp") { + provider { + HttpClient(CIO) { + baseConfig() + install(Auth) { + basic { + username = PrivateEnv.ADMIN_USER + password = PrivateEnv.ADMIN_PASSWORD } } } + } + } } diff --git a/scanner/src/main/kotlin/scanner/domain/CLIOptions.kt b/scanner/src/main/kotlin/scanner/domain/CLIOptions.kt index 0d745de..e0341f2 100644 --- a/scanner/src/main/kotlin/scanner/domain/CLIOptions.kt +++ b/scanner/src/main/kotlin/scanner/domain/CLIOptions.kt @@ -1,27 +1,32 @@ package scanner.domain data class CLIOptions( - val scanner: String, - val include: Set?, - val exclude: Set?, - val delayMS: Long?, - val workers: Int?, + val scanner: String, + val include: Set?, + val exclude: Set?, + val delayMS: Long?, + val workers: Int?, ) { constructor( - scanner: String, - include: Set?, - from: Char?, - to: Char?, - exclude: Set?, - delayMS: Long?, - workers: Int?, + scanner: String, + include: Set?, + from: Char?, + to: Char?, + exclude: Set?, + delayMS: Long?, + workers: Int?, ) : this( - scanner, - ((include - ?: setOf()) + - (from?.let { to?.let { (from..to).toSet() } } ?: setOf()).map(Char::toString)) - .takeIf { it.isNotEmpty() }, - exclude, - delayMS, - workers) + scanner, + ( + ( + include + ?: setOf() + ) + + (from?.let { to?.let { (from..to).toSet() } } ?: setOf()).map(Char::toString) + ) + .takeIf { it.isNotEmpty() }, + exclude, + delayMS, + workers + ) } diff --git a/scanner/src/main/kotlin/scanner/domain/GradleModule.kt b/scanner/src/main/kotlin/scanner/domain/GradleModule.kt index 6d0c33b..5577549 100644 --- a/scanner/src/main/kotlin/scanner/domain/GradleModule.kt +++ b/scanner/src/main/kotlin/scanner/domain/GradleModule.kt @@ -1,64 +1,65 @@ package scanner.domain -import kotlinx.serialization.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable @Serializable data class GradleModule( - @SerialName("component") val component: Component? = null, - @SerialName("createdBy") val createdBy: CreatedBy? = null, - @SerialName("formatVersion") val formatVersion: String? = null, - @SerialName("variants") val variants: List? = null, + @SerialName("component") val component: Component? = null, + @SerialName("createdBy") val createdBy: CreatedBy? = null, + @SerialName("formatVersion") val formatVersion: String? = null, + @SerialName("variants") val variants: List? = null, ) { @Serializable data class Component( - @SerialName("url") val url: String? = null, - @SerialName("attributes") val attributes: Attributes? = null, - @SerialName("group") val group: String? = null, - @SerialName("module") val module: String? = null, - @SerialName("version") val version: String? = null, + @SerialName("url") val url: String? = null, + @SerialName("attributes") val attributes: Attributes? = null, + @SerialName("group") val group: String? = null, + @SerialName("module") val module: String? = null, + @SerialName("version") val version: String? = null, ) { @Serializable data class Attributes( - @SerialName("org.gradle.status") val orgGradleStatus: String? = null, + @SerialName("org.gradle.status") val orgGradleStatus: String? = null, ) } @Serializable data class CreatedBy( - @SerialName("gradle") val gradle: Gradle? = null, + @SerialName("gradle") val gradle: Gradle? = null, ) { @Serializable data class Gradle( - @SerialName("buildId") val buildId: String? = null, - @SerialName("version") val version: String? = null, + @SerialName("buildId") val buildId: String? = null, + @SerialName("version") val version: String? = null, ) } @Serializable data class Variant( - @SerialName("attributes") val attributes: Attributes? = null, - @SerialName("available-at") val availableAt: AvailableAt? = null, - @SerialName("name") val name: String? = null, + @SerialName("attributes") val attributes: Attributes? = null, + @SerialName("available-at") val availableAt: AvailableAt? = null, + @SerialName("name") val name: String? = null, ) { @Serializable data class Attributes( - @SerialName("artifactType") val artifactType: String? = null, - @SerialName("org.gradle.usage") val orgGradleUsage: String? = null, - @SerialName("org.jetbrains.kotlin.js.compiler") - val orgJetbrainsKotlinJsCompiler: String? = null, - @SerialName("org.jetbrains.kotlin.native.target") - val orgJetbrainsKotlinNativeTarget: String? = null, - @SerialName("org.jetbrains.kotlin.platform.type") - val orgJetbrainsKotlinPlatformType: String? = null, + @SerialName("artifactType") val artifactType: String? = null, + @SerialName("org.gradle.usage") val orgGradleUsage: String? = null, + @SerialName("org.jetbrains.kotlin.js.compiler") + val orgJetbrainsKotlinJsCompiler: String? = null, + @SerialName("org.jetbrains.kotlin.native.target") + val orgJetbrainsKotlinNativeTarget: String? = null, + @SerialName("org.jetbrains.kotlin.platform.type") + val orgJetbrainsKotlinPlatformType: String? = null, ) @Serializable data class AvailableAt( - @SerialName("group") val group: String? = null, - @SerialName("module") val module: String? = null, - @SerialName("url") val url: String? = null, - @SerialName("version") val version: String? = null, + @SerialName("group") val group: String? = null, + @SerialName("module") val module: String? = null, + @SerialName("url") val url: String? = null, + @SerialName("version") val version: String? = null, ) } } diff --git a/scanner/src/main/kotlin/scanner/domain/Repository.kt b/scanner/src/main/kotlin/scanner/domain/Repository.kt index c32c0b4..beb5347 100644 --- a/scanner/src/main/kotlin/scanner/domain/Repository.kt +++ b/scanner/src/main/kotlin/scanner/domain/Repository.kt @@ -1,36 +1,45 @@ package scanner.domain -import kamp.domain.* -import org.kodein.di.* -import scanner.client.* +import kamp.domain.MavenArtifactImpl +import org.kodein.di.DirectDIAware +import org.kodein.di.instance +import scanner.client.ArtifactoryClient +import scanner.client.JBossClient +import scanner.client.MavenRepositoryClient enum class Repository( - val alias: String, - val url: String, - val client: DirectDIAware.(url: String) -> MavenRepositoryClient, + val alias: String, + val url: String, + val client: DirectDIAware.(url: String) -> MavenRepositoryClient, ) { MAVEN_CENTRAL( - "mavenCentral", - "https://repo1.maven.org/maven2", - { ArtifactoryClient(it, instance(), instance()) }), + "mavenCentral", + "https://repo1.maven.org/maven2", + { ArtifactoryClient(it, instance(), instance()) } + ), GRADLE_PLUGIN_PORTAL( - "gradlePluginPortal", - "https://plugins.gradle.org/m2", - { ArtifactoryClient(it, instance(), instance()) }), + "gradlePluginPortal", + "https://plugins.gradle.org/m2", + { ArtifactoryClient(it, instance(), instance()) } + ), SPRING( - "spring", - "https://repo.spring.io/release", - { ArtifactoryClient(it, instance(), instance()) }), + "spring", + "https://repo.spring.io/release", + { ArtifactoryClient(it, instance(), instance()) } + ), ATLASSIAN( - "atlassian", - "https://packages.atlassian.com/content/repositories/atlassian-public", - { ArtifactoryClient(it, instance(), instance()) }), + "atlassian", + "https://packages.atlassian.com/content/repositories/atlassian-public", + { ArtifactoryClient(it, instance(), instance()) } + ), J_BOSS( - "jBoss", - "https://repository.jboss.org/nexus/content/repositories/releases", - { JBossClient(it, instance(), instance()) }), + "jBoss", + "https://repository.jboss.org/nexus/content/repositories/releases", + { JBossClient(it, instance(), instance()) } + ), HORTON_WORKS( - "hortonWorks", - "https://repo.hortonworks.com/content/repositories/releases", - { JBossClient(it, instance(), instance()) }), + "hortonWorks", + "https://repo.hortonworks.com/content/repositories/releases", + { JBossClient(it, instance(), instance()) } + ), } diff --git a/scanner/src/main/kotlin/scanner/index.kt b/scanner/src/main/kotlin/scanner/index.kt index 031d12d..27797d2 100644 --- a/scanner/src/main/kotlin/scanner/index.kt +++ b/scanner/src/main/kotlin/scanner/index.kt @@ -1,50 +1,61 @@ package scanner -import kotlinx.cli.* -import scanner.config.* -import scanner.domain.* -import scanner.service.* +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.multiple +import scanner.config.di +import scanner.domain.CLIOptions +import scanner.domain.Repository +import scanner.service.Orchestrator suspend fun main(args: Array) { val parser = ArgParser("scanner") val scanner by parser.argument( - type = ArgType.Choice(Repository.values().map(Repository::alias), { it }), - description = "Repository alias to scan for") + type = ArgType.Choice(Repository.values().map(Repository::alias), { it }), + description = "Repository alias to scan for" + ) val from by parser.option( - type = ArgType.Choice(('a'..'z').toList(), { it[0] }), - shortName = "f", - description = "Repository root page filter start") + type = ArgType.Choice(('a'..'z').toList(), { it[0] }), + shortName = "f", + description = "Repository root page filter start" + ) val to by parser.option( - type = ArgType.Choice(('a'..'z').toList(), { it[0] }), - shortName = "t", - description = "Repository root page filter end") + type = ArgType.Choice(('a'..'z').toList(), { it[0] }), + shortName = "t", + description = "Repository root page filter end" + ) val include by parser - .option( - type = ArgType.String, - shortName = "i", - description = "Repository root page filter to include") - .multiple() + .option( + type = ArgType.String, + shortName = "i", + description = "Repository root page filter to include" + ) + .multiple() val exclude by parser - .option( - type = ArgType.String, - shortName = "e", - description = "Repository root page filter to exclude") - .multiple() + .option( + type = ArgType.String, + shortName = "e", + description = "Repository root page filter to exclude" + ) + .multiple() val delay by parser.option( - type = ArgType.Int, shortName = "d", description = "Worker processing delay in milliseconds") + type = ArgType.Int, shortName = "d", description = "Worker processing delay in milliseconds" + ) val workers by parser.option( - type = ArgType.Int, shortName = "w", description = "Concurrent worker count") + type = ArgType.Int, shortName = "w", description = "Concurrent worker count" + ) parser.parse(args) val cliOptions = - CLIOptions( - scanner = scanner, - include = include.toSet().takeIf { it.isNotEmpty() }, - from = from, - to = to, - exclude = exclude.toSet().takeIf { it.isNotEmpty() }, - delayMS = delay?.toLong(), - workers = workers) + CLIOptions( + scanner = scanner, + include = include.toSet().takeIf { it.isNotEmpty() }, + from = from, + to = to, + exclude = exclude.toSet().takeIf { it.isNotEmpty() }, + delayMS = delay?.toLong(), + workers = workers + ) Orchestrator(di).run(scanner, cliOptions) } diff --git a/scanner/src/main/kotlin/scanner/processor/GradleModuleProcessor.kt b/scanner/src/main/kotlin/scanner/processor/GradleModuleProcessor.kt index 53b9ed9..983ef70 100644 --- a/scanner/src/main/kotlin/scanner/processor/GradleModuleProcessor.kt +++ b/scanner/src/main/kotlin/scanner/processor/GradleModuleProcessor.kt @@ -1,7 +1,7 @@ package scanner.processor -import kamp.domain.* -import scanner.domain.* +import kamp.domain.KotlinTarget +import scanner.domain.GradleModule class GradleModuleProcessor { val kotlinVersion: String = "1.4.30" @@ -11,23 +11,23 @@ class GradleModuleProcessor { val GradleModule.supportedTargets get(): Set? = - variants - ?.mapNotNull { variant -> - variant.attributes?.let { attrs -> - when (attrs.orgJetbrainsKotlinPlatformType) { - "common" -> KotlinTarget.Common() - "androidJvm" -> KotlinTarget.JVM.Android() - "jvm" -> KotlinTarget.JVM.Java() - "js" -> - when (attrs.orgJetbrainsKotlinJsCompiler) { - "legacy" -> KotlinTarget.JS.Legacy() - "ir" -> KotlinTarget.JS.IR() - else -> null - } - "native" -> attrs.orgJetbrainsKotlinNativeTarget?.let { KotlinTarget.Native(it) } + variants + ?.mapNotNull { variant -> + variant.attributes?.let { attrs -> + when (attrs.orgJetbrainsKotlinPlatformType) { + "common" -> KotlinTarget.Common() + "androidJvm" -> KotlinTarget.JVM.Android() + "jvm" -> KotlinTarget.JVM.Java() + "js" -> + when (attrs.orgJetbrainsKotlinJsCompiler) { + "legacy" -> KotlinTarget.JS.Legacy() + "ir" -> KotlinTarget.JS.IR() else -> null } - } + "native" -> attrs.orgJetbrainsKotlinNativeTarget?.let { KotlinTarget.Native(it) } + else -> null } - ?.toSet() + } + } + ?.toSet() } diff --git a/scanner/src/main/kotlin/scanner/processor/PomProcessor.kt b/scanner/src/main/kotlin/scanner/processor/PomProcessor.kt index a7ec7d4..ab1f8bd 100644 --- a/scanner/src/main/kotlin/scanner/processor/PomProcessor.kt +++ b/scanner/src/main/kotlin/scanner/processor/PomProcessor.kt @@ -1,6 +1,6 @@ package scanner.processor -import org.jsoup.nodes.* +import org.jsoup.nodes.Document class PomProcessor { val Document.description: String? @@ -11,19 +11,19 @@ class PomProcessor { val Document.scmUrl: String? get() = - selectFirst("project>scm")?.let { - val url = - run { - it.selectFirst("url")?.text() - ?: it.selectFirst("connection")?.text() - ?: it.selectFirst("developerConnection")?.text() - } - ?.trim() + selectFirst("project>scm")?.let { + val url = + run { + it.selectFirst("url")?.text() + ?: it.selectFirst("connection")?.text() + ?: it.selectFirst("developerConnection")?.text() + } + ?.trim() - val path = - url?.trim()?.split("://")?.getOrNull(1) - ?: url?.split("@")?.getOrNull(1)?.replaceFirst(":", "/") + val path = + url?.trim()?.split("://")?.getOrNull(1) + ?: url?.split("@")?.getOrNull(1)?.replaceFirst(":", "/") - path?.removeSuffix(".git")?.removeSuffix("/")?.let { u -> "https://$u.git" } ?: url - } + path?.removeSuffix(".git")?.removeSuffix("/")?.let { u -> "https://$u.git" } ?: url + } } diff --git a/scanner/src/main/kotlin/scanner/service/MavenScannerService.kt b/scanner/src/main/kotlin/scanner/service/MavenScannerService.kt index 21dee25..9163a60 100644 --- a/scanner/src/main/kotlin/scanner/service/MavenScannerService.kt +++ b/scanner/src/main/kotlin/scanner/service/MavenScannerService.kt @@ -1,14 +1,21 @@ package scanner.service -import io.ktor.utils.io.core.* -import kamp.domain.* -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.* -import kotlinx.coroutines.flow.* -import scanner.client.* -import scanner.domain.* -import scanner.processor.* -import scanner.util.* +import io.ktor.utils.io.core.Closeable +import kamp.domain.KotlinMPPLibrary +import kamp.domain.MavenArtifact +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.ReceiveChannel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.receiveAsFlow +import scanner.client.MavenRepositoryClient +import scanner.domain.CLIOptions +import scanner.processor.GradleModuleProcessor +import scanner.processor.PomProcessor +import scanner.util.LoggerDelegate +import scanner.util.supervisedLaunch abstract class MavenScannerService : Closeable { protected val logger by LoggerDelegate() @@ -16,48 +23,49 @@ abstract class MavenScannerService : Closeable { protected abstract val gradleModuleProcessor: GradleModuleProcessor protected abstract val client: MavenRepositoryClient protected abstract fun CoroutineScope.produceArtifacts( - cliOptions: CLIOptions? = null, + cliOptions: CLIOptions? = null, ): ReceiveChannel fun CoroutineScope.scanMavenArtefacts(cliOptions: CLIOptions? = null): Flow = - run { - logger.info( - "Scanning from repository root and filtering by ${cliOptions?.include ?: setOf()}, explicitly excluding ${cliOptions?.exclude ?: setOf()}") - produceArtifacts(cliOptions) - } - .receiveAsFlow() + run { + logger.info( + "Scanning from repository root and filtering by ${cliOptions?.include ?: setOf()}, explicitly excluding ${cliOptions?.exclude ?: setOf()}" + ) + produceArtifacts(cliOptions) + } + .receiveAsFlow() suspend fun scanKotlinLibraries(cliOptions: CLIOptions? = null): Flow = - channelFlow { - val artefactsFlow = scanMavenArtefacts(cliOptions) + channelFlow { + val artefactsFlow = scanMavenArtefacts(cliOptions) - repeat(Runtime.getRuntime().availableProcessors() * 2) { - supervisedLaunch { - artefactsFlow + repeat(Runtime.getRuntime().availableProcessors() * 2) { + supervisedLaunch { + artefactsFlow .mapNotNull { artefact -> client.getGradleModule(artefact)?.let { artefact to it } } .mapNotNull { (artefact, module) -> with(gradleModuleProcessor) { module.supportedTargets - ?.takeIf { module.isRootModule && !it.isNullOrEmpty() } - ?.let { - client.getMavenPom(artefact)?.let { pom -> - with(pomProcessor) { - KotlinMPPLibrary( - targets = it, - artifact = artefact, - description = pom.description, - website = pom.url, - scm = pom.scmUrl, - ) - } + ?.takeIf { module.isRootModule && !it.isNullOrEmpty() } + ?.let { + client.getMavenPom(artefact)?.let { pom -> + with(pomProcessor) { + KotlinMPPLibrary( + targets = it, + artifact = artefact, + description = pom.description, + website = pom.url, + scm = pom.scmUrl, + ) } } + } } } .collect(::send) + } } } - } override fun close() = client.close() } diff --git a/scanner/src/main/kotlin/scanner/service/MavenScannerServiceImpl.kt b/scanner/src/main/kotlin/scanner/service/MavenScannerServiceImpl.kt index a6beab3..3caeb54 100644 --- a/scanner/src/main/kotlin/scanner/service/MavenScannerServiceImpl.kt +++ b/scanner/src/main/kotlin/scanner/service/MavenScannerServiceImpl.kt @@ -1,35 +1,40 @@ package scanner.service -import kamp.domain.* -import kotlin.time.* -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.* -import scanner.client.* -import scanner.domain.* -import scanner.processor.* -import scanner.util.* +import kamp.domain.MavenArtifactImpl +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel +import kotlinx.coroutines.channels.produce +import kotlinx.coroutines.delay +import scanner.client.MavenRepositoryClient +import scanner.domain.CLIOptions +import scanner.processor.GradleModuleProcessor +import scanner.processor.PomProcessor +import scanner.util.supervisedLaunch +import kotlin.time.milliseconds +import kotlin.time.seconds class MavenScannerServiceImpl( - override val client: MavenRepositoryClient, - override val pomProcessor: PomProcessor, - override val gradleModuleProcessor: GradleModuleProcessor, + override val client: MavenRepositoryClient, + override val pomProcessor: PomProcessor, + override val gradleModuleProcessor: GradleModuleProcessor, ) : MavenScannerService() { override fun CoroutineScope.produceArtifacts( - cliOptions: CLIOptions?, + cliOptions: CLIOptions?, ): ReceiveChannel = produce { val pageChannel = Channel>(Channel.BUFFERED) supervisedLaunch { client - .listRepositoryPath("") - ?.filter { repoItem -> - val path = repoItem.path.removePrefix("/") - val included = - cliOptions?.include?.let { filter -> filter.any { path.startsWith(it) } } ?: true - val excluded = - cliOptions?.exclude?.let { filter -> filter.any { path.startsWith(it) } } ?: false - included && !excluded - } - ?.let { pageChannel.send(it) } + .listRepositoryPath("") + ?.filter { repoItem -> + val path = repoItem.path.removePrefix("/") + val included = + cliOptions?.include?.let { filter -> filter.any { path.startsWith(it) } } ?: true + val excluded = + cliOptions?.exclude?.let { filter -> filter.any { path.startsWith(it) } } ?: false + included && !excluded + } + ?.let { pageChannel.send(it) } } // Tracker @@ -55,9 +60,9 @@ class MavenScannerServiceImpl( for (page in pageChannel) { cliOptions?.delayMS?.let { delay(it.milliseconds) } val artifactDetails = - page.find { it.value == "maven-metadata.xml" }?.let { - client.getArtifactDetails(it.path) - } + page.find { it.value == "maven-metadata.xml" }?.let { + client.getArtifactDetails(it.path) + } if (artifactDetails != null) { logger.debug("Found MC artefact ${artifactDetails.group}:${artifactDetails.name}") send(artifactDetails) diff --git a/scanner/src/main/kotlin/scanner/service/Orchestrator.kt b/scanner/src/main/kotlin/scanner/service/Orchestrator.kt index 6bbcc32..00b1dfe 100644 --- a/scanner/src/main/kotlin/scanner/service/Orchestrator.kt +++ b/scanner/src/main/kotlin/scanner/service/Orchestrator.kt @@ -1,15 +1,21 @@ package scanner.service -import io.ktor.client.* -import io.ktor.client.request.* -import kotlin.time.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import org.kodein.di.* -import scanner.domain.* -import scanner.util.* +import io.ktor.client.HttpClient +import io.ktor.client.request.post +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.collect +import kotlinx.serialization.json.Json +import org.kodein.di.DI +import org.kodein.di.DIAware +import org.kodein.di.direct +import org.kodein.di.instance +import org.kodein.di.instanceOrNull +import scanner.domain.CLIOptions +import scanner.util.LoggerDelegate +import scanner.util.PrivateEnv +import scanner.util.supervisedLaunch +import kotlin.time.measureTime class Orchestrator(override val di: DI) : DIAware { private val logger by LoggerDelegate() @@ -27,24 +33,26 @@ class Orchestrator(override val di: DI) : DIAware { logger.info("Starting $scanner scan") val count = scanRepo(scannerService, cliOptions) logger.info( - "Found $count kotlin modules with gradle metadata in $scanner repository filtered by ${cliOptions?.include ?: setOf()}, " + - "explicitly excluding ${cliOptions?.exclude ?: setOf()}") + "Found $count kotlin modules with gradle metadata in $scanner repository filtered by ${cliOptions?.include ?: setOf()}, " + + "explicitly excluding ${cliOptions?.exclude ?: setOf()}" + ) } } } logger.info( - "Finished scanning $scanner in ${ - duration.toComponents { hours, minutes, seconds, nanoseconds -> - "${hours}h ${minutes}m ${seconds}.${nanoseconds}s" - } - }") + "Finished scanning $scanner in ${ + duration.toComponents { hours, minutes, seconds, nanoseconds -> + "${hours}h ${minutes}m $seconds.${nanoseconds}s" + } + }" + ) } - ?: logger.error("ScannerService for $scanner not found") + ?: logger.error("ScannerService for $scanner not found") } private suspend fun scanRepo( - scanner: MavenScannerService<*>, - cliOptions: CLIOptions? = null, + scanner: MavenScannerService<*>, + cliOptions: CLIOptions? = null, ): Int { var count = 0 val kamp by di.instance("kamp") diff --git a/scanner/src/main/kotlin/scanner/util/LoggerDelegate.kt b/scanner/src/main/kotlin/scanner/util/LoggerDelegate.kt index eda79a4..793d9e1 100644 --- a/scanner/src/main/kotlin/scanner/util/LoggerDelegate.kt +++ b/scanner/src/main/kotlin/scanner/util/LoggerDelegate.kt @@ -1,17 +1,17 @@ package scanner.util -import kotlin.properties.* -import kotlin.reflect.* -import kotlin.reflect.full.* -import org.slf4j.* +import org.slf4j.Logger import org.slf4j.LoggerFactory.getLogger +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty +import kotlin.reflect.full.companionObject class LoggerDelegate : ReadOnlyProperty { override fun getValue(thisRef: R, property: KProperty<*>): Logger { val javaClass = - thisRef.javaClass.let { java -> - java.enclosingClass?.takeIf { it.kotlin.companionObject?.java == javaClass } ?: java - } + thisRef.javaClass.let { java -> + java.enclosingClass?.takeIf { it.kotlin.companionObject?.java == javaClass } ?: java + } return getLogger(javaClass.name) } } diff --git a/scanner/src/main/kotlin/scanner/util/env.kt b/scanner/src/main/kotlin/scanner/util/PrivateEnv.kt similarity index 91% rename from scanner/src/main/kotlin/scanner/util/env.kt rename to scanner/src/main/kotlin/scanner/util/PrivateEnv.kt index abc64ea..1ea097a 100644 --- a/scanner/src/main/kotlin/scanner/util/env.kt +++ b/scanner/src/main/kotlin/scanner/util/PrivateEnv.kt @@ -1,6 +1,6 @@ package scanner.util -import kamp.util.* +import kamp.util.Env object PrivateEnv : Env() { val API_URL by EnvDelegate { it ?: "http://localhost:8080" } diff --git a/scanner/src/main/kotlin/scanner/util/coroutines.kt b/scanner/src/main/kotlin/scanner/util/coroutines.kt index bea714f..3462bda 100644 --- a/scanner/src/main/kotlin/scanner/util/coroutines.kt +++ b/scanner/src/main/kotlin/scanner/util/coroutines.kt @@ -1,20 +1,25 @@ package scanner.util -import io.ktor.client.features.* -import io.ktor.http.* -import kotlinx.coroutines.* +import io.ktor.client.features.ClientRequestException +import io.ktor.http.HttpStatusCode +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope fun CoroutineScope.supervisedAsync(block: suspend CoroutineScope.() -> R): Deferred = - async { - try { - supervisorScope(block) - } catch (e: Exception) { - if (e !is ClientRequestException || e.response.status != HttpStatusCode.NotFound) { - e.printStackTrace() + async { + try { + supervisorScope(block) + } catch (e: Exception) { + if (e !is ClientRequestException || e.response.status != HttpStatusCode.NotFound) { + e.printStackTrace() + } + null } - null } -} fun CoroutineScope.supervisedLaunch(block: suspend CoroutineScope.() -> R): Job = launch { try { diff --git a/scanner/src/main/kotlin/scanner/util/general.kt b/scanner/src/main/kotlin/scanner/util/general.kt index 3d5841f..219485e 100644 --- a/scanner/src/main/kotlin/scanner/util/general.kt +++ b/scanner/src/main/kotlin/scanner/util/general.kt @@ -1,11 +1,10 @@ package scanner.util -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.* -import kotlinx.serialization.json.* -import org.jsoup.* -import org.jsoup.nodes.* -import scanner.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import org.jsoup.Jsoup +import org.jsoup.nodes.Document val rawJson = Json { ignoreUnknownKeys = true } val prettyJson = Json { @@ -14,4 +13,4 @@ val prettyJson = Json { } suspend fun String.asDocument(): Document = - withContext(Dispatchers.IO) { Jsoup.parse(this@asDocument) } + withContext(Dispatchers.IO) { Jsoup.parse(this@asDocument) } diff --git a/scanner/src/test/kotlin/scanner/Sandbox.kt b/scanner/src/test/kotlin/scanner/Sandbox.kt index 3d44826..58e1a6e 100644 --- a/scanner/src/test/kotlin/scanner/Sandbox.kt +++ b/scanner/src/test/kotlin/scanner/Sandbox.kt @@ -1,5 +1,5 @@ package scanner -import io.kotest.core.spec.style.* +import io.kotest.core.spec.style.FunSpec class Sandbox : FunSpec({ test("sandbox") {} }) diff --git a/scanner/src/test/kotlin/scanner/processor/GradleModuleProcessorTest.kt b/scanner/src/test/kotlin/scanner/processor/GradleModuleProcessorTest.kt index bb2a2d0..ab4de71 100644 --- a/scanner/src/test/kotlin/scanner/processor/GradleModuleProcessorTest.kt +++ b/scanner/src/test/kotlin/scanner/processor/GradleModuleProcessorTest.kt @@ -1,65 +1,65 @@ package scanner.processor -import io.kotest.core.spec.style.* -import io.kotest.matchers.* -import io.kotest.matchers.collections.* -import kamp.domain.* -import scanner.domain.* -import scanner.testutil.* +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.shouldBe +import kamp.domain.KotlinTarget +import scanner.domain.GradleModule +import scanner.testutil.parseJsonFile class GradleModuleProcessorTest : - FunSpec({ - val module = parseJsonFile("presenter-middleware-0.2.10.module") + FunSpec({ + val module = parseJsonFile("presenter-middleware-0.2.10.module") - test("isRootModule") { - with(GradleModuleProcessor()) { - module.isRootModule shouldBe true - module.copy(component = module.component?.copy(url = "http")).isRootModule shouldBe false - } + test("isRootModule") { + with(GradleModuleProcessor()) { + module.isRootModule shouldBe true + module.copy(component = module.component?.copy(url = "http")).isRootModule shouldBe false } + } - test("listSupportedTargets") { - with(GradleModuleProcessor()) { - val targets = module.supportedTargets + test("listSupportedTargets") { + with(GradleModuleProcessor()) { + val targets = module.supportedTargets - targets shouldContainExactlyInAnyOrder - setOf( - KotlinTarget.JVM.Android(), - KotlinTarget.JVM.Java(), - KotlinTarget.JVM.Java(), - KotlinTarget.Native("ios_arm64"), - KotlinTarget.Native("ios_arm64"), - KotlinTarget.Native("ios_x64"), - KotlinTarget.Common(), - ) + targets shouldContainExactlyInAnyOrder + setOf( + KotlinTarget.JVM.Android(), + KotlinTarget.JVM.Java(), + KotlinTarget.JVM.Java(), + KotlinTarget.Native("ios_arm64"), + KotlinTarget.Native("ios_arm64"), + KotlinTarget.Native("ios_x64"), + KotlinTarget.Common(), + ) - val targets1 = parseJsonFile("redux-kotlin-0.5.5.module").supportedTargets - targets1 shouldContainExactlyInAnyOrder - setOf( - KotlinTarget.Native("android_arm32"), - KotlinTarget.Native("android_arm64"), - KotlinTarget.Native("ios_arm32"), - KotlinTarget.Native("ios_arm64"), - KotlinTarget.Native("ios_x64"), - KotlinTarget.Native("watchos_x86"), - KotlinTarget.Native("watchos_arm64"), - KotlinTarget.Native("watchos_arm32"), - KotlinTarget.Native("wasm32"), - KotlinTarget.Native("tvos_x64"), - KotlinTarget.Native("tvos_arm64"), - KotlinTarget.Native("mingw_x86"), - KotlinTarget.Native("mingw_x64"), - KotlinTarget.Native("macos_x64"), - KotlinTarget.Native("linux_x64"), - KotlinTarget.Native("linux_mipsel32"), - KotlinTarget.Native("linux_mips32"), - KotlinTarget.Native("linux_arm64"), - KotlinTarget.Native("linux_arm32_hfp"), - KotlinTarget.Common(), - KotlinTarget.JVM.Java(), - KotlinTarget.JS.IR(), - KotlinTarget.JS.Legacy(), - ) - } + val targets1 = parseJsonFile("redux-kotlin-0.5.5.module").supportedTargets + targets1 shouldContainExactlyInAnyOrder + setOf( + KotlinTarget.Native("android_arm32"), + KotlinTarget.Native("android_arm64"), + KotlinTarget.Native("ios_arm32"), + KotlinTarget.Native("ios_arm64"), + KotlinTarget.Native("ios_x64"), + KotlinTarget.Native("watchos_x86"), + KotlinTarget.Native("watchos_arm64"), + KotlinTarget.Native("watchos_arm32"), + KotlinTarget.Native("wasm32"), + KotlinTarget.Native("tvos_x64"), + KotlinTarget.Native("tvos_arm64"), + KotlinTarget.Native("mingw_x86"), + KotlinTarget.Native("mingw_x64"), + KotlinTarget.Native("macos_x64"), + KotlinTarget.Native("linux_x64"), + KotlinTarget.Native("linux_mipsel32"), + KotlinTarget.Native("linux_mips32"), + KotlinTarget.Native("linux_arm64"), + KotlinTarget.Native("linux_arm32_hfp"), + KotlinTarget.Common(), + KotlinTarget.JVM.Java(), + KotlinTarget.JS.IR(), + KotlinTarget.JS.Legacy(), + ) } - }) + } + }) diff --git a/scanner/src/test/kotlin/scanner/processor/PomProcessorTest.kt b/scanner/src/test/kotlin/scanner/processor/PomProcessorTest.kt index efad2e2..f3f1cca 100644 --- a/scanner/src/test/kotlin/scanner/processor/PomProcessorTest.kt +++ b/scanner/src/test/kotlin/scanner/processor/PomProcessorTest.kt @@ -1,32 +1,32 @@ package scanner.processor -import io.kotest.core.spec.style.* -import io.kotest.matchers.* -import scanner.testutil.* +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import scanner.testutil.parseXmlFile class PomProcessorTest : - FunSpec({ - val pom = parseXmlFile("presenter-middleware-0.2.10.pom") + FunSpec({ + val pom = parseXmlFile("presenter-middleware-0.2.10.pom") - test("getDescription") { - with(PomProcessor()) { - val description = pom.description - description shouldBe - "Presenter middleware for updating views based on selectors & reselect for Redux-Kotlin. Mulitiplatform supported." - } + test("getDescription") { + with(PomProcessor()) { + val description = pom.description + description shouldBe + "Presenter middleware for updating views based on selectors & reselect for Redux-Kotlin. Mulitiplatform supported." } + } - test("getUrl") { - with(PomProcessor()) { - val description = pom.url - description shouldBe "https://github.com/reduxkotlin/presenter-middleware/" - } + test("getUrl") { + with(PomProcessor()) { + val description = pom.url + description shouldBe "https://github.com/reduxkotlin/presenter-middleware/" } + } - test("getScmUrl") { - with(PomProcessor()) { - val description = pom.scmUrl - description shouldBe "https://github.com/reduxkotlin/presenter-middleare.git" - } + test("getScmUrl") { + with(PomProcessor()) { + val description = pom.scmUrl + description shouldBe "https://github.com/reduxkotlin/presenter-middleare.git" } - }) + } + }) diff --git a/scanner/src/test/kotlin/scanner/testutil/resources.kt b/scanner/src/test/kotlin/scanner/testutil/resources.kt index be9519c..5715945 100644 --- a/scanner/src/test/kotlin/scanner/testutil/resources.kt +++ b/scanner/src/test/kotlin/scanner/testutil/resources.kt @@ -1,17 +1,18 @@ package scanner.testutil -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import org.jsoup.* +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import org.jsoup.Jsoup inline fun Any.parseJsonFile(path: String) = - this::class.java.classLoader.getResourceAsStream(path).let { - Json { ignoreUnknownKeys = true }.decodeFromString(it.reader().use { r -> r.readText() }) - } + this::class.java.classLoader.getResourceAsStream(path).let { + Json { ignoreUnknownKeys = true }.decodeFromString(it.reader().use { r -> r.readText() }) + } fun Any.parseJsonFile(path: String) = parseJsonFile(path) fun Any.parseXmlFile(path: String) = - this::class.java.classLoader.getResourceAsStream(path).let { - Jsoup.parse(it.reader().use { r -> r.readText() }) - } + this::class.java.classLoader.getResourceAsStream(path).let { + Jsoup.parse(it.reader().use { r -> r.readText() }) + } diff --git a/settings.gradle.kts b/settings.gradle.kts index 4e4482f..32bbef9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,4 @@ -import de.fayard.refreshVersions.* +import de.fayard.refreshVersions.bootstrapRefreshVersions buildscript { repositories { diff --git a/src/commonMain/kotlin/kamp/domain/KotlinMPPLibrary.kt b/src/commonMain/kotlin/kamp/domain/KotlinMPPLibrary.kt index fd27a86..0eb8f78 100644 --- a/src/commonMain/kotlin/kamp/domain/KotlinMPPLibrary.kt +++ b/src/commonMain/kotlin/kamp/domain/KotlinMPPLibrary.kt @@ -1,6 +1,7 @@ package kamp.domain -import kotlinx.serialization.* +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient @Serializable public data class KotlinMPPLibrary( diff --git a/src/commonMain/kotlin/kamp/domain/KotlinTarget.kt b/src/commonMain/kotlin/kamp/domain/KotlinTarget.kt index b403e89..f7551c2 100644 --- a/src/commonMain/kotlin/kamp/domain/KotlinTarget.kt +++ b/src/commonMain/kotlin/kamp/domain/KotlinTarget.kt @@ -1,6 +1,6 @@ package kamp.domain -import kotlinx.serialization.* +import kotlinx.serialization.Serializable @Serializable public class KotlinTarget private constructor( diff --git a/src/commonMain/kotlin/kamp/domain/MavenArtifact.kt b/src/commonMain/kotlin/kamp/domain/MavenArtifact.kt index fcf8e4e..12ad2a7 100644 --- a/src/commonMain/kotlin/kamp/domain/MavenArtifact.kt +++ b/src/commonMain/kotlin/kamp/domain/MavenArtifact.kt @@ -1,6 +1,7 @@ package kamp.domain -import kotlinx.serialization.* +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient public interface MavenArtifact { public val group: String diff --git a/src/jvmMain/kotlin/kamp/util/Env.kt b/src/jvmMain/kotlin/kamp/util/Env.kt index 1290ca6..a0e7921 100644 --- a/src/jvmMain/kotlin/kamp/util/Env.kt +++ b/src/jvmMain/kotlin/kamp/util/Env.kt @@ -1,8 +1,9 @@ package kamp.util -import kotlin.properties.* -import kotlin.reflect.* -import kotlin.reflect.full.* +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.memberProperties public abstract class Env { protected class EnvDelegate(private val converter: EnvDelegate<*>.(String?) -> T) : ReadOnlyProperty { diff --git a/versions.properties b/versions.properties index 25363f9..029e419 100644 --- a/versions.properties +++ b/versions.properties @@ -5,10 +5,10 @@ ## Generated by $ ./gradlew refreshVersions ## Please, don't put extra comments in that file yet, keeping them is not supported yet. -plugin.com.diffplug.spotless=5.11.1 - plugin.com.github.jakemarsden.git-hooks=0.0.2 +plugin.org.jlleitschuh.gradle.ktlint=10.0.0 + version.ch.qos.logback..logback-classic=1.2.3 ## # available=1.3.0-alpha0 ## # available=1.3.0-alpha1