From 2b48c71791e9ab5efaf2fe8ba337f03286ef99c8 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Mon, 28 Aug 2023 16:14:45 +0800 Subject: [PATCH 1/2] fix: Store the schema version of the BSP project after import Signed-off-by: Sheng Chen --- .../GradleBuildServerProjectImporter.java | 3 + .../gradle/bs/importer/ImporterPlugin.java | 11 +++ .../bs/importer/manager/SchemaStore.java | 84 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java index e20538e98..8e51caba8 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java @@ -46,6 +46,8 @@ public class GradleBuildServerProjectImporter extends AbstractProjectImporter { private static final String BSP_VERSION = "2.1.0-M4"; + private static final String SCHEMA_VERSION = "0.1.0"; + public static final String BUILD_GRADLE_DESCRIPTOR = "build.gradle"; public static final String BUILD_GRADLE_KTS_DESCRIPTOR = "build.gradle.kts"; public static final String SETTINGS_GRADLE_DESCRIPTOR = "settings.gradle"; @@ -179,6 +181,7 @@ private List importProjects(BuildServer buildServer, IProgressMonitor project.refreshLocal(IResource.DEPTH_INFINITE, monitor); projects.add(project); + ImporterPlugin.getSchemaStore().updateSchemaInformation(project.getLocation().toPath(), SCHEMA_VERSION); } return projects; } diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java index 8eb5f9abb..eb040585a 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java @@ -19,6 +19,7 @@ import org.eclipse.lsp4j.jsonrpc.Launcher; import org.osgi.framework.BundleContext; +import com.microsoft.gradle.bs.importer.manager.SchemaStore; import com.microsoft.java.builder.BuildStateManager; import ch.epfl.scala.bsp4j.BuildClient; @@ -37,6 +38,11 @@ public class ImporterPlugin extends Plugin { */ private DigestStore digestStore; + /** + * Cache file to store the schema version of BSP project. + */ + private SchemaStore schemaStore; + private static String bundleDirectory; @Override @@ -44,6 +50,7 @@ public void start(BundleContext context) throws Exception { BuildStateManager.getBuildStateManager().startup(); ImporterPlugin.instance = this; digestStore = new DigestStore(getStateLocation().toFile()); + schemaStore = new SchemaStore(getStateLocation().toFile()); Optional bundleFile = FileLocator.getBundleFileLocation(context.getBundle()); if (!bundleFile.isPresent()) { throw new IllegalStateException("Failed to get bundle location."); @@ -67,6 +74,10 @@ public static DigestStore getDigestStore() { return instance.digestStore; } + public static SchemaStore getSchemaStore() { + return instance.schemaStore; + } + public static BuildServer getBuildServerConnection(IPath rootPath) throws CoreException { Pair pair = instance.buildServers.get(rootPath); if (pair != null) { diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java new file mode 100644 index 000000000..40a818590 --- /dev/null +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2023 Microsoft Corporation 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: + * Microsoft Corporation - - initial API and implementation + ******************************************************************************/ + +package com.microsoft.gradle.bs.importer.manager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; + +/** + * Store the schema version of the BSP project. + */ +public class SchemaStore { + private Map schemas; + private File stateFile; + + private static final String SERIALIZATION_FILE_NAME = ".schema"; + + public SchemaStore(File stateLocation) { + this.stateFile = new File(stateLocation, SERIALIZATION_FILE_NAME); + if (stateFile.isFile()) { + schemas = deserializeSchemaFile(); + } else { + schemas = new HashMap<>(); + } + } + + /** + * Update the schema version of the BSP project. Return true if the schema version is changed. + * @throws CoreException + */ + public boolean updateSchemaInformation(Path p, String version) throws CoreException { + try { + synchronized (schemas) { + String key = p.toString(); + if (!version.equals(schemas.get(key))) { + schemas.put(key, version); + serializeSchemaFile(); + return true; + } + } + } catch (IOException e) { + JavaLanguageServerPlugin.logException("Exception occurred while serialization of schema file.", e); + } + + return false; + + } + + private void serializeSchemaFile() throws IOException { + try (ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(stateFile))) { + outStream.writeObject(schemas); + } + } + + @SuppressWarnings("unchecked") + private Map deserializeSchemaFile() { + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(stateFile))) { + return (Map) ois.readObject(); + } catch (IOException | ClassNotFoundException e) { + JavaLanguageServerPlugin.logException("Exception occurred while deserialization of schema file.", e); + return new HashMap<>(); + } + } +} From a7394945932ec78b0bfdd7ae0b82e31b6556bc72 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 29 Aug 2023 16:17:58 +0800 Subject: [PATCH 2/2] Use variable description to save schema version --- .../GradleBuildServerProjectImporter.java | 20 ++++- .../gradle/bs/importer/ImporterPlugin.java | 13 +-- .../microsoft/gradle/bs/importer/Utils.java | 23 +---- .../bs/importer/manager/SchemaStore.java | 84 ------------------- 4 files changed, 24 insertions(+), 116 deletions(-) delete mode 100644 extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java index 8e51caba8..77dd302d6 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/GradleBuildServerProjectImporter.java @@ -10,6 +10,9 @@ import java.util.Map; import java.util.Map.Entry; +import org.eclipse.core.internal.resources.Project; +import org.eclipse.core.internal.resources.ProjectDescription; +import org.eclipse.core.internal.resources.VariableDescription; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; @@ -46,6 +49,7 @@ public class GradleBuildServerProjectImporter extends AbstractProjectImporter { private static final String BSP_VERSION = "2.1.0-M4"; + private static final String SCHEMA_VERSION_KEY = "bspSchemaVersion"; private static final String SCHEMA_VERSION = "0.1.0"; public static final String BUILD_GRADLE_DESCRIPTOR = "build.gradle"; @@ -181,7 +185,6 @@ private List importProjects(BuildServer buildServer, IProgressMonitor project.refreshLocal(IResource.DEPTH_INFINITE, monitor); projects.add(project); - ImporterPlugin.getSchemaStore().updateSchemaInformation(project.getLocation().toPath(), SCHEMA_VERSION); } return projects; } @@ -190,6 +193,10 @@ private IProject createProject(File directory, IProgressMonitor monitor) throws String projectName = findFreeProjectName(directory.getName()); IWorkspace workspace = ResourcesPlugin.getWorkspace(); IProjectDescription projectDescription = workspace.newProjectDescription(projectName); + if (projectDescription instanceof ProjectDescription description) { + VariableDescription variableDescription = new VariableDescription(SCHEMA_VERSION_KEY, SCHEMA_VERSION); + description.setVariableDescription(SCHEMA_VERSION_KEY, variableDescription); + } projectDescription.setLocation(Path.fromOSString(directory.getPath())); projectDescription.setNatureIds(new String[]{ GradleBuildServerProjectNature.NATURE_ID }); ICommand buildSpec = Utils.getBuildServerBuildSpec(projectDescription); @@ -211,6 +218,17 @@ private void updateProjectDescription(IProject project, IProgressMonitor monitor Utils.getBuildServerBuildSpec(projectDescription), problemReporter }, monitor); + + // Here we don't use the public API: {@code project.setDescription()} to update the project, + // because that API will ignore the variable descriptions. + if (project instanceof Project internalProject) { + ProjectDescription description = internalProject.internalGetDescription(); + VariableDescription variableDescription = new VariableDescription(SCHEMA_VERSION_KEY, SCHEMA_VERSION); + boolean changed = description.setVariableDescription(SCHEMA_VERSION_KEY, variableDescription); + if (changed) { + internalProject.writeDescription(IResource.NONE); + } + } } private String findFreeProjectName(String baseName) { diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java index eb040585a..4aec9ca72 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/ImporterPlugin.java @@ -19,7 +19,6 @@ import org.eclipse.lsp4j.jsonrpc.Launcher; import org.osgi.framework.BundleContext; -import com.microsoft.gradle.bs.importer.manager.SchemaStore; import com.microsoft.java.builder.BuildStateManager; import ch.epfl.scala.bsp4j.BuildClient; @@ -38,11 +37,6 @@ public class ImporterPlugin extends Plugin { */ private DigestStore digestStore; - /** - * Cache file to store the schema version of BSP project. - */ - private SchemaStore schemaStore; - private static String bundleDirectory; @Override @@ -50,7 +44,6 @@ public void start(BundleContext context) throws Exception { BuildStateManager.getBuildStateManager().startup(); ImporterPlugin.instance = this; digestStore = new DigestStore(getStateLocation().toFile()); - schemaStore = new SchemaStore(getStateLocation().toFile()); Optional bundleFile = FileLocator.getBundleFileLocation(context.getBundle()); if (!bundleFile.isPresent()) { throw new IllegalStateException("Failed to get bundle location."); @@ -72,11 +65,7 @@ public static ImporterPlugin getInstance() { public static DigestStore getDigestStore() { return instance.digestStore; - } - - public static SchemaStore getSchemaStore() { - return instance.schemaStore; - } + } public static BuildServer getBuildServerConnection(IPath rootPath) throws CoreException { Pair pair = instance.buildServers.get(rootPath); diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/Utils.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/Utils.java index 611405e88..db6126b4e 100644 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/Utils.java +++ b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/Utils.java @@ -124,28 +124,13 @@ public static void addNature(IProject project, String natureId, IProgressMonitor * @throws CoreException */ public static void addBuildSpec(IProject project, String[] buildNames, IProgressMonitor monitor) throws CoreException { - SubMonitor progress = SubMonitor.convert(monitor, 1); - // get the description IProjectDescription description = project.getDescription(); - List currentBuildSpecs = Arrays.asList(description.getBuildSpec()); - List newSpecs = new LinkedList<>(); - newSpecs.addAll(currentBuildSpecs); - for (String buildName : buildNames) { - if (currentBuildSpecs.stream().anyMatch(spec -> Objects.equals(spec.getBuilderName(), buildName))) { - continue; - } - + ICommand[] commands = Arrays.stream(buildNames).map(buildName -> { ICommand buildSpec = description.newCommand(); buildSpec.setBuilderName(buildName); - newSpecs.add(0, buildSpec); - } - - if (newSpecs.size() == currentBuildSpecs.size()) { - return; - } - - description.setBuildSpec(newSpecs.toArray(new ICommand[newSpecs.size()])); - project.setDescription(description, IResource.AVOID_NATURE_CONFIG, progress.newChild(1)); + return buildSpec; + }).toArray(ICommand[]::new); + addBuildSpec(project, commands, monitor); } /** diff --git a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java b/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java deleted file mode 100644 index 40a818590..000000000 --- a/extension/jdtls.ext/com.microsoft.gradle.bs.importer/src/com/microsoft/gradle/bs/importer/manager/SchemaStore.java +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2023 Microsoft Corporation 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: - * Microsoft Corporation - - initial API and implementation - ******************************************************************************/ - -package com.microsoft.gradle.bs.importer.manager; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; - -/** - * Store the schema version of the BSP project. - */ -public class SchemaStore { - private Map schemas; - private File stateFile; - - private static final String SERIALIZATION_FILE_NAME = ".schema"; - - public SchemaStore(File stateLocation) { - this.stateFile = new File(stateLocation, SERIALIZATION_FILE_NAME); - if (stateFile.isFile()) { - schemas = deserializeSchemaFile(); - } else { - schemas = new HashMap<>(); - } - } - - /** - * Update the schema version of the BSP project. Return true if the schema version is changed. - * @throws CoreException - */ - public boolean updateSchemaInformation(Path p, String version) throws CoreException { - try { - synchronized (schemas) { - String key = p.toString(); - if (!version.equals(schemas.get(key))) { - schemas.put(key, version); - serializeSchemaFile(); - return true; - } - } - } catch (IOException e) { - JavaLanguageServerPlugin.logException("Exception occurred while serialization of schema file.", e); - } - - return false; - - } - - private void serializeSchemaFile() throws IOException { - try (ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(stateFile))) { - outStream.writeObject(schemas); - } - } - - @SuppressWarnings("unchecked") - private Map deserializeSchemaFile() { - try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(stateFile))) { - return (Map) ois.readObject(); - } catch (IOException | ClassNotFoundException e) { - JavaLanguageServerPlugin.logException("Exception occurred while deserialization of schema file.", e); - return new HashMap<>(); - } - } -}