<commit_before>package com.beust.kobalt.kotlin

import com.beust.kobalt.Args
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.kotlin.internal.ParsedBuildFile
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.Topological
import com.beust.kobalt.misc.log
import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import com.google.inject.assistedinject.Assisted
import rx.subjects.PublishSubject
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.lang.reflect.Modifier
import java.net.URL
import java.net.URLClassLoader
import java.nio.charset.Charset
import java.nio.file.Paths
import java.util.*
import java.util.jar.JarInputStream
import javax.inject.Inject

/**
 * Manage the compilation of Build.kt. There are two passes for this processing:
 * 1) Extract the repos() and plugins() statements in a separate .kt and compile it into preBuildScript.jar.
 * 2) Actually build the whole Build.kt file after adding to the classpath whatever phase 1 found (plugins, repos)
 */
public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFiles: List<BuildFile>,
        @Assisted val pluginInfo: PluginInfo, val files: KFiles, val plugins: Plugins,
        val dependencyManager: DependencyManager, val pluginProperties: PluginProperties,
        val executors: KobaltExecutors) {

    interface IFactory {
        fun create(@Assisted("buildFiles") buildFiles: List<BuildFile>, pluginInfo: PluginInfo) : BuildFileCompiler
    }

    val observable = PublishSubject.create<BuildScriptInfo>()

    private val SCRIPT_JAR = "buildScript.jar"

    fun compileBuildFiles(args: Args): List<Project> {
        //
        // Create the KobaltContext
        //
        val context = KobaltContext(args)
        context.pluginInfo = pluginInfo
        context.pluginProperties = pluginProperties
        context.dependencyManager = dependencyManager
        context.executors = executors
        Kobalt.context = context

        //
        // Find all the projects in the build file, possibly compiling them
        //
        val allProjects = findProjects(context)
        plugins.applyPlugins(context, allProjects)

        return allProjects
    }

    private fun validateProjects(projects: List<Project>) {
        val seen = hashSetOf<String>()
        projects.forEach {
            if (seen.contains(it.name)) {
                throw KobaltException("Duplicate project name: $it")
            } else {
                seen.add(it.name)
            }
        }
    }

    private fun findProjects(context: KobaltContext): List<Project> {
        val result = arrayListOf<Project>()
        buildFiles.forEach { buildFile ->
            val pair = processBuildFile(context, buildFile)
            val pluginUrls = pair.second
            val buildScriptJarFile = File(KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR))

            // If the script jar files were generated by a different version, wipe them in case the API
            // changed in-between
            buildScriptJarFile.parentFile.let { dir ->
                if (! isSameVersionFile(dir)) {
                    log(1, "Detected new installation, wiping $dir")
                    dir.listFiles().map { it.delete() }
                }
            }

            // Write the modified Build.kt (e.g. maybe profiles were applied) to a temporary file,
            // compile it and run it
            val modifiedBuildFile = KFiles.createTempFile(".kt")
            KFiles.saveFile(modifiedBuildFile, pair.first.buildScriptCode)
            maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path), "Modified Build.kt"),
                    buildScriptJarFile, pluginUrls)
            val buildScriptInfo = runBuildScriptJarFile(buildScriptJarFile, pluginUrls)
            result.addAll(buildScriptInfo.projects)
        }
        return result
    }

    private fun isUpToDate(buildFile: BuildFile, jarFile: File) =
        buildFile.exists() && jarFile.exists()
                && buildFile.lastModified < jarFile.lastModified()

    private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File,<commit_msg>Comment.<commit_after>package com.beust.kobalt.kotlin

import com.beust.kobalt.Args
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.kotlin.internal.ParsedBuildFile
import com.beust.kobalt.maven.DependencyManager
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltExecutors
import com.beust.kobalt.misc.Topological
import com.beust.kobalt.misc.log
import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import com.google.inject.assistedinject.Assisted
import rx.subjects.PublishSubject
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.lang.reflect.Modifier
import java.net.URL
import java.net.URLClassLoader
import java.nio.charset.Charset
import java.nio.file.Paths
import java.util.*
import java.util.jar.JarInputStream
import javax.inject.Inject

/**
 * Manage the compilation of Build.kt. There are two passes for this processing:
 * 1) Extract the repos() and plugins() statements in a separate .kt and compile it into preBuildScript.jar.
 * 2) Actually build the whole Build.kt file after adding to the classpath whatever phase 1 found (plugins, repos)
 */
public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val buildFiles: List<BuildFile>,
        @Assisted val pluginInfo: PluginInfo, val files: KFiles, val plugins: Plugins,
        val dependencyManager: DependencyManager, val pluginProperties: PluginProperties,
        val executors: KobaltExecutors) {

    interface IFactory {
        fun create(@Assisted("buildFiles") buildFiles: List<BuildFile>, pluginInfo: PluginInfo) : BuildFileCompiler
    }

    val observable = PublishSubject.create<BuildScriptInfo>()

    private val SCRIPT_JAR = "buildScript.jar"

    fun compileBuildFiles(args: Args): List<Project> {
        //
        // Create the KobaltContext
        //
        val context = KobaltContext(args)
        context.pluginInfo = pluginInfo
        context.pluginProperties = pluginProperties
        context.dependencyManager = dependencyManager
        context.executors = executors
        Kobalt.context = context

        //
        // Find all the projects in the build file, possibly compiling them
        //
        val allProjects = findProjects(context)
        plugins.applyPlugins(context, allProjects)

        return allProjects
    }

    /**
     * Make sure all the projects have a unique name.
     */
    private fun validateProjects(projects: List<Project>) {
        val seen = hashSetOf<String>()
        projects.forEach {
            if (seen.contains(it.name)) {
                throw KobaltException("Duplicate project name: $it")
            } else {
                seen.add(it.name)
            }
        }
    }

    private fun findProjects(context: KobaltContext): List<Project> {
        val result = arrayListOf<Project>()
        buildFiles.forEach { buildFile ->
            val pair = processBuildFile(context, buildFile)
            val pluginUrls = pair.second
            val buildScriptJarFile = File(KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR))

            // If the script jar files were generated by a different version, wipe them in case the API
            // changed in-between
            buildScriptJarFile.parentFile.let { dir ->
                if (! isSameVersionFile(dir)) {
                    log(1, "Detected new installation, wiping $dir")
                    dir.listFiles().map { it.delete() }
                }
            }

            // Write the modified Build.kt (e.g. maybe profiles were applied) to a temporary file,
            // compile it, jar it in buildScript.jar and run it
            val modifiedBuildFile = KFiles.createTempFile(".kt")
            KFiles.saveFile(modifiedBuildFile, pair.first.buildScriptCode)
            maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path), "Modified Build.kt"),
                    buildScriptJarFile, pluginUrls)
            val buildScriptInfo = runBuildScriptJarFile(buildScriptJarFile, pluginUrls)
            result.addAll(buildScriptInfo.projects)
        }
        return result
    }

    private fun isUpToDate(buildFile: BuildFile, jarFile: File) =
        buildFile.exists() && jarFile.exists()
                && buildFile.lastModified < jarFile.lastModified()

    private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File,
{'fraction_non_alphanumeric': 0.08561946902654867, 'fraction_numerical': 0.0008849557522123894, 'mean_word_length': 2.8802575107296136, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3400742', 'n_tokens_mistral': 2552, 'n_tokens_neox': 2441, 'n_words': 620}