Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tool integration with spi #41575

Closed
wants to merge 10 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.ballerina.cli.task.CreateExecutableTask;
import io.ballerina.cli.task.DumpBuildTimeTask;
import io.ballerina.cli.task.ResolveMavenDependenciesTask;
import io.ballerina.cli.task.RunBallerinaPreBuildToolsTask;
import io.ballerina.cli.utils.BuildTime;
import io.ballerina.cli.utils.FileUtils;
import io.ballerina.projects.BuildOptions;
Expand Down Expand Up @@ -176,6 +177,9 @@ public BuildCommand() {
hidden = true)
private Boolean exportComponentModel;

@CommandLine.Option(names = "--x", description = "",
hidden = true)
private String x;
@CommandLine.Option(names = "--enable-cache", description = "enable caches for the compilation", hidden = true)
private Boolean enableCache;

Expand Down Expand Up @@ -277,6 +281,7 @@ public void execute() {
TaskExecutor taskExecutor = new TaskExecutor.TaskBuilder()
// clean the target directory(projects only)
.addTask(new CleanTargetDirTask(isPackageModified, buildOptions.enableCache()), isSingleFileBuild)
.addTask(new RunBallerinaPreBuildToolsTask(outStream))
// resolve maven dependencies in Ballerina.toml
.addTask(new ResolveMavenDependenciesTask(outStream))
// compile the modules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@
public class CleanCommand implements BLauncherCmd {
private final PrintStream outStream;
private final Path projectPath;
private Path generatedDir;
private boolean exitWhenFinish;

@CommandLine.Option(names = {"--help", "-h"}, hidden = true)
private boolean helpFlag;

Expand All @@ -62,9 +63,9 @@ public CleanCommand() {
this.exitWhenFinish = true;
}

public CleanCommand(Path projectPath, boolean exitWhenFinish, Path targetDir) {
public CleanCommand(Path projectPath, PrintStream printStream, boolean exitWhenFinish, Path targetDir) {
this.projectPath = projectPath;
this.outStream = System.out;
this.outStream = printStream;
this.exitWhenFinish = exitWhenFinish;
this.targetDir = targetDir;
}
Expand Down Expand Up @@ -93,18 +94,40 @@ public void execute() {
CommandUtil.printError(this.outStream,
"provided target directory '" + this.targetDir + "' does not exist.",
null, false);
} else if (!Files.isDirectory(this.targetDir)) {
CommandUtil.printError(this.outStream,
"provided target path '" + this.targetDir + "' is not a directory.",
null, false);
} else {
ProjectUtils.deleteDirectory(this.targetDir);
this.outStream.println("Successfully deleted '" + this.targetDir + "'.");
}

//delete the generated directory
try {
Project project = BuildProject.load(this.projectPath);
this.generatedDir = project.sourceRoot().resolve(ProjectConstants.GENERATED_MODULES_ROOT);
} catch (ProjectException e) {
CommandUtil.printError(this.outStream, e.getMessage(), null, false);
CommandUtil.exitError(this.exitWhenFinish);
return;
}
if (!Files.isDirectory(this.targetDir)) {
if (Files.notExists(this.generatedDir)) {
CommandUtil.printError(this.outStream,
"provided target path '" + this.targetDir + "' is not a directory.",
"generated directory '" + this.generatedDir + "' does not exist.",
null, false);
CommandUtil.exitError(this.exitWhenFinish);
return;
}
if (!Files.isDirectory(this.generatedDir)) {
CommandUtil.printError(this.outStream,
"generated path is not a directory.",
null, false);
CommandUtil.exitError(this.exitWhenFinish);
return;
}
ProjectUtils.deleteDirectory(this.targetDir);
this.outStream.println("Successfully deleted '" + this.targetDir + "'.");
ProjectUtils.deleteDirectory(this.generatedDir);
this.outStream.println("Successfully deleted '" + this.generatedDir + "'.");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static String generateCommandHelp(String commandName, Map<String, CommandLine> s
}

private static void generateCommandDescription(CommandLine command, StringBuilder stringBuilder) {

String commandName = command.getCommandName();
BLauncherCmd bLauncherCmd = (BLauncherCmd) command.getCommandSpec().userObject();
CommandLine.Command annotation = bLauncherCmd.getClass().getAnnotation(CommandLine.Command.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ private static Optional<BLauncherCmd> getInvokedCmd(String... args) {

for (BLauncherCmd bCmd : bCmds) {
cmdParser.addSubcommand(bCmd.getName(), bCmd);
// cmdParser.setDefaultValueProvider(new SimpleDefaultProvider());
bCmd.setParentCmdParser(cmdParser);
}

Expand Down Expand Up @@ -436,3 +437,4 @@ public void setParentCmdParser(CommandLine parentCmdParser) {
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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 io.ballerina.cli.task;

import io.ballerina.cli.tool.BuildToolRunner;
import io.ballerina.cli.utils.FileUtils;
import io.ballerina.projects.Project;
import io.ballerina.projects.ProjectException;
import io.ballerina.projects.ToolContext;
import io.ballerina.tools.diagnostics.Diagnostic;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;

import java.io.IOException;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;
import java.util.ServiceLoader;

import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException;
import static io.ballerina.projects.PackageManifest.Tool;

/**
* Run .
*/
public class RunBallerinaPreBuildToolsTask implements Task {

private final PrintStream outStream;

public RunBallerinaPreBuildToolsTask(PrintStream out) {
this.outStream = out;
}

@Override
public void execute(Project project) {
Collection<Diagnostic> toolDiagnostics = project.currentPackage().manifest().diagnostics().diagnostics();
boolean hasTomlErrors = false;
for (Diagnostic d: toolDiagnostics) {
if (d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) {
System.out.println(d);
hasTomlErrors = true;
}
}
if (hasTomlErrors) {
throw createLauncherException("Ballerina toml validation for pre build tool execution contains errors");
}
List<Tool> tools = project.currentPackage().manifest().tools();
ServiceLoader<BuildToolRunner> buildRunners = ServiceLoader.load(BuildToolRunner.class);
for (Tool tool : tools) {
try {
String commandName = tool.getType();
BuildToolRunner targetTool = null;
for (BuildToolRunner buildRunner : buildRunners) {
if (buildRunner.getToolName().equals(commandName)) {
targetTool = buildRunner;
break;
}
}
if (targetTool != null) {
try {
if (tool.getOptionsToml() != null) {
boolean hasErrors = FileUtils.validateToml(tool.getOptionsToml(), tool.getType());
if (hasErrors) {
throw new ProjectException(
"Ballerina toml validation for pre build tool execution contains errors");
}
}
} catch (IOException e) {
outStream.println("WARNING: Skipping the validation of tool options due to : " +
e.getMessage());
}
ToolContext toolContext = ToolContext.from(tool, project.currentPackage());
targetTool.executeTool(toolContext);
boolean hasToolErrors = false;
for (Diagnostic d : targetTool.diagnostics()) {
outStream.println(d);
if (d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) {
hasToolErrors = true;
}
}
if (hasToolErrors) {
throw new ProjectException("Pre build tool " + tool.getType() + " execution contains errors");
}
} else {
// TODO: Install tool if not found
outStream.println("Command not found: " + commandName);
}
} catch (ProjectException e) {
throw createLauncherException(e.getMessage());
}
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.ballerina.cli.tool;

import io.ballerina.projects.ToolContext;
import io.ballerina.tools.diagnostics.Diagnostic;

import java.util.List;

public interface BuildToolRunner {
void executeTool(ToolContext toolContext);

String getToolName();

List<Diagnostic> diagnostics();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@

package io.ballerina.cli.utils;

import io.ballerina.toml.api.Toml;
import io.ballerina.toml.validator.TomlValidator;
import io.ballerina.toml.validator.schema.Schema;
import io.ballerina.tools.diagnostics.Diagnostic;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Optional;

Expand Down Expand Up @@ -88,4 +100,43 @@ private static int indexOfLastSeparator(String filename) {
return Math.max(lastUnixPos, lastWindowsPos);
}
}

public static String readSchema(String toolName) throws IOException {
String schemaFilePath = toolName + "-options-schema.json";
InputStream inputStream = io.ballerina.projects.util.FileUtils.class.getClassLoader().getResourceAsStream(schemaFilePath);

if (inputStream == null) {
throw new FileNotFoundException("Schema file for tool options inputStream not found: " + schemaFilePath);
}
StringBuilder sb = new StringBuilder();
try (
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(inputStreamReader);
) {
String content;
while ((content = br.readLine()) != null) {
if (sb.length() > 0) {
sb.append('\n');
}
sb.append(content);
}
}

return sb.toString();
}

public static boolean validateToml(Toml optionsToml, String toolName) throws IOException {
boolean hasErrors = false;
Schema schema = Schema.from(FileUtils.readSchema(toolName));
TomlValidator tomlValidator = new TomlValidator(schema);
tomlValidator.validate(optionsToml);
for (Diagnostic d : optionsToml.diagnostics()) {
System.out.println(d);
if (d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) {
hasErrors = true;
}
}
return hasErrors;
}

}
1 change: 1 addition & 0 deletions cli/ballerina-cli/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
exports io.ballerina.cli.launcher;
exports io.ballerina.cli.utils;
exports io.ballerina.cli.cmd;
exports io.ballerina.cli.tool;

requires io.ballerina.runtime;
requires io.ballerina.lang;
Expand Down
Loading
Loading