All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.jeka.core.tool.Engine Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024  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
 *
 *       https://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 dev.jeka.core.tool;

import dev.jeka.core.api.depmanagement.JkDependency;
import dev.jeka.core.api.depmanagement.JkDependencySet;
import dev.jeka.core.api.depmanagement.JkRepoSet;
import dev.jeka.core.api.depmanagement.resolution.JkDependencyResolver;
import dev.jeka.core.api.file.JkPathMatcher;
import dev.jeka.core.api.file.JkPathSequence;
import dev.jeka.core.api.file.JkPathTree;
import dev.jeka.core.api.file.JkPathTreeSet;
import dev.jeka.core.api.java.*;
import dev.jeka.core.api.kotlin.JkKotlinCompiler;
import dev.jeka.core.api.kotlin.JkKotlinJvmCompileSpec;
import dev.jeka.core.api.system.JkLocator;
import dev.jeka.core.api.system.JkLog;
import dev.jeka.core.api.system.JkProperties;
import dev.jeka.core.api.utils.JkUtilsAssert;
import dev.jeka.core.api.utils.JkUtilsIterable;
import dev.jeka.core.api.utils.JkUtilsString;
import dev.jeka.core.tool.builtins.base.BaseKBean;

import javax.tools.ToolProvider;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.stream.Collectors;

/*
 * Core of the execution engine. Responsible for :
 *     - Parse source to extract compilation directive and dependencies
 *     - Compile code on the fly
 *     - Resolve command line actions to executable tasks
 *     - Run the requested actions
 */
class Engine {

    private static final String[] PRIVATE_GLOB_PATTERN = new String[]{"**/_*", "_*"};

    private static final JkPathMatcher JAVA_JEKA_SRC_MATCHER = JkPathMatcher.of(true, "**.java")
            .and(false, PRIVATE_GLOB_PATTERN);

    private static final JkPathMatcher JAVA_CLASS_MATCHER = JkPathMatcher.of(true, "**.class")
            .and(false, PRIVATE_GLOB_PATTERN);

    private static final JkPathMatcher KOTLIN_JEKA_SRC_MATCHER = JkPathMatcher.of(true, "**.kt")
            .and(false, PRIVATE_GLOB_PATTERN);

    private static final JkPathMatcher JAVA_DEF_SOURCE_MATCHER = JkPathMatcher.of(true, "**.java")
            .and(false, "**/_*", "_*");

    private static final JkPathMatcher KOTLIN_DEF_SOURCE_MATCHER = JkPathMatcher.of(true, "**.kt")
            .and(false, "**/_*", "_*");

    private static final Comparator PATH_COMPARATOR = (o1, o2) -> {
        if (o1.getNameCount() < o2.getNameCount()) {
            return -1;
        }
        if (o1.getNameCount() > o2.getNameCount()) {
            return 1;
        }
        return o1.compareTo(o2);
    };

    static final JkPathMatcher JAVA_OR_KOTLIN_SOURCE_MATCHER = JAVA_DEF_SOURCE_MATCHER.or(KOTLIN_DEF_SOURCE_MATCHER);


    private static final String NO_JDK_MSG = String.format(
            "The running Java platform %s is not a valid JDK (no javac found).%n" +
                    "Please provide a JDK by specifying 'jeka.java.version' in jeka.properties file.%n" +
                    "Or set JAVA_HOME environment variable to a valid JDK.", System.getProperty("java.home"));

    private static final Map MAP = new HashMap<>();

    final Path baseDir;

    private final boolean skipJekaSrc;

    private final JkDependencyResolver dependencyResolver;

    private final JkDependencySet commandLineDependencies;

    private final LogSettings logSettings;

    private final BehaviorSettings behaviorSettings;

    // Computed values

    private final JkProperties properties;

    private final Path jekaSrcDir;

    private final Path jekaSrcClassDir;

    private ClasspathSetupResult classpathSetupResult;

    private KBeanResolution kbeanResolution;

    private KBeanAction.Container actionContainer;

    private JkRunbase runbase;

