mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] [dap] Add support for passing env variables to spawned processes (#107415)
* [flutter_tools] [dap] Add support for passing env variables to spawned processes * Use named args * Use in-memory fs and FakePlatform * Pass filesystem style to MemoryFileSystem
This commit is contained in:
parent
66cd09dd82
commit
78d924af1d
@ -305,7 +305,11 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
||||
...?userArgs,
|
||||
];
|
||||
|
||||
await launchAsProcess(executable, processArgs);
|
||||
await launchAsProcess(
|
||||
executable: executable,
|
||||
processArgs: processArgs,
|
||||
env: args.env,
|
||||
);
|
||||
|
||||
// Delay responding until the app is launched and (optionally) the debugger
|
||||
// is connected.
|
||||
@ -316,12 +320,17 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
||||
}
|
||||
|
||||
@visibleForOverriding
|
||||
Future<void> launchAsProcess(String executable, List<String> processArgs) async {
|
||||
Future<void> launchAsProcess({
|
||||
required String executable,
|
||||
required List<String> processArgs,
|
||||
required Map<String, String>? env,
|
||||
}) async {
|
||||
logger?.call('Spawning $executable with $processArgs in ${args.cwd}');
|
||||
final Process process = await Process.start(
|
||||
executable,
|
||||
processArgs,
|
||||
workingDirectory: args.cwd,
|
||||
environment: env,
|
||||
);
|
||||
_process = process;
|
||||
pidsToTerminate.add(process.pid);
|
||||
|
@ -20,6 +20,7 @@ class FlutterAttachRequestArguments
|
||||
super.restart,
|
||||
super.name,
|
||||
super.cwd,
|
||||
super.env,
|
||||
super.additionalProjectPaths,
|
||||
super.debugSdkLibraries,
|
||||
super.debugExternalPackageLibraries,
|
||||
@ -91,6 +92,7 @@ class FlutterLaunchRequestArguments
|
||||
super.restart,
|
||||
super.name,
|
||||
super.cwd,
|
||||
super.env,
|
||||
super.additionalProjectPaths,
|
||||
super.debugSdkLibraries,
|
||||
super.debugExternalPackageLibraries,
|
||||
|
@ -135,7 +135,11 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum
|
||||
...?args.args,
|
||||
];
|
||||
|
||||
await launchAsProcess(executable, processArgs);
|
||||
await launchAsProcess(
|
||||
executable: executable,
|
||||
processArgs: processArgs,
|
||||
env: args.env,
|
||||
);
|
||||
|
||||
// Delay responding until the debugger is connected.
|
||||
if (debug) {
|
||||
@ -144,12 +148,17 @@ class FlutterTestDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArgum
|
||||
}
|
||||
|
||||
@visibleForOverriding
|
||||
Future<void> launchAsProcess(String executable, List<String> processArgs) async {
|
||||
Future<void> launchAsProcess({
|
||||
required String executable,
|
||||
required List<String> processArgs,
|
||||
required Map<String, String>? env,
|
||||
}) async {
|
||||
logger?.call('Spawning $executable with $processArgs in ${args.cwd}');
|
||||
final Process process = await Process.start(
|
||||
executable,
|
||||
processArgs,
|
||||
workingDirectory: args.cwd,
|
||||
environment: env,
|
||||
);
|
||||
_process = process;
|
||||
pidsToTerminate.add(process.pid);
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/globals.dart' as globals show platform;
|
||||
import 'package:test/fake.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
@ -14,21 +16,27 @@ import 'package:vm_service/vm_service.dart';
|
||||
import 'mocks.dart';
|
||||
|
||||
void main() {
|
||||
// Use the real platform as a base so that Windows bots test paths.
|
||||
final FakePlatform platform = FakePlatform.fromPlatform(globals.platform);
|
||||
final FileSystemStyle fsStyle = platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
|
||||
|
||||
group('flutter adapter', () {
|
||||
final String expectedFlutterExecutable = globals.platform.isWindows
|
||||
final String expectedFlutterExecutable = platform.isWindows
|
||||
? r'C:\fake\flutter\bin\flutter.bat'
|
||||
: '/fake/flutter/bin/flutter';
|
||||
|
||||
setUpAll(() {
|
||||
Cache.flutterRoot = globals.platform.isWindows
|
||||
Cache.flutterRoot = platform.isWindows
|
||||
? r'C:\fake\flutter'
|
||||
: '/fake/flutter';
|
||||
});
|
||||
|
||||
|
||||
group('launchRequest', () {
|
||||
test('runs "flutter run" with --machine', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
group('launchRequest', () {
|
||||
test('runs "flutter run" with --machine', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -43,8 +51,33 @@ void main() {
|
||||
expect(adapter.processArgs, containsAllInOrder(<String>['run', '--machine']));
|
||||
});
|
||||
|
||||
test('includes env variables', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
cwd: '/project',
|
||||
program: 'foo.dart',
|
||||
env: <String, String>{
|
||||
'MY_TEST_ENV': 'MY_TEST_VALUE',
|
||||
},
|
||||
);
|
||||
|
||||
await adapter.configurationDoneRequest(MockRequest(), null, () {});
|
||||
await adapter.launchRequest(MockRequest(), args, responseCompleter.complete);
|
||||
await responseCompleter.future;
|
||||
|
||||
expect(adapter.env!['MY_TEST_ENV'], 'MY_TEST_VALUE');
|
||||
});
|
||||
|
||||
test('does not record the VMs PID for terminating', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -65,10 +98,12 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group('attachRequest', () {
|
||||
test('runs "flutter attach" with --machine', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
group('attachRequest', () {
|
||||
test('runs "flutter attach" with --machine', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterAttachRequestArguments args = FlutterAttachRequestArguments(
|
||||
@ -83,7 +118,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('does not record the VMs PID for terminating', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterAttachRequestArguments args = FlutterAttachRequestArguments(
|
||||
@ -105,7 +143,10 @@ void main() {
|
||||
|
||||
group('--start-paused', () {
|
||||
test('is passed for debug mode', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -121,7 +162,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('is not passed for noDebug mode', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -138,7 +182,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('is not passed if toolArgs contains --profile', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -155,7 +202,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('is not passed if toolArgs contains --release', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -173,7 +223,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('includes toolArgs', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -193,7 +246,10 @@ void main() {
|
||||
|
||||
group('includes customTool', () {
|
||||
test('with no args replaced', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
cwd: '/project',
|
||||
program: 'foo.dart',
|
||||
@ -212,7 +268,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('with all args replaced', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(fileSystem: globals.fs, platform: globals.platform);
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
cwd: '/project',
|
||||
program: 'foo.dart',
|
||||
|
@ -4,29 +4,35 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/debug_adapters/flutter_adapter_args.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/globals.dart' as globals show platform;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'mocks.dart';
|
||||
|
||||
void main() {
|
||||
// Use the real platform as a base so that Windows bots test paths.
|
||||
final FakePlatform platform = FakePlatform.fromPlatform(globals.platform);
|
||||
final FileSystemStyle fsStyle = platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix;
|
||||
|
||||
group('flutter test adapter', () {
|
||||
final String expectedFlutterExecutable = globals.platform.isWindows
|
||||
final String expectedFlutterExecutable = platform.isWindows
|
||||
? r'C:\fake\flutter\bin\flutter.bat'
|
||||
: '/fake/flutter/bin/flutter';
|
||||
|
||||
setUpAll(() {
|
||||
Cache.flutterRoot = globals.platform.isWindows
|
||||
Cache.flutterRoot = platform.isWindows
|
||||
? r'C:\fake\flutter'
|
||||
: '/fake/flutter';
|
||||
});
|
||||
|
||||
test('includes toolArgs', () async {
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(
|
||||
fileSystem: globals.fs,
|
||||
platform: globals.platform,
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
final MockRequest request = MockRequest();
|
||||
@ -45,10 +51,34 @@ void main() {
|
||||
expect(adapter.processArgs, contains('tool_arg'));
|
||||
});
|
||||
|
||||
test('includes env variables', () async {
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
final MockRequest request = MockRequest();
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
cwd: '/project',
|
||||
program: 'foo.dart',
|
||||
env: <String, String>{
|
||||
'MY_TEST_ENV': 'MY_TEST_VALUE',
|
||||
},
|
||||
);
|
||||
|
||||
await adapter.configurationDoneRequest(request, null, () {});
|
||||
await adapter.launchRequest(request, args, responseCompleter.complete);
|
||||
await responseCompleter.future;
|
||||
|
||||
expect(adapter.env!['MY_TEST_ENV'], 'MY_TEST_VALUE');
|
||||
});
|
||||
|
||||
group('includes customTool', () {
|
||||
test('with no args replaced', () async {
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(fileSystem: globals.fs,
|
||||
platform: globals.platform,);
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
final MockRequest request = MockRequest();
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
@ -68,8 +98,10 @@ void main() {
|
||||
});
|
||||
|
||||
test('with all args replaced', () async {
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(fileSystem: globals.fs,
|
||||
platform: globals.platform,);
|
||||
final MockFlutterTestDebugAdapter adapter = MockFlutterTestDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
final Completer<void> responseCompleter = Completer<void>();
|
||||
final MockRequest request = MockRequest();
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
|
@ -42,11 +42,17 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
|
||||
|
||||
late String executable;
|
||||
late List<String> processArgs;
|
||||
late Map<String, String>? env;
|
||||
|
||||
@override
|
||||
Future<void> launchAsProcess(String executable, List<String> processArgs) async {
|
||||
Future<void> launchAsProcess({
|
||||
required String executable,
|
||||
required List<String> processArgs,
|
||||
required Map<String, String>? env,
|
||||
}) async {
|
||||
this.executable = executable;
|
||||
this.processArgs = processArgs;
|
||||
this.env = env;
|
||||
|
||||
// Pretend we launched the app and got the app.started event so that
|
||||
// launchRequest will complete.
|
||||
@ -94,11 +100,25 @@ class MockFlutterTestDebugAdapter extends FlutterTestDebugAdapter {
|
||||
|
||||
late String executable;
|
||||
late List<String> processArgs;
|
||||
late Map<String, String>? env;
|
||||
|
||||
@override
|
||||
Future<void> launchAsProcess(String executable, List<String> processArgs,) async {
|
||||
Future<void> launchAsProcess({
|
||||
required String executable,
|
||||
required List<String> processArgs,
|
||||
required Map<String, String>? env,
|
||||
}) async {
|
||||
this.executable = executable;
|
||||
this.processArgs = processArgs;
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> get debuggerInitialized {
|
||||
// If we were mocking debug mode, then simulate the debugger initializing.
|
||||
return enableDebugger
|
||||
? Future<void>.value()
|
||||
: throw StateError('Invalid attempt to wait for debuggerInitialized when not debugging');
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user