();
// kotlinc
args.add(kotlinCompiler());
// classpath
args.add("-cp");
args.add(FileUtils.joinPaths(classpath.stream().toList()));
// destination
args.add("-d");
args.add(destination.getAbsolutePath());
// friend-path
if (friendPaths != null && friendPaths.exists()) {
args.add("-Xfriend-paths=" + friendPaths.getAbsolutePath());
}
// options
if (compileOptions_ != null) {
args.addAll(compileOptions_.args());
}
// plugins
if (!plugins_.isEmpty()) {
plugins_.forEach(p -> args.add("-Xplugin=" + p));
}
// sources
sources.forEach(f -> args.add(f.getAbsolutePath()));
if (LOGGER.isLoggable(Level.FINE) && !silent()) {
LOGGER.fine(String.join(" ", args));
}
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(args);
pb.directory(workDir_);
try {
var proc = pb.start();
proc.waitFor();
ExitStatusException.throwOnFailure(proc.exitValue());
} catch (IOException | InterruptedException e) {
if (LOGGER.isLoggable(Level.SEVERE) && !silent()) {
LOGGER.severe(e.getLocalizedMessage());
}
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
}
}
/**
* Part of the {@link #execute execute} operation, builds the test sources.
*
* @throws ExitStatusException if an error occurs
*/
@SuppressWarnings("PMD.SystemPrintln")
protected void executeBuildTestSources() throws ExitStatusException {
if (!silent()) {
System.out.println("Compiling Kotlin test sources.");
}
executeBuildSources(
compileTestClasspath(),
sources(testSourceFiles(), testSourceDirectories()),
buildTestDirectory(),
buildMainDirectory());
}
/**
* Part of the {@link #execute execute} operation, creates the build directories.
*
* @throws IOException if an error occurs
*/
protected void executeCreateBuildDirectories() throws IOException {
if (buildMainDirectory() != null && !buildMainDirectory().exists() && !buildMainDirectory().mkdirs()) {
throw new IOException("Could not created build main directory: " + buildMainDirectory().getAbsolutePath());
}
if (buildTestDirectory() != null && !buildTestDirectory().exists() && !buildTestDirectory().mkdirs()) {
throw new IOException("Could not created build test directory: " + buildTestDirectory().getAbsolutePath());
}
}
/**
* Configures a compile operation from a {@link BaseProject}.
*
* Sets the following from the project:
*
* - {@link #kotlinHome()} to the {@code KOTLIN_HOME} environment variable, if set.
* - {@link #workDir()} to the project's directory.
* - {@link #buildMainDirectory() buildMainDirectory}
* - {@link #buildTestDirectory() buildTestDirectory}
* - {@link #compileMainClasspath() compileMainClassPath}
* - {@link #compileTestClasspath() compilesTestClassPath}
* - {@link #mainSourceDirectories()} () mainSourceDirectories} to the {@code kotlin} directory in
* {@link BaseProject#srcMainDirectory() srcMainDirectory}
* - {@link #testSourceDirectories() testSourceDirectories} to the {@code kotlin} directory in
* {@link BaseProject#srcTestDirectory() srcTestDirectory}
* - {@link CompileOptions#jdkRelease jdkRelease} to {@link BaseProject#javaRelease() javaRelease}
* - {@link CompileOptions#noStdLib(boolean) noStdLib} to {@code true}
*
*
* @param project the project to configure the compile operation from
* @return this operation instance
*/
public CompileKotlinOperation fromProject(BaseProject project) {
project_ = project;
var env = System.getenv("KOTLIN_HOME");
if (env != null) {
kotlinHome_ = new File(env);
}
workDir_ = new File(project.workDirectory().getAbsolutePath());
var op = buildMainDirectory(project.buildMainDirectory())
.buildTestDirectory(project.buildTestDirectory())
.compileMainClasspath(project.compileMainClasspath())
.compileTestClasspath(project.compileTestClasspath())
.mainSourceDirectories(new File(project.srcMainDirectory(), "kotlin"))
.testSourceDirectories(new File(project.srcTestDirectory(), "kotlin"));
if (project.javaRelease() != null && !compileOptions_.hasRelease()) {
compileOptions_.jdkRelease(project.javaRelease());
}
compileOptions_.noStdLib(true);
return op;
}
private String kotlinCompiler() {
if (kotlinc_ != null) {
return kotlinc_.getAbsolutePath();
} else if (kotlinHome_ != null) {
var kotlinc = Path.of(kotlinHome_.getAbsolutePath(), "bin", "kotlinc").toFile();
if (kotlinc.exists() && kotlinc.canExecute()) {
return kotlinc.getAbsolutePath();
}
}
return "kotlinc";
}
/**
* Provides the Kotlin home directory, if it differs from the default {@code KOTLIN_HOME}.
*
* @param dir the directory
* @return this operation instance
*/
public CompileKotlinOperation kotlinHome(File dir) {
kotlinHome_ = dir;
return this;
}
/**
* Provides the Kotlin home directory, if it differs from the default {@code KOTLIN_HOME}.
*
* @param dir the directory path
* @return this operation instance
*/
public CompileKotlinOperation kotlinHome(String dir) {
return kotlinHome(new File(dir));
}
/**
* Provides the Kotlin home directory, if it differs from the default {@code KOTLIN_HOME}.
*
* @param dir the directory path
* @return this operation instance
*/
public CompileKotlinOperation kotlinHome(Path dir) {
return kotlinHome(dir.toFile());
}
/**
* Retrieves the Kotlin home directory.
*
* @return the directory
*/
public File kotlinHome() {
return kotlinHome_;
}
/**
* Retrieves the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @return the executable path
*/
public File kotlinc() {
return kotlinc_;
}
/**
* Provides the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @param executable the executable path
* @return this operation instance
*/
public CompileKotlinOperation kotlinc(File executable) {
kotlinc_ = executable;
return this;
}
/**
* Provides the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @param executable the executable path
* @return this operation instance
*/
public CompileKotlinOperation kotlinc(String executable) {
return kotlinc(new File(executable));
}
/**
* Provides the path to the Kotlin compiler ({@code kotlinc}) executable, if not in {@link #kotlinHome()}.
*
* @param executable the executable path
* @return this operation instance
*/
public CompileKotlinOperation kotlinc(Path executable) {
return kotlinc(executable.toFile());
}
/**
* Provides main source directories that should be compiled.
*
* @param directories one or more main source directories
* @return this operation instance
* @see #mainSourceDirectories(Collection)
*/
public CompileKotlinOperation mainSourceDirectories(File... directories) {
return mainSourceDirectories(List.of(directories));
}
/**
* Provides main source directories that should be compiled.
*
* @param directories one or more main source directories
* @return this operation instance
* @see #mainSourceDirectoriesPaths(Collection)
*/
public CompileKotlinOperation mainSourceDirectories(Path... directories) {
return mainSourceDirectoriesPaths(List.of(directories));
}
/**
* Provides main source directories that should be compiled.
*
* @param directories one or more main source directories
* @return this operation instance
* @see #mainSourceDirectoriesStrings(Collection)
*/
public CompileKotlinOperation mainSourceDirectories(String... directories) {
return mainSourceDirectoriesStrings(List.of(directories));
}
/**
* Provides the main source directories that should be compiled.
*
* @param directories the main source directories
* @return this operation instance
* @see #mainSourceDirectories(File...)
*/
public CompileKotlinOperation mainSourceDirectories(Collection directories) {
mainSourceDirectories_.addAll(directories);
return this;
}
/**
* Retrieves the main source directories that should be compiled.
*
* @return the main source directories
*/
public Collection mainSourceDirectories() {
return mainSourceDirectories_;
}
/**
* Provides the main source directories that should be compiled.
*
* @param directories the main source directories
* @return this operation instance
* @see #mainSourceDirectories(Path...)
*/
public CompileKotlinOperation mainSourceDirectoriesPaths(Collection directories) {
return mainSourceDirectories(directories.stream().map(Path::toFile).toList());
}
/**
* Provides the main source directories that should be compiled.
*
* @param directories the main source directories
* @return this operation instance
* @see #mainSourceDirectories(String...)
*/
public CompileKotlinOperation mainSourceDirectoriesStrings(Collection directories) {
return mainSourceDirectories(directories.stream().map(File::new).toList());
}
/**
* Provides main source files that should be compiled.
*
* @param files one or more main source files
* @return this operation instance
* @see #mainSourceFiles(Collection)
*/
public CompileKotlinOperation mainSourceFiles(File... files) {
return mainSourceFiles(List.of(files));
}
/**
* Provides main source files that should be compiled.
*
* @param files one or more main source files
* @return this operation instance
* @see #mainSourceFilesStrings(Collection)
*/
public CompileKotlinOperation mainSourceFiles(String... files) {
return mainSourceFilesStrings(List.of(files));
}
/**
* Provides main source files that should be compiled.
*
* @param files one or more main source files
* @return this operation instance
* @see #mainSourceFilesPaths(Collection)
*/
public CompileKotlinOperation mainSourceFiles(Path... files) {
return mainSourceFilesPaths(List.of(files));
}
/**
* Provides the main source files that should be compiled.
*
* @param files the main source files
* @return this operation instance
* @see #mainSourceFiles(File...)
*/
public CompileKotlinOperation mainSourceFiles(Collection files) {
mainSourceFiles_.addAll(files);
return this;
}
/**
* Retrieves the main files that should be compiled.
*
* @return the files
*/
public Collection mainSourceFiles() {
return mainSourceFiles_;
}
/**
* Provides the main source files that should be compiled.
*
* @param files the main source files
* @return this operation instance
* @see #mainSourceFiles(Path...)
*/
public CompileKotlinOperation mainSourceFilesPaths(Collection files) {
return mainSourceFiles(files.stream().map(Path::toFile).toList());
}
/**
* Provides the main source files that should be compiled.
*
* @param files the main source files
* @return this operation instance
* @see #mainSourceFiles(String...)
*/
public CompileKotlinOperation mainSourceFilesStrings(Collection files) {
return mainSourceFiles(files.stream().map(File::new).toList());
}
/**
* Provides compiler plugins.
*
* @param directory the directory containing the plugin JARs
* @param plugins one or more plugins
* @return this class instance
*/
public CompileKotlinOperation plugins(String directory, CompilerPlugin... plugins) {
return plugins(new File(directory), plugins);
}
/**
* Provides compiler plugins.
*
* @param plugins one or more plugins
* @return this class instance
*/
public CompileKotlinOperation plugins(String... plugins) {
return plugins(List.of(plugins));
}
/**
* Retrieves the compiler plugins.
*
* @return the compiler plugins
*/
public Collection plugins() {
return plugins_;
}
/**
* Provides compiler plugins.
*
* @param plugins the compiler plugins
* @return this class instance
*/
public CompileKotlinOperation plugins(Collection plugins) {
plugins_.addAll(plugins);
return this;
}
/**
* Provides compiler plugins.
*
* @param directory the directory containing the plugin JARs
* @param plugins one or more plugins
* @return this class instance
*/
public CompileKotlinOperation plugins(File directory, CompilerPlugin... plugins) {
for (var plugin : plugins) {
plugins_.add(new File(directory, plugin.jar).getAbsolutePath());
}
return this;
}
/**
* Provides compiler plugins.
*
* @param directory the directory containing the plugin JARs
* @param plugins one or more plugins
* @return this class instance
*/
public CompileKotlinOperation plugins(Path directory, CompilerPlugin... plugins) {
return plugins(directory.toFile(), plugins);
}
/**
* Provides compiler plugins located in the {@link #kotlinHome()} lib directory.
*
* @param plugins one or more plugins
* @return this class instance
* @see #plugins(File, CompilerPlugin...)
*/
public CompileKotlinOperation plugins(CompilerPlugin... plugins) {
if (kotlinHome_ != null) {
var kotlinLib = new File(kotlinHome_, "lib");
for (var plugin : plugins) {
plugins(kotlinLib, plugin);
}
} else {
if (LOGGER.isLoggable(Level.WARNING) && !silent()) {
LOGGER.warning("The Kotlin home must be set to specify compiler plugins directly.");
}
}
return this;
}
// Combine Kotlin sources
private Collection sources(Collection files, Collection directories) {
var sources = new ArrayList<>(files);
sources.addAll(directories);
return sources;
}
/**
* Provides test source directories that should be compiled.
*
* @param directories one or more test source directories
* @return this operation instance
* @see #testSourceDirectories(Collection)
*/
public CompileKotlinOperation testSourceDirectories(File... directories) {
return testSourceDirectories(List.of(directories));
}
/**
* Provides test source directories that should be compiled.
*
* @param directories one or more test source directories
* @return this operation instance
* @see #testSourceDirectoriesPaths(Collection)
*/
public CompileKotlinOperation testSourceDirectories(Path... directories) {
return testSourceDirectoriesPaths(List.of(directories));
}
/**
* Provides test source directories that should be compiled.
*
* @param directories one or more test source directories
* @return this operation instance
* @see #testSourceDirectoriesStrings(Collection)
*/
public CompileKotlinOperation testSourceDirectories(String... directories) {
return testSourceDirectoriesStrings(List.of(directories));
}
/**
* Provides the test source directories that should be compiled.
*
* @param directories the test source directories
* @return this operation instance
* @see #testSourceDirectories(File...)
*/
public CompileKotlinOperation testSourceDirectories(Collection directories) {
testSourceDirectories_.addAll(directories);
return this;
}
/**
* Retrieves the test source directories that should be compiled.
*
* @return the test source directories
*/
public Collection testSourceDirectories() {
return testSourceDirectories_;
}
/**
* Provides the test source directories that should be compiled.
*
* @param directories the test source directories
* @return this operation instance
* @see #testSourceDirectories(Path...)
*/
public CompileKotlinOperation testSourceDirectoriesPaths(Collection directories) {
return testSourceDirectories(directories.stream().map(Path::toFile).toList());
}
/**
* Provides the test source directories that should be compiled.
*
* @param directories the test source directories
* @return this operation instance
* @see #testSourceDirectories(String...)
*/
public CompileKotlinOperation testSourceDirectoriesStrings(Collection directories) {
return testSourceDirectories(directories.stream().map(File::new).toList());
}
/**
* Provides test source files that should be compiled.
*
* @param files one or more test source files
* @return this operation instance
* @see #testSourceFiles(Collection)
*/
public CompileKotlinOperation testSourceFiles(File... files) {
return testSourceFiles(List.of(files));
}
/**
* Provides the test sources files that should be compiled.
*
* @param files one or more test source files
* @return this operation instance
* @see #testSourceFilesStrings(Collection)
*/
public CompileKotlinOperation testSourceFiles(String... files) {
return testSourceFilesStrings(List.of(files));
}
/**
* Provides the test sources files that should be compiled.
*
* @param files one or more test source files
* @return this operation instance
* @see #testSourceFilesPaths(Collection)
*/
public CompileKotlinOperation testSourceFiles(Path... files) {
return testSourceFilesPaths(List.of(files));
}
/**
* Provides the test source files that should be compiled.
*
* @param files the test source files
* @return this operation instance
* @see #testSourceFiles(File...)
*/
public CompileKotlinOperation testSourceFiles(Collection files) {
testSourceFiles_.addAll(files);
return this;
}
/**
* Retrieves the test files that should be compiled.
*
* @return the test files
*/
public Collection testSourceFiles() {
return testSourceFiles_;
}
/**
* Provides the test source files that should be compiled.
*
* @param files the test source files
* @return this operation instance
* @see #testSourceFiles(Path...)
*/
public CompileKotlinOperation testSourceFilesPaths(Collection files) {
return testSourceFiles(files.stream().map(Path::toFile).toList());
}
/**
* Provides the test source files that should be compiled.
*
* @param files the test source files
* @return this operation instance
* @see #testSourceFiles(String...)
*/
public CompileKotlinOperation testSourceFilesStrings(Collection files) {
return testSourceFiles(files.stream().map(File::new).toList());
}
/**
* Retrieves the working directory.
*
* @return the directory
*/
public File workDir() {
return workDir_;
}
/**
* Provides the working directory, if it differs from the project's directory.
*
* @param dir the directory
* @return this operation instance
*/
public CompileKotlinOperation workDir(File dir) {
workDir_ = dir;
return this;
}
/**
* Provides the working directory, if it differs from the project's directory.
*
* @param dir the directory
* @return this operation instance
*/
public CompileKotlinOperation workDir(Path dir) {
return workDir(dir.toFile());
}
/**
* Provides the working directory, if it differs from the project's directory.
*
* @param dir the directory path
* @return this operation instance
*/
public CompileKotlinOperation workDir(String dir) {
return workDir(new File(dir));
}
}