    private Engine(Path baseDir,
                   boolean skipJekaSrc,
                   JkRepoSet downloadRepos,
                   JkDependencySet commandLineDependencies,
                   LogSettings logSettings,
                   BehaviorSettings behaviorSettings) {

        this.baseDir = baseDir;
        this.skipJekaSrc = skipJekaSrc;
        this.commandLineDependencies = commandLineDependencies;
        this.logSettings = logSettings;
        this.behaviorSettings = behaviorSettings;
        this.properties = JkRunbase.constructProperties(baseDir);
        this.jekaSrcDir = baseDir.resolve(JkConstants.JEKA_SRC_DIR);
        this.jekaSrcClassDir = baseDir.resolve(JkConstants.JEKA_SRC_CLASSES_DIR);

        // Set dependency resolver
        this.dependencyResolver = JkDependencyResolver.of(downloadRepos)
                .setUseFileSystemCache(true)
                .setFileSystemCacheDir(baseDir.resolve(JkConstants.JEKA_WORK_PATH).resolve("jeka-src-deps"));

        // In lenient mode, we ignore dep resolution failure
        this.dependencyResolver.getDefaultParams().setFailOnDependencyResolutionError(
                !behaviorSettings.forceMode);
    }

    static Engine of(Path baseDir, boolean skipJekaSrc, JkRepoSet downloadRepos,
                     JkDependencySet commandLineDependencies, LogSettings logSettings,
                     BehaviorSettings behaviorSettings) {

        Path path = baseDir.toAbsolutePath().normalize();


        // ensure only 1 baseProcessor per base
        return MAP.computeIfAbsent(path,
                key -> new Engine(key, skipJekaSrc, downloadRepos, commandLineDependencies, logSettings, behaviorSettings));
    }

    private static String classNameFromClassFilePath(Path relativePath) {
        final String dotName = relativePath.toString().replace('\\', '/').replace('/', '.');
        return JkUtilsString.substringBeforeLast(dotName, ".");
    }

    private static Optional firstMatchingClassname(List classNames, String candidate) {
        return classNames.stream()
                .filter(className -> KBean.nameMatches(className, candidate))
                .findFirst();
    }

    Engine withBaseDir(Path baseDir) {
        return of(baseDir, this.skipJekaSrc, this.dependencyResolver.getRepos(), this.commandLineDependencies,
                this.logSettings, this.behaviorSettings);
    }

