<commit_before>/*
 * Copyright 2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.instantexecution.serialization.codecs

import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.internal.GeneratedSubclasses
import org.gradle.api.internal.TaskInputsInternal
import org.gradle.api.internal.TaskInternal
import org.gradle.api.internal.TaskOutputsInternal
import org.gradle.api.internal.project.ProjectState
import org.gradle.api.internal.project.ProjectStateRegistry
import org.gradle.api.internal.provider.Providers
import org.gradle.api.internal.tasks.TaskDestroyablesInternal
import org.gradle.api.internal.tasks.properties.InputFilePropertyType
import org.gradle.api.internal.tasks.properties.InputParameterUtils
import org.gradle.api.internal.tasks.properties.OutputFilePropertyType
import org.gradle.api.internal.tasks.properties.PropertyValue
import org.gradle.api.internal.tasks.properties.PropertyVisitor
import org.gradle.api.specs.Spec
import org.gradle.api.tasks.FileNormalizer
import org.gradle.execution.plan.LocalTaskNode
import org.gradle.execution.plan.TaskNodeFactory
import org.gradle.instantexecution.coroutines.runToCompletion
import org.gradle.instantexecution.extensions.uncheckedCast
import org.gradle.instantexecution.problems.PropertyKind
import org.gradle.instantexecution.problems.PropertyTrace
import org.gradle.instantexecution.serialization.Codec
import org.gradle.instantexecution.serialization.IsolateContext
import org.gradle.instantexecution.serialization.IsolateOwner
import org.gradle.instantexecution.serialization.MutableIsolateContext
import org.gradle.instantexecution.serialization.ReadContext
import org.gradle.instantexecution.serialization.WriteContext
import org.gradle.instantexecution.serialization.beans.BeanPropertyWriter
import org.gradle.instantexecution.serialization.beans.readPropertyValue
import org.gradle.instantexecution.serialization.beans.writeNextProperty
import org.gradle.instantexecution.serialization.readCollection
import org.gradle.instantexecution.serialization.readEnum
import org.gradle.instantexecution.serialization.readNonNull
import org.gradle.instantexecution.serialization.withIsolate
import org.gradle.instantexecution.serialization.withPropertyTrace
import org.gradle.instantexecution.serialization.writeCollection
import org.gradle.instantexecution.serialization.writeEnum
import org.gradle.util.DeferredUtil


class TaskNodeCodec(
    private val projectStateRegistry: ProjectStateRegistry,
    private val userTypesCodec: Codec<Any?>,
    private val taskNodeFactory: TaskNodeFactory
) : Codec<LocalTaskNode> {

    override suspend fun WriteContext.encode(value: LocalTaskNode) {
        val task = value.task
        runToCompletionWithMutableStateOf(task.project) {
            writeTask(task)
        }
    }

    override suspend fun ReadContext.decode(): LocalTaskNode {
        val task = readTask()
        val node = taskNodeFactory.getOrCreateNode(task) as LocalTaskNode
        node.isolated()
        return node
    }

    private
    suspend fun WriteContext.writeTask(task: TaskInternal) {
        val taskType = GeneratedSubclasses.unpackType(task)
        writeClass(taskType)
        writeString(task.project.path)
        writeString(task.name)

        withTaskOf(taskType, task, userTypesCodec) {
            writeUpToDateSpec(task)
            beanStateWriterFor(task.javaClass).run {
                writeStateOf(task)
                writeRegisteredPropertiesOf(task, this as BeanPropertyWriter)
                writeDestroyablesOf(task)
            }
            writeRegisteredServicesOf(task)
        }
    }

    private
    suspend fun ReadContext.readTask(): Task {
        val taskType = readClass().asSubclass(Task::class.java)
        val projectPath = readString()
        val taskName = readString()

        val task = createTask(projectPath, taskName, taskType)

        withTaskOf(taskType, task, userTypesCodec) {
            readUpToDateSpec(task)
            beanStateReaderFor(task.javaClass).run {
                readStateOf(task)
                readRegisteredPropertiesOf(task)
                readDestroyablesOf(task)
            }
            readRegisteredServicesOf(task)
        }

        return task
    }

    private
    suspend fun WriteContext.writeUpToDateSpec(task: TaskInternal) {
        // TODO - should just write this as a bean field of the outputs object, and also do this for the registered properties above
        if (task.outputs.upToDateSpec.isEmpty) {
            writeBoolean(false)
        } else {
            writeBoolean(true)
            write(task.outputs.upToDateSpec)
        }
    }

    private
    suspend fun ReadContext.readUpToDateSpec(task: TaskInternal) {
        if (readBoolean()) {
            task.outputs.upToDateWhen(readNonNull<Spec<Task>>())
        }
    }

    private
    suspend fun WriteContext.writeRegisteredServicesOf(task: TaskInternal) {
        writeCollection(task.requiredServices)
    }

    private
    suspend fun ReadContext.readRegisteredServicesOf(task: TaskInternal) {
        readCollection {
            task.usesService(readNonNull())
        }
    }

    private
    suspend fun WriteContext.writeDestroyablesOf(task: TaskInternal) {
        writeCollection((task.destroyables as TaskDestroyablesInternal).registeredPaths)
    }

    private
    suspend fun ReadContext.readDestroyablesOf(task: TaskInternal) {
        readCollection {
            task.destroyables.register(readNonNull())
        }
    }

    /**
     * Runs the suspending [block] to completion against the [public mutable state][ProjectState.withMutableState] of [project].
     */
    private
    fun runToCompletionWithMutableStateOf(project: Project, block: suspend () -> Unit) {<commit_msg>Let instant execution capture Task.localState<commit_after>/*
 * Copyright 2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.instantexecution.serialization.codecs

import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.internal.GeneratedSubclasses
import org.gradle.api.internal.TaskInputsInternal
import org.gradle.api.internal.TaskInternal
import org.gradle.api.internal.TaskOutputsInternal
import org.gradle.api.internal.project.ProjectState
import org.gradle.api.internal.project.ProjectStateRegistry
import org.gradle.api.internal.provider.Providers
import org.gradle.api.internal.tasks.TaskDestroyablesInternal
import org.gradle.api.internal.tasks.TaskLocalStateInternal
import org.gradle.api.internal.tasks.properties.InputFilePropertyType
import org.gradle.api.internal.tasks.properties.InputParameterUtils
import org.gradle.api.internal.tasks.properties.OutputFilePropertyType
import org.gradle.api.internal.tasks.properties.PropertyValue
import org.gradle.api.internal.tasks.properties.PropertyVisitor
import org.gradle.api.specs.Spec
import org.gradle.api.tasks.FileNormalizer
import org.gradle.execution.plan.LocalTaskNode
import org.gradle.execution.plan.TaskNodeFactory
import org.gradle.instantexecution.coroutines.runToCompletion
import org.gradle.instantexecution.extensions.uncheckedCast
import org.gradle.instantexecution.problems.PropertyKind
import org.gradle.instantexecution.problems.PropertyTrace
import org.gradle.instantexecution.serialization.Codec
import org.gradle.instantexecution.serialization.IsolateContext
import org.gradle.instantexecution.serialization.IsolateOwner
import org.gradle.instantexecution.serialization.MutableIsolateContext
import org.gradle.instantexecution.serialization.ReadContext
import org.gradle.instantexecution.serialization.WriteContext
import org.gradle.instantexecution.serialization.beans.BeanPropertyWriter
import org.gradle.instantexecution.serialization.beans.readPropertyValue
import org.gradle.instantexecution.serialization.beans.writeNextProperty
import org.gradle.instantexecution.serialization.readCollection
import org.gradle.instantexecution.serialization.readEnum
import org.gradle.instantexecution.serialization.readNonNull
import org.gradle.instantexecution.serialization.withIsolate
import org.gradle.instantexecution.serialization.withPropertyTrace
import org.gradle.instantexecution.serialization.writeCollection
import org.gradle.instantexecution.serialization.writeEnum
import org.gradle.util.DeferredUtil


class TaskNodeCodec(
    private val projectStateRegistry: ProjectStateRegistry,
    private val userTypesCodec: Codec<Any?>,
    private val taskNodeFactory: TaskNodeFactory
) : Codec<LocalTaskNode> {

    override suspend fun WriteContext.encode(value: LocalTaskNode) {
        val task = value.task
        runToCompletionWithMutableStateOf(task.project) {
            writeTask(task)
        }
    }

    override suspend fun ReadContext.decode(): LocalTaskNode {
        val task = readTask()
        val node = taskNodeFactory.getOrCreateNode(task) as LocalTaskNode
        node.isolated()
        return node
    }

    private
    suspend fun WriteContext.writeTask(task: TaskInternal) {
        val taskType = GeneratedSubclasses.unpackType(task)
        writeClass(taskType)
        writeString(task.project.path)
        writeString(task.name)

        withTaskOf(taskType, task, userTypesCodec) {
            writeUpToDateSpec(task)
            beanStateWriterFor(task.javaClass).run {
                writeStateOf(task)
                writeRegisteredPropertiesOf(task, this as BeanPropertyWriter)
                writeDestroyablesOf(task)
                writeLocalStateOf(task)
            }
            writeRegisteredServicesOf(task)
        }
    }

    private
    suspend fun ReadContext.readTask(): Task {
        val taskType = readClass().asSubclass(Task::class.java)
        val projectPath = readString()
        val taskName = readString()

        val task = createTask(projectPath, taskName, taskType)

        withTaskOf(taskType, task, userTypesCodec) {
            readUpToDateSpec(task)
            beanStateReaderFor(task.javaClass).run {
                readStateOf(task)
                readRegisteredPropertiesOf(task)
                readDestroyablesOf(task)
                readLocalStateOf(task)
            }
            readRegisteredServicesOf(task)
        }

        return task
    }

    private
    suspend fun WriteContext.writeUpToDateSpec(task: TaskInternal) {
        // TODO - should just write this as a bean field of the outputs object, and also do this for the registered properties above
        if (task.outputs.upToDateSpec.isEmpty) {
            writeBoolean(false)
        } else {
            writeBoolean(true)
            write(task.outputs.upToDateSpec)
        }
    }

    private
    suspend fun ReadContext.readUpToDateSpec(task: TaskInternal) {
        if (readBoolean()) {
            task.outputs.upToDateWhen(readNonNull<Spec<Task>>())
        }
    }

    private
    suspend fun WriteContext.writeRegisteredServicesOf(task: TaskInternal) {
        writeCollection(task.requiredServices)
    }

    private
    suspend fun ReadContext.readRegisteredServicesOf(task: TaskInternal) {
        readCollection {
            task.usesService(readNonNull())
        }
    }

    private
    suspend fun WriteContext.writeDestroyablesOf(task: TaskInternal) {
        writeCollection((task.destroyables as TaskDestroyablesInternal).registeredPaths)
    }

    private
    suspend fun ReadContext.readDestroyablesOf(task: TaskInternal) {
        readCollection {
            task.destroyables.register(readNonNull())
        }
    }

    private
    suspend fun WriteContext.writeLocalStateOf(task: TaskInternal) {
        writeCollection((task.localState as TaskLocalStateInternal).registeredPaths)
    }

    private
    suspend fun ReadContext.readLocalStateOf(task: TaskInternal) {
        readCollection {
            task.localState.register(readNonNull())
        }
    }

    /**
     * Runs the suspending [block] to completion against the [public mutable state][ProjectState.withMutableState] of [project].
     */
    private
    fun runToCompletionWithMutableStateOf(project: Project, block: suspend () -> Unit) {
{'fraction_non_alphanumeric': 0.07546313799621929, 'fraction_numerical': 0.0012098298676748581, 'mean_word_length': 3.5764705882352943, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3409190', 'n_tokens_mistral': 3628, 'n_tokens_neox': 3374, 'n_words': 725}