Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

A strategy for parsing build files instead of queries & aspect #509

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bundles/com.salesforce.bazel.eclipse.core/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes>
<attribute name="module" value="true"/>
</attributes>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions bundles/com.salesforce.bazel.eclipse.core/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@
class="com.salesforce.bazel.eclipse.core.model.discovery.BazelBuildfileTargetDiscovery"
name="buildfiles">
</targetDiscoveryStrategy>
<targetProvisioningStrategy
class="com.salesforce.bazel.eclipse.core.model.discovery.BuildfileDrivenProvisioningStrategy"
name="project-per-buildfile">
</targetProvisioningStrategy>
<targetProvisioningStrategy
class="com.salesforce.bazel.eclipse.core.model.discovery.BuildFileAndVisibilityDrivenProvisioningStrategy"
name="build-file-and-visibility-driven">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,7 @@ private void linkSourceFilesWithoutCommonRoot(JavaSourceInfo sourceInfo, IFolder
Set<IFile> 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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -41,7 +43,7 @@

/**
* Implementation of {@link TargetProvisioningStrategy} which provisions projects based on parsing <code>BUILD</code>
* files directly and computing their classpath based on visibility in the build graph.
* files directly.
* <p>
* This strategy implements behavior which intentionally deviates from Bazel dominated strategies in favor of a better
* developer experience in IDEs.
Expand All @@ -50,8 +52,6 @@
* <li>The macro translation is extensible so translators for custom macros can be provided and included in the
* analysis.</li>
* <li>A heuristic is used to merge <code>java_*</code> targets in the same package into a single Eclipse project.</li>
* <li>The classpath is computed based on visibility, which eventually allows to compute the deps list by IDEs based on
* actual use.</li>
* <li>Projects are created directly in the package location.</li>
* <li>The root (empty) package <code>//</code> is not supported.</li>
* </ul>
Expand Down Expand Up @@ -153,9 +153,30 @@ public Map<BazelProject, CompileAndRuntimeClasspath> computeClasspaths(Collectio
protected List<BazelProject> doProvisionProjects(Collection<TargetExpression> 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<String, StarlarkMacroCallAnalyzer> 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<BazelProject>();
for (Path packagePath : packages) {
Expand All @@ -179,7 +200,7 @@ protected List<BazelProject> doProvisionProjects(Collection<TargetExpression> ta
var javaInfo = new JavaProjectInfo(bazelPackage);
var relevantTargets = new ArrayList<TargetName>();
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);
Expand Down Expand Up @@ -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<String, ? extends MacroCallAnalyzer> projectViewAnalyzers) throws CoreException {
// get the analyzers to check
List<MacroCallAnalyzer> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>analyze</code> function
*/
@StarlarkBuiltin(name = "AnalyzeInfo", documented = false)
public class StarlarkAnalyzeInfo {
public class StarlarkAnalyzeInfo implements StarlarkValue {

private List<String> convertToStringList(Sequence<?> exclude, String nameForErrorMessage) throws EvalException {
List<String> stringList = new ArrayList<>();
Expand All @@ -54,12 +55,11 @@ private List<String> 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));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,23 @@ class StarlarkFunctionCallInfo implements StarlarkValue {
private static final Logger LOG = LoggerFactory.getLogger(StarlarkFunctionCallInfo.class);

private final FunctionCall functionCall;
private volatile Dict<String, Object> args;

public StarlarkFunctionCallInfo(FunctionCall functionCall) {
this.functionCall = functionCall;
}

private Dict<String, Object> evaluateArgs(StarlarkThread thread) {
var callExpression = functionCall.getCallExpression();

Builder<String, Object> 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");
Expand All @@ -84,7 +82,11 @@ private Dict<String, Object> evaluateArgs(StarlarkThread thread) {

@StarlarkMethod(name = "args", structField = true, useStarlarkThread = true)
public Dict<String, Object> 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)
Expand Down
Loading
Loading