This is an automated email from the ASF dual-hosted git repository. sdedic pushed a commit to branch sdedic/feature/project-dependency-add_base2 in repository https://gitbox.apache.org/repos/asf/netbeans.git
commit d6864666dd5bda44039388f07c0d1bf0ba191b1a Author: Svata Dedic <[email protected]> AuthorDate: Wed Dec 13 22:43:40 2023 +0100 Prototype of dependencies.find command --- .../modules/nbcode/integration/ExtraGsonSetup.java | 49 ++++- .../commands/DependencyFindRequest.java | 87 +++++++++ .../integration/commands/DependencyFindResult.java | 67 +++++++ .../commands/ProjectDependenciesCommand.java | 200 +++++++++++++++++++++ 4 files changed, 402 insertions(+), 1 deletion(-) diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/ExtraGsonSetup.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/ExtraGsonSetup.java index d63d16d59a..56ebb6e78a 100644 --- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/ExtraGsonSetup.java +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/ExtraGsonSetup.java @@ -21,11 +21,21 @@ package org.netbeans.modules.nbcode.integration; import com.google.gson.ExclusionStrategy; import com.google.gson.FieldAttributes; import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.netbeans.modules.java.lsp.server.LspGsonSetup; import org.netbeans.modules.project.dependency.ArtifactSpec; +import org.netbeans.modules.project.dependency.Dependency; +import org.netbeans.modules.project.dependency.Scope; import org.openide.util.lookup.ServiceProvider; /** @@ -40,6 +50,11 @@ public class ExtraGsonSetup implements LspGsonSetup{ "data" // NOI18N )); + private static final Set<String> DEPENDENCY_BLOCK_FIELDS = new HashSet<>(Arrays.asList( + "parent", // NOI18N + "data" // NOI18N + )); + @Override public void configureBuilder(GsonBuilder b) { b.addSerializationExclusionStrategy(new ExclusionStrategy() { @@ -50,7 +65,9 @@ public class ExtraGsonSetup implements LspGsonSetup{ if (fa.getDeclaringClass() == ArtifactSpec.class) { return ARTIFACT_BLOCK_FIELDS.contains(fa.getName()); } else if (Throwable.class.isAssignableFrom(fa.getDeclaredClass())) { - + return DEPENDENCY_BLOCK_FIELDS.contains(fa.getName()); + } else if (fa.getDeclaringClass() == Dependency.class) { + } return false; } @@ -60,6 +77,36 @@ public class ExtraGsonSetup implements LspGsonSetup{ return false; } }); + b.registerTypeAdapter(ArtifactSpec.class, new ArtifactDeserializer()); + b.registerTypeAdapter(Scope.class, new ScopeSerializer()); } + class ScopeSerializer implements JsonSerializer<Scope> { + + @Override + public JsonElement serialize(Scope t, Type type, JsonSerializationContext jsc) { + return jsc.serialize(t.name()); + } + } + + + class ArtifactDeserializer implements JsonDeserializer<ArtifactSpec> { + + @Override + public ArtifactSpec deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException { + JsonObject obj = je.getAsJsonObject(); + String g = obj.has("groupId") ? obj.getAsJsonPrimitive("groupId").getAsString() : null; + String a = obj.has("artifactId") ? obj.getAsJsonPrimitive("artifactId").getAsString() : null; + String v = obj.has("versionSpec") ? obj.getAsJsonPrimitive("versionSpec").getAsString() : null; + String c = obj.has("classifier") ? obj.getAsJsonPrimitive("classifier").getAsString() : null; + String t = obj.has("type") ? obj.getAsJsonPrimitive("type").getAsString() : null; + + + ArtifactSpec.Builder b = ArtifactSpec.builder(g, a, v, null).classifier(c).type(t); + if (v != null && v.contains("-SNAPSHOT")) { + b.versionKind(ArtifactSpec.VersionKind.SNAPSHOT); + } + return b.build(); + } + } } diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindRequest.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindRequest.java new file mode 100644 index 0000000000..5f15529bf9 --- /dev/null +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindRequest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.nbcode.integration.commands; + +import java.util.List; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; +import org.eclipse.xtext.xbase.lib.Pure; +import org.netbeans.modules.project.dependency.ArtifactSpec; + +/** + * + * @author sdedic + */ +public class DependencyFindRequest { + /** + * URI of the project. + */ + @NonNull + private String uri; + + /** + * Scope(s) to search. + */ + private List<String> scopes; + + /** + * Artifacts to search for. + */ + private List<ArtifactSpec> artifacts; + + /** + * Return contents of the dependency + */ + private boolean returnContents; + + @Pure + @NonNull + public String getUri() { + return uri; + } + + @Pure + public List<String> getScopes() { + return scopes; + } + + @Pure + public List<ArtifactSpec> getArtifacts() { + return artifacts; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setScopes(List<String> scopes) { + this.scopes = scopes; + } + + public void setArtifacts(List<ArtifactSpec> artifacts) { + this.artifacts = artifacts; + } + + public boolean isReturnContents() { + return returnContents; + } + + public void setReturnContents(boolean returnContents) { + this.returnContents = returnContents; + } +} diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindResult.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindResult.java new file mode 100644 index 0000000000..3b6f7fded7 --- /dev/null +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/DependencyFindResult.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.nbcode.integration.commands; + +import java.util.Collections; +import java.util.List; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; +import org.eclipse.xtext.xbase.lib.Pure; +import org.netbeans.modules.project.dependency.ArtifactSpec; +import org.netbeans.modules.project.dependency.Dependency; + +/** + * + * @author sdedic + */ +public class DependencyFindResult { + @NonNull + private String uri; + private ArtifactSpec project; + private List<Dependency> matches = Collections.emptyList(); + + @Pure + public ArtifactSpec getProject() { + return project; + } + + public void setProject(ArtifactSpec project) { + this.project = project; + } + + @Pure + @NonNull + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + @Pure + @NonNull + public List<Dependency> getMatches() { + return matches; + } + + @Pure + public void setMatches(List<Dependency> matches) { + this.matches = matches == null ? Collections.emptyList() : matches; + } +} diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectDependenciesCommand.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectDependenciesCommand.java new file mode 100644 index 0000000000..6a6594f096 --- /dev/null +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectDependenciesCommand.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.nbcode.integration.commands; + +import com.google.gson.Gson; +import java.net.MalformedURLException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.project.dependency.ArtifactSpec; +import org.netbeans.modules.project.dependency.Dependency; +import org.netbeans.modules.project.dependency.DependencyResult; +import org.netbeans.modules.project.dependency.ProjectDependencies; +import org.netbeans.modules.project.dependency.ProjectOperationException; +import org.netbeans.modules.project.dependency.Scope; +import org.netbeans.spi.lsp.CommandProvider; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.URLMapper; +import org.openide.util.Lookup; +import org.openide.util.RequestProcessor; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author sdedic + */ +@ServiceProvider(service = CommandProvider.class) +public class ProjectDependenciesCommand implements CommandProvider { + + private static final RequestProcessor RP = new RequestProcessor(ProjectDependenciesCommand.class.getName(), 5); + + private static final String COMMAND_GET_DEPENDENCIES = "nbls.project.dependencies.find"; + private static final String COMMAND_CHANGE_DEPENDENCIES = "nbls.project.dependencies.change"; + + private static final Set COMMANDS = new HashSet<>(Arrays.asList( + COMMAND_GET_DEPENDENCIES, + COMMAND_CHANGE_DEPENDENCIES + )); + + @Override + public Set<String> getCommands() { + return COMMANDS; + } + + private final Gson gson = new Gson(); + + static class K { + final Dependency d; + + public K(Dependency d) { + this.d = d; + } + + public int hashCode() { + return d.getArtifact().hashCode() << 7 + d.getScope().name().hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof K)) { + return false; + } + K other = (K)o; + return other.d.getArtifact().equals(d.getArtifact()) && other.d.getScope().equals(d.getScope()); + } + } + + private Gson gson() { + Gson inst = Lookup.getDefault().lookup(Gson.class); + return inst != null ? inst : gson; + } + + @Override + public CompletableFuture<Object> runCommand(String command, List<Object> arguments) { + switch (command) { + case COMMAND_GET_DEPENDENCIES: { + DependencyFindRequest request = gson().fromJson(gson().toJson(arguments.get(0)), DependencyFindRequest.class); + FileObject dir; + try { + dir = Utils.fromUri(request.getUri()); + } catch (MalformedURLException ex) { + CompletableFuture res = new CompletableFuture(); + res.completeExceptionally(ex); + return res; + } + if (dir == null) { + throw new IllegalArgumentException("Not a file"); + } + + Project p = FileOwnerQuery.getOwner(dir); + if (p == null) { + return CompletableFuture.completedFuture(null); + } + List<ArtifactSpec> matches = request.getArtifacts(); + // PENDING: make 'online' a parameter + Scope[] scopes = request.getScopes() == null ? + null : request.getScopes().stream().map(sn -> Scope.named(sn)).toArray(s -> new Scope[s]); + ProjectDependencies.DependencyQueryBuilder b = ProjectDependencies.newBuilder(). + online(). + scope(scopes); + CompletableFuture future = new CompletableFuture(); + // do not block the main thread + RP.post(() -> { + DependencyResult r; + + try { + r = ProjectDependencies.findDependencies(p, b.build()); + } catch (ProjectOperationException ex) { + future.completeExceptionally(ex); + return; + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) { + future.completeExceptionally(t); + return; + } + DependencyFindResult res = new DependencyFindResult(); + res.setUri(URLMapper.findURL(p.getProjectDirectory(), URLMapper.EXTERNAL).toString()); + res.setProject(r.getRoot().getArtifact()); + + Queue<Dependency> toProcess = new ArrayDeque<>(); + List<Dependency> accepted = new ArrayList<>(); + toProcess.addAll(r.getRoot().getChildren()); + + Set<K> seen = new HashSet<>(); + NEXT: while (!toProcess.isEmpty()) { + Dependency d = toProcess.poll(); + ArtifactSpec a = d.getArtifact(); + if (a == null) { + // PENDING: not supported atm + continue; + } + if (!seen.add(new K(d))) { + continue; + } + toProcess.addAll(d.getChildren()); + if (matches != null && !matches.isEmpty()) { + for (ArtifactSpec test : matches) { + if (test.getGroupId() != null && !test.getGroupId().equals(a.getGroupId())) { + continue NEXT; + } + if (test.getArtifactId() != null && !test.getArtifactId().equals(a.getArtifactId())) { + continue NEXT; + } + if (test.getVersionSpec() != null && !test.getVersionSpec().equals(a.getVersionSpec())) { + continue NEXT; + } + if (test.getClassifier() != null && !test.getClassifier().equals(a.getClassifier())) { + continue NEXT; + } + if (test.getType()!= null && !test.getType().equals(a.getType())) { + continue NEXT; + } + // match found, OK + break; + } + } + + if (request.isReturnContents()) { + accepted.add(d); + } else { + accepted.add(Dependency.create(a, d.getScope(), Collections.emptyList(), null)); + } + } + res.setMatches(accepted); + future.complete(res); + }); + return future; + } + + case COMMAND_CHANGE_DEPENDENCIES: + } + return null; + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected] For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists
