Skip to content

Fix env var conflict #619

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

Closed
Closed
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
1 change: 1 addition & 0 deletions bundled/scripts/noConfigScripts/debugpy
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#! /bin/bash
# Bash script
export DEBUGPY_ADAPTER_ENDPOINTS=$VSCODE_DEBUGPY_ADAPTER_ENDPOINTS
python3 $BUNDLED_DEBUGPY_PATH --listen 0 --wait-for-client $@
5 changes: 3 additions & 2 deletions bundled/scripts/noConfigScripts/debugpy.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# PowerShell script
if ($PSVersionTable.OS -match "Windows") {
$os = [System.Environment]::OSVersion.Platform
if ($os -eq [System.PlatformID]::Win32NT) {
python $env:BUNDLED_DEBUGPY_PATH --listen 0 --wait-for-client $args
} else {
python3 $env:BUNDLED_DEBUGPY_PATH --listen 0 --wait-for-client $args
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,18 @@ export async function getConfigurationsForWorkspace(workspace: WorkspaceFolder):
traceLog('Getting configurations for workspace');
const filename = path.join(workspace.uri.fsPath, '.vscode', 'launch.json');
if (!(await fs.pathExists(filename))) {
// Check launch config in the workspace file
const codeWorkspaceConfig = getConfiguration('launch', workspace);
if (!codeWorkspaceConfig.configurations || !Array.isArray(codeWorkspaceConfig.configurations)) {
return [];
}
traceLog('Using configuration in workspace');
return codeWorkspaceConfig.configurations;
return getConfigurationsFromSettings(workspace);
}

const text = await fs.readFile(filename, 'utf-8');
const parsed = parse(text, [], { allowTrailingComma: true, disallowComments: false });
if (!parsed.configurations || !Array.isArray(parsed.configurations)) {
throw Error('Missing field in launch.json: configurations');
// no launch.json or no configurations found in launch.json, look in settings.json
if (!parsed || !parsed.configurations) {
traceLog('No configurations found in launch.json, looking in settings.json.');
return getConfigurationsFromSettings(workspace);
}
// configurations found in launch.json, verify them then return
if (!Array.isArray(parsed.configurations) || parsed.configurations.length === 0) {
throw Error('Invalid configurations in launch.json');
}
if (!parsed.version) {
throw Error('Missing field in launch.json: version');
Expand All @@ -42,3 +41,18 @@ export async function getConfigurationsByUri(uri?: Uri): Promise<DebugConfigurat
}
return [];
}

export function getConfigurationsFromSettings(workspace: WorkspaceFolder): DebugConfiguration[] {
// look in settings.json
const codeWorkspaceConfig = getConfiguration('launch', workspace);
// if this includes user configs, how do I make sure it selects the workspace ones first
if (
!codeWorkspaceConfig.configurations ||
!Array.isArray(codeWorkspaceConfig.configurations) ||
codeWorkspaceConfig.configurations.length === 0
) {
throw Error('No configurations found in launch.json or settings.json');
}
traceLog('Using configuration in workspace settings.json.');
return codeWorkspaceConfig.configurations;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function buildFileWithArgsLaunchDebugConfiguration(
request: 'launch',
program: '${file}',
console: 'integratedTerminal',
args: ['${command:pickArgs}'],
args: '${command:pickArgs}',
};
sendTelemetryEvent(EventName.DEBUGGER_CONFIGURATION_PROMPTS, undefined, {
configurationType: DebugConfigurationType.launchFileWithArgs,
Expand Down
11 changes: 7 additions & 4 deletions src/extension/noConfigDebugInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ export async function registerNoConfigDebug(

// create a temp directory for the noConfigDebugAdapterEndpoints
// file path format: extPath/.noConfigDebugAdapterEndpoints/endpoint-stableWorkspaceHash.txt
const workspaceUri = workspace.workspaceFolders?.[0]?.uri;
if (!workspaceUri) {
let workspaceString = workspace.workspaceFile?.fsPath;
if (!workspaceString) {
workspaceString = workspace.workspaceFolders?.map((e) => e.uri.fsPath).join(';');
}
if (!workspaceString) {
traceError('No workspace folder found');
return Promise.resolve(new Disposable(() => {}));
}

// create a stable hash for the workspace folder, reduce terminal variable churn
const hash = crypto.createHash('sha256');
hash.update(workspaceUri.toString());
hash.update(workspaceString.toString());
const stableWorkspaceHash = hash.digest('hex').slice(0, 16);

const tempDirPath = path.join(extPath, '.noConfigDebugAdapterEndpoints');
Expand All @@ -65,7 +68,7 @@ export async function registerNoConfigDebug(
collection.replace('PYDEVD_DISABLE_FILE_VALIDATION', '1');

// Add env vars for DEBUGPY_ADAPTER_ENDPOINTS, BUNDLED_DEBUGPY_PATH, and PATH
collection.replace('DEBUGPY_ADAPTER_ENDPOINTS', tempFilePath);
collection.replace('VSCODE_DEBUGPY_ADAPTER_ENDPOINTS', tempFilePath);

const noConfigScriptsDir = path.join(extPath, 'bundled', 'scripts', 'noConfigScripts');
const pathSeparator = process.platform === 'win32' ? ';' : ':';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use strict';

import * as assert from 'assert';
import * as sinon from 'sinon';
import * as typemoq from 'typemoq';
import * as fs from 'fs-extra';
import { WorkspaceFolder, Uri, WorkspaceConfiguration } from 'vscode';
import {
getConfigurationsForWorkspace,
getConfigurationsFromSettings,
} from '../../../../extension/debugger/configuration/launch.json/launchJsonReader';
import * as vscodeapi from '../../../../extension/common/vscodeapi';

suite('Debugging - launchJsonReader', () => {
let sandbox: sinon.SinonSandbox;

setup(() => {
sandbox = sinon.createSandbox();
});

teardown(() => {
sandbox.restore();
});

suite('getConfigurationsForWorkspace', () => {
test('Should return configurations from launch.json if it exists', async () => {
const workspace = typemoq.Mock.ofType<WorkspaceFolder>();
workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace'));

const launchJsonContent = `{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Program",
"type": "python",
"request": "launch",
"program": "${workspace.object.uri}/app.py"
}
]
}`;

sandbox.stub(fs, 'pathExists').resolves(true);
sandbox.stub(fs, 'readFile').resolves(launchJsonContent);

const configurations = await getConfigurationsForWorkspace(workspace.object);
assert.strictEqual(configurations.length, 1);
assert.strictEqual(configurations[0].name, 'Launch Program');
});

test('Should return configurations from settings.json if launch.json does not exist', async () => {
const workspace = typemoq.Mock.ofType<WorkspaceFolder>();
workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace'));

const mockConfig = typemoq.Mock.ofType<WorkspaceConfiguration>();
mockConfig
.setup((c) => c.configurations)
.returns(() => [
{
name: 'Launch Program 2',
type: 'python',
request: 'launch',
program: '${workspaceFolder}/app.py',
},
]);

sandbox.stub(fs, 'pathExists').resolves(false);
sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object);

const configurations = await getConfigurationsForWorkspace(workspace.object);
assert.strictEqual(configurations.length, 1);
assert.strictEqual(configurations[0].name, 'Launch Program 2');
});
});

suite('getConfigurationsFromSettings', () => {
test('Should return configurations from settings.json', () => {
const workspace = typemoq.Mock.ofType<WorkspaceFolder>();
workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace'));

const mockConfig = typemoq.Mock.ofType<WorkspaceConfiguration>();
mockConfig
.setup((c) => c.configurations)
.returns(() => [
{
name: 'Launch Program 3',
type: 'python',
request: 'launch',
program: '${workspaceFolder}/app.py',
},
]);

sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object);

const configurations = getConfigurationsFromSettings(workspace.object);
assert.strictEqual(configurations.length, 1);
assert.strictEqual(configurations[0].name, 'Launch Program 3');
});

test('Should error if no configurations in settings.json', () => {
const workspace = typemoq.Mock.ofType<WorkspaceFolder>();
workspace.setup((w) => w.uri).returns(() => Uri.file('/path/to/workspace'));

const mockConfig = typemoq.Mock.ofType<WorkspaceConfiguration>();
mockConfig.setup((c) => c.get('configurations')).returns(() => []);
mockConfig.setup((c) => c.configurations).returns(() => []);

sandbox.stub(vscodeapi, 'getConfiguration').returns(mockConfig.object);

assert.throws(
() => getConfigurationsFromSettings(workspace.object),
Error,
'No configurations found in launch.json or settings.json',
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ suite('Debugging - Configuration Provider File with Arguments', () => {
request: 'launch',
program: '${file}',
console: 'integratedTerminal',
args: ['${command:pickArgs}'],
args: '${command:pickArgs}',
};

expect(state.config).to.be.deep.equal(config);
Expand Down
Loading