    /*
     * Resolves dependencies and compiles and sources classes contained in jeka/def.
     * It returns a path sequence containing the resolved dependencies and result of compilation.
     */
    ClasspathSetupResult resolveClassPaths() {

        if (classpathSetupResult != null) {
            return classpathSetupResult;
        }

        JkLog.debugStartTask("Resolve classpath for jeka-src");

        if (behaviorSettings.cleanWork) {
            Path workDir = baseDir.resolve(JkConstants.JEKA_WORK_PATH);
            JkLog.debug("Clean .jaka-work directory  %s ", workDir.toAbsolutePath().normalize());
            JkPathTree.of(workDir).deleteContent();
        }

        // That is nice that this clean occurs here, because it will happen for sub-basedir as well.
        if (behaviorSettings.cleanOutput) {
            Path outputDir = baseDir.resolve(JkConstants.OUTPUT_PATH);
            JkPathTree.of(outputDir).deleteContent();
            JkLog.verbose("Clean %s dir", outputDir);
        }

        // Parse info from source code
        JkLog.debugStartTask("Scan jeka-src code for finding dependencies");
        final ParsedSourceInfo parsedSourceInfo = SourceParser.of(this.baseDir).parse();
        JkLog.debugEndTask();

        // Compute and get the classpath from sub-dirs
        List subBaseDirs = parsedSourceInfo.importedBaseDirs.stream()
                .map(this::withBaseDir)
                .collect(Collectors.toList());

        JkPathSequence addedClasspathFromSubDirs = subBaseDirs.stream()
                .map(Engine::resolveClassPaths)
                .map(classpathSetupResult -> classpathSetupResult.runClasspath)
                .reduce(JkPathSequence.of(), JkPathSequence::and);

        // compute classpath to look in for finding KBeans
        String classpathProp = properties.get(JkConstants.CLASSPATH_INJECT_PROP, "");
        List jekaPropsDeps = Arrays.stream(classpathProp.split(" "))
                .flatMap(desc -> Arrays.stream(desc.split(",")))     // handle ' ' or ',' separators
                .map(String::trim)
                .filter(desc -> !desc.isEmpty())
                .map(desc -> JkDependency.of(baseDir, desc))
                .collect(Collectors.toList());
        JkDependencySet dependencies = commandLineDependencies
                .and(jekaPropsDeps)
                .and(parsedSourceInfo.getDependencies())
                .andVersionProvider(JkConstants.JEKA_VERSION_PROVIDER);

        JkPathSequence kbeanClasspath = JkPathSequence.of(dependencyResolver.resolveFiles(dependencies))
                .and(JkLocator.getJekaJarPath());

        if (skipJekaSrc) {
            JkLog.debugEndTask();
            this.classpathSetupResult = compileLessClasspathResult(parsedSourceInfo, subBaseDirs, kbeanClasspath, dependencies);
            return this.classpathSetupResult;
        }

        // compute classpath for compiling 'jeka-src'
        JkPathSequence compileClasspath = kbeanClasspath
                .and(addedClasspathFromSubDirs)
                .and(JkPathTree.of(baseDir.resolve(JkConstants.JEKA_BOOT_DIR)).getFiles());

        // Compile jeka-src
        CompileResult compileResult = compileJekaSrc(compileClasspath, parsedSourceInfo.compileOptions);

        // Add compile result to he run compile
        JkPathSequence runClasspath = compileClasspath.and(compileResult.extraClasspath).withoutDuplicates();

        // If private dependencies has been defined, this means that jeka-src is supposed to host
        // an application that wants to control its classpath. Thus, we only put the dependency explicitly
        // exported.
        final JkPathSequence exportedClasspath;
        final JkDependencySet exportedDependencies;
        if (parsedSourceInfo.hasPrivateDependencies()) {
            exportedDependencies = parsedSourceInfo.getExportedDependencies()
                    .andVersionProvider(JkConstants.JEKA_VERSION_PROVIDER);
            exportedClasspath = JkPathSequence.of(
                    dependencyResolver.resolveFiles(parsedSourceInfo.getExportedDependencies()));
        } else {
            exportedDependencies = parsedSourceInfo.getDependencies();
            exportedClasspath = compileClasspath;
        }

        // Prepare result and return
        this.classpathSetupResult = new ClasspathSetupResult(compileResult.success,
                runClasspath, kbeanClasspath, exportedClasspath, exportedDependencies, subBaseDirs, dependencies);
        JkLog.debugEndTask();
        return classpathSetupResult;
    }

    KBeanResolution resolveKBeans() {
        if (classpathSetupResult == null) {
            resolveClassPaths();
        }
        if (kbeanResolution != null) {
            return kbeanResolution;
        }

        // Find all KBean class available for this
        List kbeanClassNames = findKBeanClassNames();

        // Filter to find kbeans defined in jeka-src
        List localKbeanClassNames = JkPathTree.of(jekaSrcClassDir).streamBreathFirst()
                .excludeDirectories()
                .relativizeFromRoot()
                .filter(path -> path.getFileName().toString().endsWith(".class"))
                .sorted(PATH_COMPARATOR)
                .map(Engine::classNameFromClassFilePath)
                .filter(kbeanClassNames::contains)
                .collect(Collectors.toList());

        DefaultAndInitKBean defaultAndInitKBean = defaultAndInitKbean(kbeanClassNames, localKbeanClassNames);
        kbeanResolution = new KBeanResolution(kbeanClassNames, localKbeanClassNames,
                defaultAndInitKBean.initKbeanClassName, defaultAndInitKBean.defaultKBeanClassName);
        return kbeanResolution;
    }

    JkRunbase initRunbase(KBeanAction.Container actionContainer) {
        if (runbase != null) {
            return runbase;
        }
        this.actionContainer = actionContainer;

        JkRunbase.setMasterBaseDir(baseDir); // master base dir is used to display relative path on console output
        JkRunbase.setKBeanResolution(getKbeanResolution());
        runbase = JkRunbase.get(baseDir);
        runbase.setDependencyResolver(dependencyResolver);
        runbase.setClasspath(classpathSetupResult.runClasspath);
        runbase.setExportedClassPath(classpathSetupResult.exportedClasspath);
        runbase.setExportedDependencies(classpathSetupResult.exportedDependencies);
        runbase.setFullDependencies(classpathSetupResult.fullDependencies);
        runbase.assertValid(); // fail-fast. bugfix purpose

        // initialise runbase with resolved commands
        runbase.init(this.actionContainer);
        if (logSettings.runtimeInformation) {
            JkLog.info("KBeans Init        :");
            JkLog.info(runbase.getEffectiveActions().toColumnText()
                    .setSeparator(" | ")
                    .setMarginLeft("   | ")
                    .toString());
        }
        return runbase;
    }

