fix(shorebird_cli): use jdk-dir override for JAVA_HOME (#2959)

This commit is contained in:
Felix Angelov
2025-03-12 15:48:17 -05:00
committed by GitHub
parent 0a0f7afb48
commit 60dfb6e143
4 changed files with 145 additions and 5 deletions
@@ -8,6 +8,7 @@ import 'package:shorebird_cli/src/android_studio.dart';
import 'package:shorebird_cli/src/extensions/string.dart';
import 'package:shorebird_cli/src/os/os.dart';
import 'package:shorebird_cli/src/platform.dart';
import 'package:shorebird_cli/src/shorebird_flutter.dart';
import 'package:shorebird_cli/src/shorebird_process.dart';
/// A reference to a [Java] instance.
@@ -37,9 +38,13 @@ class Java {
/// Returns a path to the user's JDK. If one is not found, returns `null`.
///
/// This first looks for the Java bundled with Android Studio, then the
/// JAVA_HOME environment variable.
/// This first looks a jdk-dir override, then for the Java bundled with
/// Android Studio, then the JAVA_HOME environment variable.
String? get home {
const jdkDir = 'jdk-dir';
final config = shorebirdFlutter.getConfig();
if (config.containsKey(jdkDir)) return config[jdkDir] as String;
if (!_androidStudioJavaPath.isNullOrEmpty) {
return _androidStudioJavaPath;
}
@@ -121,6 +121,32 @@ class ShorebirdFlutter {
return match?.group(1);
}
/// Executes `flutter config --list` and returns the output as a map.
Map<String, dynamic> getConfig() {
final args = ['config', '--list'];
final result = process.runSync(executable, args);
if (result.exitCode != ExitCode.success.code) {
throw ProcessException(
executable,
args,
'${result.stderr}',
result.exitCode,
);
}
final output = '${result.stdout}';
final config = <String, dynamic>{};
final lines = LineSplitter.split(output).toList();
for (final line in lines.skip(1)) {
final parts = line.split(':');
if (parts.length == 2) {
final key = parts[0].trim();
final value = parts[1].trim();
config[key] = value;
}
}
return config;
}
/// Converts a full git revision to a short revision string.
String shortRevisionString(String revision) => revision.substring(0, 10);
@@ -8,6 +8,7 @@ import 'package:shorebird_cli/src/android_studio.dart';
import 'package:shorebird_cli/src/executables/executables.dart';
import 'package:shorebird_cli/src/os/os.dart';
import 'package:shorebird_cli/src/platform.dart';
import 'package:shorebird_cli/src/shorebird_flutter.dart';
import 'package:shorebird_cli/src/shorebird_process.dart';
import 'package:test/test.dart';
@@ -18,6 +19,7 @@ void main() {
late AndroidStudio androidStudio;
late OperatingSystemInterface osInterface;
late Platform platform;
late ShorebirdFlutter shorebirdFlutter;
late ShorebirdProcess shorebirdProcess;
late Java java;
@@ -29,6 +31,7 @@ void main() {
osInterfaceRef.overrideWith(() => osInterface),
processRef.overrideWith(() => shorebirdProcess),
platformRef.overrideWith(() => platform),
shorebirdFlutterRef.overrideWith(() => shorebirdFlutter),
},
);
}
@@ -43,6 +46,7 @@ void main() {
androidStudio = MockAndroidStudio();
osInterface = MockOperatingSystemInterface();
platform = MockPlatform();
shorebirdFlutter = MockShorebirdFlutter();
shorebirdProcess = MockShorebirdProcess();
java = Java();
@@ -52,6 +56,8 @@ void main() {
when(() => platform.isLinux).thenReturn(false);
when(() => osInterface.which(any())).thenReturn(null);
when(shorebirdFlutter.getConfig).thenReturn({});
});
group('version', () {
@@ -146,7 +152,7 @@ void main() {
group('when Android Studio is installed', () {
late Directory jbrDir;
group('when on macOS', () {
group('on macOS', () {
setUp(() {
when(() => platform.isMacOS).thenReturn(true);
@@ -169,6 +175,19 @@ void main() {
when(() => platform.environment).thenReturn({'HOME': tempDir.path});
});
group('when flutter config contains jdk override', () {
const jdkDirOverride = '/jdk';
setUp(() {
when(
shorebirdFlutter.getConfig,
).thenReturn({'jdk-dir': jdkDirOverride});
});
test('returns value of jdk-dir', () {
expect(runWithOverrides(() => java.home), equals(jdkDirOverride));
});
});
test('returns correct path', () async {
await expectLater(
runWithOverrides(() => java.home),
@@ -184,7 +203,7 @@ void main() {
});
});
group('when on Windows', () {
group('on Windows', () {
late Directory jbrDir;
setUp(() {
@@ -221,7 +240,7 @@ void main() {
});
});
group('when on Linux', () {
group('on Linux', () {
setUp(() {
when(() => platform.isLinux).thenReturn(true);
@@ -257,6 +276,19 @@ void main() {
).thenReturn({'JAVA_HOME': javaHome});
});
group('when flutter config contains jdk override', () {
const jdkDirOverride = '/jdk';
setUp(() {
when(
shorebirdFlutter.getConfig,
).thenReturn({'jdk-dir': jdkDirOverride});
});
test('returns value of jdk-dir', () {
expect(runWithOverrides(() => java.home), equals(jdkDirOverride));
});
});
test('returns value of JAVA_HOME', () {
expect(runWithOverrides(() => java.home), equals(javaHome));
});
@@ -137,6 +137,83 @@ void main() {
});
});
group('getConfig', () {
late ShorebirdProcessResult configProcessResult;
setUp(() {
configProcessResult = MockProcessResult();
when(
() => process.runSync(any(), any()),
).thenReturn(configProcessResult);
});
group('when process exists with non-zero code', () {
setUp(() {
when(
() => configProcessResult.exitCode,
).thenReturn(ExitCode.software.code);
when(() => configProcessResult.stderr).thenReturn('oops');
});
test('throws ProcessException', () {
expect(
() => runWithOverrides(shorebirdFlutter.getConfig),
throwsA(isA<ProcessException>()),
);
verify(
() => process.runSync('flutter', ['config', '--list']),
).called(1);
});
});
group('when process completes successfully', () {
setUp(() {
when(() => configProcessResult.stdout).thenReturn('''
All Settings:
enable-web: (Not set)
enable-linux-desktop: (Not set)
enable-macos-desktop: (Not set)
enable-windows-desktop: (Not set)
enable-android: (Not set)
enable-ios: (Not set)
enable-fuchsia: (Not set) (Unavailable)
enable-custom-devices: (Not set)
cli-animations: (Not set)
enable-native-assets: (Not set) (Unavailable)
enable-flutter-preview: (Not set) (Unavailable)
enable-swift-package-manager: (Not set)
explicit-package-dependencies: (Not set)
jdk-dir: ./jdk/dir/override
''');
when(
() => configProcessResult.exitCode,
).thenReturn(ExitCode.success.code);
});
test('returns correct config map', () {
expect(
runWithOverrides(shorebirdFlutter.getConfig),
equals({
'enable-web': '(Not set)',
'enable-linux-desktop': '(Not set)',
'enable-macos-desktop': '(Not set)',
'enable-windows-desktop': '(Not set)',
'enable-android': '(Not set)',
'enable-ios': '(Not set)',
'enable-fuchsia': '(Not set) (Unavailable)',
'enable-custom-devices': '(Not set)',
'cli-animations': '(Not set)',
'enable-native-assets': '(Not set) (Unavailable)',
'enable-flutter-preview': '(Not set) (Unavailable)',
'enable-swift-package-manager': '(Not set)',
'explicit-package-dependencies': '(Not set)',
'jdk-dir': './jdk/dir/override',
}),
);
});
});
});
group('getSystemVersion', () {
test(
'throws ProcessException when process exits with non-zero code',