diff --git a/cli/ballerina-cli/build.gradle b/cli/ballerina-cli/build.gradle index d788d007c3be..5ce7b99e4f00 100644 --- a/cli/ballerina-cli/build.gradle +++ b/cli/ballerina-cli/build.gradle @@ -121,6 +121,7 @@ test { dependsOn copyProfilerResources systemProperty "ballerina.home", "$buildDir" + environment "BALLERINA_HOME_DIR", "${buildDir}/user-home" useTestNG() { suites 'src/test/resources/testng.xml' diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java index 5e4f99910c68..3fd79706c3bd 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java @@ -90,6 +90,7 @@ import static io.ballerina.projects.util.ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; import static io.ballerina.projects.util.ProjectConstants.CONFIG_DIR; import static io.ballerina.projects.util.ProjectConstants.REPOSITORIES_DIR; +import static io.ballerina.projects.util.ProjectUtils.BAL_TOOLS_TOML_PATH; /** * This class contains utility functions needed for Bal Tool tasks in the Main class. @@ -117,8 +118,6 @@ public final class BalToolsUtil { // if a command is a built-in tool command, add it to this list private static final List builtInToolCommands = List.of(); - private static final Path balToolsTomlPath = RepoUtils.createAndGetHomeReposPath().resolve( - Path.of(CONFIG_DIR, BAL_TOOLS_TOML)); private static final Path balaCacheDirPath = ProjectUtils.createAndGetHomeReposPath() .resolve(REPOSITORIES_DIR).resolve(CENTRAL_REPOSITORY_CACHE_NAME) .resolve(ProjectConstants.BALA_DIR_NAME); @@ -157,7 +156,7 @@ public static void addToolIfCommandIsABuiltInTool(String commandName) { if (!builtInToolCommands.contains(commandName)) { return; } - BalToolsToml balToolsToml = BalToolsToml.from(balToolsTomlPath); + BalToolsToml balToolsToml = BalToolsToml.from(BAL_TOOLS_TOML_PATH); BalToolsManifest balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); // if built in tool is already added, return if (balToolsManifest.getActiveTool(commandName).isPresent()) { @@ -263,7 +262,7 @@ public static List findJarFiles(File directory) { * bal-tools.toml file when the user moves from updates 6, 7 to update 8 and above. */ public static void updateOldBalToolsToml() { - BalToolsToml balToolsToml = BalToolsToml.from(balToolsTomlPath); + BalToolsToml balToolsToml = BalToolsToml.from(BAL_TOOLS_TOML_PATH); BalToolsManifestBuilder balToolsManifestBuilder = BalToolsManifestBuilder.from(balToolsToml); BalToolsManifest balToolsManifest = balToolsManifestBuilder.build(); Map oldTools = balToolsManifestBuilder.getOldTools(); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java index 8f28489847f9..770f5d897486 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java @@ -28,17 +28,21 @@ import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; import org.testng.annotations.DataProvider; +import org.wso2.ballerinalang.compiler.util.ProjectDirConstants; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.stream.Stream; import static io.ballerina.projects.util.ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; +import static io.ballerina.projects.util.ProjectConstants.REPOSITORIES_DIR; /** * Command tests super class. @@ -51,7 +55,10 @@ public abstract class BaseCommandTest { protected PrintStream printStream; protected Path homeCache; private final String userDir = System.getProperty("user.dir"); - + final Path testDotBallerina = Paths.get(System.getenv(ProjectDirConstants.HOME_REPO_ENV_KEY)); + final Path testCentralRepoCache = testDotBallerina.resolve(REPOSITORIES_DIR) + .resolve(CENTRAL_REPOSITORY_CACHE_NAME); + @BeforeClass public void setup() throws IOException { System.setProperty("java.command", "java"); @@ -61,6 +68,16 @@ public void setup() throws IOException { this.printStream = new PrintStream(this.console); } + @BeforeSuite + public void copyBalTools() throws IOException { + // copy the bal-tools.toml to /.ballerina/.config/ + Path balToolsTomlSrcPath = Paths.get("src/test/resources/test-resources/" + + "buildToolResources/tools/bal-tools.toml"); + Path balToolsTomlDstPath = testDotBallerina.resolve(".config"); + Files.createDirectories(balToolsTomlDstPath); + Files.copy(balToolsTomlSrcPath, balToolsTomlDstPath.resolve("bal-tools.toml")); + } + @BeforeMethod public void beforeMethod() { this.console = new ByteArrayOutputStream(); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java index 65256ca36247..1d180a2f3913 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java @@ -25,11 +25,8 @@ import io.ballerina.projects.SemanticVersion; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; -import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import org.ballerinalang.test.BCompileUtil; -import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; @@ -640,18 +637,14 @@ public void testBuildEmptyProjectWithCompilerPlugin() throws IOException { @Test(description = "Build an empty package with code generator build tools") public void testBuildEmptyProjectWithBuildTools() throws IOException { BCompileUtil.compileAndCacheBala(testResources.resolve("buildToolResources").resolve("tools") - .resolve("ballerina-generate-file").toString(), testDistCacheDirectory, projectEnvironmentBuilder); + .resolve("ballerina-generate-file").toString(), testCentralRepoCache, projectEnvironmentBuilder); Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", RepoUtils.getBallerinaShortVersion()); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - try (MockedStatic repoUtils = Mockito.mockStatic( - BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - new CommandLine(buildCommand).parseArgs(); - buildCommand.execute(); - } + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + new CommandLine(buildCommand).parseArgs(); + buildCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals(buildLog.replace("\r", "").replace("\\", "/"), getOutput("build-empty-project-with-build-tools.txt")); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java index 80f7efef4e41..eb536283d3a2 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java @@ -21,12 +21,11 @@ import io.ballerina.cli.launcher.BLauncherException; import io.ballerina.cli.task.RunBuildToolsTask; import io.ballerina.projects.BuildOptions; +import io.ballerina.projects.JvmTarget; import io.ballerina.projects.Project; import io.ballerina.projects.directory.BuildProject; -import io.ballerina.projects.util.BuildToolUtils; +import io.ballerina.projects.util.ProjectConstants; import org.ballerinalang.test.BCompileUtil; -import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -42,7 +41,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; -import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; /** * Test cases for the RunBuildToolsTask. @@ -51,9 +49,6 @@ */ public class RunBuildToolsTaskTest extends BaseCommandTest { private Path buildToolResources; - private static final Path testBuildDirectory = Path.of("build").toAbsolutePath(); - private static final Path testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path mockCentralBalaDirPath = testDistCacheDirectory.resolve("bala"); private static final long TWO_DAYS = 2 * 24 * 60 * 60 * 1000; private static final long HALF_DAY = 12 * 60 * 60 * 1000; @@ -67,6 +62,7 @@ public void setup() throws IOException { super.setup(); Files.createDirectories(LOG_FILE.getParent()); Files.writeString(LOG_FILE, ""); + // copy all test resources try { Path testResources = super.tmpDir.resolve("build-tool-test-resources"); @@ -77,19 +73,27 @@ public void setup() throws IOException { } catch (Exception e) { Assert.fail("error loading resources"); } + // compile and cache tools BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("dummy-tool-pkg").toString(), testDistCacheDirectory); + .resolve("dummy-tool-pkg").toString(), testCentralRepoCache); BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("invalid-name-tool-pkg").toString(), testDistCacheDirectory); + .resolve("invalid-name-tool-pkg").toString(), testCentralRepoCache); BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("ballerina-generate-file").toString(), testDistCacheDirectory); + .resolve("ballerina-generate-file").toString(), testCentralRepoCache); BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("hidden-cmd-tool-pkg").toString(), testDistCacheDirectory); + .resolve("hidden-cmd-tool-pkg").toString(), testCentralRepoCache); BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("missing-interface-tool-pkg").toString(), testDistCacheDirectory); + .resolve("missing-interface-tool-pkg").toString(), testCentralRepoCache); BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") - .resolve("no-options-tool-pkg").toString(), testDistCacheDirectory); + .resolve("no-options-tool-pkg").toString(), testCentralRepoCache); + + BCompileUtil.compileAndCacheBala(buildToolResources.resolve("tools") + .resolve("dummy-tool-pkg-higher-dist").toString(), testCentralRepoCache); + + Path balaPath = testCentralRepoCache.resolve("bala").resolve("foo") + .resolve("dummypkghigherdist").resolve("1.4.0").resolve(JvmTarget.JAVA_21.code()); + replacePkgDistVersion(balaPath); // add build.json files addBuildJsonToProjects("project-lt-24h-with-build-tool", System.currentTimeMillis() - HALF_DAY); addBuildJsonToProjects("project-gt-24h-with-build-tool", System.currentTimeMillis() - TWO_DAYS); @@ -98,26 +102,24 @@ public void setup() throws IOException { @Test(description = "Resolve a tool offline", dataProvider = "buildToolOfflineProvider") public void testOfflineToolResolution(String projectName, String outputFileName, boolean sticky, boolean isError) throws IOException { + Path projectPath = buildToolResources.resolve(projectName); Project project = BuildProject.load(projectPath, BuildOptions.builder().setOffline(true).setSticky(sticky).build()); RunBuildToolsTask runBuildToolsTask = new RunBuildToolsTask(printStream); - try (MockedStatic repoUtils = Mockito.mockStatic( - BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(mockCentralBalaDirPath); - try { - runBuildToolsTask.execute(project); - } catch (BLauncherException e) { - if (!isError) { - String errorMsg = "Error executing build tools task for project: " + projectName - + (sticky ? "with sticky." : "without sticky. ") + e.getMessage(); - Assert.fail(errorMsg); - } - List messages = e.getMessages(); - Assert.assertEquals(messages.size(), 1); - Assert.assertEquals(messages.get(0), "error: build tool execution contains errors"); + try { + runBuildToolsTask.execute(project); + } catch (BLauncherException e) { + if (!isError) { + String errorMsg = "Error executing build tools task for project: " + projectName + + (sticky ? " with sticky." : " without sticky. ") + e.getMessage(); + Assert.fail(errorMsg); } + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), "error: build tool execution contains errors"); } + String buildLog = readOutput(true); Assert.assertEquals(buildLog.replace("\r", ""), getOutput(outputFileName)); } @@ -127,11 +129,7 @@ public void testProjectForAddedGeneratedCode() throws IOException { Path projectPath = buildToolResources.resolve("project-with-generate-file-tool"); Project project = BuildProject.load(projectPath, BuildOptions.builder().setOffline(true).build()); RunBuildToolsTask runBuildToolsTask = new RunBuildToolsTask(printStream); - try (MockedStatic repoUtils = Mockito.mockStatic( - BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(mockCentralBalaDirPath); - runBuildToolsTask.execute(project); - } + runBuildToolsTask.execute(project); String buildLog = readOutput(true); Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-tool-generate-file.txt")); AtomicBoolean fileFound = new AtomicBoolean(false); @@ -241,6 +239,12 @@ public Object[][] buildToolOfflineProvider() { false, false }, + { + "project-with-higher-dist-build-tool", + "build-tool-higher-dist-resolve-failed.txt", + false, + true + } }; } @@ -268,4 +272,15 @@ public void cleanUp() throws IOException { Files.deleteIfExists(LOG_FILE.getParent()); Files.deleteIfExists(LOG_FILE.getParent().getParent()); } + + private void replacePkgDistVersion(Path balaPath) { + Path packageJson = balaPath.resolve(ProjectConstants.PACKAGE_JSON); + try { + String content = Files.readString(packageJson); + content = content.replace(RepoUtils.getBallerinaShortVersion(), "2201.99.0"); + Files.writeString(packageJson, content); + } catch (IOException e) { + Assert.fail("Error replacing distribution version in bala"); + } + } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java index f8b5daff4463..f38a073dd7d6 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java @@ -5,12 +5,9 @@ import io.ballerina.projects.ProjectEnvironmentBuilder; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; -import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.ballerinalang.test.BCompileUtil; -import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; @@ -415,18 +412,14 @@ public void testRunEmptyPackage() throws IOException { public void testRunEmptyProjectWithBuildTools() throws IOException { BCompileUtil.compileAndCacheBala( testResources.resolve("buildToolResources/tools/ballerina-generate-file").toString(), - testDistCacheDirectory, projectEnvironmentBuilder); + testCentralRepoCache, projectEnvironmentBuilder); Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", RepoUtils.getBallerinaShortVersion()); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - try (MockedStatic repoUtils = Mockito.mockStatic( - BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); - RunCommand runCommand = new RunCommand(projectPath, printStream, false); - new CommandLine(runCommand).parseArgs(); - runCommand.execute(); - } + RunCommand runCommand = new RunCommand(projectPath, printStream, false); + new CommandLine(runCommand).parseArgs(); + runCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("run-empty-project-with-build-tools.txt")); } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java index fdf429d69190..a4492bd2a747 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java @@ -23,7 +23,6 @@ import io.ballerina.projects.ProjectEnvironmentBuilder; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; -import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; import org.apache.commons.codec.digest.DigestUtils; @@ -417,18 +416,14 @@ public void testTestEmptyPackage() throws IOException { public void testTestEmptyProjectWithBuildTools() throws IOException { BCompileUtil.compileAndCacheBala( testResources.resolve("buildToolResources/tools/ballerina-generate-file").toString(), - testDistCacheDirectory, projectEnvironmentBuilder); + testCentralRepoCache, projectEnvironmentBuilder); Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", RepoUtils.getBallerinaShortVersion()); System.setProperty("user.dir", projectPath.toString()); - try (MockedStatic repoUtils = Mockito.mockStatic( - BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); - TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); - new CommandLine(testCommand).parseArgs(); - testCommand.execute(); - } + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs(); + testCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals(buildLog.replace("\r", ""), getOutput("test-empty-project-with-build-tools.txt")); } diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/fresh-project-with-central-build-tool/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/fresh-project-with-central-build-tool/Ballerina.toml index 77d666333090..55041b9f4c39 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/fresh-project-with-central-build-tool/Ballerina.toml +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/fresh-project-with-central-build-tool/Ballerina.toml @@ -3,7 +3,7 @@ org = "foo" name = "winery" version = "0.1.0" -[[tool.dummy_tool]] +[[tool.dummy_tool2]] id = "main_dummy" filePath = "delivery.json" targetModule = "mod_main" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Ballerina.toml new file mode 100644 index 000000000000..7523e9cfeccc --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Ballerina.toml @@ -0,0 +1,10 @@ +[package] +org = "foo" +name = "winery" +version = "0.1.0" + +[[tool.dummy_tool_higher_dist]] +id = "main_dummy" +filePath = "delivery.json" +targetModule = "mod_main" +options.mode = "client" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Dependencies.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Dependencies.toml new file mode 100644 index 000000000000..4fc4e41578b0 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/Dependencies.toml @@ -0,0 +1,23 @@ + # AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.8.5" + +[[package]] +org = "foo" +name = "winery" +version = "0.1.0" +modules = [ + {org = "foo", packageName = "winery", moduleName = "winery"} +] + +[[tool]] +id = "dummy_tool" +org = "foo" +name = "dummypkg" +version = "1.4.0" + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/main.bal new file mode 100644 index 000000000000..fd36f05068fe --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/project-with-higher-dist-build-tool/main.bal @@ -0,0 +1,3 @@ +public function main() { + return; +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/bal-tools.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/bal-tools.toml new file mode 100644 index 000000000000..6fd2a7450f79 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/bal-tools.toml @@ -0,0 +1,48 @@ +[[tool]] +id = "dummy_tool" +org = "foo" +name = "dummypkg" +version = "1.4.0" +active = false + +[[tool]] +id = "hidden_cmd_dummy_tool" +org = "foo" +name = "hidden_cmd_pkg" +version = "1.4.0" +active = false + +[[tool]] +id = "missing_interface_dummy_tool" +org = "foo" +name = "missing_interface_pkg" +version = "1.4.0" +active = false + +[[tool]] +id = "no_options_tool" +org = "foo" +name = "no_options_pkg" +version = "1.4.0" +active = false + +[[tool]] +id = "dummy_tool_invalid_name" +org = "foo" +name = "dummypkg_invalid_name" +version = "1.4.0" +active = false + +[[tool]] +id = "dummy_tool_higher_dist" +org = "foo" +name = "dummypkghigherdist" +version = "1.4.0" +active = false + +[[tool]] +id = "generate_file" +org = "foo" +name = "ballerina_generate_file" +version = "0.1.0" +active = false diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/BalTool.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/BalTool.toml new file mode 100644 index 000000000000..5714fddd7242 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/BalTool.toml @@ -0,0 +1,5 @@ +[tool] +id="dummy_tool_higher_dist" + +[[dependency]] +path="./resources/sample-dummy-build-tool-1.4.0.jar" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/Ballerina.toml new file mode 100644 index 000000000000..cb0022ccad21 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "foo" +name = "dummypkghigherdist" +version = "1.4.0" +distribution = "2201.99.0" + +[build-options] +observabilityIncluded = true diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/main.bal new file mode 100644 index 000000000000..6b71ef415c69 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/main.bal @@ -0,0 +1,2 @@ +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/resources/sample-dummy-build-tool-1.4.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/resources/sample-dummy-build-tool-1.4.0.jar new file mode 100644 index 000000000000..a933078f43e8 Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg-higher-dist/resources/sample-dummy-build-tool-1.4.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-higher-dist-resolve-failed.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-higher-dist-resolve-failed.txt new file mode 100644 index 000000000000..65b6559077e5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-higher-dist-resolve-failed.txt @@ -0,0 +1,3 @@ + +Executing Build Tools +ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool_higher_dist' cannot be resolved diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt index ee003828e127..c82fe6570eaf 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt @@ -1,3 +1,3 @@ Executing Build Tools -ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool' cannot be resolved +ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool2' cannot be resolved diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-higher-dist-resolve-failed.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-higher-dist-resolve-failed.txt new file mode 100644 index 000000000000..65b6559077e5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-higher-dist-resolve-failed.txt @@ -0,0 +1,3 @@ + +Executing Build Tools +ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool_higher_dist' cannot be resolved diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt index ee003828e127..c82fe6570eaf 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt @@ -1,3 +1,3 @@ Executing Build Tools -ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool' cannot be resolved +ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool2' cannot be resolved diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java index 12c5a832f77e..edb776c76b37 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java @@ -22,11 +22,15 @@ import io.ballerina.projects.buildtools.ToolContext; import io.ballerina.projects.environment.PackageLockingMode; import io.ballerina.projects.environment.ToolResolutionRequest; +import io.ballerina.projects.internal.PackageDiagnostic; +import io.ballerina.projects.internal.ProjectDiagnosticErrorCode; import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import io.ballerina.toml.semantic.diagnostics.TomlDiagnostic; import io.ballerina.toml.semantic.diagnostics.TomlNodeLocation; import io.ballerina.tools.diagnostics.Diagnostic; +import io.ballerina.tools.diagnostics.DiagnosticInfo; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; import org.ballerinalang.central.client.CentralAPIClient; import org.ballerinalang.central.client.exceptions.CentralClientException; import org.ballerinalang.central.client.model.ToolResolutionCentralRequest; @@ -43,6 +47,7 @@ import java.util.Set; import java.util.stream.Collectors; +import static io.ballerina.projects.util.ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; import static io.ballerina.projects.util.ProjectConstants.DEFAULT_VERSION; import static io.ballerina.projects.util.ProjectUtils.getAccessTokenOfCLI; import static io.ballerina.projects.util.ProjectUtils.initializeProxy; @@ -125,18 +130,28 @@ private void resolveToolDependencies() { if (resolutionRequiredTools.isEmpty()) { return; } + PackageLockingMode packageLockingMode = getPackageLockingMode(currentProject); + updateLockedToolDependencyVersions(resolutionRequiredTools, currentProject); try { - resolvedTools.addAll(resolveToolVersions(currentProject, resolutionRequiredTools)); + resolvedTools.addAll(resolveToolVersions(packageLockingMode, currentProject.buildOptions().offlineBuild(), + resolutionRequiredTools)); } catch (CentralClientException e) { - throw new ProjectException("Failed to resolve build tools: " + e.getMessage()); + DiagnosticInfo diagnosticInfo = new DiagnosticInfo( + ProjectDiagnosticErrorCode.CENTRAL_CONNECTION_ERROR.diagnosticId(), + "connection to central failed. Continuing the tool resolution offline, reason: '" + + e.getMessage() + "'", + DiagnosticSeverity.WARNING); + PackageDiagnostic diagnostic = new PackageDiagnostic(diagnosticInfo, + currentProject.currentPackage().descriptor().name().toString()); + diagnosticList.add(diagnostic); + resolvedTools.addAll(getToolResolutionResponseOffline(resolutionRequiredTools, packageLockingMode)); } } - private List resolveToolVersions(Project project, List unresolvedTools) + private List resolveToolVersions(PackageLockingMode packageLockingMode, boolean offline, + List unresolvedTools) throws CentralClientException { - PackageLockingMode packageLockingMode = getPackageLockingMode(project); - updateLockedToolDependencyVersions(unresolvedTools, project); - if (project.buildOptions().offlineBuild()) { + if (offline) { return getToolResolutionResponseOffline(unresolvedTools, packageLockingMode); } Set resolutionRequests = getToolResolutionRequests(unresolvedTools, packageLockingMode); @@ -173,29 +188,33 @@ private List getToolResolutionResponseOffline(List unresol PackageLockingMode packageLockingMode) { List resolvedTools = new ArrayList<>(); for (BuildTool tool: unresolvedTools) { - BuildToolId id = tool.id(); - PackageOrg org = tool.org(); - PackageName name = tool.name(); + String id = tool.id().toString(); PackageVersion version = tool.version(); - if (tool.org() == null || tool.name() == null) { - TomlDiagnostic diagnostic = BuildToolUtils.getCannotResolveBuildToolDiagnostic(tool.id().value(), + + Optional latestCompatibleVersion = BuildToolUtils + .getCompatibleToolVersionsAvailableLocally(tool, version, packageLockingMode);; + if (latestCompatibleVersion.isEmpty()) { + String toolIdAndVersionOpt = id + (version == null ? "" : ":" + tool.version().toString()); + TomlDiagnostic diagnostic = BuildToolUtils.getCannotResolveBuildToolDiagnostic(toolIdAndVersionOpt, tool.location()); diagnosticList.add(diagnostic); continue; } - List versions = BuildToolUtils.getCompatibleToolVersionsInLocalCache(org, name); - Optional latestCompVersion = - BuildToolUtils.getLatestCompatibleVersion(version.value(), versions, packageLockingMode); - if (latestCompVersion.isEmpty()) { - String toolIdAndVersionOpt = tool.id().value() - + (tool.version() == null ? "" : ":" + tool.version().toString()); + BalToolsManifest.Tool latestTool = latestCompatibleVersion.get(); + if (!BuildToolUtils.isToolAvailableLocally(latestTool.org(), + latestTool.name(), latestTool.version(), CENTRAL_REPOSITORY_CACHE_NAME)) { + String toolIdAndVersionOpt = id + ":" + version.toString(); TomlDiagnostic diagnostic = BuildToolUtils.getCannotResolveBuildToolDiagnostic(toolIdAndVersionOpt, tool.location()); diagnosticList.add(diagnostic); continue; } - resolvedTools.add(BuildTool.from(id, org, name, - PackageVersion.from(latestCompVersion.get()), tool.location())); + resolvedTools.add(BuildTool.from( + tool.id(), + PackageOrg.from(latestTool.org()), + PackageName.from(latestTool.name()), + PackageVersion.from(latestTool.version()), + tool.location())); } return resolvedTools; } @@ -263,13 +282,15 @@ private List getToolResolutionResponse(ToolResolutionCentralRequest t diagnosticList.add(diagnostic); continue; } - resolvedTools.add(BuildTool.from( + BuildTool buildTool = BuildTool.from( BuildToolId.from(tool.id()), PackageOrg.from(tool.org()), PackageName.from(tool.name()), PackageVersion.from(tool.version()), location - )); + ); + resolvedTools.add(buildTool); + BuildToolUtils.addToolToBalToolsToml(buildTool); } return resolvedTools; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java index 4f33729745f9..b16f7660508f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java @@ -68,6 +68,9 @@ public enum ProjectDiagnosticErrorCode implements DiagnosticCode { // Error codes used in resources resolution CONFLICTING_RESOURCE_FILE("BCE5601", "conflicting.resources.type"), DEPRECATED_RESOURCES_STRUCTURE("BCE5602", "deprecated.resources.structure"), + + // Error code for central connection failures + CENTRAL_CONNECTION_ERROR("BCE5701", "central.connection.error"); ; private final String diagnosticId; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java index 63e3d22943b0..932dc4fb16a2 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java @@ -18,15 +18,20 @@ package io.ballerina.projects.util; +import io.ballerina.projects.BalToolsManifest; +import io.ballerina.projects.BalToolsToml; +import io.ballerina.projects.BuildTool; import io.ballerina.projects.JvmTarget; import io.ballerina.projects.PackageManifest; import io.ballerina.projects.PackageName; import io.ballerina.projects.PackageOrg; +import io.ballerina.projects.PackageVersion; import io.ballerina.projects.ProjectException; import io.ballerina.projects.SemanticVersion; import io.ballerina.projects.buildtools.CodeGeneratorTool; import io.ballerina.projects.buildtools.ToolConfig; import io.ballerina.projects.environment.PackageLockingMode; +import io.ballerina.projects.internal.BalToolsManifestBuilder; import io.ballerina.projects.internal.BalaFiles; import io.ballerina.projects.internal.ProjectDiagnosticErrorCode; import io.ballerina.toml.semantic.diagnostics.TomlDiagnostic; @@ -42,6 +47,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; import java.util.stream.Stream; @@ -50,6 +56,7 @@ import static io.ballerina.projects.util.ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; import static io.ballerina.projects.util.ProjectConstants.REPOSITORIES_DIR; import static io.ballerina.projects.util.ProjectUtils.CompatibleRange; +import static io.ballerina.projects.util.ProjectUtils.BAL_TOOLS_TOML_PATH; /** * Utility methods required for build tools. @@ -162,58 +169,17 @@ private static Optional getTargetToolRec( return Optional.empty(); } - /** - * Find the tool versions that reside in the central cache in user home, filter the tools compatible with the - * current Ballerina distribution and return. - * - * @param org organization of the tool package - * @param name package name of the tool package - * @return list of all compatible tool versions - */ - public static List getCompatibleToolVersionsInLocalCache(PackageOrg org, PackageName name) { - List availableVersions = new ArrayList<>(); - List versions = new ArrayList<>(); - try { - Path centralBalaDirPath = getCentralBalaDirPath(); - Path balaPackagePath = centralBalaDirPath.resolve(org.value()).resolve(name.value()); - if (Files.exists(balaPackagePath)) { - try (Stream versionFiles = Files.list(balaPackagePath)) { - versions.addAll(versionFiles.toList()); - } - } - } catch (IOException e) { - throw new ProjectException("Error while accessing Distribution cache: " + e.getMessage()); - } - versions.removeAll(getIncompatibleVersions(versions, org, name)); - versions.stream().map(path -> Optional.ofNullable(path) - .map(Path::getFileName) - .map(Path::toString) - .orElse("0.0.0")).forEach(version -> { - try { - availableVersions.add(SemanticVersion.from(version)); - } catch (ProjectException ignored) { - } - }); - return availableVersions; - } - - /** - * Out of the passed list of tool versions, select the ones within the compatibility range of package locking mode, - * and get the latest out of them. + /** Returns whether the tool is available locally. * - * @param version currently recorded version - * @param versions list of versions that are candidates for the latest version - * @param packageLockingMode locking mode of the package - * @return return the latest compatible version if any + * @param org organization of the package + * @param name name of the package + * @return whether the tool is available locally */ - public static Optional getLatestCompatibleVersion( - SemanticVersion version, - List versions, - PackageLockingMode packageLockingMode) { - CompatibleRange compatibleRange = ProjectUtils.getCompatibleRange(version, packageLockingMode); - List versionsInCompatibleRange = ProjectUtils.getVersionsInCompatibleRange( - version, versions, compatibleRange); - return getLatestVersion(versionsInCompatibleRange); + public static boolean isToolAvailableLocally(String org, String name, String version, String repositoryName) { + Path toolCacheDir = RepoUtils.createAndGetHomeReposPath() + .resolve(REPOSITORIES_DIR).resolve(repositoryName) + .resolve(BALA_DIR_NAME).resolve(org).resolve(name).resolve(version); + return toolCacheDir.toFile().isDirectory(); } /** @@ -267,24 +233,97 @@ public static TomlNodeLocation getFirstToolEntryLocation(String toolId, List getIncompatibleVersions(List versions, PackageOrg org, PackageName name) { - List incompatibleVersions = new ArrayList<>(); - if (!versions.isEmpty()) { - for (Path ver : versions) { - Path pkgJsonPath = getPackagePath(org.value(), name.value(), - Optional.of(ver.getFileName()).get().toFile().getName()).resolve(ProjectConstants.PACKAGE_JSON); - if (Files.exists(pkgJsonPath)) { - String packageVer = BalaFiles.readPkgJson(pkgJsonPath).getBallerinaVersion(); - String packVer = RepoUtils.getBallerinaShortVersion(); - if (!isCompatible(packageVer, packVer)) { - incompatibleVersions.add(ver); - } - } else { - incompatibleVersions.add(ver); + /** + * Get the available tool versions from the bal-tools.toml and find the versions compatible + * with the current distribution in the central cache. + * + * @param tool build tool + * @param minVersion compatible range of the tool + * @param packageLockingMode locking mode of the package + * @return list of all compatible tool versions + */ + public static Optional getCompatibleToolVersionsAvailableLocally( + BuildTool tool, PackageVersion minVersion, PackageLockingMode packageLockingMode) { + PackageOrg org = tool.org(); + PackageName name = tool.name(); + Map> toolVersions; + + if (tool.org() == null || tool.name() == null) { + BalToolsToml balToolsToml = BalToolsToml.from(BAL_TOOLS_TOML_PATH); + BalToolsManifest balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); + toolVersions = balToolsManifest.tools().get(tool.id().toString()); + if (toolVersions == null) { + return Optional.empty(); + } + if (toolVersions.values().stream().findAny().isPresent()) { + org = PackageOrg.from( + toolVersions.values().stream().findAny().get().values().stream().findAny().get().org()); + name = PackageName.from( + toolVersions.values().stream().findAny().get().values().stream().findAny().get().name()); + } + } + + List distCompatibleVersions = getCompatibleToolVersions(org, name); + SemanticVersion minSemVer = (minVersion == null) ? null : minVersion.value(); + CompatibleRange compatibleRange = ProjectUtils.getCompatibleRange(minSemVer, packageLockingMode); + List versionsInCompatibleRange = ProjectUtils.getVersionsInCompatibleRange( + minSemVer, distCompatibleVersions, compatibleRange); + Optional latestVersion = getLatestVersion(versionsInCompatibleRange); + + if (latestVersion.isEmpty()) { + return Optional.empty(); + } + return Optional.of(new BalToolsManifest.Tool(tool.id().toString(), org.value(), name.value(), + latestVersion.get().toString(), false, null)); + } + + /** + * Find the tool versions that reside in the central cache in user home, filter the tools compatible with the + * current Ballerina distribution and return. + * + * @param org organization of the tool package + * @param name package name of the tool package + * @return list of all compatible tool versions + */ + private static List getCompatibleToolVersions(PackageOrg org, PackageName name) { + List versions = new ArrayList<>(); + Path centralBalaDirPath = getCentralBalaDirPath(); + Path balaParentPath = centralBalaDirPath.resolve(org.value()).resolve(name.value()); + if (Files.exists(balaParentPath)) { + try (Stream versionFiles = Files.list(balaParentPath)) { + versions.addAll(versionFiles.map(path -> Optional.of(path.getFileName()).get().toString()) + .toList()); + } catch (IOException e) { + throw new ProjectException("Error while accessing the central cache: " + e.getMessage()); + } + } + List compatibleVersions = new ArrayList<>(); + for (String version : versions) { + Path balaPackagePath = getPackagePath(org.value(), name.value(), version); + if (Files.exists(balaPackagePath)) { + String packageVer = BalaFiles.readPkgJson(balaPackagePath.resolve(ProjectConstants.PACKAGE_JSON)) + .getBallerinaVersion(); + String packVer = RepoUtils.getBallerinaShortVersion(); + if (isCompatible(packageVer, packVer)) { + compatibleVersions.add(SemanticVersion.from(version)); } } } - return incompatibleVersions; + return compatibleVersions; + } + + public static void addToolToBalToolsToml(BuildTool tool) { + BalToolsToml balToolsToml = BalToolsToml.from(BAL_TOOLS_TOML_PATH); + BalToolsManifest balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); + + balToolsManifest.addTool( + tool.id().toString(), + tool.org().toString(), + tool.name().toString(), + tool.version().toString(), + false, + null); + balToolsToml.modify(balToolsManifest); } private static Path getPackagePath(String org, String name, String version) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java index 760313d232fb..128dbd27b65f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java @@ -103,10 +103,12 @@ import static io.ballerina.projects.util.ProjectConstants.BALLERINA_HOME; import static io.ballerina.projects.util.ProjectConstants.BALLERINA_HOME_BRE; import static io.ballerina.projects.util.ProjectConstants.BALLERINA_TOML; +import static io.ballerina.projects.util.ProjectConstants.BAL_TOOLS_TOML; import static io.ballerina.projects.util.ProjectConstants.BLANG_COMPILED_JAR_EXT; import static io.ballerina.projects.util.ProjectConstants.BLANG_COMPILED_PKG_BINARY_EXT; import static io.ballerina.projects.util.ProjectConstants.BUILD_FILE; import static io.ballerina.projects.util.ProjectConstants.CACHES_DIR_NAME; +import static io.ballerina.projects.util.ProjectConstants.CONFIG_DIR; import static io.ballerina.projects.util.ProjectConstants.DIFF_UTILS_JAR; import static io.ballerina.projects.util.ProjectConstants.DIR_PATH_SEPARATOR; import static io.ballerina.projects.util.ProjectConstants.DOT; @@ -136,6 +138,9 @@ public final class ProjectUtils { private static final Pattern separatedIdentifierWithHyphenPattern = Pattern.compile("^[a-zA-Z0-9_.-]*$"); private static final List projectLoadingDiagnostic = new ArrayList<>(); + public static final Path BAL_TOOLS_TOML_PATH = RepoUtils.createAndGetHomeReposPath().resolve( + Path.of(CONFIG_DIR, BAL_TOOLS_TOML)); + private ProjectUtils() { } diff --git a/compiler/ballerina-lang/src/main/resources/dependencies-toml-schema.json b/compiler/ballerina-lang/src/main/resources/dependencies-toml-schema.json index e272c21ec601..076d289c2dec 100644 --- a/compiler/ballerina-lang/src/main/resources/dependencies-toml-schema.json +++ b/compiler/ballerina-lang/src/main/resources/dependencies-toml-schema.json @@ -163,10 +163,10 @@ "properties": { "id": { "type": "string", - "pattern": "^[a-zA-Z0-9_]*$", + "pattern": "^[a-zA-Z0-9_-]*$", "maxLength": 256, "message": { - "pattern": "invalid 'id' under [[tool]]: 'id' can only contain alphanumerics and underscores", + "pattern": "invalid 'id' under [[tool]]: 'id' can only contain alphanumerics, underscore and hyphen", "maxLength": "invalid 'id' under [[tool]]: maximum length of 'id' is 256 characters" }, "allOf": [