From 21862ef8476eecf034a5f75411ca4fe83d5a4013 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Thu, 19 Dec 2019 18:51:38 +0300 Subject: [PATCH] Refactor framework tests --- backend.native/tests/build.gradle | 242 ++++++------------ .../org/jetbrains/kotlin/ExecutorService.kt | 3 +- .../org/jetbrains/kotlin/FrameworkTest.kt | 108 +++++--- .../jetbrains/kotlin/KonanTestExecutable.kt | 5 + .../org/jetbrains/kotlin/KotlinNativeTest.kt | 24 +- .../main/kotlin/org/jetbrains/kotlin/Utils.kt | 25 +- 6 files changed, 186 insertions(+), 221 deletions(-) diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index dc4fc43a48d..dc018afc94b 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -365,7 +365,7 @@ Task linkTest(String name, Closure configureClosure) { extraOpts task.flags extraOpts project.globalTestArgs } - UtilsKt.dependOnKonanBuildingTask(project, lib, target, task) + UtilsKt.dependsOnKonanBuildingTask(task, lib, target) // Build an executable with library program(name, targets: [targetName]) { @@ -397,8 +397,9 @@ Task dynamicTest(String name, Closure configureClosure) { extraOpts task.flags extraOpts project.globalTestArgs } - UtilsKt.dependsOnDist(project, "compileKonan${name.capitalize()}${targetName.capitalize()}") } + def buildTask = UtilsKt.findKonanBuildTask(project, name, target) + UtilsKt.dependsOnDist(buildTask) } } } @@ -3548,7 +3549,7 @@ Task interopTestBase(String name, boolean multiFile, Closure c if (task.enabled) { konanArtifacts { def lib = task.interop - UtilsKt.dependOnKonanBuildingTask(project, lib, target, task) + UtilsKt.dependsOnKonanBuildingTask(task, lib, target) program(name, targets: [target.name]) { libraries { @@ -4015,12 +4016,46 @@ standaloneTest("fake_override_0") { goldValue = "Moved\nMoved\nChild\nSuper\n" } +Task frameworkTest(String name, Closure configurator) { + return KotlinNativeTestKt.createTest(project, name, FrameworkTest) { task -> + task.configure(configurator) + if (task.enabled) { + konanArtifacts { + task.frameworks.forEach { fr -> + framework(fr.name, targets: [target.name]) { + fr.sources.forEach { src -> + srcFiles src + } + baseDir "$testOutputFramework/${task.testName}" + + if (fr.library != null) { + libraries { + file konanArtifacts[fr.library].getArtifactByTarget(target.name) + } + linkerOpts "-L$buildDir" + UtilsKt.dependsOnKonanBuildingTask(task, fr.library, target) + } + + if (!useCustomDist) { + dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' + } + + extraOpts fr.bitcode ? "-Xembed-bitcode" : "-Xembed-bitcode-marker" + extraOpts fr.opts + extraOpts project.globalTestArgs + + artifactName fr.artifact + } + } + } + } + } +} + if (isAppleTarget(project)) { - task testObjCExport(type: FrameworkTest) { + frameworkTest('testObjCExport') { final String frameworkName = 'Kt' testName = "ObjCExport" - frameworkNames = [frameworkName] - final String dir = "$testOutputFramework/$testName" final File lazyHeader = file("$dir/$target-lazy.h") @@ -4046,8 +4081,8 @@ if (isAppleTarget(project)) { } + def libraryName = frameworkName + "Library" konanArtifacts { - def libraryName = frameworkName + "Library" library(libraryName, targets: [target.name]) { srcDir "objcexport/library" artifactName "test-library" @@ -4059,45 +4094,18 @@ if (isAppleTarget(project)) { extraOpts "-Xshort-module-name=MyLibrary" extraOpts "-module-name", "org.jetbrains.kotlin.native.test-library" } - - framework(frameworkName, targets: [target.name]) { - srcFiles fileTree("objcexport") { - include "*.kt" - } - baseDir dir - - if (!useCustomDist) { - dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' - } - - dependsOn konanArtifacts[libraryName].getByTarget(target.name) - libraries { - file konanArtifacts[libraryName].getArtifactByTarget(target.name) - } - - extraOpts "-Xembed-bitcode-marker" - extraOpts "-Xemit-lazy-objc-header=$lazyHeader" - extraOpts project.globalTestArgs - } } - swiftSources = fileTree('objcexport') { - include '*.swift' - }*.absolutePath + it.createFramework(frameworkName, ['objcexport'], false, + frameworkName, libraryName, ["-Xemit-lazy-objc-header=$lazyHeader"]) + swiftSources = ['objcexport'] } - task testObjCExportStatic(type: FrameworkTest) { + frameworkTest('testObjCExportStatic') { final String frameworkName = 'KtStatic' final String frameworkArtifactName = 'Kt' - testName = "ObjCExportStatic" - frameworkNames = [frameworkName] - frameworkArtifactNames = [frameworkArtifactName] - - codesign = false - - final String dir = "$testOutputFramework/$testName" + final String libraryName = frameworkName + "Library" konanArtifacts { - def libraryName = frameworkName + "Library" library(libraryName, targets: [target.name]) { srcDir "objcexport/library" artifactName "test-library" @@ -4109,146 +4117,47 @@ if (isAppleTarget(project)) { extraOpts "-Xshort-module-name=MyLibrary" extraOpts "-module-name", "org.jetbrains.kotlin.native.test-library" } - - framework(frameworkName, targets: [target.name]) { - srcFiles fileTree("objcexport") { - include "*.kt" - } - baseDir dir - - if (!useCustomDist) { - dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' - } - - dependsOn konanArtifacts[libraryName].getByTarget(target.name) - libraries { - file konanArtifacts[libraryName].getArtifactByTarget(target.name) - } - - extraOpts "-Xembed-bitcode-marker" - extraOpts "-Xstatic-framework" - extraOpts project.globalTestArgs - - artifactName frameworkArtifactName - } } - swiftSources = fileTree('objcexport') { - include '*.swift' - }*.absolutePath + + testName = "ObjCExportStatic" + codesign = false + it.createFramework(frameworkName, ['objcexport'], false, frameworkArtifactName, libraryName, ['-Xstatic-framework']) + swiftSources = ['objcexport'] } - task testValuesGenericsFramework(type: FrameworkTest) { - final String frameworkName = 'ValuesGenerics' - testName = frameworkName - frameworkNames = [frameworkName] - konanArtifacts { - framework(frameworkName, targets: [ target ]) { - srcFiles 'objcexport/values.kt' - srcDir 'framework/values_generics' - baseDir "$testOutputFramework/$testName" - - if (!useCustomDist) { - dependsOn ":${target}CrossDistRuntime", ':distCompiler' - } - - extraOpts "-Xembed-bitcode-marker" - extraOpts project.globalTestArgs - } - } - swiftSources = ['framework/values_generics/values.swift'] + frameworkTest('testValuesGenericsFramework') { + testName = 'ValuesGenerics' + it.createFramework('ValuesGenerics', ['objcexport/values.kt', 'framework/values_generics']) + swiftSources = ['framework/values_generics/'] } - task testStdlibFramework(type: FrameworkTest) { - final String frameworkName = 'Stdlib' - testName = frameworkName - frameworkNames = [frameworkName] + frameworkTest("testStdlibFramework") { + testName = 'Stdlib' + it.createFramework('Stdlib', ['framework/stdlib'], true) if (cacheTesting == null) fullBitcode = true - konanArtifacts { - framework(frameworkName, targets: [target.name]) { - srcDir 'framework/stdlib' - baseDir "$testOutputFramework/$testName" - - if (!useCustomDist) { - dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' - } - - extraOpts "-Xembed-bitcode" - extraOpts project.globalTestArgs - } - } - swiftSources = ['framework/stdlib/stdlib.swift'] + swiftSources = ['framework/stdlib/'] } if (cacheTesting != null && cacheTesting.isDynamic) { // testMultipleFrameworks disabled until https://youtrack.jetbrains.com/issue/KT-34262 is fixed. - } else task testMultipleFrameworks(type: FrameworkTest) { + } else frameworkTest("testMultipleFrameworks") { testName = "MultipleFrameworks" - final String firstFrameworkName = 'First' - final String secondFrameworkName = 'Second' - frameworkNames = [firstFrameworkName, secondFrameworkName] - - final String dir = "$testOutputFramework/$testName" - - konanArtifacts { - framework(firstFrameworkName, targets: [target.name]) { - srcDir 'framework/multiple/framework1' - srcDir 'framework/multiple/shared' - baseDir dir - - if (!useCustomDist) { - dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' - } - - extraOpts "-Xembed-bitcode" - extraOpts project.globalTestArgs - } - - framework(secondFrameworkName, targets: [target.name]) { - srcDir 'framework/multiple/framework2' - srcDir 'framework/multiple/shared' - baseDir dir - - if (!useCustomDist) { - dependsOn ":${target.name}CrossDistRuntime", ':distCompiler' - } - - extraOpts "-Xembed-bitcode" - extraOpts project.globalTestArgs - } - } - swiftSources = ['framework/multiple/multiple.swift'] + it.createFramework('First', + ['framework/multiple/framework1', 'framework/multiple/shared'], + true // bitcode + ) + it.createFramework('Second', + ['framework/multiple/framework2', 'framework/multiple/shared'], + true // bitcode + ) + swiftSources = ['framework/multiple'] } - task testGh3343Framework(type: FrameworkTest) { - final String frameworkName = 'Gh3343' - testName = frameworkName - frameworkNames = [frameworkName] - - def mainTask = it - - konanArtifacts { - def lib = "objcGh3343" - UtilsKt.dependOnKonanBuildingTask(project, lib, target, mainTask) - - framework(frameworkName, targets: [ target ]) { - libraries { - artifact lib - } - srcDir 'framework/gh3343' - baseDir "$testOutputFramework/$testName" - - if (!useCustomDist) { - dependsOn ":${target}CrossDistRuntime", ':distCompiler' - } - - linkerOpts "-L$buildDir" - extraOpts "-Xembed-bitcode-marker" - extraOpts project.globalTestArgs - } - } - swiftSources = ['framework/gh3343/uselib.swift'] + frameworkTest("testGh3343Framework") { + testName = 'Gh3343' + it.createFramework('Gh3343', ['framework/gh3343'], false, 'Gh3343', 'objcGh3343') + swiftSources = ['framework/gh3343/'] } - } /** @@ -4453,7 +4362,8 @@ task buildKonanTests { t -> // Set build dependencies. dependsOn compileKonanLocalTest - UtilsKt.dependsOnDist(project, "compileKonanLocalTest${target.name.capitalize()}") + def buildTask = UtilsKt.findKonanBuildTask(project, "localTest", target) + UtilsKt.dependsOnDist(buildTask) // Local tests build into a single binary should depend on this task project.tasks diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/ExecutorService.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/ExecutorService.kt index 4145953766d..cd9acf57247 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/ExecutorService.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/ExecutorService.kt @@ -501,7 +501,8 @@ fun KonanTestExecutable.configureXcodeBuild() { // Create a Frameworks folder inside the build dir. it += "mkdir -p \"\$TARGET_BUILD_DIR/\$FRAMEWORKS_FOLDER_PATH\"" // Copy each framework to the Frameworks dir. - it += frameworkArtifactNames.map { name -> + it += frameworks.map { framework -> + val name = framework.artifact "cp -r \"$testOutput/$testName/${project.testTarget.name}/$name.framework\" " + "\"\$TARGET_BUILD_DIR/\$FRAMEWORKS_FOLDER_PATH/$name.framework\"" } diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/FrameworkTest.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/FrameworkTest.kt index 0720d374f8e..4cc63573f36 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/FrameworkTest.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/FrameworkTest.kt @@ -4,10 +4,14 @@ import groovy.lang.Closure import org.gradle.api.Action import org.gradle.api.DefaultTask import org.gradle.api.Task +import org.gradle.api.file.FileCollection +import org.gradle.api.file.FileTree import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction +import org.gradle.language.base.plugins.LifecycleBasePlugin import org.jetbrains.kotlin.konan.target.* +import java.io.File import java.io.FileWriter import java.nio.file.Files @@ -21,7 +25,7 @@ import java.nio.file.Paths * * @property swiftSources Swift-language test sources that use a given framework * @property testName test name - * @property frameworkNames names of frameworks + * @property frameworks names of frameworks */ open class FrameworkTest : DefaultTask(), KonanTestExecutable { @Input @@ -31,10 +35,7 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { lateinit var testName: String @Input - lateinit var frameworkNames: List - - @Input - lateinit var frameworkArtifactNames: List + lateinit var frameworks: MutableList @Input var fullBitcode: Boolean = false @@ -44,6 +45,56 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { val testOutput: String = project.testOutputFramework + /** + * Framework description. + * @param name is the framework name, + * @param sources framework sources, + * @param bitcode bitcode embedding in the framework, + * @param artifact the name of the resulting artifact, + * @param library library dependency name, + * @param opts additional options for the compiler. + */ + data class Framework( + val name: String, + val sources: List, + val bitcode: Boolean = false, + val artifact: String = name, + val library: String? = null, + val opts: List = emptyList() + ) + + @JvmOverloads + fun createFramework(name: String, + sources: List, + bitcode: Boolean = false, + artifact: String = name, + library: String? = null, + opts: List = emptyList() + ) = Framework( + name, + sources.toFiles(Language.Kotlin).map { it.path }, + bitcode, artifact, library, opts + ).also { + if (!::frameworks.isInitialized) { + frameworks = mutableListOf(it) + } else { + frameworks.add(it) + } + } + + enum class Language(val extension: String) { + Kotlin(".kt"), ObjC(".m"), Swift(".swift") + } + + fun Language.filesFrom(dir: String): FileTree = project.fileTree(dir) { + // include only files with + it.include("*${this.extension}") + } + + fun List.toFiles(language: Language): List = + this.map { language.filesFrom(it) } + .flatMap { it.files } + override val executable: String get() { check(::testName.isInitialized) { "Test name should be set" } @@ -54,38 +105,31 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { override var doBeforeBuild: Action? = null + override val buildTasks: List + get() = frameworks.map { project.tasks.getByName("compileKonan${it.name}") } + + @Suppress("UnstableApiUsage") override fun configure(config: Closure<*>): Task { super.configure(config) - val target = project.testTarget.name - // set crossdist build dependency if custom konan.home wasn't set - if (!(project.property("useCustomDist") as Boolean)) { - setRootDependency("${target}CrossDist", "${target}CrossDistRuntime", "distCompiler") - } + this.dependsOnDist() + + // Set Gradle properties for the better navigation + group = LifecycleBasePlugin.VERIFICATION_GROUP + description = "Kotlin/Native test infrastructure task" + check(::testName.isInitialized) { "Test name should be set" } - check(::frameworkNames.isInitialized) { "Framework names should be set" } + check(::frameworks.isInitialized) { "Frameworks should be set" } - if (!::frameworkArtifactNames.isInitialized) { - frameworkArtifactNames = frameworkNames - } - - frameworkNames.forEach { frameworkName -> - val compileTask = project.tasks.getByName("compileKonan$frameworkName") - doBeforeBuild?.let { compileTask.doFirst(it) } - dependsOn(compileTask) - } - // Build test executable as a first action of the task before executing the test - this.doFirst { buildTestExecutable() } return this } - private fun setRootDependency(vararg s: String) = s.forEach { dependsOn(project.rootProject.tasks.getByName(it)) } - private fun buildTestExecutable() { val frameworkParentDirPath = "$testOutput/$testName/${project.testTarget.name}" - frameworkArtifactNames.forEach { frameworkName -> - val frameworkPath = "$frameworkParentDirPath/$frameworkName.framework" - val frameworkBinaryPath = "$frameworkPath/$frameworkName" + frameworks.forEach { framework -> + val frameworkArtifact = framework.artifact + val frameworkPath = "$frameworkParentDirPath/$frameworkArtifact.framework" + val frameworkBinaryPath = "$frameworkPath/$frameworkArtifact" validateBitcodeEmbedding(frameworkBinaryPath) if (codesign) codesign(project, frameworkPath) } @@ -93,8 +137,8 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { // create a test provider and get main entry point val provider = Paths.get(testOutput, testName, "provider.swift") FileWriter(provider.toFile()).use { writer -> - val providers = swiftSources - .map { Paths.get(it).fileName.toString().removeSuffix(".swift").capitalize() } + val providers = swiftSources.toFiles(Language.Swift) + .map { it.name.toString().removeSuffix(".swift").capitalize() } .map { "${it}Tests" } writer.write(""" @@ -109,8 +153,8 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { val swiftMain = Paths.get(testHome.toString(), "main.swift").toString() // Compile swift sources - val sources = swiftSources.map { Paths.get(it).toString() } + - listOf(provider.toString(), swiftMain) + val sources = swiftSources.toFiles(Language.Swift) + .map { it.path } + listOf(provider.toString(), swiftMain) val options = listOf( "-g", "-Xlinker", "-rpath", "-Xlinker", "@executable_path/Frameworks", @@ -123,6 +167,8 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable { @TaskAction fun run() { + // Build test executable as a first action of the task before executing the test + buildTestExecutable() doBeforeRun?.execute(this) runTest(executorService = project.executor, testExecutable = Paths.get(executable)) } diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KonanTestExecutable.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KonanTestExecutable.kt index 5e1a5cfae24..32c7a518f8c 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KonanTestExecutable.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KonanTestExecutable.kt @@ -25,4 +25,9 @@ interface KonanTestExecutable : Task { * or as its `doFirst` action. */ var doBeforeBuild: Action? + + /** + * Build tasks that this [executable] depends on, or is built from. + */ + val buildTasks: List } \ No newline at end of file diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt index 097395d4386..7a69db2502f 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt @@ -78,6 +78,9 @@ abstract class KonanTest : DefaultTask(), KonanTestExecutable { @Input @Optional override var doBeforeRun: Action? = null + override val buildTasks: List + get() = listOf(project.findKonanBuildTask(name, project.testTarget)) + @Suppress("UnstableApiUsage") override fun configure(config: Closure<*>): Task { super.configure(config) @@ -117,20 +120,19 @@ abstract class KonanTest : DefaultTask(), KonanTestExecutable { /** * Create a test task of the given type. Supports configuration with Closure passed form build.gradle file. */ -fun Project.createTest(name: String, type: Class, config: Closure<*>): T = +fun Project.createTest(name: String, type: Class, config: Closure<*>): T = project.tasks.create(name, type).apply { // Apply closure set in build.gradle to get all parameters. this.configure(config) if (enabled) { - // Configure test task. - val target = project.testTarget - // If run task depends on something, compile task should also depend on this. - val compileTask = project.tasks.getByName("compileKonan${name.capitalize()}${target.name.capitalize()}") - compileTask.sameDependenciesAs(this) - // Run task should depend on compile task - this.dependsOn(compileTask) - doBeforeBuild?.let { compileTask.doFirst(it) } - compileTask.enabled = enabled + // If run task depends on something, build tasks should also depend on this. + buildTasks.forEach { buildTask -> + buildTask.sameDependenciesAs(this) + // Run task should depend on compile task + this.dependsOn(buildTask) + doBeforeBuild?.let { buildTask.doFirst(it) } + buildTask.enabled = enabled + } } } @@ -177,7 +179,7 @@ open class KonanGTest : KonanTest() { .apply { if (find()) fail(group(1).toInt()) } if (total == 0) { // No test were run. Try to find if we've tried to run something - this.error(Pattern.compile("\\[={10}] Running ([0-9]*) tests from ([0-9]*) test cases\\..*") + error(Pattern.compile("\\[={10}] Running ([0-9]*) tests from ([0-9]*) test cases\\..*") .matcher(output) .run { if (find()) group(1).toInt() else 1 }) } diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/Utils.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/Utils.kt index d32c3035a0f..9892faef254 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/Utils.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/Utils.kt @@ -12,8 +12,6 @@ import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.konan.properties.saveProperties import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.library.KLIB_PROPERTY_NATIVE_TARGETS -import java.io.FileInputStream -import java.io.IOException import java.io.File import java.util.concurrent.TimeUnit import java.net.HttpURLConnection @@ -99,6 +97,9 @@ fun Project.getFilesToCompile(compile: List, exclude: List): Lis //region Task dependency. +fun Project.findKonanBuildTask(artifact: String, target: KonanTarget): Task = + tasks.getByName("compileKonan${artifact.capitalize()}${target.name.capitalize()}") + fun Project.dependsOnDist(taskName: String) { project.tasks.getByName(taskName).dependsOnDist() } @@ -111,7 +112,7 @@ fun Task.dependsOnDist() { val target = project.testTarget if (target != HostManager.host) { // if a test_target property is set then tests should depend on a crossDist - // otherwise runtime components would not be build for a target. + // otherwise, runtime components would not be build for a target. dependsOn(rootTasks.getByName("${target.name}CrossDist")) } } @@ -134,14 +135,14 @@ fun Task.sameDependenciesAs(task: Task) { } /** - * Set dependency on [lib] built by the Konan Plugin for the [task], - * also make [lib] depend on `dist` and all dependencies of the [task] to make [lib] execute before the [task]. + * Set dependency on [artifact] built by the Konan Plugin for the receiver task, + * also make [artifact] depend on `dist` and all dependencies of the task to make [artifact] execute before the task. */ -fun Project.dependOnKonanBuildingTask(lib: String, target: KonanTarget, task: Task) { - val libTask = "compileKonan${lib.capitalize()}${target.name.capitalize()}" - this.dependsOnDist(libTask) - libTask.sameDependenciesAs(task) - task.dependsOn(libTask) +fun Task.dependsOnKonanBuildingTask(artifact: String, target: KonanTarget) { + val buildTask = project.findKonanBuildTask(artifact, target) + buildTask.dependsOnDist() + buildTask.sameDependenciesAs(this) + dependsOn(buildTask) } //endregion @@ -210,7 +211,7 @@ fun getBuild(buildLocator: String, user: String, password: String) = fun sendGetRequest(url: String, username: String? = null, password: String? = null) : String { val connection = URL(url).openConnection() as HttpURLConnection if (username != null && password != null) { - val auth = Base64.getEncoder().encode((username + ":" + password).toByteArray()).toString(Charsets.UTF_8) + val auth = Base64.getEncoder().encode(("$username:$password").toByteArray()).toString(Charsets.UTF_8) connection.addRequestProperty("Authorization", "Basic $auth") } connection.setRequestProperty("Accept", "application/json"); @@ -318,4 +319,4 @@ fun Project.mergeManifestsByTargets(source: File, destination: File) { destinationProperties[KLIB_PROPERTY_NATIVE_TARGETS] = mergedNativeTargets.joinToString(" ") destinationFile.saveProperties(destinationProperties) -} +} \ No newline at end of file