From 1722f46f31981ab898010da6afef247f31427037 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Fri, 29 Oct 2021 12:49:10 -0400 Subject: [PATCH 1/7] Added new config option --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index c8b07627..bae608bb 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,12 @@ "default": "", "markdownDescription": "Pass additional arguments to the language server." }, + "haskell.envVars": { + "scope": "resource", + "type": "object", + "default": {}, + "markdownDescription": "Define environment variables for compilation/execution." + }, "haskell.updateBehavior": { "scope": "machine", "type": "string", From 2bfde49c0a9d17b0163810056b64496151f5b0a3 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Fri, 29 Oct 2021 12:54:44 -0400 Subject: [PATCH 2/7] Assigned variables to environment --- src/extension.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/extension.ts b/src/extension.ts index 4af9a344..adc673b9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,6 +25,11 @@ import { DocsBrowser } from './docsBrowser'; import { downloadHaskellLanguageServer } from './hlsBinaries'; import { directoryExists, executableExists, ExtensionLogger, resolvePathPlaceHolders } from './utils'; +// Used for environment variables later on +interface IEnvVars { + [key: string]: string; +} + // The current map of documents & folders to language servers. // It may be null to indicate that we are in the process of launching a server, // in which case don't try to launch another one for that uri @@ -203,6 +208,11 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold args = args.concat(extraArgs.split(' ')); } + const envVars: IEnvVars = workspace.getConfiguration('haskell', uri).envVars; + for (const [key, val] of Object.entries(envVars)) { + process.env[key] = val; + } + // If we're operating on a standalone file (i.e. not in a folder) then we need // to launch the server in a reasonable current directory. Otherwise the cradle // guessing logic in hie-bios will be wrong! From 3f167498d1abcb617faf00d3d0591c5ef0a1abda Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Fri, 29 Oct 2021 18:30:54 -0400 Subject: [PATCH 3/7] Pass environment variables to the language server --- src/extension.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index adc673b9..0971d0b5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -208,11 +208,6 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold args = args.concat(extraArgs.split(' ')); } - const envVars: IEnvVars = workspace.getConfiguration('haskell', uri).envVars; - for (const [key, val] of Object.entries(envVars)) { - process.env[key] = val; - } - // If we're operating on a standalone file (i.e. not in a folder) then we need // to launch the server in a reasonable current directory. Otherwise the cradle // guessing logic in hie-bios will be wrong! @@ -222,8 +217,10 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold logger.info(`Activating the language server in the parent dir of the file: ${uri.fsPath}`); } + const envVars: IEnvVars = workspace.getConfiguration('haskell', uri).envVars; const exeOptions: ExecutableOptions = { cwd: folder ? undefined : path.dirname(uri.fsPath), + env: Object.assign(process.env, envVars), }; // We don't want empty strings in our args From 683f6a40c80c540d194d68d3eee39e45f81e2faf Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Thu, 4 Nov 2021 18:42:24 -0400 Subject: [PATCH 4/7] Improved naming/language for extension setting --- package.json | 4 ++-- src/extension.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6ccb04f1..5974a8a3 100644 --- a/package.json +++ b/package.json @@ -144,11 +144,11 @@ "default": "", "markdownDescription": "Pass additional arguments to the language server." }, - "haskell.envVars": { + "haskell.serverEnvironment": { "scope": "resource", "type": "object", "default": {}, - "markdownDescription": "Define environment variables for compilation/execution." + "markdownDescription": "Define environment variables for the language server." }, "haskell.updateBehavior": { "scope": "machine", diff --git a/src/extension.ts b/src/extension.ts index bbffb5ee..64c49f12 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -217,10 +217,10 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold logger.info(`Activating the language server in the parent dir of the file: ${uri.fsPath}`); } - const envVars: IEnvVars = workspace.getConfiguration('haskell', uri).envVars; + const serverEnvironment: IEnvVars = workspace.getConfiguration('haskell', uri).serverEnvironment; const exeOptions: ExecutableOptions = { cwd: folder ? undefined : path.dirname(uri.fsPath), - env: Object.assign(process.env, envVars), + env: Object.assign(process.env, serverEnvironment), }; // We don't want empty strings in our args From 9dfda3c8442a1d8e9292c2ab67b1690080cc3952 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Thu, 4 Nov 2021 18:45:39 -0400 Subject: [PATCH 5/7] Added test for passing environment variables --- test/suite/extension.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index ac2e118c..cb20b5d3 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -65,6 +65,7 @@ suite('Extension Test Suite', () => { await getHaskellConfig().update('logFile', 'hls.log'); await getHaskellConfig().update('trace.server', 'messages'); await getHaskellConfig().update('releasesDownloadStoragePath', path.normalize(getWorkspaceFile('bin').fsPath)); + await getHaskellConfig().update('serverEnvironment', { XDG_CACHE_HOME: path.normalize(getWorkspaceFile('cache-test').fsPath) }); const contents = new TextEncoder().encode('main = putStrLn "hi vscode tests"'); await vscode.workspace.fs.writeFile(getWorkspaceFile('Main.hs'), contents); }); @@ -99,6 +100,14 @@ suite('Extension Test Suite', () => { assert.ok(await withTimeout(30, existsWorkspaceFile('hls.log')), 'Server log not created in 30 seconds'); }); + test('Server should inherit environment variables defined in the settings', async () => { + await vscode.workspace.openTextDocument(getWorkspaceFile('Main.hs')); + assert.ok( + await withTimeout(30, existsWorkspaceFile('cache-test/*.hiedb')), + 'Server did not inherit XDG_CACHE_DIR from environment variables set in the settings' + ); + }); + suiteTeardown(async () => { disposables.forEach((d) => d.dispose()); await vscode.commands.executeCommand(CommandNames.StopServerCommandName); From 0b31d669aeab17b9f480b60482694200e96b11bc Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Thu, 4 Nov 2021 18:48:51 -0400 Subject: [PATCH 6/7] Logged environment variables passed to the server --- src/extension.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/extension.ts b/src/extension.ts index 64c49f12..73bf44c7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -238,6 +238,12 @@ async function activateServerForFolder(context: ExtensionContext, uri: Uri, fold if (exeOptions.cwd) { logger.info(`server cwd: ${exeOptions.cwd}`); } + if (serverEnvironment) { + logger.info('server environment variables:'); + Object.entries(serverEnvironment).forEach(([key, val]: [string, string | undefined]) => { + logger.info(` ${key}=${val}`); + }); + } const pat = folder ? `${folder.uri.fsPath}/**/*` : '**/*'; logger.info(`document selector patten: ${pat}`); From 592a8c8b3e57c88d139a17a41423eb9dd083c839 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme Date: Fri, 5 Nov 2021 13:57:12 -0400 Subject: [PATCH 7/7] Fixed test case --- test/suite/extension.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/suite/extension.test.ts b/test/suite/extension.test.ts index cb20b5d3..08a6aacc 100644 --- a/test/suite/extension.test.ts +++ b/test/suite/extension.test.ts @@ -103,7 +103,8 @@ suite('Extension Test Suite', () => { test('Server should inherit environment variables defined in the settings', async () => { await vscode.workspace.openTextDocument(getWorkspaceFile('Main.hs')); assert.ok( - await withTimeout(30, existsWorkspaceFile('cache-test/*.hiedb')), + // Folder will have already been created by this point, so it will not trigger watcher in existsWorkspaceFile() + vscode.workspace.getWorkspaceFolder(getWorkspaceFile('cache-test')), 'Server did not inherit XDG_CACHE_DIR from environment variables set in the settings' ); });