From 11143e4ba1c2a7e7f4a0059cdf8e62d0b4de9269 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 7 Mar 2022 16:12:01 +0300 Subject: [PATCH] 0.5.3-dev-4 --- CHANGELOG.md | 1 + build.gradle.kts | 2 +- .../data/GoalExecutionRestriction.kt | 14 ++++ .../kscience/dataforge/data/GoalLogger.kt | 3 + dataforge-io/build.gradle.kts | 2 +- .../space/kscience/dataforge/io/Binary.kt | 18 +++++ .../space/kscience/dataforge/io/ioMisc.kt | 57 +++++++++++++-- .../space/kscience/dataforge/io/fileIO.kt | 40 +++++------ .../space/kscience/dataforge/io/resourceIO.kt | 9 +++ .../space/kscience/dataforge/meta/Scheme.kt | 2 +- .../kscience/dataforge/meta/Specification.kt | 3 +- .../meta/descriptors/MetaDescriptorBuilder.kt | 5 +- .../dataforge/workspace/ContextGoalLogger.kt | 4 ++ .../kscience/dataforge/workspace/Task.kt | 69 +++++++++++++++++-- .../dataforge/workspace/WorkspaceBuilder.kt | 31 ++++++++- gradle.properties | 5 +- settings.gradle.kts | 28 +++++++- 17 files changed, 248 insertions(+), 45 deletions(-) create mode 100644 dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/resourceIO.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 16af39ea..599556c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added - Add `specOrNull` delegate to meta and Scheme +- Suspended read methods to the `Binary` ### Changed - `Factory` is now `fun interface` and uses `build` instead of `invoke`. `invoke moved to an extension. diff --git a/build.gradle.kts b/build.gradle.kts index 574b51bc..93588123 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { allprojects { group = "space.kscience" - version = "0.5.3-dev-1" + version = "0.5.3-dev-4" repositories{ mavenCentral() } diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalExecutionRestriction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalExecutionRestriction.kt index f8ce5a83..81f53a91 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalExecutionRestriction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalExecutionRestriction.kt @@ -3,11 +3,25 @@ package space.kscience.dataforge.data import kotlin.coroutines.CoroutineContext public enum class GoalExecutionRestrictionPolicy { + /** + * Allow eager execution + */ NONE, + + /** + * Give warning on eager execution + */ WARNING, + + /** + * Throw error on eager execution + */ ERROR } +/** + * A special coroutine context key that allows or disallows goal execution during configuration time (eager execution). + */ public class GoalExecutionRestriction( public val policy: GoalExecutionRestrictionPolicy = GoalExecutionRestrictionPolicy.ERROR, ) : CoroutineContext.Element { diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalLogger.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalLogger.kt index f8b89b97..604bcb1d 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalLogger.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GoalLogger.kt @@ -2,6 +2,9 @@ package space.kscience.dataforge.data import kotlin.coroutines.CoroutineContext +/** + * Coroutine context element that provides logging capabilities + */ public interface GoalLogger : CoroutineContext.Element { override val key: CoroutineContext.Key<*> get() = GoalLogger diff --git a/dataforge-io/build.gradle.kts b/dataforge-io/build.gradle.kts index cb5d3c1a..4bc7f276 100644 --- a/dataforge-io/build.gradle.kts +++ b/dataforge-io/build.gradle.kts @@ -18,7 +18,7 @@ kotlin { commonMain { dependencies { api(project(":dataforge-context")) - api("io.ktor:ktor-io:${ru.mipt.npm.gradle.KScienceVersions.ktorVersion}") + api(npmlibs.ktor.io) } } } diff --git a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/Binary.kt b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/Binary.kt index 54353a15..7473b783 100644 --- a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/Binary.kt +++ b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/Binary.kt @@ -12,12 +12,15 @@ public interface Binary { public val size: Int + /** * Read maximum of [atMost] bytes as input from the binary, starting at [offset]. The generated input is always closed * when leaving scope, so it could not be leaked outside of scope of [block]. */ public fun read(offset: Int = 0, atMost: Int = size - offset, block: Input.() -> R): R + public suspend fun readSuspend(offset: Int = 0, atMost: Int = size - offset, block: suspend Input.() -> R): R + public companion object { public val EMPTY: Binary = ByteArrayBinary(ByteArray(0)) } @@ -39,6 +42,21 @@ internal class ByteArrayBinary( ) return input.use(block) } + + override suspend fun readSuspend(offset: Int, atMost: Int, block: suspend Input.() -> R): R { + require(offset >= 0) { "Offset must be positive" } + require(offset < array.size) { "Offset $offset is larger than array size" } + val input = ByteReadPacket( + array, + offset + start, + min(atMost, size - offset) + ) + return try { + block(input) + } finally { + input.close() + } + } } public fun ByteArray.asBinary(): Binary = ByteArrayBinary(this) diff --git a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt index e0255530..5895380e 100644 --- a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt +++ b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt @@ -3,6 +3,8 @@ package space.kscience.dataforge.io import io.ktor.utils.io.charsets.Charsets import io.ktor.utils.io.charsets.decodeExactBytes import io.ktor.utils.io.core.* +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.misc.DFExperimental import kotlin.math.min public fun Output.writeRawString(str: String) { @@ -41,11 +43,58 @@ public class BinaryView(private val source: Binary, private val start: Int, over require(start + size <= source.size) { "View boundary is outside source binary size" } } - override fun read(offset: Int, atMost: Int, block: Input.() -> R): R { - return source.read(start + offset, min(size, atMost), block) - } + override fun read(offset: Int, atMost: Int, block: Input.() -> R): R = + source.read(start + offset, min(size, atMost), block) + + override suspend fun readSuspend(offset: Int, atMost: Int, block: suspend Input.() -> R): R = + source.readSuspend(start + offset, min(size, atMost), block) } public fun Binary.view(start: Int, size: Int): BinaryView = BinaryView(this, start, size) -public operator fun Binary.get(range: IntRange): BinaryView = view(range.first, range.last - range.first) \ No newline at end of file +public operator fun Binary.get(range: IntRange): BinaryView = view(range.first, range.last - range.first) + +/** + * Return inferred [EnvelopeFormat] if only one format could read given file. If no format accepts the binary, return null. If + * multiple formats accepts binary, throw an error. + */ +public fun IOPlugin.peekBinaryEnvelopeFormat(binary: Binary): EnvelopeFormat? { + val formats = envelopeFormatFactories.mapNotNull { factory -> + factory.peekFormat(this@peekBinaryEnvelopeFormat, binary) + } + + return when (formats.size) { + 0 -> null + 1 -> formats.first() + else -> error("Envelope format binary recognition clash: $formats") + } +} + +/** + * Zero-copy read this binary as an envelope using given [this@toEnvelope] + */ +@DFExperimental +public fun EnvelopeFormat.readBinary(binary: Binary): Envelope { + val partialEnvelope: PartialEnvelope = binary.read { + run { + readPartial(this@read) + } + } + val offset: Int = partialEnvelope.dataOffset.toInt() + val size: Int = partialEnvelope.dataSize?.toInt() ?: (binary.size - offset) + val envelopeBinary = BinaryView(binary, offset, size) + return SimpleEnvelope(partialEnvelope.meta, envelopeBinary) +} + +/** + * A zero-copy read from + */ +@DFExperimental +public fun IOPlugin.readEnvelopeBinary( + binary: Binary, + readNonEnvelopes: Boolean = false, + formatPicker: IOPlugin.(Binary) -> EnvelopeFormat? = IOPlugin::peekBinaryEnvelopeFormat, +): Envelope = formatPicker(binary)?.readBinary(binary) ?: if (readNonEnvelopes) { + // if no format accepts file, read it as binary + SimpleEnvelope(Meta.EMPTY, binary) +} else error("Can't infer format for $binary") \ No newline at end of file diff --git a/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt index 05296047..1b600200 100644 --- a/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt +++ b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt @@ -2,6 +2,7 @@ package space.kscience.dataforge.io import io.ktor.utils.io.core.* import io.ktor.utils.io.streams.asOutput +import kotlinx.coroutines.runBlocking import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.isEmpty @@ -9,7 +10,6 @@ import space.kscience.dataforge.misc.DFExperimental import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardOpenOption -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.inputStream import kotlin.math.min import kotlin.reflect.full.isSupertypeOf @@ -23,8 +23,11 @@ internal class PathBinary( override val size: Int = Files.size(path).toInt() - fileOffset, ) : Binary { - @OptIn(ExperimentalPathApi::class) - override fun read(offset: Int, atMost: Int, block: Input.() -> R): R { + override fun read(offset: Int, atMost: Int, block: Input.() -> R): R = runBlocking { + readSuspend(offset, atMost, block) + } + + override suspend fun readSuspend(offset: Int, atMost: Int, block: suspend Input.() -> R): R { val actualOffset = offset + fileOffset val actualSize = min(atMost, size - offset) val array = path.inputStream().use { @@ -69,15 +72,14 @@ public fun Path.rewrite(block: Output.() -> Unit): Unit { stream.asOutput().use(block) } -public fun Path.readEnvelope(format: EnvelopeFormat): Envelope { - val partialEnvelope: PartialEnvelope = asBinary().read { - format.run { - readPartial(this@read) - } +@DFExperimental +public fun EnvelopeFormat.readFile(path: Path): Envelope { + val partialEnvelope: PartialEnvelope = path.asBinary().read { + readPartial(this@read) } val offset: Int = partialEnvelope.dataOffset.toInt() - val size: Int = partialEnvelope.dataSize?.toInt() ?: (Files.size(this).toInt() - offset) - val binary = PathBinary(this, offset, size) + val size: Int = partialEnvelope.dataSize?.toInt() ?: (Files.size(path).toInt() - offset) + val binary = PathBinary(path, offset, size) return SimpleEnvelope(partialEnvelope.meta, binary) } @@ -110,10 +112,8 @@ public fun IOPlugin.readMetaFile( val extension = actualPath.fileName.toString().substringAfterLast('.') val metaFormat = formatOverride ?: resolveMetaFormat(extension) ?: error("Can't resolve meta format $extension") - return metaFormat.run { - actualPath.read { - readMeta(this, descriptor) - } + return actualPath.read { + metaFormat.readMeta(this, descriptor) } } @@ -145,15 +145,7 @@ public fun IOPlugin.writeMetaFile( */ public fun IOPlugin.peekFileEnvelopeFormat(path: Path): EnvelopeFormat? { val binary = path.asBinary() - val formats = envelopeFormatFactories.mapNotNull { factory -> - factory.peekFormat(this@peekFileEnvelopeFormat, binary) - } - - return when (formats.size) { - 0 -> null - 1 -> formats.first() - else -> error("Envelope format binary recognition clash: $formats") - } + return peekBinaryEnvelopeFormat(binary) } public val IOPlugin.Companion.META_FILE_NAME: String get() = "@meta" @@ -204,7 +196,7 @@ public fun IOPlugin.readEnvelopeFile( } return formatPicker(path)?.let { format -> - path.readEnvelope(format) + format.readFile(path) } ?: if (readNonEnvelopes) { // if no format accepts file, read it as binary SimpleEnvelope(Meta.EMPTY, path.asBinary()) } else error("Can't infer format for file $path") diff --git a/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/resourceIO.kt b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/resourceIO.kt new file mode 100644 index 00000000..f1997d21 --- /dev/null +++ b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/resourceIO.kt @@ -0,0 +1,9 @@ +package space.kscience.dataforge.io + +import io.ktor.utils.io.core.Input +import io.ktor.utils.io.streams.asInput + +public fun IOPlugin.resource(name: String): Binary? = context.javaClass.getResource(name)?.readBytes()?.asBinary() + +public inline fun IOPlugin.readResource(name: String, block: Input.() -> R): R = + context.javaClass.getResource(name)?.openStream()?.asInput()?.block() ?: error("Can't read resource $name") \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt index fa829d29..c04c136d 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt @@ -154,7 +154,7 @@ public inline fun T.copy(spec: SchemeSpec, block: T.() -> Unit = */ public open class SchemeSpec( private val builder: () -> T, -) : Specification, Described { +) : Specification { override fun read(source: Meta): T = builder().also { it.wrap(MutableMeta().withDefault(source)) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt index 4cac7c72..6d3afbea 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt @@ -1,12 +1,13 @@ package space.kscience.dataforge.meta +import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty -public interface ReadOnlySpecification { +public interface ReadOnlySpecification: Described { /** * Read generic read-only meta with this [Specification] producing instance of desired type. diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt index d123bb54..b0e45b67 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt @@ -10,7 +10,7 @@ import space.kscience.dataforge.values.ValueType import space.kscience.dataforge.values.asValue import kotlin.collections.set -public class MetaDescriptorBuilder internal constructor() { +public class MetaDescriptorBuilder @PublishedApi internal constructor() { public var info: String? = null public var children: MutableMap = linkedMapOf() public var multiple: Boolean = false @@ -78,6 +78,7 @@ public class MetaDescriptorBuilder internal constructor() { allowedValues = values.map { Value.of(it) } } + @PublishedApi internal fun build(): MetaDescriptor = MetaDescriptor( info = info, children = children.mapValues { it.value.build() }, @@ -93,7 +94,7 @@ public class MetaDescriptorBuilder internal constructor() { public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder = item(Name.parse(name), block) -public fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor = +public inline fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor = MetaDescriptorBuilder().apply(block).build() /** diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/ContextGoalLogger.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/ContextGoalLogger.kt index 22273878..e1eb652d 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/ContextGoalLogger.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/ContextGoalLogger.kt @@ -6,6 +6,10 @@ import space.kscience.dataforge.context.info import space.kscience.dataforge.context.logger import space.kscience.dataforge.data.GoalLogger +/** + * A coroutine context key that injects a [Context] bound logger into the scope. + * The message body is computed asynchronously + */ public class ContextGoalLogger(public val context: Context) : GoalLogger { override fun emit(vararg tags: String, message: suspend () -> String) { context.launch { diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt index dcf63db2..75c411ce 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt @@ -5,15 +5,20 @@ import space.kscience.dataforge.data.DataSetBuilder import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.GoalExecutionRestriction import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MetaRepr +import space.kscience.dataforge.meta.Specification import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.Type import space.kscience.dataforge.names.Name import space.kscience.dataforge.workspace.Task.Companion.TYPE import kotlin.reflect.KType import kotlin.reflect.typeOf +/** + * A configurable task that could be executed on a workspace. The [TaskResult] represents a lazy result of the task. + * In general no computations should be made until the result is called. + */ @Type(TYPE) public interface Task : Described { @@ -32,7 +37,26 @@ public interface Task : Described { } } -public class TaskResultBuilder( +/** + * A [Task] with [Specification] for wrapping and unwrapping task configuration + */ +public interface TaskWithSpec : Task { + public val spec: Specification + override val descriptor: MetaDescriptor? get() = spec.descriptor + + public suspend fun execute(workspace: Workspace, taskName: Name, configuration: C): TaskResult + + override suspend fun execute(workspace: Workspace, taskName: Name, taskMeta: Meta): TaskResult = + execute(workspace, taskName, spec.read(taskMeta)) +} + +public suspend fun TaskWithSpec.execute( + workspace: Workspace, + taskName: Name, + block: C.() -> Unit = {}, +): TaskResult = execute(workspace, taskName, spec(block)) + +public class TaskResultBuilder( public val workspace: Workspace, public val taskName: Name, public val taskMeta: Meta, @@ -48,7 +72,6 @@ public class TaskResultBuilder( * @param builder for resulting data set */ @Suppress("FunctionName") -@DFInternal public fun Task( resultType: KType, descriptor: MetaDescriptor? = null, @@ -70,9 +93,45 @@ public fun Task( } } -@OptIn(DFInternal::class) @Suppress("FunctionName") public inline fun Task( descriptor: MetaDescriptor? = null, noinline builder: suspend TaskResultBuilder.() -> Unit, -): Task = Task(typeOf(), descriptor, builder) \ No newline at end of file +): Task = Task(typeOf(), descriptor, builder) + + +/** + * Create a [Task] that composes a result using [builder]. Only data from the workspace could be used. + * Data dependency cycles are not allowed. + * + * @param resultType the type boundary for data produced by this task + * @param specification a specification for task configuration + * @param builder for resulting data set + */ +@Suppress("FunctionName") +public fun Task( + resultType: KType, + specification: Specification, + builder: suspend TaskResultBuilder.(C) -> Unit, +): TaskWithSpec = object : TaskWithSpec { + override val spec: Specification = specification + + override suspend fun execute( + workspace: Workspace, + taskName: Name, + configuration: C, + ): TaskResult = withContext(GoalExecutionRestriction() + workspace.goalLogger) { + //TODO use safe builder and check for external data on add and detects cycles + val taskMeta = configuration.toMeta() + val dataset = DataTree(resultType) { + TaskResultBuilder(workspace, taskName, taskMeta, this).apply { builder(configuration) } + } + workspace.wrapResult(dataset, taskName, taskMeta) + } +} + +@Suppress("FunctionName") +public inline fun Task( + specification: Specification, + noinline builder: suspend TaskResultBuilder.(C) -> Unit, +): Task = Task(typeOf(), specification, builder) \ No newline at end of file diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt index ec078020..6a3608bb 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt @@ -8,7 +8,9 @@ import space.kscience.dataforge.data.DataSet import space.kscience.dataforge.data.DataSetBuilder import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MetaRepr import space.kscience.dataforge.meta.MutableMeta +import space.kscience.dataforge.meta.Specification import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder import space.kscience.dataforge.misc.DFBuilder @@ -28,19 +30,34 @@ public data class TaskReference(public val taskName: Name, public val t error("Task $taskName does not belong to the workspace") } } - } public interface TaskContainer { + /** + * Register task in container + */ public fun registerTask(taskName: Name, task: Task<*>) } +@Deprecated("use buildTask instead", ReplaceWith("buildTask(name, descriptorBuilder, builder)")) public inline fun TaskContainer.registerTask( name: String, - noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, + descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, noinline builder: suspend TaskResultBuilder.() -> Unit, ): Unit = registerTask(Name.parse(name), Task(MetaDescriptor(descriptorBuilder), builder)) +public inline fun TaskContainer.buildTask( + name: String, + descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, + noinline builder: suspend TaskResultBuilder.() -> Unit, +): TaskReference { + val theName = Name.parse(name) + val descriptor = MetaDescriptor(descriptorBuilder) + val task = Task(descriptor, builder) + registerTask(theName, task) + return TaskReference(theName, task) +} + public inline fun TaskContainer.task( descriptor: MetaDescriptor, noinline builder: suspend TaskResultBuilder.() -> Unit, @@ -51,6 +68,16 @@ public inline fun TaskContainer.task( ReadOnlyProperty { _, _ -> TaskReference(taskName, task) } } +public inline fun TaskContainer.task( + specification: Specification, + noinline builder: suspend TaskResultBuilder.(C) -> Unit, +): PropertyDelegateProvider>> = PropertyDelegateProvider { _, property -> + val taskName = Name.parse(property.name) + val task = Task(specification, builder) + registerTask(taskName, task) + ReadOnlyProperty { _, _ -> TaskReference(taskName, task) } +} + public inline fun TaskContainer.task( noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, noinline builder: suspend TaskResultBuilder.() -> Unit, diff --git a/gradle.properties b/gradle.properties index 8687cb20..9b925f8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,7 @@ -org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G +org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G org.gradle.parallel=true kotlin.code.style=official -kotlin.parallel.tasks.in.project=true #kotlin.mpp.enableGranularSourceSetsMetadata=true #kotlin.native.enableDependencyPropagation=false @@ -10,3 +9,5 @@ kotlin.mpp.stability.nowarn=true publishing.github=false publishing.sonatype=false + +toolsVersion=0.11.1-kotlin-1.6.10 diff --git a/settings.gradle.kts b/settings.gradle.kts index 2e5ee74f..a19ee5f0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,12 +1,19 @@ +rootProject.name = "dataforge-core" + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +enableFeaturePreview("VERSION_CATALOGS") + pluginManagement { + + val toolsVersion: String by extra + repositories { + mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() } - val toolsVersion = "0.10.7" - plugins { id("ru.mipt.npm.gradle.project") version toolsVersion id("ru.mipt.npm.gradle.mpp") version toolsVersion @@ -15,6 +22,23 @@ pluginManagement { } } +dependencyResolutionManagement { + + val toolsVersion: String by extra + + repositories { + mavenLocal() + maven("https://repo.kotlin.link") + mavenCentral() + } + + versionCatalogs { + create("npmlibs") { + from("ru.mipt.npm:version-catalog:$toolsVersion") + } + } +} + include( ":dataforge-meta", ":dataforge-io",