    void run() {
        runbase.run(actionContainer);
    }

    DefaultAndInitKBean defaultAndInitKbean(List kbeanClassNames, List localKbeanClassNames) {
        return new DefaultAndInitKBean(kbeanClassNames, localKbeanClassNames);
    }

    JkRunbase getRunbase() {
        return runbase;
    }

    ClasspathSetupResult getClasspathSetupResult() {
        return classpathSetupResult;
    }

    KBeanResolution getKbeanResolution() {
        return kbeanResolution;
    }


    // non-private for testing purpose
    class DefaultAndInitKBean {

        final String initKbeanClassName;

        final String defaultKBeanClassName;

        private DefaultAndInitKBean(List kbeanClassNames, List localKbeanClassNames) {
            String defaultKBeanName = behaviorSettings.kbeanName
                    .orElse(properties.get(JkConstants.DEFAULT_KBEAN_PROP));
            JkLog.debug("Default KBean Name : " + defaultKBeanName);
            defaultKBeanClassName = firstMatchingClassname(kbeanClassNames, defaultKBeanName)
                    .orElse(localKbeanClassNames.stream().findFirst().orElse(null));
            JkLog.debug("Default KBean Class Name : " + defaultKBeanClassName);
            if (defaultKBeanName != null && defaultKBeanClassName == null) {
                JkLog.warn("Specified default KBean '%s' not found among KBeans %s", defaultKBeanName, kbeanClassNames);
            }

            // The first KBean to be initialized
            if (localKbeanClassNames.contains(defaultKBeanClassName)) {
                initKbeanClassName = defaultKBeanClassName;
            } else {
                initKbeanClassName = localKbeanClassNames.stream().findFirst().orElse(defaultKBeanClassName);
            }
        }
    }

    private CompileResult compileJekaSrc(JkPathSequence classpath, List compileOptions) {

        JkPathSequence extraClasspath = JkPathSequence.of();
        boolean hasKotlinSources = hasKotlinSource();

        // Avoid compilation if sources didn't change
        EngineCompilationUpdateTracker updateTracker = new EngineCompilationUpdateTracker(baseDir);
        if (!updateTracker.needRecompile(classpath)) {
            if (hasKotlinSources) {
                JkPathSequence kotlinStdLibPath = updateTracker.readKotlinLibsFile();
                extraClasspath = extraClasspath.and(kotlinStdLibPath);
            }
            extraClasspath = extraClasspath.and(jekaSrcClassDir);
            return new CompileResult(true, extraClasspath);
        }

        // Compile Kotlin code if any
        KotlinCompileResult kotlinCompileResult = new KotlinCompileResult(true, JkPathSequence.of());
        if (hasKotlinSource()) {
            kotlinCompileResult = compileWithKotlin(classpath, compileOptions);
            extraClasspath = extraClasspath.and(kotlinCompileResult.kotlinLibPath);
            updateTracker.updateKotlinLibs(kotlinCompileResult.kotlinLibPath);
        }

        // Compile  Java
        boolean javaCompileSuccess = compileJava(classpath, compileOptions);

        // Copy resources
        if (Files.isDirectory(jekaSrcDir)) {
            JkPathTree.of(jekaSrcDir)
                    .andMatching(false, "**/*.java", "*.java", "**/*.kt", "*.kt")
                    .copyTo(jekaSrcClassDir, StandardCopyOption.REPLACE_EXISTING);
        }

        // Prepare and return result
        updateTracker.updateCompileFlag();
        extraClasspath = extraClasspath.and(jekaSrcClassDir);
        boolean globalSuccess = javaCompileSuccess && kotlinCompileResult.success;
        if (!globalSuccess && !behaviorSettings.forceMode) {
            throw new JkException("Compilation of %s failed.", jekaSrcDir);
        }



        return new CompileResult(globalSuccess, extraClasspath);
    }

    private boolean hasKotlinSource() {
        return JkPathTree.of(jekaSrcDir).andMatcher(KOTLIN_JEKA_SRC_MATCHER)
                .count(1, false) > 0;
    }

