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

[Code] compute url for language server plugin #32644

Merged
merged 1 commit into from
Mar 8, 2019
Merged
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: 2 additions & 0 deletions x-pack/plugins/code/common/language_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export interface LanguageServer {
version?: string;
build?: string;
status?: LanguageServerStatus;
downloadUrl?: any;
pluginName?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@

import {
EuiButton,
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiLoadingSpinner,
EuiModal,
EuiModalBody,
EuiModalFooter,
Expand All @@ -18,18 +17,18 @@ import {
EuiOverlayMask,
EuiPanel,
EuiSpacer,
EuiTabbedContent,
EuiText,
EuiTextColor,
} from '@elastic/eui';
import React from 'react';
import { connect } from 'react-redux';
import styled from 'styled-components';
import { InstallationType } from '../../../common/installation';
import { LanguageServer, LanguageServerStatus } from '../../../common/language_server';
import { requestInstallLanguageServer } from '../../actions/language_server';
import { RootState } from '../../reducers';
import { JavaIcon, TypeScriptIcon } from '../shared/icons';
const JAVA_URL =
'https://download.elasticsearch.org/code/java-langserver/snapshot/java_languageserver-1.0.0-SNAPSHOT-darwin.zip';

const LanguageServerState = styled(EuiTextColor)`
color: ${props => props.color};
Expand All @@ -55,25 +54,17 @@ const LanguageServerLi = (props: {
let state = null;
if (status === LanguageServerStatus.RUNNING) {
state = <LanguageServerState>Running ...</LanguageServerState>;
button = (
<EuiButton size="s" color="secondary" onClick={onInstallClick}>
Re-install
</EuiButton>
);
} else if (status === LanguageServerStatus.NOT_INSTALLED) {
state = <LanguageServerState color={'subdued'}>Not Installed</LanguageServerState>;
button = props.loading ? (
<EuiButton size="s" color="secondary">
<EuiLoadingSpinner size="s" />
Installing
</EuiButton>
) : (
} else if (status === LanguageServerStatus.READY) {
state = <LanguageServerState color={'subdued'}>Installed</LanguageServerState>;
}
if (props.languageServer.installationType === InstallationType.Plugin) {
button = (
<EuiButton size="s" color="secondary" onClick={onInstallClick}>
Install
Setup
</EuiButton>
);
} else if (status === LanguageServerStatus.READY) {
state = <LanguageServerState color={'subdued'}>Installed</LanguageServerState>;
}
return (
<EuiFlexItem>
Expand Down Expand Up @@ -108,6 +99,7 @@ interface State {
showingInstruction: boolean;
name?: string;
url?: string;
pluginName?: string;
}

class AdminLanguageSever extends React.PureComponent<Props, State> {
Expand All @@ -116,22 +108,22 @@ class AdminLanguageSever extends React.PureComponent<Props, State> {
this.state = { showingInstruction: false };
}

public toggleInstruction = (showingInstruction: boolean, name?: string, url?: string) => {
this.setState({ showingInstruction, name, url });
public toggleInstruction = (
showingInstruction: boolean,
name?: string,
url?: string,
pluginName?: string
) => {
this.setState({ showingInstruction, name, url, pluginName });
};

public render() {
const languageServers = this.props.languageServers.map(ls => (
<LanguageServerLi
languageServer={ls}
key={ls.name}
requestInstallLanguageServer={
() =>
this.toggleInstruction(
true,
ls.name,
JAVA_URL
) /*this.props.requestInstallLanguageServer*/
requestInstallLanguageServer={() =>
this.toggleInstruction(true, ls.name, ls.downloadUrl, ls.pluginName)
}
loading={this.props.installLoading[ls.name]}
/>
Expand All @@ -156,6 +148,7 @@ class AdminLanguageSever extends React.PureComponent<Props, State> {
<LanguageServerInstruction
show={this.state.showingInstruction}
name={this.state.name!}
pluginName={this.state.pluginName!}
url={this.state.url!}
close={() => this.toggleInstruction(false)}
/>
Expand All @@ -164,36 +157,57 @@ class AdminLanguageSever extends React.PureComponent<Props, State> {
}
}

const SupportedOS = [
{ id: 'win', name: 'Windows' },
{ id: 'linux', name: 'Linux' },
{ id: 'darwin', name: 'macOS' },
];

const LanguageServerInstruction = (props: {
name: string;
pluginName: string;
url: string;
show: boolean;
close: () => void;
}) => {
const tabs = SupportedOS.map(({ id, name }) => {
const url = props.url ? props.url.replace('$OS', id) : '';
const installCode = `bin/kibana-plugin install ${url}`;
return {
id,
name,
content: (
<EuiText grow={false}>
<h3>Install</h3>
<p>
Stop your kibana Code node, then use the following command to install ${props.name}{' '}
Language Server plugin:
<EuiCodeBlock language="shell">{installCode}</EuiCodeBlock>
</p>
<h3>Uninstall</h3>
<p>
Stop your kibana Code node, then use the following command to remove ${props.name}{' '}
Language Server plugin:
<pre>
<code>bin/kibana-plugin remove {props.pluginName}</code>
</pre>
</p>
</EuiText>
),
};
});

return (
<React.Fragment>
{' '}
{props.show && (
<EuiOverlayMask>
<EuiModal onClose={props.close}>
<EuiModal onClose={props.close} maxWidth={false}>
<EuiModalHeader>
<EuiModalHeaderTitle>Install Instruction</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiText grow={false}>
<h3>Download</h3>
<p>
Download {props.name} language server plugin from
<EuiLink href={props.url}> here.</EuiLink>
</p>
<h3>Install</h3>
<p>
Stop your kibana code node. Install it using kibana-plugin command.
<pre>
<code>bin/kibana-plugin install {JAVA_URL}</code>
</pre>
</p>
</EuiText>
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[1]} size={'m'} />
</EuiModalBody>
<EuiModalFooter>
<EuiButton onClick={props.close} fill>
Expand Down
36 changes: 24 additions & 12 deletions x-pack/plugins/code/server/lsp/install_manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import path from 'path';
import tar from 'tar-fs';
import URL from 'url';
import zlib from 'zlib';
import {LanguageServers} from './language_servers';
import {InstallManager} from "./install_manager";
import {ServerOptions} from "../server_options";
import { LanguageServers } from './language_servers';
import { InstallManager } from "./install_manager";
import { ServerOptions } from "../server_options";
import rimraf from 'rimraf';
import {LanguageServerStatus} from '../../common/language_server';
import {Server} from 'hapi';
import {InstallationType} from "../../common/installation";
import { LanguageServerStatus } from '../../common/language_server';
import { Server } from 'hapi';
import { InstallationType } from "../../common/installation";

const LANG_SERVER_NAME = 'Java';
const langSrvDef = LanguageServers.find(l => l.name === LANG_SERVER_NAME)!;
Expand All @@ -34,6 +34,18 @@ const options: ServerOptions = {
} as ServerOptions;

const server = new Server();
server.config = () => {
return {
get(key: string): any {
if (key === 'pkg.version') {
return '8.0.0';
}
},
has(key: string): boolean {
return key === 'pkg.version';
}
}
}

const manager = new InstallManager(server, options);

Expand All @@ -53,7 +65,7 @@ beforeAll(async () => {

});
beforeEach(() => {
const downloadUrl = URL.parse(langSrvDef.downloadUrl!(langSrvDef));
const downloadUrl = URL.parse(langSrvDef.downloadUrl!(langSrvDef, server.config().get('pkg.version')));
nock.cleanAll();
// mimic github's behavior, redirect to a s3 address
nock(`${downloadUrl.protocol}//${downloadUrl.host!}`)
Expand All @@ -77,9 +89,9 @@ afterAll(() => {
nock.cleanAll();
rimraf.sync(fakeTestDir);
});


test('it can download a package', async() => {

test('it can download a package', async () => {
const manager = new InstallManager(server, options);
langSrvDef.installationType = InstallationType.Download
const p = await manager.downloadFile(langSrvDef);
Expand All @@ -88,10 +100,10 @@ test('it can download a package', async() => {
expect(fs.statSync(p).size).toBe(fs.statSync(fakePackageFile).size)
});

test('it can install language server', async() => {
test('it can install language server', async () => {
expect(manager.status(langSrvDef)).toBe(LanguageServerStatus.NOT_INSTALLED);
langSrvDef.installationType = InstallationType.Download
const installPromise = manager.install(langSrvDef);
const installPromise = manager.install(langSrvDef);
expect(manager.status(langSrvDef)).toBe(LanguageServerStatus.INSTALLING);
await installPromise;
expect(manager.status(langSrvDef)).toBe(LanguageServerStatus.READY);
Expand All @@ -102,7 +114,7 @@ test('it can install language server', async() => {
});


test('install language server by plugin', async() => {
test('install language server by plugin', async () => {
langSrvDef.installationType = InstallationType.Plugin
expect(manager.status(langSrvDef)).toBe(LanguageServerStatus.NOT_INSTALLED);
const testDir = path.join(fakeTestDir, 'test_plugin');
Expand Down
19 changes: 15 additions & 4 deletions x-pack/plugins/code/server/lsp/install_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ export class InstallManager {
}

public async downloadFile(def: LanguageServerDefinition): Promise<string> {
const url = typeof def.downloadUrl === 'function' ? def.downloadUrl(def) : def.downloadUrl;
const url =
typeof def.downloadUrl === 'function'
? def.downloadUrl(def, this.getKibanaVersion())
: def.downloadUrl;

const res = await fetch(url!);
if (!res.ok) {
Expand Down Expand Up @@ -150,14 +153,22 @@ export class InstallManager {
}
return undefined;
} else {
let version = def.version!;
if (def.build) {
version += '-' + def.build;
let version = def.version;
if (version) {
if (def.build) {
version += '-' + def.build;
}
} else {
version = this.getKibanaVersion();
}
return path.join(this.basePath, def.installationFolderName || def.name, version);
}
}

private getKibanaVersion(): string {
return this.server.config().get('pkg.version');
}

private async unPack(packageFile: string, def: LanguageServerDefinition) {
const dest = this.installationPath(def)!;
this.sendEvent({
Expand Down
12 changes: 4 additions & 8 deletions x-pack/plugins/code/server/lsp/language_servers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface LanguageServerDefinition extends LanguageServer {
builtinWorkspaceFolders: boolean;
launcher: LauncherConstructor;
installationFolderName?: string;
downloadUrl?: (lang: LanguageServerDefinition) => string | string;
downloadUrl?: (lang: LanguageServerDefinition, version: string) => string | string;
embedPath?: string;
installationPluginName?: string;
}
Expand All @@ -38,14 +38,10 @@ export const JAVA: LanguageServerDefinition = {
languages: ['java'],
launcher: JavaLauncher,
installationType: InstallationType.Plugin,
installationPluginName: 'javaLanguageServer',
installationPluginName: 'java-langserver',
installationFolderName: 'jdt',
version: '1.0.0-SNAPSHOT',
build: '201812040656',
downloadUrl: (lang: LanguageServerDefinition) =>
`https://github.com/Poytr1/eclipse.jdt.ls/releases/download/v${
lang.version
}/jdt-language-server-${lang.version}-${lang.build}.tar.gz`,
downloadUrl: (lang: LanguageServerDefinition, version: string) =>
`https://download.elasticsearch.org/code/java-langserver/release/java-langserver-${version}-$OS.zip`,
};
export const GO: LanguageServerDefinition = {
name: 'Go',
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/code/server/routes/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ export function installRoute(
lspService: LspService,
installManager: InstallManager
) {
const kibanaVersion = server.config().get('pkg.version') as string;
const status = (def: LanguageServerDefinition) => ({
name: def.name,
status: lspService.languageServerStatus(def.name),
version: def.version,
build: def.build,
languages: def.languages,
installationType: def.installationType,
downloadUrl:
typeof def.downloadUrl === 'function' ? def.downloadUrl(def, kibanaVersion) : def.downloadUrl,
pluginName: def.pluginName,
});

server.route({
Expand Down