1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:file/memory.dart';
6library;
7
8import 'package:process/process.dart';
9import 'package:unified_analytics/unified_analytics.dart';
10
11import 'android/android_sdk.dart';
12import 'android/android_studio.dart';
13import 'android/gradle_utils.dart';
14import 'android/java.dart';
15import 'artifacts.dart';
16import 'base/bot_detector.dart';
17import 'base/config.dart';
18import 'base/context.dart';
19import 'base/error_handling_io.dart';
20import 'base/file_system.dart';
21import 'base/io.dart';
22import 'base/logger.dart';
23import 'base/net.dart';
24import 'base/os.dart';
25import 'base/platform.dart';
26import 'base/process.dart';
27import 'base/signals.dart';
28import 'base/template.dart';
29import 'base/terminal.dart';
30import 'base/time.dart';
31import 'base/user_messages.dart';
32import 'build_system/build_system.dart';
33import 'build_system/build_targets.dart';
34import 'cache.dart';
35import 'custom_devices/custom_devices_config.dart';
36import 'device.dart';
37import 'doctor.dart';
38import 'ios/ios_workflow.dart';
39import 'ios/plist_parser.dart';
40import 'ios/simulators.dart';
41import 'ios/xcodeproj.dart';
42import 'macos/cocoapods.dart';
43import 'macos/cocoapods_validator.dart';
44import 'macos/xcdevice.dart';
45import 'macos/xcode.dart';
46import 'native_assets.dart';
47import 'persistent_tool_state.dart';
48import 'pre_run_validator.dart';
49import 'project.dart';
50import 'reporting/crash_reporting.dart';
51import 'reporting/reporting.dart';
52import 'runner/local_engine.dart';
53import 'version.dart';
54
55// TODO(ianh): We should remove all the global variables and replace them with
56// arguments (to constructors, methods, etc, as appropriate).
57
58Artifacts? get artifacts => context.get<Artifacts>();
59BuildSystem get buildSystem => context.get<BuildSystem>()!;
60BuildTargets get buildTargets => context.get<BuildTargets>()!;
61Cache get cache => context.get<Cache>()!;
62CocoaPodsValidator? get cocoapodsValidator => context.get<CocoaPodsValidator>();
63Config get config => context.get<Config>()!;
64CrashReporter? get crashReporter => context.get<CrashReporter>();
65DeviceManager? get deviceManager => context.get<DeviceManager>();
66Doctor? get doctor => context.get<Doctor>();
67HttpClientFactory? get httpClientFactory => context.get<HttpClientFactory>();
68IOSSimulatorUtils? get iosSimulatorUtils => context.get<IOSSimulatorUtils>();
69Logger get logger => context.get<Logger>()!;
70OperatingSystemUtils get os => context.get<OperatingSystemUtils>()!;
71Signals get signals => context.get<Signals>() ?? LocalSignals.instance;
72AndroidStudio? get androidStudio => context.get<AndroidStudio>();
73AndroidSdk? get androidSdk => context.get<AndroidSdk>();
74FlutterVersion get flutterVersion => context.get<FlutterVersion>()!;
75Usage get flutterUsage => context.get<Usage>()!;
76XcodeProjectInterpreter? get xcodeProjectInterpreter => context.get<XcodeProjectInterpreter>();
77XCDevice? get xcdevice => context.get<XCDevice>();
78Xcode? get xcode => context.get<Xcode>();
79IOSWorkflow? get iosWorkflow => context.get<IOSWorkflow>();
80LocalEngineLocator? get localEngineLocator => context.get<LocalEngineLocator>();
81
82PersistentToolState? get persistentToolState => PersistentToolState.instance;
83
84BotDetector get botDetector => context.get<BotDetector>() ?? _defaultBotDetector;
85final _defaultBotDetector = BotDetector(
86 httpClientFactory: context.get<HttpClientFactory>() ?? () => HttpClient(),
87 platform: platform,
88 persistentToolState:
89 persistentToolState ??
90 PersistentToolState(fileSystem: fs, logger: logger, platform: platform),
91);
92Future<bool> get isRunningOnBot => botDetector.isRunningOnBot;
93
94// Analytics instance for package:unified_analytics for analytics
95// reporting for all Flutter and Dart related tooling
96Analytics get analytics => context.get<Analytics>()!;
97
98/// Currently active implementation of the file system.
99///
100/// By default it uses local disk-based implementation. Override this in tests
101/// with [MemoryFileSystem].
102FileSystem get fs => ErrorHandlingFileSystem(
103 delegate: context.get<FileSystem>() ?? localFileSystem,
104 platform: platform,
105);
106
107FileSystemUtils get fsUtils =>
108 context.get<FileSystemUtils>() ?? FileSystemUtils(fileSystem: fs, platform: platform);
109
110const ProcessManager _kLocalProcessManager = LocalProcessManager();
111
112/// The active process manager.
113ProcessManager get processManager => context.get<ProcessManager>() ?? _kLocalProcessManager;
114ProcessUtils get processUtils => context.get<ProcessUtils>()!;
115
116const Platform _kLocalPlatform = LocalPlatform();
117Platform get platform => context.get<Platform>() ?? _kLocalPlatform;
118
119UserMessages get userMessages => context.get<UserMessages>()!;
120
121final _default = OutputPreferences(
122 wrapText: stdio.hasTerminal,
123 showColor: platform.stdoutSupportsAnsi,
124 stdio: stdio,
125);
126OutputPreferences get outputPreferences => context.get<OutputPreferences>() ?? _default;
127
128/// The current system clock instance.
129SystemClock get systemClock => context.get<SystemClock>() ?? _systemClock;
130var _systemClock = const SystemClock();
131
132ProcessInfo get processInfo => context.get<ProcessInfo>()!;
133
134/// Display an error level message to the user. Commands should use this if they
135/// fail in some way.
136///
137/// Set [emphasis] to true to make the output bold if it's supported.
138/// Set [color] to a [TerminalColor] to color the output, if the logger
139/// supports it. The [color] defaults to [TerminalColor.red].
140void printError(
141 String message, {
142 StackTrace? stackTrace,
143 bool? emphasis,
144 TerminalColor? color,
145 int? indent,
146 int? hangingIndent,
147 bool? wrap,
148}) {
149 logger.printError(
150 message,
151 stackTrace: stackTrace,
152 emphasis: emphasis ?? false,
153 color: color,
154 indent: indent,
155 hangingIndent: hangingIndent,
156 wrap: wrap,
157 );
158}
159
160/// Display a warning level message to the user. Commands should use this if they
161/// have important warnings to convey that aren't fatal.
162///
163/// Set [emphasis] to true to make the output bold if it's supported.
164/// Set [color] to a [TerminalColor] to color the output, if the logger
165/// supports it. The [color] defaults to [TerminalColor.cyan].
166void printWarning(
167 String message, {
168 bool? emphasis,
169 TerminalColor? color,
170 int? indent,
171 int? hangingIndent,
172 bool? wrap,
173}) {
174 logger.printWarning(
175 message,
176 emphasis: emphasis ?? false,
177 color: color,
178 indent: indent,
179 hangingIndent: hangingIndent,
180 wrap: wrap,
181 );
182}
183
184/// Display normal output of the command. This should be used for things like
185/// progress messages, success messages, or just normal command output.
186///
187/// Set `emphasis` to true to make the output bold if it's supported.
188///
189/// Set `newline` to false to skip the trailing linefeed.
190///
191/// If `indent` is provided, each line of the message will be prepended by the
192/// specified number of whitespaces.
193void printStatus(
194 String message, {
195 bool? emphasis,
196 bool? newline,
197 TerminalColor? color,
198 int? indent,
199 int? hangingIndent,
200 bool? wrap,
201}) {
202 logger.printStatus(
203 message,
204 emphasis: emphasis ?? false,
205 color: color,
206 newline: newline ?? true,
207 indent: indent,
208 hangingIndent: hangingIndent,
209 wrap: wrap,
210 );
211}
212
213/// Display the [message] inside a box.
214///
215/// For example, this is the generated output:
216///
217/// ┌─ [title] ─┐
218/// │ [message] │
219/// └───────────┘
220///
221/// If a terminal is attached, the lines in [message] are automatically wrapped based on
222/// the available columns.
223void printBox(String message, {String? title}) {
224 logger.printBox(message, title: title);
225}
226
227/// Use this for verbose tracing output. Users can turn this output on in order
228/// to help diagnose issues with the toolchain or with their setup.
229void printTrace(String message) => logger.printTrace(message);
230
231AnsiTerminal get terminal {
232 return context.get<AnsiTerminal>() ?? _defaultAnsiTerminal;
233}
234
235final _defaultAnsiTerminal = AnsiTerminal(
236 stdio: stdio,
237 platform: platform,
238 now: DateTime.now(),
239 shutdownHooks: shutdownHooks,
240);
241
242/// The global Stdio wrapper.
243Stdio get stdio => context.get<Stdio>() ?? (_stdioInstance ??= Stdio());
244Stdio? _stdioInstance;
245
246PlistParser get plistParser =>
247 context.get<PlistParser>() ??
248 (_plistInstance ??= PlistParser(
249 fileSystem: fs,
250 processManager: processManager,
251 logger: logger,
252 ));
253PlistParser? _plistInstance;
254
255/// The global template renderer.
256TemplateRenderer get templateRenderer => context.get<TemplateRenderer>()!;
257
258/// Global [ShutdownHooks] that should be run before the tool process exits.
259///
260/// This is depended on by [localFileSystem] which is called before any
261/// [AppContext] is set up, and thus this cannot be a Context getter.
262final shutdownHooks = ShutdownHooks();
263
264// Unless we're in a test of this class's signal handling features, we must
265// have only one instance created with the singleton LocalSignals instance
266// and the catchable signals it considers to be fatal.
267LocalFileSystem? _instance;
268LocalFileSystem get localFileSystem =>
269 _instance ??= LocalFileSystem(LocalSignals.instance, Signals.defaultExitSignals, shutdownHooks);
270
271/// Gradle utils in the current [AppContext].
272GradleUtils? get gradleUtils => context.get<GradleUtils>();
273
274CocoaPods? get cocoaPods => context.get<CocoaPods>();
275
276FlutterProjectFactory get projectFactory {
277 return context.get<FlutterProjectFactory>() ??
278 FlutterProjectFactory(logger: logger, fileSystem: fs);
279}
280
281CustomDevicesConfig get customDevicesConfig => context.get<CustomDevicesConfig>()!;
282
283PreRunValidator get preRunValidator =>
284 context.get<PreRunValidator>() ?? const NoOpPreRunValidator();
285
286// Used to build RegExp instances which can detect the VM service message.
287final kVMServiceMessageRegExp = RegExp(
288 r'The Dart VM service is listening on ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)',
289);
290
291/// Contains information about the JRE/JDK to use for Java-dependent operations.
292///
293/// A value of `null` indicates that no installation of java could be found on
294/// the host machine.
295Java? get java => context.get<Java>();
296
297TestCompilerNativeAssetsBuilder? get nativeAssetsBuilder =>
298 context.get<TestCompilerNativeAssetsBuilder>();
299