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/BuildfileDrivenProvisioningStrategy.java b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BuildfileDrivenProvisioningStrategy.java index e546c98c6..6345a7e8f 100644 --- a/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BuildfileDrivenProvisioningStrategy.java +++ b/bundles/com.salesforce.bazel.eclipse.core/src/com/salesforce/bazel/eclipse/core/model/discovery/BuildfileDrivenProvisioningStrategy.java @@ -26,12 +26,14 @@ import com.google.idea.blaze.base.model.primitives.TargetExpression; import com.google.idea.blaze.base.model.primitives.TargetName; +import com.google.idea.blaze.base.model.primitives.WorkspacePath; import com.salesforce.bazel.eclipse.core.classpath.BazelClasspathScope; import com.salesforce.bazel.eclipse.core.classpath.CompileAndRuntimeClasspath; import com.salesforce.bazel.eclipse.core.model.BazelProject; import com.salesforce.bazel.eclipse.core.model.BazelTarget; import com.salesforce.bazel.eclipse.core.model.BazelWorkspace; import com.salesforce.bazel.eclipse.core.model.buildfile.FunctionCall; +import com.salesforce.bazel.eclipse.core.model.discovery.analyzers.starlark.StarlarkMacroCallAnalyzer; import com.salesforce.bazel.eclipse.core.model.discovery.classpath.ClasspathEntry; import com.salesforce.bazel.eclipse.core.model.discovery.classpath.libs.ExternalLibrariesDiscovery; import com.salesforce.bazel.eclipse.core.model.discovery.projects.JavaProjectInfo; @@ -41,7 +43,7 @@ /** * Implementation of {@link TargetProvisioningStrategy} which provisions projects based on parsing BUILD - * files directly and computing their classpath based on visibility in the build graph. + * files directly. *

* This strategy implements behavior which intentionally deviates from Bazel dominated strategies in favor of a better * developer experience in IDEs. @@ -50,8 +52,6 @@ *

  • The macro translation is extensible so translators for custom macros can be provided and included in the * analysis.
  • *
  • A heuristic is used to merge java_* targets in the same package into a single Eclipse project.
  • - *
  • The classpath is computed based on visibility, which eventually allows to compute the deps list by IDEs based on - * actual use.
  • *
  • Projects are created directly in the package location.
  • *
  • The root (empty) package // is not supported.
  • * @@ -153,9 +153,30 @@ public Map computeClasspaths(Collectio protected List doProvisionProjects(Collection targetsOrPackages, BazelWorkspace workspace, TracingSubMonitor monitor) throws CoreException { - // obtain package paths + // extract package paths from label to provision var packages = targetsOrPackages.parallelStream().map(this::extractPackagePath).distinct().toList(); + // load macro analyzers specified in project view + Map starlarkAnalyzers = new HashMap<>(); + for (var settingsEntry : workspace.getBazelProjectView().targetProvisioningSettings().entrySet()) { + if (settingsEntry.getKey().startsWith("macro:")) { + try { + var macroName = settingsEntry.getKey().substring("macro:".length()); + var sclFile = new WorkspacePath(settingsEntry.getValue()); + var analyzer = new StarlarkMacroCallAnalyzer(workspace, sclFile); + starlarkAnalyzers.put(macroName, analyzer); + } catch (Exception e) { + throw new CoreException( + Status.error( + format( + "Error loading macro call analyzer for setting '%s': %s", + settingsEntry, + e.getMessage()), + e)); + } + } + } + monitor.beginTask("Provisioning projects", packages.size() * 3); var result = new ArrayList(); for (Path packagePath : packages) { @@ -179,7 +200,7 @@ protected List doProvisionProjects(Collection ta var javaInfo = new JavaProjectInfo(bazelPackage); var relevantTargets = new ArrayList(); for (FunctionCall macroCall : topLevelMacroCalls) { - var relevant = processMacroCall(macroCall, javaInfo); + var relevant = processMacroCall(macroCall, javaInfo, starlarkAnalyzers); if (!relevant) { if (LOG.isDebugEnabled()) { LOG.debug("Skipping not relevant macro call '{}'.", macroCall); @@ -241,13 +262,22 @@ private Path extractPackagePath(TargetExpression targetExpression) { return Path.of(targetExpressionStr.substring(startIndex, colonIndex)); } - private boolean processMacroCall(FunctionCall macroCall, JavaProjectInfo javaInfo) throws CoreException { - var analyzers = extensionLookup.createMacroCallAnalyzers(macroCall.getResolvedFunctionName()); - if (analyzers.isEmpty()) { - if (LOG.isDebugEnabled()) { - LOG.debug("No analyzers available for function '{}'", macroCall.getResolvedFunctionName()); + private boolean processMacroCall(FunctionCall macroCall, JavaProjectInfo javaInfo, + Map projectViewAnalyzers) throws CoreException { + // get the analyzers to check + List analyzers; + var projectViewAnalyzer = projectViewAnalyzers.get(macroCall.getResolvedFunctionName()); + if (projectViewAnalyzer != null) { + // any analyzer from project view takes precedences + analyzers = List.of(projectViewAnalyzer); + } else { + analyzers = extensionLookup.createMacroCallAnalyzers(macroCall.getResolvedFunctionName()); + if (analyzers.isEmpty()) { + if (LOG.isDebugEnabled()) { + LOG.debug("No analyzers available for function '{}'", macroCall.getResolvedFunctionName()); + } + return false; // no analyzers } - return false; // no analyzers } for (MacroCallAnalyzer analyzer : analyzers) { 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..088b32963 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,25 +51,23 @@ 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; } private Dict evaluateArgs(StarlarkThread thread) { - var callExpression = functionCall.getCallExpression(); - Builder result = Dict.builder(); + var callExpression = functionCall.getCallExpression(); for (Argument argument : callExpression.getArguments()) { if (argument.getName() == null) { continue; } try { - var parserInput = ParserInput .fromString(argument.getValue().prettyPrint(), format("argument %s", argument.getName())); - result.put(argument.getName(), Starlark.eval(parserInput, FileOptions.DEFAULT, predeclared, thread)); } catch (InterruptedException e) { throw new OperationCanceledException("Interrupted Starlark execution"); @@ -84,7 +82,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..a87bfa156 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 @@ -16,6 +16,7 @@ import static java.lang.String.format; import java.io.IOException; +import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; @@ -48,7 +49,7 @@ * though. Bazel specific Starlark globals are not supported. *

    *

    - * The analyzer must be defined in a .bzl file. The file must define a function named analyze. + * The analyzer must be defined in a .scl file. The file must define a function named analyze. * The function will be called with the following named parameters: *

      *
    • function_info - info about the function call (see {@link StarlarkFunctionCallInfo} for details)
    • @@ -64,67 +65,103 @@ */ public class StarlarkMacroCallAnalyzer implements MacroCallAnalyzer { + private static final Object[] NO_ARGS = {}; + + 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); + Starlark.addMethods(env, new StarlarkAnalyzeInfo(), starlarkSemantics); var module = Module.withPredeclared(starlarkSemantics, env.buildOrThrow()); var thread = StarlarkThread.createTransient(mu, starlarkSemantics); 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 sclFile) + throws CoreException, OperationCanceledException { + + analyzeFile = bazelWorkspace.getLocation().append(sclFile.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); + try (var mu = Mutability.create("analyze evaluation")) { + ImmutableMap.Builder env = ImmutableMap.builder(); + //Starlark.addMethods(env, new CqueryDialectGlobals(), starlarkSemantics); + var module = Module.withPredeclared(starlarkSemantics, env.buildOrThrow()); + + var thread = StarlarkThread.createTransient(mu, starlarkSemantics); thread.setMaxExecutionSteps(500_000L); - var kwargs = Map. of("macro_info", new StarlarkFunctionCallInfo(macroCall)); - var result = Starlark.call(thread, analyzeFunction, null, kwargs); - } catch (EvalException e) { + var kwargs = Map. of(FUNCTION_INFO, new StarlarkFunctionCallInfo(macroCall)); + var result = Starlark.call(thread, analyzeFunction, List.of(), 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 | RuntimeException e) { throw new CoreException( Status.error( format("Error executiong 'analyze' in file '%s': %s", analyzeFile, e.getMessage()), 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..dc6870eac --- /dev/null +++ b/bundles/testdata/workspaces/002/.bazelproject @@ -0,0 +1,19 @@ +# 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 +target_provisioning_settings: + macro:my_macro=tools/ide/my_macro_analyzer.scl + 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/BUILD.bazel b/bundles/testdata/workspaces/002/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/bundles/testdata/workspaces/002/MODULE.bazel b/bundles/testdata/workspaces/002/MODULE.bazel new file mode 100644 index 000000000..10b498b04 --- /dev/null +++ b/bundles/testdata/workspaces/002/MODULE.bazel @@ -0,0 +1,30 @@ +module( + name = "testdata_workspaces_002", +) + +bazel_dep(name = "rules_java", version = "8.6.3") +bazel_dep(name = "rules_jvm_external", version = "6.6") + +maven_deps = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +maven_deps.artifact( + testonly = True, + artifact = "junit", + group = "junit", + version = "4.13.2", +) +maven_deps.install( + name = "maven_deps", + artifacts = [ + "com.google.guava:guava:33.4.0-jre", + "junit:junit:4.13.2", + "org.apache.commons:commons-lang3:jar:3.17.0", + ], + fail_if_repin_required = True, + fetch_sources = True, + generate_compat_repositories = False, + lock_file = "@//:maven_install.json", # repin with: REPIN=1 bazel run @maven_deps//:pin + resolver = "maven", + strict_visibility = True, + version_conflict_policy = "pinned", +) +use_repo(maven_deps, "maven_deps") diff --git a/bundles/testdata/workspaces/002/maven_install.json b/bundles/testdata/workspaces/002/maven_install.json new file mode 100755 index 000000000..83c1d31af --- /dev/null +++ b/bundles/testdata/workspaces/002/maven_install.json @@ -0,0 +1,243 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": -772885195, + "__RESOLVED_ARTIFACTS_HASH": -1746335676, + "artifacts": { + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7", + "sources": "1c9e85e272d0708c6a591dc74828c71603053b48cc75ae83cce56912a2aa063b" + }, + "version": "3.0.2" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "77440e270b0bc9a249903c5a076c36a722c4886ca4f42675f2903a1c53ed61a5", + "sources": "7e117e0931cb2cb4226372af336189b49edb79969d120ec958a6df0beacb0612" + }, + "version": "2.36.0" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064", + "sources": "dd3bfa5e2ec5bc5397efb2c3cef044c192313ff77089573667ff97a60c6978e0" + }, + "version": "1.0.2" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "b918c98a7e44dbe94ebd9fe3e40cddaadb5a93e6a78eb6008b42df237241e538", + "sources": "55ef6603b6ab1f6e3ae810b127561650ed682eb5f3fb50a212a658a74087b457" + }, + "version": "33.4.0-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64", + "sources": "bd60019a0423c3a025ef6ab24fe0761f5f45ffb48a8cca74a01b678de1105d38" + }, + "version": "3.0.0" + }, + "junit:junit": { + "shasums": { + "jar": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", + "sources": "34181df6482d40ea4c046b063cb53c7ffae94bdf1b1d62695bdf3adf9dea7e3a" + }, + "version": "4.13.2" + }, + "org.apache.commons:commons-lang3": { + "shasums": { + "jar": "6ee731df5c8e5a2976a1ca023b6bb320ea8d3539fbe64c8a1d5cb765127c33b4", + "sources": "5fdcac21ad329766054a95367d7583dfcdca737d221d5e01a5f2a198c04c6b18" + }, + "version": "3.17.0" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6", + "sources": "d6bdee58964cd05aabfca4e44947d3cbdada6bf617ed618b62b3b0d5a21de339" + }, + "version": "3.43.0" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", + "sources": "e223d2d8fbafd66057a8848cc94222d63c3cedd652cc48eddc0ab5c39c0f84df" + }, + "version": "1.3" + } + }, + "dependencies": { + "com.google.guava:guava": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.checkerframework:checker-qual" + ], + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ] + }, + "packages": { + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.function", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.management", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "org.apache.commons:commons-lang3": [ + "org.apache.commons.lang3", + "org.apache.commons.lang3.arch", + "org.apache.commons.lang3.builder", + "org.apache.commons.lang3.compare", + "org.apache.commons.lang3.concurrent", + "org.apache.commons.lang3.concurrent.locks", + "org.apache.commons.lang3.event", + "org.apache.commons.lang3.exception", + "org.apache.commons.lang3.function", + "org.apache.commons.lang3.math", + "org.apache.commons.lang3.mutable", + "org.apache.commons.lang3.reflect", + "org.apache.commons.lang3.stream", + "org.apache.commons.lang3.text", + "org.apache.commons.lang3.text.translate", + "org.apache.commons.lang3.time", + "org.apache.commons.lang3.tuple", + "org.apache.commons.lang3.util" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.count.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest", + "org.hamcrest.core", + "org.hamcrest.internal" + ] + }, + "repositories": { + "https://repo1.maven.org/maven2/": [ + "com.google.code.findbugs:jsr305", + "com.google.code.findbugs:jsr305:jar:sources", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_annotations:jar:sources", + "com.google.guava:failureaccess", + "com.google.guava:failureaccess:jar:sources", + "com.google.guava:guava", + "com.google.guava:guava:jar:sources", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.google.j2objc:j2objc-annotations:jar:sources", + "junit:junit", + "junit:junit:jar:sources", + "org.apache.commons:commons-lang3", + "org.apache.commons:commons-lang3:jar:sources", + "org.checkerframework:checker-qual", + "org.checkerframework:checker-qual:jar:sources", + "org.hamcrest:hamcrest-core", + "org.hamcrest:hamcrest-core:jar:sources" + ] + }, + "services": {}, + "skipped": [], + "version": "2" +} diff --git a/bundles/testdata/workspaces/002/module1/.bazeltargets b/bundles/testdata/workspaces/002/module1/.bazeltargets new file mode 100644 index 000000000..120d56ae4 --- /dev/null +++ b/bundles/testdata/workspaces/002/module1/.bazeltargets @@ -0,0 +1,2 @@ +# targets used to setup the project +# (do not modify manually; synchronize projects to update) \ No newline at end of file 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/module2/.bazeltargets b/bundles/testdata/workspaces/002/module2/.bazeltargets new file mode 100644 index 000000000..8a685b617 --- /dev/null +++ b/bundles/testdata/workspaces/002/module2/.bazeltargets @@ -0,0 +1,4 @@ +# targets used to setup the project +# (do not modify manually; synchronize projects to update) +module2 +module2-test \ No newline at end of file diff --git a/bundles/testdata/workspaces/002/module2/BUILD b/bundles/testdata/workspaces/002/module2/BUILD new file mode 100644 index 000000000..1af35428f --- /dev/null +++ b/bundles/testdata/workspaces/002/module2/BUILD @@ -0,0 +1,21 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library ( + name = "module2", + srcs = glob(["java/src/**/*.java"]), + visibility = ["//module1:__pkg__"], + deps = [ + "//module3", + "@maven_deps//:org_apache_commons_commons_lang3" + ] +) + +java_test( + name = "module2-test", + srcs = ["java/test/library/GreetingTest.java"], + test_class = "library.GreetingTest", + deps = [ + "module2", + "@maven_deps//:junit_junit", + ], +) diff --git a/bundles/testdata/workspaces/002/module2/java/src/library/Greeting.java b/bundles/testdata/workspaces/002/module2/java/src/library/Greeting.java new file mode 100644 index 000000000..ea3109f10 --- /dev/null +++ b/bundles/testdata/workspaces/002/module2/java/src/library/Greeting.java @@ -0,0 +1,12 @@ +package library; + +import log.Logger; + +public class Greeting { + + public String greet(String name) { + Logger.logDebug("Greeting.greet"); + return "Hello ".concat(name); + } + +} diff --git a/bundles/testdata/workspaces/002/module2/java/test/library/GreetingTest.java b/bundles/testdata/workspaces/002/module2/java/test/library/GreetingTest.java new file mode 100644 index 000000000..462df6e83 --- /dev/null +++ b/bundles/testdata/workspaces/002/module2/java/test/library/GreetingTest.java @@ -0,0 +1,11 @@ +package library; + +import org.junit.Assert; +import org.junit.Test; + +public class GreetingTest { + @Test + public void testGreet() { + Assert.assertEquals("Hello JUnit", new Greeting().greet("JUnit")); + } +} diff --git a/bundles/testdata/workspaces/002/module3/.bazeltargets b/bundles/testdata/workspaces/002/module3/.bazeltargets new file mode 100644 index 000000000..337763597 --- /dev/null +++ b/bundles/testdata/workspaces/002/module3/.bazeltargets @@ -0,0 +1,3 @@ +# targets used to setup the project +# (do not modify manually; synchronize projects to update) +module3 \ No newline at end of file diff --git a/bundles/testdata/workspaces/002/module3/BUILD b/bundles/testdata/workspaces/002/module3/BUILD new file mode 100644 index 000000000..f2f951ffc --- /dev/null +++ b/bundles/testdata/workspaces/002/module3/BUILD @@ -0,0 +1,7 @@ +load("@rules_java//java:defs.bzl", "java_library") + +java_library ( + name = "module3", + srcs = glob(["java/src/**/*.java"]), + visibility = ["//module1:__pkg__", "//module2:__pkg__"] +) diff --git a/bundles/testdata/workspaces/002/module3/java/src/log/Logger.java b/bundles/testdata/workspaces/002/module3/java/src/log/Logger.java new file mode 100644 index 000000000..e1bdd8c6c --- /dev/null +++ b/bundles/testdata/workspaces/002/module3/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/tools/ide/my_macro_analyzer.scl b/bundles/testdata/workspaces/002/tools/ide/my_macro_analyzer.scl new file mode 100644 index 000000000..22a14d516 --- /dev/null +++ b/bundles/testdata/workspaces/002/tools/ide/my_macro_analyzer.scl @@ -0,0 +1,3 @@ +def analyze(function_info): + + return False diff --git a/bundles/testdata/workspaces/002/tools/macro/.bazeltargets b/bundles/testdata/workspaces/002/tools/macro/.bazeltargets new file mode 100644 index 000000000..120d56ae4 --- /dev/null +++ b/bundles/testdata/workspaces/002/tools/macro/.bazeltargets @@ -0,0 +1,2 @@ +# targets used to setup the project +# (do not modify manually; synchronize projects to update) \ 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"); + } + +}