Convert language servers to Boot apps

This commit is contained in:
Kris De Volder
2018-10-02 15:39:15 -07:00
parent 4cb796c81c
commit 6717306d8f
30 changed files with 394 additions and 234 deletions

View File

@@ -16,15 +16,13 @@
<dependencies.version>${project.version}</dependencies.version>
</properties>
<distributionManagement>
<repository>
<id>distribution-repository</id>
<name>Temporary Staging Repository</name>
<url>file://${basedir}/dist</url>
</repository>
</distributionManagement>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>language-server-starter</artifactId>
<version>${dependencies.version}</version>
</dependency>
<!-- Language Servers -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>

View File

@@ -14,6 +14,7 @@ import java.time.Duration;
import org.springframework.ide.vscode.commons.languageserver.util.Settings;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.stereotype.Component;
/**
* Provides access to configuration options that allow user to
@@ -22,6 +23,7 @@ import org.springframework.ide.vscode.commons.util.Log;
*
* @author Kris De Volder
*/
@Component
public class BoshCliConfig {
/**

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.bosh;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -29,6 +30,9 @@ import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.yaml.snakeyaml.nodes.Node;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import reactor.core.publisher.Flux;
public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServer> {
@@ -44,7 +48,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
@FunctionalInterface
private interface Handler {
Flux<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
List<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
}
public BoshDefintionFinder(BoshLanguageServer server, BoshSchemas schema, YamlAstCache asts, ASTTypeCache astTypes) {
@@ -64,7 +68,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
}
@Override
protected Flux<Location> findDefinitions(TextDocumentPositionParams params) {
public List<Location> handle(TextDocumentPositionParams params) {
try {
TextDocument doc = server.getTextDocumentService().get(params);
if (doc!=null) {
@@ -85,7 +89,7 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
} catch (Exception e) {
Log.log(e);
}
return Flux.empty();
return ImmutableList.of();
}
/**
@@ -101,14 +105,19 @@ public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServ
String name = NodeUtil.asScalar(refNode);
if (name!=null) {
Collection<Node> candidates = astTypes.getNodes(uri, def);
return Flux.fromIterable(candidates)
.filter((node) -> name.equals(NodeUtil.asScalar(node)))
.map((node) -> toLocation(doc, node))
.filter(Optional::isPresent)
.map(Optional::get);
Builder<Location> definitions = ImmutableList.builder();
for (Node node : candidates) {
if (name.equals(NodeUtil.asScalar(node))) {
Optional<Location> loc = toLocation(doc, node);
if (loc.isPresent()) {
definitions.add(loc.get());
}
}
}
return definitions.build();
}
}
return Flux.empty();
return ImmutableList.of();
};
handlers.put(ref, handler);
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,24 +10,35 @@
*******************************************************************************/
package org.springframework.ide.vscode.bosh;
import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.bosh.models.BoshCommandCloudConfigProvider;
import org.springframework.ide.vscode.bosh.models.BoshCommandReleasesProvider;
import org.springframework.ide.vscode.bosh.models.BoshCommandStemcellsProvider;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.util.LogRedirect;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "bosh-language-server";
LogRedirect.redirectToFile(serverName);
BoshCliConfig cliConfig = new BoshCliConfig();
LaunguageServerApp.start(serverName, () -> new BoshLanguageServer(
@SpringBootApplication
public class BoshLanguageServerBootApp {
private static final String SERVER_NAME = "bosh-language-server";
public static void main(String[] args) throws Exception {
LogRedirect.bootRedirectToFile(SERVER_NAME); //TODO: use boot (or logback realy) to configure logging instead.
SpringApplication.run(BoshLanguageServerBootApp.class, args);
}
@Bean public String serverName() {
return SERVER_NAME;
}
@Bean BoshLanguageServer languageServer(BoshCliConfig cliConfig) {
return new BoshLanguageServer(
cliConfig,
new BoshCommandCloudConfigProvider(cliConfig),
new BoshCommandStemcellsProvider(cliConfig),
new BoshCommandReleasesProvider(cliConfig)
));
);
}
}

View File

@@ -16,7 +16,6 @@ import java.util.Collection;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@@ -34,8 +34,11 @@ import org.eclipse.lsp4j.jsonrpc.MessageConsumer;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.LanguageClientAware;
import org.eclipse.lsp4j.services.LanguageServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.AsyncRunner;
import org.springframework.ide.vscode.commons.util.Log;
@@ -53,37 +56,48 @@ import org.springframework.ide.vscode.commons.util.Log;
* @author Kris De Volder
* @author Martin Lippert
*/
public abstract class LaunguageServerApp {
public class LaunguageServerApp {
public static final String STS4_LANGUAGESERVER_NAME = "sts4.languageserver.name";
public static final String STANDALONE_STARTUP = "standalone-startup";
private static final int SERVER_STANDALONE_PORT = 5007;
public static void start(String name, Provider<SimpleLanguageServer> languageServerFactory) throws IOException, InterruptedException {
System.setProperty(STS4_LANGUAGESERVER_NAME, name); //makes it easy to recognize language server processes.
LaunguageServerApp app = new LaunguageServerApp() {
@Override
protected SimpleLanguageServer createServer() {
return languageServerFactory.get();
}
};
final static Logger log = LoggerFactory.getLogger(LaunguageServerApp.class);
private final String name;
private final Provider<SimpleLanguageServer> languageServerFactory;
public LaunguageServerApp(String name, Provider<SimpleLanguageServer> languageServerFactory) {
super();
this.name = name;
this.languageServerFactory = languageServerFactory;
}
public void start() throws Exception {
System.setProperty(STS4_LANGUAGESERVER_NAME, name); //makes it easy to recognize language server processes.
LaunguageServerApp app = this;
if (System.getProperty(STANDALONE_STARTUP, "false").equals("true")) {
app.startAsServer();
}
else {
app.start();
} else {
app.startAsClient();
}
}
public static void startAsServer(Provider<SimpleLanguageServer> languageServerFactory) throws IOException, InterruptedException {
LaunguageServerApp app = new LaunguageServerApp() {
@Override
protected SimpleLanguageServer createServer() {
return languageServerFactory.get();
}
};
app.startAsServer();
public void startAsync() {
//TODO: feel a bit wasteful to have thread dedicated to just waiting for the server to stop.
// Not sure how we can really avoid this though. Lsp4j is providing
// lots of api that returns Futures which the only way to deal with them is blocking threads calling
// their get method.
new Thread(
() -> {
try {
start();
} catch (Exception e) {
log.error("", e);
}
},
"LanguageServerApp lifecycle"
).start();
}
protected static class Connection {
@@ -122,14 +136,14 @@ public abstract class LaunguageServerApp {
}
}
public void start() throws IOException {
public void startAsClient() throws IOException {
Log.info("Starting LS");
Connection connection = null;
try {
LoggingFormat.startLogging();
connection = connectToNode();
run(connection);
runAsync(connection).get();
} catch (Throwable t) {
Log.log(t);
System.exit(1);
@@ -152,8 +166,8 @@ public abstract class LaunguageServerApp {
* Source of inspiration:
* https://github.com/itemis/xtext-languageserver-example/blob/master/org.xtext.example.mydsl.ide/src/org/xtext/example/mydsl/ide/RunServer.java
*/
public void startAsServer() throws IOException, InterruptedException {
Log.info("Starting LS as standlone server port = "+SERVER_STANDALONE_PORT);
public void startAsServer() throws Exception {
log.info("Starting LS as standlone server port = {}", SERVER_STANDALONE_PORT);
Function<MessageConsumer, MessageConsumer> wrapper = consumer -> {
MessageConsumer result = consumer;
@@ -165,33 +179,30 @@ public abstract class LaunguageServerApp {
new InetSocketAddress("localhost", SERVER_STANDALONE_PORT), createServerThreads(), wrapper);
languageServer.connect(launcher.getRemoteProxy());
Future<?> future = launcher.startListening();
while (!future.isDone()) {
Thread.sleep(10_000l);
}
launcher.startListening().get();
}
/**
* Creates the thread pool / executor passed to lsp4j server intialization. From the looks of things,
* @return
*/
protected ExecutorService createServerThreads() {
protected ExecutorService createServerThreads() {
return Executors.newCachedThreadPool();
}
private <T> Launcher<T> createSocketLauncher(Object localService, Class<T> remoteInterface, SocketAddress socketAddress, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) throws IOException {
AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(socketAddress);
AsynchronousSocketChannel socketChannel;
try {
socketChannel = serverSocket.accept().get();
return Launcher.createIoLauncher(localService, remoteInterface, Channels.newInputStream(socketChannel), Channels.newOutputStream(socketChannel), executorService, wrapper);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
}
private <T> Launcher<T> createSocketLauncher(
Object localService, Class<T> remoteInterface,
SocketAddress socketAddress, ExecutorService executorService,
Function<MessageConsumer, MessageConsumer> wrapper
) throws Exception {
AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(socketAddress);
AsynchronousSocketChannel socketChannel = serverSocket.accept().get();
log.info("Client connected via socket");
return Launcher.createIoLauncher(localService, remoteInterface, Channels.newInputStream(socketChannel),
Channels.newOutputStream(socketChannel), executorService, wrapper);
}
private static Connection connectToNode() throws IOException {
private static Connection connectToNode() throws IOException {
String port = System.getProperty("server.port");
if (port != null) {
@@ -217,10 +228,8 @@ public abstract class LaunguageServerApp {
* Listen for requests from the parent node process.
* Send replies asynchronously.
* When the request stream is closed, wait for 5s for all outstanding responses to compute, then return.
* @throws ExecutionException
* @throws InterruptedException
*/
protected void run(Connection connection) throws InterruptedException, ExecutionException {
protected Future<Void> runAsync(Connection connection) throws Exception {
LanguageServer server = createServer();
ExecutorService executor = createServerThreads();
Function<MessageConsumer, MessageConsumer> wrapper = (MessageConsumer consumer) -> {
@@ -229,7 +238,7 @@ public abstract class LaunguageServerApp {
consumer.consume(msg);
} catch (UnsupportedOperationException e) {
//log a warning and ignore. We are getting some messages from vsCode the server doesn't know about
Log.warn("Unsupported message was ignored!", e);
log.warn("Unsupported message was ignored!", e);
}
};
};
@@ -246,9 +255,10 @@ public abstract class LaunguageServerApp {
((LanguageClientAware) server).connect(client);
}
launcher.startListening().get();
return launcher.startListening();
}
protected abstract SimpleLanguageServer createServer();
final SimpleLanguageServer createServer() {
return languageServerFactory.get();
}
}

View File

@@ -10,8 +10,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.definition;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.TextDocumentPositionParams;
@@ -20,7 +20,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import reactor.core.publisher.Flux;
import com.google.common.collect.ImmutableList;
/**
* {@link SimpleDefinitionFinder} provides a 'dummy' implementation of
@@ -35,21 +35,7 @@ public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements D
}
@Override
public List<Location> handle(TextDocumentPositionParams position) {
return findDefinitions(position)
.collect(Collectors.toList()).block();
}
/**
* This is meant to be overridden by subclass. This method provides a simple implementation
* of 'goto definition' (which is not one you probably want to use in practice, but it
* might be usful just to test whether things are wired up correctly to make the
* 'goto definition' action in vscode work.
* <p>
* The implementation provided here simply looks for the first occurrence of the word
* currently pointed at in the current document using String.indexOf.
*/
protected Flux<Location> findDefinitions(TextDocumentPositionParams params) {
public List<Location> handle(TextDocumentPositionParams params) {
try {
TextDocument doc = server.getTextDocumentService().get(params);
if (doc != null) {
@@ -68,20 +54,17 @@ public class SimpleDefinitionFinder<T extends SimpleLanguageServer> implements D
String text = doc.get();
int def = text.indexOf(word);
if (def>=0) {
return Flux.just(
new Location(params.getTextDocument().getUri(),
doc.toRange(def, word.length())
)
)
.doOnNext((Location loc) -> {
Log.log("definition: "+loc);
});
Location loc = new Location(params.getTextDocument().getUri(),
doc.toRange(def, word.length())
);
Log.log("definition: "+loc);
return ImmutableList.of(loc);
}
}
} catch (Exception e) {
Log.log(e);
}
return Flux.empty();
return Collections.emptyList();
}
}

View File

@@ -144,7 +144,11 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA
private Map<String, ExecuteCommandHandler> commands = new HashMap<>();
private AsyncRunner async = new AsyncRunner(Schedulers.newSingle("SimpleLanguaserver main thread"));
private AsyncRunner async = new AsyncRunner(Schedulers.newSingle(runable -> {
Thread t = new Thread(runable, "SimpleLanguaserver main thread");
t.setDaemon(true);
return t;
}));
private ClasspathListenerManager classpathListenerManager;
@Override
@@ -214,7 +218,7 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA
@Override
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
Log.debug("Initializing: "+params);
log.info("Initializing: "+params);
// multi-root workspace handling
List<WorkspaceFolder> workspaceFolders = getWorkspaceFolders(params);

View File

@@ -18,7 +18,6 @@ import org.slf4j.Logger;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
public class AsyncRunner {

View File

@@ -17,12 +17,24 @@ import java.io.PrintStream;
public class LogRedirect {
public static void bootRedirectToFile(String name) throws IOException {
String logfilePath = System.getProperty("sts.log.file");
if (StringUtil.hasText(logfilePath)) {
File logfile = new File(logfilePath);
System.err.println("Redirecting log output to: "+logfile);
PrintStream logFile = new PrintStream(new FileOutputStream(logfile, false));
System.setErr(logFile);
System.setOut(logFile); //Spring boot actually logs on sysout instead of syserr.
}
}
public static void redirectToFile(String name) throws IOException {
String logfilePath = System.getProperty("sts.log.file");
if (StringUtil.hasText(logfilePath)) {
File logfile = new File(logfilePath);
System.err.println("Redirecting log output to: "+logfile);
System.setErr(new PrintStream(new FileOutputStream(logfile, false)));
PrintStream logFile = new PrintStream(new FileOutputStream(logfile, false));
System.setErr(logFile);
}
}

View File

@@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>language-server-starter</artifactId>
<name>language-server-starter</name>
<description>Spring Boot Starter for building Language Server</description>
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-language-server</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,28 @@
package org.springframework.ide.vscode.languageserver.starter;
import javax.inject.Provider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
@Configuration
public class LanguageServerAutoconf {
@Bean public LaunguageServerApp serverApp(
@Qualifier("serverName") String serverName,
Provider<SimpleLanguageServer> languageServerFactory
) {
return new LaunguageServerApp(serverName, languageServerFactory);
}
@Bean public CommandLineRunner serverStarter(LaunguageServerApp serverApp) {
return args -> {
serverApp.startAsync();
};
}
}

View File

@@ -9,6 +9,12 @@
<version>1.1.0-SNAPSHOT</version>
<name>commons-parent</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<modules>
<module>commons-language-server</module>
<module>language-server-test-harness</module>
@@ -20,6 +26,8 @@
<module>commons-maven</module>
<module>commons-gradle</module>
<module>commons-boot-app-cli</module>
<module>language-server-starter</module>
</modules>
<repositories>
@@ -74,14 +82,13 @@
<yaml-version>1.17</yaml-version>
<junit-version>4.11</junit-version>
<assertj-version>3.5.2</assertj-version>
<slf4j-version>1.7.22</slf4j-version>
<slf4j-version>1.7.25</slf4j-version>
<guava-version>19.0</guava-version>
<mockito-version>1.10.19</mockito-version>
<jackson-2-version>2.5.0</jackson-2-version>
<jersey-2-version>2.10</jersey-2-version>
<lsp4j-version>0.4.0-SNAPSHOT</lsp4j-version>
<cglib-version>3.2.7</cglib-version>
<boot-version>2.0.4.RELEASE</boot-version>
<!-- NOTE: Reactor version must match version used by the CF client -->
<cloudfoundry-client-version>3.8.0.RELEASE</cloudfoundry-client-version>
<reactor-version>3.1.5.RELEASE</reactor-version>
@@ -111,11 +118,11 @@
<artifactId>slf4j-api</artifactId>
<version>${slf4j-version}</version>
</dependency>
<dependency>
<!-- <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j-version}</version>
</dependency>
</dependency> -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@@ -25,10 +25,16 @@
</distributionManagement>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Language Servers -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-language-server</artifactId>
<artifactId>language-server-starter</artifactId>
<version>${dependencies.version}</version>
</dependency>
<!-- Yaml -->

View File

@@ -10,7 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -28,13 +30,16 @@ import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.yaml.snakeyaml.nodes.Node;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import reactor.core.publisher.Flux;
public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<ConcourseLanguageServer> {
@FunctionalInterface
private interface Handler {
Flux<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
List<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
}
private final ASTTypeCache astTypes;
@@ -64,19 +69,24 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<ConcourseL
Handler handler = (Node refNode, TextDocument doc, YamlFileAST ast) -> {
String name = NodeUtil.asScalar(refNode);
if (name!=null) {
return Flux.fromStream(definitionsPath.traverseAmbiguously(ast))
.filter((node) -> name.equals(NodeUtil.asScalar(node)))
.map((node) -> toLocation(doc, node))
.filter(Optional::isPresent)
.map(Optional::get);
Builder<Location> definitions = ImmutableList.builder();
definitionsPath.traverseAmbiguously(ast).forEach(node -> {
if (name.equals(NodeUtil.asScalar(node))) {
Optional<Location> loc = toLocation(doc, node);
if (loc.isPresent()) {
definitions.add(loc.get());
}
}
});
return definitions.build();
}
return Flux.empty();
return ImmutableList.of();
};
handlers.put(refType, handler);
}
@Override
protected Flux<Location> findDefinitions(TextDocumentPositionParams params) {
public List<Location> handle(TextDocumentPositionParams params) {
try {
TextDocument doc = server.getTextDocumentService().get(params);
if (doc!=null) {
@@ -97,7 +107,7 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<ConcourseL
} catch (Exception e) {
Log.log(e);
}
return Flux.empty();
return ImmutableList.of();
}
Optional<Location> toLocation(TextDocument doc, Node node) {

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
import org.springframework.ide.vscode.concourse.github.DefaultGithubInfoProvider;
@SpringBootApplication
public class ConcourseLanguageServerBootApp {
private static final String SERVER_NAME = "concourse-language-server";
public static void main(String[] args) throws Exception {
LogRedirect.bootRedirectToFile(SERVER_NAME); //TODO: use boot (or logback realy) to configure logging instead.
SpringApplication.run(ConcourseLanguageServerBootApp.class, args);
}
@Bean public String serverName() {
return SERVER_NAME;
}
@Bean ConcourseLanguageServer languageServer() {
return new ConcourseLanguageServer(YamlCompletionEngineOptions.DEFAULT, new DefaultGithubInfoProvider());
}
}

View File

@@ -1,34 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.concourse;
import java.io.IOException;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
import org.springframework.ide.vscode.concourse.github.DefaultGithubInfoProvider;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import static org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp.STANDALONE_STARTUP;
public class Main {
private static final YamlCompletionEngineOptions OPTIONS = YamlCompletionEngineOptions.DEFAULT;
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "concourse-language-server";
if (!Boolean.getBoolean(STANDALONE_STARTUP)) {
LogRedirect.redirectToFile(serverName);
}
LaunguageServerApp.start(serverName, () -> new ConcourseLanguageServer(OPTIONS, new DefaultGithubInfoProvider()));
}
}

View File

@@ -128,11 +128,11 @@ public class DefaultGithubInfoProvider implements GithubInfoProvider {
return reposByOwner.get(ownerName, loader(() -> {
GHPerson owner = getOwner(ownerName);
if (owner!=null) {
return Flux.fromIterable(owner.listRepositories())
.filter(repo -> repo.getOwnerName().equals(ownerName))
.map(GHRepository::getName)
.collect(CollectorUtil.toImmutableSet())
.block();
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (GHRepository repo : owner.listRepositories()) {
builder.add(repo.getName());
}
return builder.build();
}
return null;
}))

View File

@@ -34,6 +34,12 @@
</distributionManagement>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>language-server-starter</artifactId>
<version>${dependencies.version}</version>
</dependency>
<!-- Language Servers -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
@@ -47,6 +53,17 @@
<version>${dependencies.version}</version>
</dependency>
<!-- CF -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>${reactor-version}</version>
</dependency>
<dependency>
<groupId>io.projectreactor.ipc</groupId>
<artifactId>reactor-netty</artifactId>
<version>${reactor-netty}</version>
</dependency>
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-cf</artifactId>

View File

@@ -1,28 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.manifest.yaml;
import java.io.IOException;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.LogRedirect;
public class Main {
SimpleLanguageServer server = new ManifestYamlLanguageServer();
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "manifest-yaml-language-server";
LogRedirect.redirectToFile(serverName);
LaunguageServerApp.start(serverName, ManifestYamlLanguageServer::new);
}
}

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.manifest.yaml;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
@SpringBootApplication
public class ManifestYamlLanguageServerBootApp {
private static final String SERVER_NAME = "manifest-yaml-language-server";
public static void main(String[] args) throws Exception {
LogRedirect.bootRedirectToFile(SERVER_NAME); //TODO: use boot (or logback realy) to configure logging instead.
SpringApplication.run(ManifestYamlLanguageServerBootApp.class, args);
}
@Bean public String serverName() {
return SERVER_NAME;
}
@Bean ManifestYamlLanguageServer languageServer() {
return new ManifestYamlLanguageServer();
}
}

View File

@@ -24,8 +24,14 @@
</repository>
</repositories>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>language-server-starter</artifactId>
<version>${dependencies.version}</version>
</dependency>
<!-- other -->
<dependency>
<!-- Local modified JSON lib packaged to support order in maps -->
<groupId>org.springframework.ide.eclipse</groupId>
@@ -62,11 +68,6 @@
<artifactId>commons-boot-app-cli</artifactId>
<version>${dependencies.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${boot-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.LogRedirect;
@SpringBootApplication
public class BootLanguagServerBootApp {
private static final String SERVER_NAME = "boot-language-server";
public static void main(String[] args) throws Exception {
LogRedirect.bootRedirectToFile(SERVER_NAME); //TODO: use boot (or logback realy) to configure logging instead.
SpringApplication.run(BootLanguagServerBootApp.class, args);
}
@Bean public String serverName() {
return SERVER_NAME;
}
@Bean SimpleLanguageServer languageServer() {
return BootLanguageServer.create(BootLanguageServerParams.createDefault()).getServer();
}
}

View File

@@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016, 2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot;
import java.io.IOException;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.util.LogRedirect;
/**
* Starts up Language Server process
*
* @author Alex Boyko
* @author Kris De Volder
*
*/
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "boot-language-server";
LogRedirect.redirectToFile(serverName);
LaunguageServerApp.start(serverName,
() -> BootLanguageServer.create(BootLanguageServerParams.createDefault()).getServer()
);
}
}

View File

@@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -126,7 +126,8 @@ export function activate(options: ActivatorOptions, context: VSCode.ExtensionCon
'-Dspring.lsp.client-port='+port,
'-Dserver.port=' + port,
'-Dsts.lsp.client=vscode',
'-Dsts.log.file=' + logfile
'-Dsts.log.file=' + logfile, //old style log redirect
'-Dlogging.file=' + logfile // spring boot log redirect
];
if (options.checkjvm) {
options.checkjvm(context, jvm);

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -e
#if [ ! -d "node_modules/commons-vscode" ]; then
./scripts/preinstall.sh
#fi
npm install
npm run vsce-package
npm run vsce-package
rm -fr ~/.vscode/extensions/pivotal.vscode-concourse*
rm -fr ~/.vscode/extensions/.obsolete
code --install-extension vscode-concourse-*.vsix

View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -e
npm install
npm run vsce-package
rm -fr ~/.vscode/extensions/pivotal.vscode-manifest-yaml*
rm -fr ~/.vscode/extensions/.obsolete
code --install-extension vscode-*.vsix