    private KotlinCompileResult compileWithKotlin(JkPathSequence classpath, List compileOptions) {
        String kotVer = properties.get(JkKotlinCompiler.KOTLIN_VERSION_OPTION);
        JkUtilsAssert.state(!JkUtilsString.isBlank(kotVer),
                "No Kotlin version has been defined for %s.%n" +
                        " Please, mention 'jeka.kotlin.version=xxx' in %s.",
                baseDir,
                baseDir.resolve(JkConstants.PROPERTIES_FILE));
        JkKotlinCompiler kotlinCompiler = JkKotlinCompiler.ofJvm(dependencyResolver.getRepos(), kotVer)
                .setLogOutput(true)
                .setFailOnError(!behaviorSettings.forceMode)
                .addOption("-nowarn");
        compileOptions.forEach(option -> kotlinCompiler.addOption(option));
        JkPathSequence kotlinClasspath = classpath.and(kotlinCompiler.getStdJdk8Lib());
        final JkKotlinJvmCompileSpec kotlinCompileSpec = JkKotlinJvmCompileSpec.of()
                .setClasspath(kotlinClasspath)
                .setSources(JkPathTreeSet.ofRoots(jekaSrcDir))
                .setOutputDir(jekaSrcClassDir);
        if (JkLog.isVerbose()) {
            kotlinCompiler.addOption("-verbose");
        }

        // perform compilation in console spinner
        boolean success = kotlinCompiler.compile(kotlinCompileSpec);

        return new KotlinCompileResult(success, kotlinCompiler.getStdJdk8Lib());
    }

    private boolean compileJava(JkPathSequence classpath, List compileOptions) {
        final JkPathTree jekaSource = JkPathTree.of(jekaSrcDir).andMatcher(JAVA_JEKA_SRC_MATCHER);
        JkJavaCompileSpec javaCompileSpec = JkJavaCompileSpec.of()
                .setClasspath(classpath.and(jekaSrcClassDir)) // for handling compiled kotlin code
                .setOutputDir(jekaSrcClassDir)
                .setSources(jekaSource.toSet())
                .addOptions(compileOptions);
        if (javaCompileSpec.getSources().containFiles() && ToolProvider.getSystemJavaCompiler() == null) {
            throw new JkException(NO_JDK_MSG);
        }
        if (jekaSource.containFiles()) {
            return JkJavaCompilerToolChain.of().compile(javaCompileSpec);
        }
        JkLog.verbose("jeka-src dir does not contain sources. Skip compile");
        return true;
    }

    private List findKBeanClassNames() {

        JkInternalClasspathScanner scanner = JkInternalClasspathScanner.of();

        // Find classes in jeka-src-classes. As it is small scope, we don't need caching
        final List jekaSrcKBeans;
        if (JkPathTree.of(jekaSrcClassDir).withMatcher(JAVA_CLASS_MATCHER).containFiles() && !skipJekaSrc) {
            ClassLoader srcClassloader = JkUrlClassLoader.of(jekaSrcClassDir).get();
            jekaSrcKBeans = scanner.findClassesExtending(srcClassloader, KBean.class, jekaSrcClassDir);
        } else {
            jekaSrcKBeans = Collections.emptyList();
        }

        // Find KBeans in dependencies. We need caching as there are potentially a lot of jars to scan
        JkPathSequence kbeanClasspath = classpathSetupResult.kbeanClasspath;

        // -- Look cached result in files
        Path classpathCache = baseDir.resolve(JkConstants.JEKA_WORK_PATH).resolve(JkConstants.KBEAN_CLASSPATH_CACHE_FILE);
        JkPathSequence cachedClasspath = JkPathSequence.readFromQuietly(classpathCache);
        Path kbeanCache = baseDir.resolve(JkConstants.JEKA_WORK_PATH).resolve(JkConstants.KBEAN_CLASS_NAMES_CACHE_FILE);

        // -- If cache matches, returns cached resul
        // -- kbeanCache file may not exist is compilation is skipped
        if (cachedClasspath.equals(kbeanClasspath) && Files.exists(kbeanCache)) {
            List cachedKbeans = JkUtilsIterable.readStringsFrom(kbeanCache, "\n");
            if (!cachedKbeans.isEmpty()) {
                List result = new LinkedList<>(jekaSrcKBeans);
                result.addAll(cachedKbeans);
                return result;
            }
        }

        // -- Scan deps
        ClassLoader depClassloader = JkUrlClassLoader.of(classpathSetupResult.kbeanClasspath).get();

        // If we skip jeka-src, we need look in KBean classes in parent classloaders as we are
        // probably relying on IDE classloader.
        boolean ignoreParentClassloaders = !skipJekaSrc;
        List depsKBeans = scanner.findClassesExtending(
                depClassloader,
                KBean.class,
                ignoreParentClassloaders,
                true,
                true);

        // -- Update cache
        kbeanClasspath.writeTo(classpathCache);
        JkUtilsIterable.writeStringsTo(kbeanCache, "\n", depsKBeans);

        // Prepare and return result
        List result = new LinkedList<>(jekaSrcKBeans);
        result.addAll(depsKBeans);
        return result;
    }

