From 59c57bac10bb007afca0c7e0e20236db04f68faa Mon Sep 17 00:00:00 2001 From: Gunnar Wagenknecht Date: Sun, 8 Dec 2024 11:23:31 +0100 Subject: [PATCH] Begin work on tests --- .../.classpath | 2 +- .../.settings/org.eclipse.jdt.core.prefs | 6 +- .../META-INF/MANIFEST.MF | 2 +- .../plugin.xml | 4 + .../bazel/eclipse/core/model/BazelModel.java | 6 +- .../discovery/BaseProvisioningStrategy.java | 2 +- .../starlark/StarlarkAnalyzeInfo.java | 8 +- .../starlark/StarlarkFunctionCallInfo.java | 7 +- .../starlark/StarlarkMacroCallAnalyzer.java | 78 ++- .../StarlarkNativeModuleApiDummy.java | 25 +- .../testdata/src/testdata/SharedTestData.java | 2 + bundles/testdata/workspaces/001/MODULE.bazel | 6 + bundles/testdata/workspaces/002/.bazelproject | 16 + bundles/testdata/workspaces/002/.gitignore | 11 + bundles/testdata/workspaces/002/MODULE.bazel | 6 + bundles/testdata/workspaces/002/WORKSPACE | 27 + bundles/testdata/workspaces/002/module1/BUILD | 5 + .../002/module1/java/src/log/Logger.java | 16 + .../workspaces/002/third_party/maven/BUILD | 0 .../002/third_party/maven/dependencies.bzl | 31 + .../testdata/workspaces/002/tools/macro/BUILD | 0 .../workspaces/002/tools/macro/defs.bzl | 9 + docs/common/projectviews.md | 21 +- .../.classpath | 2 +- ...pse.core.tests - all headless tests.launch | 556 +++++++++++++++--- .../.settings/org.eclipse.jdt.core.prefs | 6 +- .../META-INF/MANIFEST.MF | 9 +- .../StarlarkMacroCallAnalyzerTest.java | 68 +++ .../it/Workspace002Test_Provisioning.java | 101 ++++ 29 files changed, 895 insertions(+), 137 deletions(-) create mode 100644 bundles/testdata/workspaces/001/MODULE.bazel create mode 100644 bundles/testdata/workspaces/002/.bazelproject create mode 100644 bundles/testdata/workspaces/002/.gitignore create mode 100644 bundles/testdata/workspaces/002/MODULE.bazel create mode 100644 bundles/testdata/workspaces/002/WORKSPACE create mode 100644 bundles/testdata/workspaces/002/module1/BUILD create mode 100644 bundles/testdata/workspaces/002/module1/java/src/log/Logger.java create mode 100644 bundles/testdata/workspaces/002/third_party/maven/BUILD create mode 100644 bundles/testdata/workspaces/002/third_party/maven/dependencies.bzl create mode 100644 bundles/testdata/workspaces/002/tools/macro/BUILD create mode 100644 bundles/testdata/workspaces/002/tools/macro/defs.bzl create mode 100644 tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzerTest.java create mode 100644 tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/tests/it/Workspace002Test_Provisioning.java diff --git a/bundles/com.salesforce.bazel.eclipse.core/.classpath b/bundles/com.salesforce.bazel.eclipse.core/.classpath index d4dbdb136..c5714f713 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/.classpath +++ b/bundles/com.salesforce.bazel.eclipse.core/.classpath @@ -1,6 +1,6 @@ - + diff --git a/bundles/com.salesforce.bazel.eclipse.core/.settings/org.eclipse.jdt.core.prefs b/bundles/com.salesforce.bazel.eclipse.core/.settings/org.eclipse.jdt.core.prefs index fe700e3ba..f486898e3 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/com.salesforce.bazel.eclipse.core/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,9 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -12,7 +12,7 @@ org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=true diff --git a/bundles/com.salesforce.bazel.eclipse.core/META-INF/MANIFEST.MF b/bundles/com.salesforce.bazel.eclipse.core/META-INF/MANIFEST.MF index fdb0341c9..71f87ca96 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/META-INF/MANIFEST.MF +++ b/bundles/com.salesforce.bazel.eclipse.core/META-INF/MANIFEST.MF @@ -54,5 +54,5 @@ Require-Bundle: org.eclipse.core.jobs;bundle-version="3.12.0", org.eclipse.jdt.junit.core;bundle-version="3.11.0", org.eclipse.core.filesystem;bundle-version="1.9.500", org.eclipse.core.variables;bundle-version="3.6.0" -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Bundle-ActivationPolicy: lazy diff --git a/bundles/com.salesforce.bazel.eclipse.core/plugin.xml b/bundles/com.salesforce.bazel.eclipse.core/plugin.xml index 656b40970..531feace2 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/plugin.xml +++ b/bundles/com.salesforce.bazel.eclipse.core/plugin.xml @@ -124,6 +124,10 @@ class="com.salesforce.bazel.eclipse.core.model.discovery.BazelBuildfileTargetDiscovery" name="buildfiles"> + + diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/BazelModel.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/BazelModel.java index 053c24d3f..cac9f2eca 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/BazelModel.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/BazelModel.java @@ -13,6 +13,8 @@ */ package com.salesforce.bazel.eclipse.core.model; +import static java.util.Objects.requireNonNull; + import java.util.List; import org.eclipse.core.resources.IProject; @@ -105,7 +107,9 @@ public IPath getLocation() { * @return the owning model manager */ public BazelModelManager getModelManager() { - return modelManager; + return requireNonNull( + modelManager, + "not initialized properly; allowed only in unit tests, then mocking is required"); } @Override diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BaseProvisioningStrategy.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BaseProvisioningStrategy.java index b5f5edf51..f98277b3d 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BaseProvisioningStrategy.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BaseProvisioningStrategy.java @@ -1655,7 +1655,7 @@ private void linkSourceFilesWithoutCommonRoot(JavaSourceInfo sourceInfo, IFolder Set linkedFiles = new HashSet<>(); for (JavaSourceEntry fileEntry : files) { // peek at Java package to find proper "root" - var packagePath = fileEntry.getDetectedPackagePath(); + var packagePath = fileEntry.hasDetectedPackagePath() ? fileEntry.getDetectedPackagePath() : IPath.EMPTY; var packageFolder = virtualSourceFolder.getFolder(packagePath); if (!packageFolder.exists()) { createFolderAndParents(packageFolder, monitor.split(1)); diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkAnalyzeInfo.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkAnalyzeInfo.java index c8d166a80..63c0b4de9 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkAnalyzeInfo.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkAnalyzeInfo.java @@ -26,12 +26,13 @@ import net.starlark.java.eval.Sequence; import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkInt; +import net.starlark.java.eval.StarlarkValue; /** * A data type for returning information from the analyze function */ @StarlarkBuiltin(name = "AnalyzeInfo", documented = false) -public class StarlarkAnalyzeInfo { +public class StarlarkAnalyzeInfo implements StarlarkValue { private List convertToStringList(Sequence exclude, String nameForErrorMessage) throws EvalException { List stringList = new ArrayList<>(); @@ -54,12 +55,11 @@ private List convertToStringList(Sequence exclude, String nameForErro @ParamType(type = Sequence.class, generic1 = String.class) }, defaultValue = "[]", named = true, documented = false), @Param(name = "exclude_directories", defaultValue = "1", named = true, documented = false), @Param(name = "allow_empty", defaultValue = "unbound", named = true, documented = false) }) - StarlarkGlobInfo glob(Sequence include, Sequence exclude, StarlarkInt excludeDirectories, Object allowEmpty) - throws EvalException, InterruptedException { + StarlarkGlobInfo ProjectInfo(Sequence include, Sequence exclude, StarlarkInt excludeDirectories, + Object allowEmpty) throws EvalException, InterruptedException { var includeStringList = convertToStringList(include, "include"); var excludeStringList = convertToStringList(exclude, "exclude"); return new StarlarkGlobInfo(new GlobInfo(includeStringList, excludeStringList)); - } } diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkFunctionCallInfo.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkFunctionCallInfo.java index 4778ce5da..07538d5ee 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkFunctionCallInfo.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkFunctionCallInfo.java @@ -51,6 +51,7 @@ class StarlarkFunctionCallInfo implements StarlarkValue { private static final Logger LOG = LoggerFactory.getLogger(StarlarkFunctionCallInfo.class); private final FunctionCall functionCall; + private volatile Dict args; public StarlarkFunctionCallInfo(FunctionCall functionCall) { this.functionCall = functionCall; @@ -84,7 +85,11 @@ private Dict evaluateArgs(StarlarkThread thread) { @StarlarkMethod(name = "args", structField = true, useStarlarkThread = true) public Dict getArgs(StarlarkThread thread) { - return evaluateArgs(thread); + var args = this.args; + if (args != null) { + return args; + } + return this.args = evaluateArgs(thread); } @StarlarkMethod(name = "resolved_function_name", structField = true) diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzer.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzer.java index f22f1638f..8598b462f 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzer.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzer.java @@ -64,22 +64,25 @@ */ public class StarlarkMacroCallAnalyzer implements MacroCallAnalyzer { + private static final String FUNCTION_INFO = "function_info"; + private static final StarlarkSemantics starlarkSemantics = StarlarkSemantics.builder().setBool(StarlarkSemantics.EXPERIMENTAL_ENABLE_STARLARK_SET, true).build(); - private final IPath analyzeFile; - private final StarlarkFunction analyzeFunction; - - public StarlarkMacroCallAnalyzer(BazelWorkspace bazelWorkspace, WorkspacePath bzlFile) + /** + * Parses the given input for an 'analyze' function. + * + * @param input + * the input to parse + * @param file + * for error reporting only + * @return the parsed function (never null) + * @throws CoreException, + * {@link OperationCanceledException} + */ + /* for test only */ + static StarlarkFunction parseInputAndGetAnalyzeFunction(ParserInput input, String file) throws CoreException, OperationCanceledException { - analyzeFile = bazelWorkspace.getLocation().append(bzlFile.relativePath()); - ParserInput input; - try { - input = ParserInput.readFile(analyzeFile.toOSString()); - } catch (IOException e) { - throw new CoreException(Status.error(format("Failed to read file '%s'", analyzeFile), e)); - } - try (var mu = Mutability.create("analyzer")) { ImmutableMap.Builder env = ImmutableMap.builder(); //Starlark.addMethods(env, new CqueryDialectGlobals(), starlarkSemantics); @@ -89,41 +92,68 @@ public StarlarkMacroCallAnalyzer(BazelWorkspace bazelWorkspace, WorkspacePath bz Starlark.execFile(input, FileOptions.DEFAULT, module, thread); var analyzeFn = module.getGlobal("analyze"); if (analyzeFn == null) { - throw new CoreException( - Status.error(format("File '%s' does not define 'analyze' function", analyzeFile))); + throw new CoreException(Status.error(format("File '%s' does not define 'analyze' function", file))); } - if (!(analyzeFn instanceof StarlarkFunction)) { + if (!(analyzeFn instanceof StarlarkFunction analyzeFunction)) { throw new CoreException( Status.error( format( "File '%s' 'analyze' is not a function. Got '%s'.", - analyzeFile, + file, Starlark.type(analyzeFn)))); } - analyzeFunction = (StarlarkFunction) analyzeFn; - if (analyzeFunction.getParameterNames().size() != 1) { + if (!analyzeFunction.getParameterNames().contains(FUNCTION_INFO) + || (analyzeFunction.getParameterNames().size() != 1)) { throw new CoreException( - Status.error(format("File '%s' 'format' function must take exactly 1 argument", analyzeFile))); + Status.error( + format( + "File '%s' 'analyze' function must take exactly 1 named argument 'function_info'", + file))); } + + return analyzeFunction; } catch (SyntaxError.Exception e) { - throw new CoreException( - Status.error(format("Syntax error in file '%s': %s", analyzeFile, e.getMessage()), e)); + throw new CoreException(Status.error(format("Syntax error in file '%s': %s", file, e.getMessage()), e)); } catch (EvalException e) { - throw new CoreException( - Status.error(format("Evaluation error in file '%s': %s", analyzeFile, e.getMessage()), e)); + throw new CoreException(Status.error(format("Evaluation error in file '%s': %s", file, e.getMessage()), e)); } catch (InterruptedException e) { throw new OperationCanceledException("Interrupted while executing Starlark"); } } + private final IPath analyzeFile; + + private final StarlarkFunction analyzeFunction; + + public StarlarkMacroCallAnalyzer(BazelWorkspace bazelWorkspace, WorkspacePath bzlFile) + throws CoreException, OperationCanceledException { + + analyzeFile = bazelWorkspace.getLocation().append(bzlFile.relativePath()); + + ParserInput input; + try { + input = ParserInput.readFile(analyzeFile.toOSString()); + } catch (IOException e) { + throw new CoreException(Status.error(format("Failed to read file '%s'", analyzeFile), e)); + } + + analyzeFunction = parseInputAndGetAnalyzeFunction(input, analyzeFile.toOSString()); + } + @Override public boolean analyze(FunctionCall macroCall, JavaProjectInfo javaInfo) throws CoreException { try { var thread = StarlarkThread.createTransient(Mutability.create("analyze evaluation"), starlarkSemantics); thread.setMaxExecutionSteps(500_000L); - var kwargs = Map. of("macro_info", new StarlarkFunctionCallInfo(macroCall)); + var kwargs = Map. of(FUNCTION_INFO, new StarlarkFunctionCallInfo(macroCall)); var result = Starlark.call(thread, analyzeFunction, null, kwargs); + if (Starlark.isNullOrNone(result) || !Starlark.truth(result)) { + return false; + } + if (!(result instanceof StarlarkAnalyzeInfo)) { + throw Starlark.errorf("Return value is not of type AnalyzeInfo. Got '%s'", result); + } } catch (EvalException e) { throw new CoreException( Status.error( diff --git a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkNativeModuleApiDummy.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkNativeModuleApiDummy.java index e8b9065c3..b4322c054 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkNativeModuleApiDummy.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkNativeModuleApiDummy.java @@ -13,9 +13,6 @@ */ package com.salesforce.bazel.eclipse.core.model.discovery.analyzers.starlark; -import java.util.ArrayList; -import java.util.List; - import com.salesforce.bazel.eclipse.core.model.buildfile.GlobInfo; import net.starlark.java.annot.Param; @@ -24,7 +21,6 @@ import net.starlark.java.annot.StarlarkMethod; import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Sequence; -import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkInt; /** @@ -33,17 +29,6 @@ @StarlarkBuiltin(name = "native", documented = false) public class StarlarkNativeModuleApiDummy { - private List convertToStringList(Sequence exclude, String nameForErrorMessage) throws EvalException { - List stringList = new ArrayList<>(); - for (Object value : exclude) { - if (!(value instanceof String s)) { - throw Starlark.errorf("Invalid 'glob' argument type in '%s': %s", nameForErrorMessage, value); - } - stringList.add(s); - } - return stringList; - } - /** * Support for glob to turn into {@link StarlarkGlobInfo}. * @@ -56,12 +41,8 @@ private List convertToStringList(Sequence exclude, String nameForErro @ParamType(type = Sequence.class, generic1 = String.class) }, defaultValue = "[]", named = true, documented = false), @Param(name = "exclude_directories", defaultValue = "1", named = true, documented = false), @Param(name = "allow_empty", defaultValue = "unbound", named = true, documented = false) }) - StarlarkGlobInfo glob(Sequence include, Sequence exclude, StarlarkInt excludeDirectories, Object allowEmpty) - throws EvalException, InterruptedException { - - var includeStringList = convertToStringList(include, "include"); - var excludeStringList = convertToStringList(exclude, "exclude"); - return new StarlarkGlobInfo(new GlobInfo(includeStringList, excludeStringList)); - + StarlarkGlobInfo glob(Sequence include, Sequence exclude, StarlarkInt excludeDirectories, + Object allowEmpty) throws EvalException, InterruptedException { + return new StarlarkGlobInfo(new GlobInfo(include, exclude)); } } diff --git a/bundles/testdata/src/testdata/SharedTestData.java b/bundles/testdata/src/testdata/SharedTestData.java index 719697c79..2c906d8fe 100644 --- a/bundles/testdata/src/testdata/SharedTestData.java +++ b/bundles/testdata/src/testdata/SharedTestData.java @@ -10,6 +10,8 @@ public interface SharedTestData { String WORKSPACE_001 = "/workspaces/001"; + String WORKSPACE_002 = "/workspaces/001"; + IPath BAZELPROJECT_FILE = new Path(".bazelproject"); } diff --git a/bundles/testdata/workspaces/001/MODULE.bazel b/bundles/testdata/workspaces/001/MODULE.bazel new file mode 100644 index 000000000..00bb18361 --- /dev/null +++ b/bundles/testdata/workspaces/001/MODULE.bazel @@ -0,0 +1,6 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### diff --git a/bundles/testdata/workspaces/002/.bazelproject b/bundles/testdata/workspaces/002/.bazelproject new file mode 100644 index 000000000..2f38bccea --- /dev/null +++ b/bundles/testdata/workspaces/002/.bazelproject @@ -0,0 +1,16 @@ +# The project view file (.bazelproject) is used to import targets into the IDE. +# +# See: https://ij.bazel.build/docs/project-views.html +# +# This files provides a default experience for developers working with the project + + +directories: + . + +derive_targets_from_directories: true + +java_language_level: 21 + +target_discovery_strategy: buildfiles +target_provisioning_strategy: project-per-buildfile diff --git a/bundles/testdata/workspaces/002/.gitignore b/bundles/testdata/workspaces/002/.gitignore new file mode 100644 index 000000000..772f56657 --- /dev/null +++ b/bundles/testdata/workspaces/002/.gitignore @@ -0,0 +1,11 @@ +# Eclipse metadata +.classpath +.project +.settings/ +.eclipse/ + +# Bazel folder +/bazel-* + +# ignore the Bazel version file +.bazelversion diff --git a/bundles/testdata/workspaces/002/MODULE.bazel b/bundles/testdata/workspaces/002/MODULE.bazel new file mode 100644 index 000000000..00bb18361 --- /dev/null +++ b/bundles/testdata/workspaces/002/MODULE.bazel @@ -0,0 +1,6 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### diff --git a/bundles/testdata/workspaces/002/WORKSPACE b/bundles/testdata/workspaces/002/WORKSPACE new file mode 100644 index 000000000..13047945f --- /dev/null +++ b/bundles/testdata/workspaces/002/WORKSPACE @@ -0,0 +1,27 @@ +workspace(name = "testdata_workspaces_002") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# bazel-skylib 0.8.0 released 2019.03.20 (https://github.com/bazelbuild/bazel-skylib/releases/tag/0.8.0) +skylib_version = "0.8.0" +http_archive( + name = "bazel_skylib", + type = "tar.gz", + url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz".format (skylib_version, skylib_version), + sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e", +) + +http_archive( + name = "salesforce_rules_mybuilder", + url = "https://github.com/salesforce/bazel-java-builder-template/archive/c443e2391ff547c01f5ca3f14a1e84d85c13d16d.zip", + strip_prefix = "bazel-java-builder-template-c443e2391ff547c01f5ca3f14a1e84d85c13d16d", + sha256 = "8e0aac87c235744884161e69346d6a6d3d729ef8072e33a9883fbb27735d01d8", +) + +load("@salesforce_rules_mybuilder//mybuilder:repositories.bzl", "rules_mybuilder_dependencies", "rules_mybuilder_toolchains") +rules_mybuilder_dependencies() +rules_mybuilder_toolchains() + +# Maven dependencies +load("//third_party/maven:dependencies.bzl", "maven_dependencies") +maven_dependencies() diff --git a/bundles/testdata/workspaces/002/module1/BUILD b/bundles/testdata/workspaces/002/module1/BUILD new file mode 100644 index 000000000..5fed393a3 --- /dev/null +++ b/bundles/testdata/workspaces/002/module1/BUILD @@ -0,0 +1,5 @@ +load("//tools/macro:defs.bzl", "my_macro") + +my_macro ( + name = "module1", +) diff --git a/bundles/testdata/workspaces/002/module1/java/src/log/Logger.java b/bundles/testdata/workspaces/002/module1/java/src/log/Logger.java new file mode 100644 index 000000000..e1bdd8c6c --- /dev/null +++ b/bundles/testdata/workspaces/002/module1/java/src/log/Logger.java @@ -0,0 +1,16 @@ +package log; + +import java.time.Instant; + +public final class Logger { + + private Logger() { + throw new RuntimeException(); + } + + public static void logDebug(String message) { + String output = String.format("[DEBUG] %s", message); + System.out.println(output); + } + +} diff --git a/bundles/testdata/workspaces/002/third_party/maven/BUILD b/bundles/testdata/workspaces/002/third_party/maven/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/bundles/testdata/workspaces/002/third_party/maven/dependencies.bzl b/bundles/testdata/workspaces/002/third_party/maven/dependencies.bzl new file mode 100644 index 000000000..19ca173e8 --- /dev/null +++ b/bundles/testdata/workspaces/002/third_party/maven/dependencies.bzl @@ -0,0 +1,31 @@ +load("@bazel_tools//tools/build_defs/repo:jvm.bzl", "jvm_maven_import_external") + +def maven_dependencies( + maven_servers = ["https://repo1.maven.org/maven2/"]): + + jvm_maven_import_external( + name = "com_google_guava", + artifact = "com.google.guava:guava:28.2-jre", + artifact_sha256 = "fc3aa363ad87223d1fbea584eee015a862150f6d34c71f24dc74088a635f08ef", + fetch_sources = True, + licenses = ["notice"], + server_urls = maven_servers, + ) + + jvm_maven_import_external( + name = "junit", + artifact = "junit:junit:4.13", + artifact_sha256 = "4b8532f63bdc0e0661507f947eb324a954d1dbac631ad19c8aa9a00feed1d863", + fetch_sources = True, + licenses = ["notice"], + server_urls = maven_servers, + ) + + jvm_maven_import_external( + name = "org_apache_commons_commons_lang3", + artifact = "org.apache.commons:commons-lang3:jar:3.12.0", + artifact_sha256 = "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e", + fetch_sources = True, + licenses = ["notice"], + server_urls = maven_servers, + ) \ No newline at end of file diff --git a/bundles/testdata/workspaces/002/tools/macro/BUILD b/bundles/testdata/workspaces/002/tools/macro/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/bundles/testdata/workspaces/002/tools/macro/defs.bzl b/bundles/testdata/workspaces/002/tools/macro/defs.bzl new file mode 100644 index 000000000..fdbc2fbcb --- /dev/null +++ b/bundles/testdata/workspaces/002/tools/macro/defs.bzl @@ -0,0 +1,9 @@ +load("@rules_java//java:defs.bzl", "java_library", "java_test") + +def my_macro(name, **kwargs): + + java_library ( + name = name, + srcs = native.glob(["java/src/**/*.java"]), + **kwargs + ) diff --git a/docs/common/projectviews.md b/docs/common/projectviews.md index 53639796f..c464a3f06 100644 --- a/docs/common/projectviews.md +++ b/docs/common/projectviews.md @@ -75,7 +75,7 @@ Does nothing when `derive_targets_from_directories` is not set or set to `false` The default value is `default`, which maps to `bazel-query` and will use `bazel query` to discover targets. It's possible to add custom strategies via an extension point. -#### `bazel query` +#### `bazel-query` This performs a `bazel query` to obtain all list of all `BUILD` files. The list is then processed and directory information is translated into a list of Bazel packages. @@ -86,6 +86,13 @@ The remaining list of packages is queried again using `bazel query` to obtain al See [BazelQueryTargetDiscovery.java](../../bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BazelQueryTargetDiscovery.java) to read more about default discovery behavior. +#### `buildfiles` + +This also performs a `bazel query` but ignores targets. +It's a perfect combination (and performance optimization) when used with the `project-per-buildfile` target provisioning strategy. + +See [BazelBuildfileTargetDiscovery.java](../../bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BazelBuildfileTargetDiscovery.java) to read more about discovery behavior. + ### `target_provisioning_strategy` Customize how targets are imported/resolved. @@ -146,6 +153,18 @@ For details please read the JavaDoc (and Java code) of [ProjectPerPackageProvisi * It requires running `bazel build` to detect classpath configuration. * Is not fully implemented and required help/work/contributions. +#### `project-per-buildfile` + +This is an experimental strategy which tries to avoid running Bazel commands for importing projects. +It does so by parsing `BUILD` files directly. +Each `BUILD` file is mapped to a single project. +Nested packages in the same source folder are ignored. + +When it discovers an unknown function it can delegate to extensible analyzers for computing project information. +Analyzers can we written in Java as IDE plug-ins or Starlark functions. +However, the Starlark dialect is very limited and does not support the full Bazel dialect and built-in functions. +It purely exists to allow macro/rule implementors to also provide the IDE with necessary information. + ### `target_provisioning_settings` A list of settings to further tweak the `target_provisioning_strategy`. diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/.classpath b/tests/com.salesforce.bazel.eclipse.core.tests/.classpath index 675a5e296..1aa9eca95 100644 --- a/tests/com.salesforce.bazel.eclipse.core.tests/.classpath +++ b/tests/com.salesforce.bazel.eclipse.core.tests/.classpath @@ -1,6 +1,6 @@ - + diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/.settings/com.salesforce.bazel.eclipse.core.tests - all headless tests.launch b/tests/com.salesforce.bazel.eclipse.core.tests/.settings/com.salesforce.bazel.eclipse.core.tests - all headless tests.launch index 1b2e4c3fd..83eeecb80 100644 --- a/tests/com.salesforce.bazel.eclipse.core.tests/.settings/com.salesforce.bazel.eclipse.core.tests - all headless tests.launch +++ b/tests/com.salesforce.bazel.eclipse.core.tests/.settings/com.salesforce.bazel.eclipse.core.tests - all headless tests.launch @@ -17,6 +17,16 @@ + + + + + + + + + + @@ -47,30 +57,24 @@ - - + - + - + + - - - - - - - - - + + + @@ -87,16 +91,10 @@ - - - - - + - - + - @@ -105,15 +103,14 @@ - + - - + @@ -134,23 +131,6 @@ - - - - - - - - - - - - - - - - - @@ -163,13 +143,6 @@ - - - - - - - @@ -180,7 +153,7 @@ - + @@ -193,23 +166,12 @@ - - - - - - - - - - - @@ -224,6 +186,7 @@ + @@ -249,15 +212,11 @@ - - - - - - - + + - + + @@ -267,12 +226,469 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/.settings/org.eclipse.jdt.core.prefs b/tests/com.salesforce.bazel.eclipse.core.tests/.settings/org.eclipse.jdt.core.prefs index 1f3e19a99..3ee841fb0 100644 --- a/tests/com.salesforce.bazel.eclipse.core.tests/.settings/org.eclipse.jdt.core.prefs +++ b/tests/com.salesforce.bazel.eclipse.core.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,13 +1,13 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=21 org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=true diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/META-INF/MANIFEST.MF b/tests/com.salesforce.bazel.eclipse.core.tests/META-INF/MANIFEST.MF index 1ebe18c6a..f22cd4cc2 100644 --- a/tests/com.salesforce.bazel.eclipse.core.tests/META-INF/MANIFEST.MF +++ b/tests/com.salesforce.bazel.eclipse.core.tests/META-INF/MANIFEST.MF @@ -6,11 +6,12 @@ Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Bazel Eclipse Feature Fragment-Host: com.salesforce.bazel.eclipse.core;bundle-version="2.0.0" Automatic-Module-Name: com.salesforce.bazel.eclipse.core.tests -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Import-Package: org.hamcrest;version="2.2.0", org.hamcrest.collection;version="2.2.0", - org.junit.jupiter.api;version="5.9.2", - org.junit.jupiter.api.extension;version="5.9.2", - org.junit.jupiter.api.io;version="5.9.2" + org.junit.jupiter.api;version="[5.11.0,6.0.0)", + org.junit.jupiter.api.extension;version="[5.11.0,6.0.0)", + org.junit.jupiter.api.function;version="[5.11.0,6.0.0)", + org.junit.jupiter.api.io;version="[5.11.0,6.0.0)" Require-Bundle: testdata;bundle-version="1.0.0", com.salesforce.bazel.sdk diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzerTest.java b/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzerTest.java new file mode 100644 index 000000000..9e7622b3f --- /dev/null +++ b/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/model/discovery/analyzers/starlark/StarlarkMacroCallAnalyzerTest.java @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2024 Salesforce and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Salesforce - adapted from M2E, JDT or other Eclipse project + */ +package com.salesforce.bazel.eclipse.core.model.discovery.analyzers.starlark; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.eclipse.core.runtime.CoreException; +import org.junit.jupiter.api.Test; + +import net.starlark.java.syntax.ParserInput; + +class StarlarkMacroCallAnalyzerTest { + + @Test + void parseInputAndGetAnalyzeFunction_fails_for_missing_function() throws Exception { + assertThrows(CoreException.class, () -> { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + def analyze_wrong_name(): + return None + """, "test only"), "test only"); + }); + assertThrows(CoreException.class, () -> { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + """, "test only"), "test only"); + }); + } + + @Test + void parseInputAndGetAnalyzeFunction_fails_for_missing_or_misnamed_args() throws Exception { + assertThrows(CoreException.class, () -> { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + def analyze(): + return None + """, "test only"), "test only"); + }); + assertThrows(CoreException.class, () -> { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + def analyze(wrong_name): + return None + """, "test only"), "test only"); + }); + assertThrows(CoreException.class, () -> { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + def analyze(function_info, additional_name): + return None + """, "test only"), "test only"); + }); + } + + @Test + void parseInputAndGetAnalyzeFunction_ok() throws Exception { + StarlarkMacroCallAnalyzer.parseInputAndGetAnalyzeFunction(ParserInput.fromString(""" + def analyze(function_info): + return None + """, "test only"), "test only"); + } +} diff --git a/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/tests/it/Workspace002Test_Provisioning.java b/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/tests/it/Workspace002Test_Provisioning.java new file mode 100644 index 000000000..71ace4afa --- /dev/null +++ b/tests/com.salesforce.bazel.eclipse.core.tests/src/com/salesforce/bazel/eclipse/core/tests/it/Workspace002Test_Provisioning.java @@ -0,0 +1,101 @@ +package com.salesforce.bazel.eclipse.core.tests.it; + +import static com.salesforce.bazel.eclipse.core.BazelCoreSharedContstants.BAZEL_NATURE_ID; +import static java.lang.String.format; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static testdata.SharedTestData.BAZELPROJECT_FILE; +import static testdata.SharedTestData.WORKSPACE_002; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.launching.IVMInstall; +import org.eclipse.jdt.launching.IVMInstallType; +import org.eclipse.jdt.launching.JavaRuntime; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.salesforce.bazel.eclipse.core.BazelCore; +import com.salesforce.bazel.sdk.BazelVersion; + +import testdata.SharedTestData; +import testdata.utils.LoggingProgressProviderExtension; +import testdata.utils.ProvisionWorkspaceExtension; + +/** + * Integration tests using the 001 test workspace. + *

+ * This test imports a Bazel workspace into Eclipse and then performs a bunch of tests with it. It cannot be execute as + * a plain JUnit test but needs to run in an Eclipse environment. + *

+ */ +@TestMethodOrder(MethodOrderer.MethodName.class) +@ExtendWith(LoggingProgressProviderExtension.class) +public class Workspace002Test_Provisioning { + + private static final BazelVersion BAZEL_VERSION = new BazelVersion(7, 4, 1); + + @RegisterExtension + static ProvisionWorkspaceExtension provisionedWorkspace = + new ProvisionWorkspaceExtension(WORKSPACE_002, SharedTestData.class, BAZELPROJECT_FILE, BAZEL_VERSION); + + private void assertProjectWithProperNatures(IProject project) throws CoreException { + assertTrue(project.exists(), format("Project '%s' expected to exist!", project.getName())); + assertTrue( + project.hasNature(JavaCore.NATURE_ID), + format("Project '%s' expected to hava Java nature!", project.getName())); + assertTrue( + project.hasNature(BAZEL_NATURE_ID), + format("Project '%s' expected to hava Bazel nature!", project.getName())); + } + + /** + * @throws java.lang.Exception + */ + @BeforeEach + void setUp() throws Exception {} + + /** + * @throws java.lang.Exception + */ + @AfterEach + void tearDown() throws Exception {} + + @Test + void test0001_check_basic_assumptions_in_the_model() throws CoreException { + var root = ResourcesPlugin.getWorkspace().getRoot(); + + var workspaceProject = root.getProject("testdata_workspaces_002"); + assertProjectWithProperNatures(workspaceProject); + + var bazelWorkspaceProject = BazelCore.create(workspaceProject); + assertTrue(bazelWorkspaceProject.isWorkspaceProject(), "Expect to have the workspace project at this point!"); + } + + @Test + void test0002_jdk_setup_for_workspace() throws CoreException { + var bazelWorkspace = provisionedWorkspace.getBazelWorkspace(); + + var vmInstallTypes = JavaRuntime.getVMInstallTypes(); + IVMInstall workspaceVm = null; + for (IVMInstallType vmInstallType : vmInstallTypes) { + var vmInstalls = vmInstallType.getVMInstalls(); + for (IVMInstall vm : vmInstalls) { + if (vm.getName().contains(bazelWorkspace.getName())) { + assertNull(workspaceVm, "multiple VMs found for workspace; this is not ok"); + workspaceVm = vm; + } + } + } + assertNotNull(workspaceVm, "no VMs found for workspace; this is not ok"); + } + +}