From bef9185c6c8ce3bf918b935f0cdb0b4f6c8cb024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Sp=C3=B6nemann?= Date: Fri, 10 Jan 2020 11:02:23 +0100 Subject: [PATCH] arduino/arduino-pro-ide#31: Include clangd for linux with 'bin' and 'lib' folders --- arduino-ide-extension/scripts/download-cli.js | 5 +- arduino-ide-extension/scripts/download-ls.js | 24 ++++---- arduino-ide-extension/scripts/downloader.js | 55 +++++++++++++++++-- .../src/node/arduino-backend-module.ts | 12 +++- .../arduino-language-server-contribution.ts | 8 ++- 5 files changed, 79 insertions(+), 25 deletions(-) diff --git a/arduino-ide-extension/scripts/download-cli.js b/arduino-ide-extension/scripts/download-cli.js index 7efad7c7..79ac7cfa 100755 --- a/arduino-ide-extension/scripts/download-cli.js +++ b/arduino-ide-extension/scripts/download-cli.js @@ -12,7 +12,6 @@ const DEFAULT_VERSION = '0.7.1'; // require('moment')().format('YYYYMMDD'); - const os = require('os'); const path = require('path'); const shell = require('shelljs'); const downloader = require('./downloader'); @@ -35,7 +34,7 @@ const { platform, arch } = process; const build = path.join(__dirname, '..', 'build'); - const cli = path.join(build, `arduino-cli${os.platform() === 'win32' ? '.exe' : ''}`); + const cli = path.join(build, `arduino-cli${platform === 'win32' ? '.exe' : ''}`); const suffix = (() => { switch (platform) { @@ -57,6 +56,6 @@ } const url = `https://downloads.arduino.cc/arduino-cli${version.startsWith('nightly-') ? '/nightly' : ''}/arduino-cli_${version}_${suffix}`; - downloader.download(url, cli, 'arduino-cli', force); + downloader.downloadUnzipFile(url, cli, 'arduino-cli', force); })(); diff --git a/arduino-ide-extension/scripts/download-ls.js b/arduino-ide-extension/scripts/download-ls.js index 6bcd63c8..89b0a139 100755 --- a/arduino-ide-extension/scripts/download-ls.js +++ b/arduino-ide-extension/scripts/download-ls.js @@ -8,7 +8,6 @@ const DEFAULT_ALS_VERSION = 'nightly'; const DEFAULT_CLANGD_VERSION = '9.0.0'; - const os = require('os'); const path = require('path'); const shell = require('shelljs'); const downloader = require('./downloader'); @@ -39,22 +38,25 @@ const { platform, arch } = process; const build = path.join(__dirname, '..', 'build'); - const als = path.join(build, `arduino-language-server${os.platform() === 'win32' ? '.exe' : ''}`); - const clangd = path.join(build, `clangd${os.platform() === 'win32' ? '.exe' : ''}`); + const alsTarget = path.join(build, `arduino-language-server${platform === 'win32' ? '.exe' : ''}`); - let alsSuffix, clangdSuffix; + let clangdTarget, alsSuffix, clangdSuffix; switch (platform) { case 'darwin': + clangdTarget = path.join(build, 'bin', 'clangd') alsSuffix = 'Darwin_amd64.zip'; clangdSuffix = 'macos.zip'; break; + case 'linux': + clangdTarget = path.join(build, 'bin', 'clangd') + alsSuffix = 'Linux_amd64.zip'; + clangdSuffix = 'linux.zip' + break; case 'win32': + clangdTarget = path.join(build, 'clangd.exe') alsSuffix = 'Windows_NT_amd64.zip'; clangdSuffix = 'windows.zip'; break; - case 'linux': - alsSuffix = 'Linux_amd64.zip'; - break; } if (!alsSuffix) { shell.echo(`The arduino-language-server is not available for ${platform} ${arch}.`); @@ -62,11 +64,9 @@ } const alsUrl = `https://downloads.arduino.cc/arduino-language-server/${alsVersion === 'nightly' ? 'nightly/arduino-language-server' : 'arduino-language-server_' + alsVersion}_${alsSuffix}`; - downloader.download(alsUrl, als, 'arduino-language-server', force); + downloader.downloadUnzipAll(alsUrl, build, alsTarget, force); - if (clangdSuffix) { - const clangdUrl = `https://downloads.arduino.cc/arduino-language-server/clangd/clangd_${clangdVersion}_${clangdSuffix}`; - downloader.download(clangdUrl, clangd, 'clangd', force); - } + const clangdUrl = `https://downloads.arduino.cc/arduino-language-server/clangd/clangd_${clangdVersion}_${clangdSuffix}`; + downloader.downloadUnzipAll(clangdUrl, build, clangdTarget, force); })(); diff --git a/arduino-ide-extension/scripts/downloader.js b/arduino-ide-extension/scripts/downloader.js index 929404c9..7342f80a 100644 --- a/arduino-ide-extension/scripts/downloader.js +++ b/arduino-ide-extension/scripts/downloader.js @@ -17,9 +17,13 @@ process.on('uncaughtException', error => { throw error; }); -exports.download = async (url, targetFile, filePrefix, force) => { - const { platform, arch } = process; - +/** + * @param url {string} Download URL + * @param targetFile {string} Path to the file to copy from the decompressed archive + * @param filePrefix {string} Prefix of the file name found in the archive + * @param force {boolean} Whether to download even if the target file exists + */ +exports.downloadUnzipFile = async (url, targetFile, filePrefix, force) => { if (fs.existsSync(targetFile) && !force) { shell.echo(`Skipping download because file already exists: ${targetFile}`); return; @@ -65,7 +69,48 @@ exports.download = async (url, targetFile, filePrefix, force) => { if (!fs.existsSync(targetFile)) { shell.echo(`Could not find file: ${targetFile}`); shell.exit(1); - } else { - shell.echo(`Done: ${targetFile}`); } + shell.echo(`Done: ${targetFile}`); +} + +/** + * @param url {string} Download URL + * @param targetDir {string} Directory into which to decompress the archive + * @param targetFile {string} Path to the main file expected after decompressing + * @param force {boolean} Whether to download even if the target file exists + */ +exports.downloadUnzipAll = async (url, targetDir, targetFile, force) => { + if (fs.existsSync(targetFile) && !force) { + shell.echo(`Skipping download because file already exists: ${targetFile}`); + return; + } + if (!fs.existsSync(targetDir)) { + if (shell.mkdir('-p', targetDir).code !== 0) { + shell.echo('Could not create new directory.'); + shell.exit(1); + } + } + + shell.echo(`>>> Downloading from '${url}'...`); + const data = await download(url); + shell.echo(`<<< Download succeeded.`); + + shell.echo('>>> Decompressing...'); + const files = await decompress(data, targetDir, { + plugins: [ + unzip(), + untargz() + ] + }); + if (files.length === 0) { + shell.echo('Error ocurred while decompressing the archive.'); + shell.exit(1); + } + shell.echo('<<< Decompressing succeeded.'); + + if (!fs.existsSync(targetFile)) { + shell.echo(`Could not find file: ${targetFile}`); + shell.exit(1); + } + shell.echo(`Done: ${targetFile}`); } diff --git a/arduino-ide-extension/src/node/arduino-backend-module.ts b/arduino-ide-extension/src/node/arduino-backend-module.ts index 6e32e533..66f7a5e5 100644 --- a/arduino-ide-extension/src/node/arduino-backend-module.ts +++ b/arduino-ide-extension/src/node/arduino-backend-module.ts @@ -64,7 +64,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bindBackendService(SketchesServicePath, SketchesService); }); bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule); - + // Config service bind(ConfigServiceImpl).toSelf().inSingletonScope(); bind(ConfigService).toService(ConfigServiceImpl); @@ -161,8 +161,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { // Set up cpp extension if (!process.env.CPP_CLANGD_COMMAND) { - const executable = os.platform() === 'win32' ? 'clangd.exe' : 'clangd'; - const clangdCommand = join(__dirname, '..', '..', 'build', executable); + const segments = ['..', '..', 'build']; + if (os.platform() === 'win32') { + segments.push('clangd.exe'); + } else { + segments.push('bin'); + segments.push('clangd'); + } + const clangdCommand = join(__dirname, ...segments); if (fs.existsSync(clangdCommand)) { process.env.CPP_CLANGD_COMMAND = clangdCommand; } diff --git a/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts b/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts index 0404185b..24de4ef2 100644 --- a/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts +++ b/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts @@ -24,8 +24,8 @@ export class ArduinoLanguageServerContribution extends BaseLanguageServerContrib } async start(clientConnection: IConnection, options: LanguageServerStartOptions): Promise { - const clangd = await this.resolveExecutable('clangd'); const languageServer = await this.resolveExecutable('arduino-language-server'); + const clangd = await this.resolveExecutable('clangd'); const cli = await this.resolveExecutable('arduino-cli'); // Add '-log' argument to enable logging to files const args: string[] = ['-clangd', clangd, '-cli', cli]; @@ -47,7 +47,11 @@ export class ArduinoLanguageServerContribution extends BaseLanguageServerContrib protected resolveExecutable(name: string): Promise { return new Promise((resolve, reject) => { - const path = `${process.env.PATH}${delimiter}${join(__dirname, '..', '..', '..', 'build')}`; + const segments = ['..', '..', '..', 'build']; + if (name === 'clangd' && os.platform() !== 'win32') { + segments.push('bin'); + } + const path = `${process.env.PATH}${delimiter}${join(__dirname, ...segments)}`; const suffix = os.platform() === 'win32' ? '.exe' : ''; which(name + suffix, { path }, (err, execPath) => { if (err) {