![auto-submit[bot]](/assets/img/avatar_default.png)
Reverts: flutter/flutter#143166
Initiated by: guidezpl
Reason for reverting: breaks devicelab windows tests
Original PR Author: guidezpl
Reviewed By: {loic-sharma}
This change reverts the following previous change:
Reland #128236, reverted in https://github.com/flutter/flutter/pull/143125.
This PR contains [one additional commit](199baea9a9
), fixing the 2 failed tests.
## Original description
Improves the build output:
1. Gives confirmation that the build succeeded, in green
1. Gives the path to the built executable, without a trailing period to make it slightly easier to cmd/ctrl+open
1. Gives the size of the built executable (when the built executable is self contained)
### `apk`, `appbundle`
<img width="607" alt="image" src="https://github.com/flutter/flutter/assets/6655696/ecc52abe-cd2e-4116-b22a-8385ae3e980d">
<img width="634" alt="image" src="https://github.com/flutter/flutter/assets/6655696/8af8bd33-c0bd-4215-9a06-9652ee019436">
### `macos`, `ios`, `ipa`
Build executables are self-contained and use a newly introduced `OperatingSystemUtils.getDirectorySize`.
<img width="514" alt="image" src="https://github.com/flutter/flutter/assets/6655696/b5918a69-3959-4417-9205-4f501d185257">
<img width="581" alt="image" src="https://github.com/flutter/flutter/assets/6655696/d72fd420-18cf-4470-9e4b-b6ac10fbcd50">
<img width="616" alt="image" src="https://github.com/flutter/flutter/assets/6655696/5f235ce1-252a-4c13-898f-139f6c7bc698">
### `windows`, `linux`, and `web`
Build executables aren't self-contained, and folder size can sometimes overestimate distribution size, therefore their size isn't mentioned (see discussion below).
<img width="647" alt="image" src="https://github.com/flutter/flutter/assets/6655696/7179e771-1eb7-48f6-b770-975bc073437b">
<img width="658" alt="image" src="https://github.com/flutter/flutter/assets/6655696/a6801cab-7b5a-4975-a406-f4c9fa44d7a2">
<img width="608" alt="image" src="https://github.com/flutter/flutter/assets/6655696/ee7c4125-a273-4a65-95d7-ab441edf8ac5">
### Size reporting
When applicable, the printed size matches the OS reported size.
- macOS
<img width="391" alt="image" src="https://github.com/flutter/flutter/assets/6655696/881cbfb1-d355-444b-ab44-c1a6343190ce">
- Windows
<img width="338" alt="image" src="https://github.com/flutter/flutter/assets/6655696/3b806def-3d15-48a9-8a25-df200d6feef7">
- Linux
<img width="320" alt="image" src="https://github.com/flutter/flutter/assets/6655696/89a4aa3d-2148-4f3b-b231-f93a057fee2b">
## Related issues
Part of #120127
Fixes https://github.com/flutter/flutter/issues/121401
686 lines
17 KiB
Dart
686 lines
17 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
|
|
|
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
|
import 'package:flutter_tools/src/android/android_studio.dart';
|
|
import 'package:flutter_tools/src/android/java.dart';
|
|
import 'package:flutter_tools/src/base/bot_detector.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/os.dart';
|
|
import 'package:flutter_tools/src/base/time.dart';
|
|
import 'package:flutter_tools/src/base/version.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/convert.dart';
|
|
import 'package:flutter_tools/src/features.dart';
|
|
import 'package:flutter_tools/src/ios/plist_parser.dart';
|
|
import 'package:flutter_tools/src/project.dart';
|
|
import 'package:flutter_tools/src/version.dart';
|
|
import 'package:test/fake.dart';
|
|
|
|
/// Environment with DYLD_LIBRARY_PATH=/path/to/libraries
|
|
class FakeDyldEnvironmentArtifact extends ArtifactSet {
|
|
FakeDyldEnvironmentArtifact() : super(DevelopmentArtifact.iOS);
|
|
@override
|
|
Map<String, String> get environment => <String, String>{
|
|
'DYLD_LIBRARY_PATH': '/path/to/libraries',
|
|
};
|
|
|
|
@override
|
|
Future<bool> isUpToDate(FileSystem fileSystem) => Future<bool>.value(true);
|
|
|
|
@override
|
|
String get name => 'fake';
|
|
|
|
@override
|
|
Future<void> update(ArtifactUpdater artifactUpdater, Logger logger, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils, {bool offline = false}) async {
|
|
}
|
|
}
|
|
|
|
/// A fake process implementation which can be provided all necessary values.
|
|
class FakeProcess implements Process {
|
|
FakeProcess({
|
|
this.pid = 1,
|
|
Future<int>? exitCode,
|
|
IOSink? stdin,
|
|
this.stdout = const Stream<List<int>>.empty(),
|
|
this.stderr = const Stream<List<int>>.empty(),
|
|
}) : exitCode = exitCode ?? Future<int>.value(0),
|
|
stdin = stdin ?? MemoryIOSink();
|
|
|
|
@override
|
|
final int pid;
|
|
|
|
@override
|
|
final Future<int> exitCode;
|
|
|
|
@override
|
|
final io.IOSink stdin;
|
|
|
|
@override
|
|
final Stream<List<int>> stdout;
|
|
|
|
@override
|
|
final Stream<List<int>> stderr;
|
|
|
|
@override
|
|
bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// An IOSink that completes a future with the first line written to it.
|
|
class CompleterIOSink extends MemoryIOSink {
|
|
CompleterIOSink({
|
|
this.throwOnAdd = false,
|
|
});
|
|
|
|
final bool throwOnAdd;
|
|
|
|
final Completer<List<int>> _completer = Completer<List<int>>();
|
|
|
|
Future<List<int>> get future => _completer.future;
|
|
|
|
@override
|
|
void add(List<int> data) {
|
|
if (!_completer.isCompleted) {
|
|
// When throwOnAdd is true, complete with empty so any expected output
|
|
// doesn't appear.
|
|
_completer.complete(throwOnAdd ? <int>[] : data);
|
|
}
|
|
if (throwOnAdd) {
|
|
throw Exception('CompleterIOSink Error');
|
|
}
|
|
super.add(data);
|
|
}
|
|
}
|
|
|
|
/// An IOSink that collects whatever is written to it.
|
|
class MemoryIOSink implements IOSink {
|
|
@override
|
|
Encoding encoding = utf8;
|
|
|
|
final List<List<int>> writes = <List<int>>[];
|
|
|
|
@override
|
|
void add(List<int> data) {
|
|
writes.add(data);
|
|
}
|
|
|
|
@override
|
|
Future<void> addStream(Stream<List<int>> stream) {
|
|
final Completer<void> completer = Completer<void>();
|
|
late StreamSubscription<List<int>> sub;
|
|
sub = stream.listen(
|
|
(List<int> data) {
|
|
try {
|
|
add(data);
|
|
// Catches all exceptions to propagate them to the completer.
|
|
} catch (err, stack) { // ignore: avoid_catches_without_on_clauses
|
|
sub.cancel();
|
|
completer.completeError(err, stack);
|
|
}
|
|
},
|
|
onError: completer.completeError,
|
|
onDone: completer.complete,
|
|
cancelOnError: true,
|
|
);
|
|
return completer.future;
|
|
}
|
|
|
|
@override
|
|
void writeCharCode(int charCode) {
|
|
add(<int>[charCode]);
|
|
}
|
|
|
|
@override
|
|
void write(Object? obj) {
|
|
add(encoding.encode('$obj'));
|
|
}
|
|
|
|
@override
|
|
void writeln([ Object? obj = '' ]) {
|
|
add(encoding.encode('$obj\n'));
|
|
}
|
|
|
|
@override
|
|
void writeAll(Iterable<dynamic> objects, [ String separator = '' ]) {
|
|
bool addSeparator = false;
|
|
for (final dynamic object in objects) {
|
|
if (addSeparator) {
|
|
write(separator);
|
|
}
|
|
write(object);
|
|
addSeparator = true;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void addError(dynamic error, [ StackTrace? stackTrace ]) {
|
|
throw UnimplementedError();
|
|
}
|
|
|
|
@override
|
|
Future<void> get done => close();
|
|
|
|
@override
|
|
Future<void> close() async { }
|
|
|
|
@override
|
|
Future<void> flush() async { }
|
|
|
|
void clear() {
|
|
writes.clear();
|
|
}
|
|
|
|
String getAndClear() {
|
|
final String result = utf8.decode(writes.expand((List<int> l) => l).toList());
|
|
clear();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class MemoryStdout extends MemoryIOSink implements io.Stdout {
|
|
@override
|
|
bool get hasTerminal => _hasTerminal;
|
|
set hasTerminal(bool value) {
|
|
_hasTerminal = value;
|
|
}
|
|
bool _hasTerminal = true;
|
|
|
|
@override
|
|
// ignore: override_on_non_overriding_member
|
|
String get lineTerminator => '\n';
|
|
@override
|
|
// ignore: override_on_non_overriding_member
|
|
set lineTerminator(String value) {
|
|
throw UnimplementedError('Setting the line terminator is not supported');
|
|
}
|
|
|
|
@override
|
|
io.IOSink get nonBlocking => this;
|
|
|
|
@override
|
|
bool get supportsAnsiEscapes => _supportsAnsiEscapes;
|
|
set supportsAnsiEscapes(bool value) {
|
|
_supportsAnsiEscapes = value;
|
|
}
|
|
bool _supportsAnsiEscapes = true;
|
|
|
|
@override
|
|
int get terminalColumns {
|
|
if (_terminalColumns != null) {
|
|
return _terminalColumns!;
|
|
}
|
|
throw const io.StdoutException('unspecified mock value');
|
|
}
|
|
set terminalColumns(int value) => _terminalColumns = value;
|
|
int? _terminalColumns;
|
|
|
|
@override
|
|
int get terminalLines {
|
|
if (_terminalLines != null) {
|
|
return _terminalLines!;
|
|
}
|
|
throw const io.StdoutException('unspecified mock value');
|
|
}
|
|
set terminalLines(int value) => _terminalLines = value;
|
|
int? _terminalLines;
|
|
}
|
|
|
|
/// A Stdio that collects stdout and supports simulated stdin.
|
|
class FakeStdio extends Stdio {
|
|
final MemoryStdout _stdout = MemoryStdout()..terminalColumns = 80;
|
|
final MemoryIOSink _stderr = MemoryIOSink();
|
|
final FakeStdin _stdin = FakeStdin();
|
|
|
|
@override
|
|
MemoryStdout get stdout => _stdout;
|
|
|
|
@override
|
|
MemoryIOSink get stderr => _stderr;
|
|
|
|
@override
|
|
Stream<List<int>> get stdin => _stdin;
|
|
|
|
void simulateStdin(String line) {
|
|
_stdin.controller.add(utf8.encode('$line\n'));
|
|
}
|
|
|
|
@override
|
|
bool hasTerminal = true;
|
|
|
|
List<String> get writtenToStdout => _stdout.writes.map<String>(_stdout.encoding.decode).toList();
|
|
List<String> get writtenToStderr => _stderr.writes.map<String>(_stderr.encoding.decode).toList();
|
|
}
|
|
|
|
class FakeStdin extends Fake implements Stdin {
|
|
final StreamController<List<int>> controller = StreamController<List<int>>();
|
|
|
|
void Function(bool mode)? echoModeCallback;
|
|
|
|
bool _echoMode = true;
|
|
|
|
@override
|
|
bool get echoMode => _echoMode;
|
|
|
|
@override
|
|
set echoMode(bool mode) {
|
|
_echoMode = mode;
|
|
if (echoModeCallback != null) {
|
|
echoModeCallback!(mode);
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool lineMode = true;
|
|
|
|
@override
|
|
Stream<S> transform<S>(StreamTransformer<List<int>, S> transformer) {
|
|
return controller.stream.transform(transformer);
|
|
}
|
|
|
|
@override
|
|
StreamSubscription<List<int>> listen(
|
|
void Function(List<int> event)? onData, {
|
|
Function? onError,
|
|
void Function()? onDone,
|
|
bool? cancelOnError,
|
|
}) {
|
|
return controller.stream.listen(
|
|
onData,
|
|
onError: onError,
|
|
onDone: onDone,
|
|
cancelOnError: cancelOnError,
|
|
);
|
|
}
|
|
}
|
|
|
|
class FakePlistParser implements PlistParser {
|
|
FakePlistParser([Map<String, Object>? underlyingValues]):
|
|
_underlyingValues = underlyingValues ?? <String, Object>{};
|
|
|
|
final Map<String, Object> _underlyingValues;
|
|
|
|
void setProperty(String key, Object value) {
|
|
_underlyingValues[key] = value;
|
|
}
|
|
|
|
@override
|
|
String? plistXmlContent(String plistFilePath) => throw UnimplementedError();
|
|
|
|
@override
|
|
Map<String, Object> parseFile(String plistFilePath) {
|
|
return _underlyingValues;
|
|
}
|
|
|
|
@override
|
|
T? getValueFromFile<T>(String plistFilePath, String key) {
|
|
return _underlyingValues[key] as T?;
|
|
}
|
|
|
|
@override
|
|
bool replaceKey(String plistFilePath, {required String key, String? value}) {
|
|
if (value == null) {
|
|
_underlyingValues.remove(key);
|
|
return true;
|
|
}
|
|
setProperty(key, value);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class FakeBotDetector implements BotDetector {
|
|
const FakeBotDetector(bool isRunningOnBot)
|
|
: _isRunningOnBot = isRunningOnBot;
|
|
|
|
@override
|
|
Future<bool> get isRunningOnBot async => _isRunningOnBot;
|
|
|
|
final bool _isRunningOnBot;
|
|
}
|
|
|
|
class FakeFlutterVersion implements FlutterVersion {
|
|
FakeFlutterVersion({
|
|
this.branch = 'master',
|
|
this.dartSdkVersion = '12',
|
|
this.devToolsVersion = '2.8.0',
|
|
this.engineRevision = 'abcdefghijklmnopqrstuvwxyz',
|
|
this.engineRevisionShort = 'abcde',
|
|
this.repositoryUrl = 'https://github.com/flutter/flutter.git',
|
|
this.frameworkVersion = '0.0.0',
|
|
this.frameworkRevision = '11111111111111111111',
|
|
this.frameworkRevisionShort = '11111',
|
|
this.frameworkAge = '0 hours ago',
|
|
this.frameworkCommitDate = '12/01/01',
|
|
this.gitTagVersion = const GitTagVersion.unknown(),
|
|
this.flutterRoot = '/path/to/flutter',
|
|
this.nextFlutterVersion,
|
|
});
|
|
|
|
final String branch;
|
|
|
|
bool get didFetchTagsAndUpdate => _didFetchTagsAndUpdate;
|
|
bool _didFetchTagsAndUpdate = false;
|
|
|
|
/// Will be returned by [fetchTagsAndGetVersion] if not null.
|
|
final FlutterVersion? nextFlutterVersion;
|
|
|
|
@override
|
|
FlutterVersion fetchTagsAndGetVersion({
|
|
SystemClock clock = const SystemClock(),
|
|
}) {
|
|
_didFetchTagsAndUpdate = true;
|
|
return nextFlutterVersion ?? this;
|
|
}
|
|
|
|
bool get didCheckFlutterVersionFreshness => _didCheckFlutterVersionFreshness;
|
|
bool _didCheckFlutterVersionFreshness = false;
|
|
|
|
@override
|
|
String get channel {
|
|
if (kOfficialChannels.contains(branch) || kObsoleteBranches.containsKey(branch)) {
|
|
return branch;
|
|
}
|
|
return kUserBranch;
|
|
}
|
|
|
|
@override
|
|
final String flutterRoot;
|
|
|
|
@override
|
|
final String devToolsVersion;
|
|
|
|
@override
|
|
final String dartSdkVersion;
|
|
|
|
@override
|
|
final String engineRevision;
|
|
|
|
@override
|
|
final String engineRevisionShort;
|
|
|
|
@override
|
|
final String? repositoryUrl;
|
|
|
|
@override
|
|
final String frameworkVersion;
|
|
|
|
@override
|
|
final String frameworkRevision;
|
|
|
|
@override
|
|
final String frameworkRevisionShort;
|
|
|
|
@override
|
|
final String frameworkAge;
|
|
|
|
@override
|
|
final String frameworkCommitDate;
|
|
|
|
@override
|
|
final GitTagVersion gitTagVersion;
|
|
|
|
@override
|
|
FileSystem get fs => throw UnimplementedError('FakeFlutterVersion.fs is not implemented');
|
|
|
|
@override
|
|
Future<void> checkFlutterVersionFreshness() async {
|
|
_didCheckFlutterVersionFreshness = true;
|
|
}
|
|
|
|
@override
|
|
Future<void> ensureVersionFile() async { }
|
|
|
|
@override
|
|
String getBranchName({bool redactUnknownBranches = false}) {
|
|
if (!redactUnknownBranches || kOfficialChannels.contains(branch) || kObsoleteBranches.containsKey(branch)) {
|
|
return branch;
|
|
}
|
|
return kUserBranch;
|
|
}
|
|
|
|
@override
|
|
String getVersionString({bool redactUnknownBranches = false}) {
|
|
return '${getBranchName(redactUnknownBranches: redactUnknownBranches)}/$frameworkRevision';
|
|
}
|
|
|
|
@override
|
|
Map<String, Object> toJson() {
|
|
return <String, Object>{};
|
|
}
|
|
}
|
|
|
|
// A test implementation of [FeatureFlags] that allows enabling without reading
|
|
// config. If not otherwise specified, all values default to false.
|
|
class TestFeatureFlags implements FeatureFlags {
|
|
TestFeatureFlags({
|
|
this.isLinuxEnabled = false,
|
|
this.isMacOSEnabled = false,
|
|
this.isWebEnabled = false,
|
|
this.isWindowsEnabled = false,
|
|
this.isAndroidEnabled = true,
|
|
this.isIOSEnabled = true,
|
|
this.isFuchsiaEnabled = false,
|
|
this.areCustomDevicesEnabled = false,
|
|
this.isFlutterWebWasmEnabled = false,
|
|
this.isCliAnimationEnabled = true,
|
|
this.isNativeAssetsEnabled = false,
|
|
this.isPreviewDeviceEnabled = false,
|
|
});
|
|
|
|
@override
|
|
final bool isLinuxEnabled;
|
|
|
|
@override
|
|
final bool isMacOSEnabled;
|
|
|
|
@override
|
|
final bool isWebEnabled;
|
|
|
|
@override
|
|
final bool isWindowsEnabled;
|
|
|
|
@override
|
|
final bool isAndroidEnabled;
|
|
|
|
@override
|
|
final bool isIOSEnabled;
|
|
|
|
@override
|
|
final bool isFuchsiaEnabled;
|
|
|
|
@override
|
|
final bool areCustomDevicesEnabled;
|
|
|
|
@override
|
|
final bool isFlutterWebWasmEnabled;
|
|
|
|
@override
|
|
final bool isCliAnimationEnabled;
|
|
|
|
@override
|
|
final bool isNativeAssetsEnabled;
|
|
|
|
@override
|
|
final bool isPreviewDeviceEnabled;
|
|
|
|
@override
|
|
bool isEnabled(Feature feature) {
|
|
return switch (feature) {
|
|
flutterWebFeature => isWebEnabled,
|
|
flutterLinuxDesktopFeature => isLinuxEnabled,
|
|
flutterMacOSDesktopFeature => isMacOSEnabled,
|
|
flutterWindowsDesktopFeature => isWindowsEnabled,
|
|
flutterAndroidFeature => isAndroidEnabled,
|
|
flutterIOSFeature => isIOSEnabled,
|
|
flutterFuchsiaFeature => isFuchsiaEnabled,
|
|
flutterCustomDevicesFeature => areCustomDevicesEnabled,
|
|
cliAnimation => isCliAnimationEnabled,
|
|
nativeAssets => isNativeAssetsEnabled,
|
|
_ => false,
|
|
};
|
|
}
|
|
}
|
|
|
|
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
|
|
FakeOperatingSystemUtils({this.hostPlatform = HostPlatform.linux_x64});
|
|
|
|
final List<List<String>> chmods = <List<String>>[];
|
|
|
|
@override
|
|
void makeExecutable(File file) { }
|
|
|
|
@override
|
|
HostPlatform hostPlatform = HostPlatform.linux_x64;
|
|
|
|
@override
|
|
void chmod(FileSystemEntity entity, String mode) {
|
|
chmods.add(<String>[entity.path, mode]);
|
|
}
|
|
|
|
@override
|
|
File? which(String execName) => null;
|
|
|
|
@override
|
|
List<File> whichAll(String execName) => <File>[];
|
|
|
|
@override
|
|
void unzip(File file, Directory targetDirectory) { }
|
|
|
|
@override
|
|
void unpack(File gzippedTarFile, Directory targetDirectory) { }
|
|
|
|
@override
|
|
Stream<List<int>> gzipLevel1Stream(Stream<List<int>> stream) => stream;
|
|
|
|
@override
|
|
String get name => 'fake OS name and version';
|
|
|
|
@override
|
|
String get pathVarSeparator => ';';
|
|
|
|
@override
|
|
Future<int> findFreePort({bool ipv6 = false}) async => 12345;
|
|
}
|
|
|
|
class FakeStopwatch implements Stopwatch {
|
|
@override
|
|
bool get isRunning => _isRunning;
|
|
bool _isRunning = false;
|
|
|
|
@override
|
|
void start() => _isRunning = true;
|
|
|
|
@override
|
|
void stop() => _isRunning = false;
|
|
|
|
@override
|
|
Duration elapsed = Duration.zero;
|
|
|
|
@override
|
|
int get elapsedMicroseconds => elapsed.inMicroseconds;
|
|
|
|
@override
|
|
int get elapsedMilliseconds => elapsed.inMilliseconds;
|
|
|
|
@override
|
|
int get elapsedTicks => elapsed.inMilliseconds;
|
|
|
|
@override
|
|
int get frequency => 1000;
|
|
|
|
@override
|
|
void reset() {
|
|
_isRunning = false;
|
|
elapsed = Duration.zero;
|
|
}
|
|
|
|
@override
|
|
String toString() => '$runtimeType $elapsed $isRunning';
|
|
}
|
|
|
|
class FakeStopwatchFactory implements StopwatchFactory {
|
|
FakeStopwatchFactory({
|
|
Stopwatch? stopwatch,
|
|
Map<String, Stopwatch>? stopwatches
|
|
}) : stopwatches = <String, Stopwatch>{
|
|
if (stopwatches != null) ...stopwatches,
|
|
if (stopwatch != null) '': stopwatch,
|
|
};
|
|
|
|
Map<String, Stopwatch> stopwatches;
|
|
|
|
@override
|
|
Stopwatch createStopwatch([String name = '']) {
|
|
return stopwatches[name] ?? FakeStopwatch();
|
|
}
|
|
}
|
|
|
|
class FakeFlutterProjectFactory implements FlutterProjectFactory {
|
|
@override
|
|
FlutterProject fromDirectory(Directory directory) {
|
|
return FlutterProject.fromDirectoryTest(directory);
|
|
}
|
|
|
|
@override
|
|
Map<String, FlutterProject> get projects => throw UnimplementedError();
|
|
}
|
|
|
|
class FakeAndroidSdk extends Fake implements AndroidSdk {
|
|
|
|
@override
|
|
late bool platformToolsAvailable;
|
|
|
|
@override
|
|
late bool licensesAvailable;
|
|
|
|
@override
|
|
AndroidSdkVersion? latestVersion;
|
|
}
|
|
|
|
class FakeAndroidStudio extends Fake implements AndroidStudio {
|
|
@override
|
|
String get javaPath => 'java';
|
|
}
|
|
|
|
class FakeJava extends Fake implements Java {
|
|
FakeJava({
|
|
this.javaHome = '/android-studio/jbr',
|
|
String binary = '/android-studio/jbr/bin/java',
|
|
Version? version,
|
|
bool canRun = true,
|
|
}): binaryPath = binary,
|
|
version = version ?? const Version.withText(19, 0, 2, 'openjdk 19.0.2 2023-01-17'),
|
|
_environment = <String, String>{
|
|
if (javaHome != null) Java.javaHomeEnvironmentVariable: javaHome,
|
|
'PATH': '/android-studio/jbr/bin',
|
|
},
|
|
_canRun = canRun;
|
|
|
|
@override
|
|
String? javaHome;
|
|
|
|
@override
|
|
String binaryPath;
|
|
|
|
final Map<String, String> _environment;
|
|
final bool _canRun;
|
|
|
|
@override
|
|
Map<String, String> get environment => _environment;
|
|
|
|
@override
|
|
Version? version;
|
|
|
|
@override
|
|
bool canRun() {
|
|
return _canRun;
|
|
}
|
|
}
|