    static class ClasspathSetupResult {

        final JkPathSequence runClasspath;
        final JkPathSequence kbeanClasspath;
        final JkPathSequence exportedClasspath;
        final List subBaseDirs;
        final JkDependencySet exportedDependencies;
        final boolean compileResult;
        final JkDependencySet fullDependencies;

        ClasspathSetupResult(boolean compileResult,
                             JkPathSequence runClasspath,  // The full classpath to run Jeka upon
                             JkPathSequence kbeanClasspath, // The classpath to find in KBeans
                             JkPathSequence exportedClasspath,
                             JkDependencySet exportedDependencies,
                             List subBaseDirs,
                             JkDependencySet fullDependencies) {
            this.compileResult = compileResult;
            this.runClasspath = runClasspath;
            this.kbeanClasspath = kbeanClasspath;  // does not contain jeka-src-classes
            this.exportedClasspath = exportedClasspath;
            this.exportedDependencies = exportedDependencies;
            this.subBaseDirs = subBaseDirs;
            this.fullDependencies = fullDependencies;

        }

    }

    static class KBeanResolution {

        final List allKbeans;

        final List localKBean;

        final String initKBeanClassname;

        final String defaultKbeanClassname;

        public KBeanResolution(List allKbeans, List localKBean,
                               String initKBeanClassname, String defaultKbeanClassname) {
            this.allKbeans = allKbeans;
            this.localKBean = localKBean;
            this.initKBeanClassname = initKBeanClassname;
            this.defaultKbeanClassname = defaultKbeanClassname;
        }

        Optional findKbeanClassName(String kbeanName) {
            if (JkUtilsString.isBlank(kbeanName)) {
                return Optional.of(Optional.ofNullable(defaultKbeanClassname).orElse(BaseKBean.class.getName()));
            }
            return this.allKbeans.stream()
                    .filter(className -> KBean.nameMatches(className, kbeanName))
                    .findFirst();
        }

        Optional> findInitBeanClass() {
            return initKBeanClassname == null ? Optional.empty() : Optional.of(JkClassLoader.ofCurrent()
                    .load(initKBeanClassname));
        }
    }

    // For test-purpose only
    void setKBeanResolution(KBeanResolution kbeanResolution) {
        this.kbeanResolution = kbeanResolution;
    }

    private static class KotlinCompileResult {

        final boolean success;

        final JkPathSequence kotlinLibPath;


        public KotlinCompileResult(boolean success, JkPathSequence kotlinLibPath) {
            this.success = success;
            this.kotlinLibPath = kotlinLibPath;
        }
    }

    private static class CompileResult {

        final boolean success;

        private final JkPathSequence extraClasspath;

        CompileResult(boolean success, JkPathSequence extraClasspath) {
            this.success = success;
            this.extraClasspath = extraClasspath;
        }
    }

    private ClasspathSetupResult compileLessClasspathResult(
            ParsedSourceInfo parsedSourceInfo,
            List subBaseDirs,
            JkPathSequence classpath,
            JkDependencySet fullDependencies) {

        return new ClasspathSetupResult(
                true,
                classpath,
                classpath,
                JkPathSequence.of(
                        dependencyResolver.resolveFiles(parsedSourceInfo.getExportedDependencies())),
                parsedSourceInfo.getExportedDependencies()
                        .andVersionProvider(JkConstants.JEKA_VERSION_PROVIDER),
                subBaseDirs,
                fullDependencies);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy