• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 The Chromium 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
5import '../application_package.dart';
6import '../base/io.dart';
7import '../base/os.dart';
8import '../base/platform.dart';
9import '../base/process_manager.dart';
10import '../build_info.dart';
11import '../cache.dart';
12import '../desktop.dart';
13import '../device.dart';
14import '../globals.dart';
15import '../macos/application_package.dart';
16import '../project.dart';
17import '../protocol_discovery.dart';
18import 'build_macos.dart';
19import 'macos_workflow.dart';
20
21/// A device that represents a desktop MacOS target.
22class MacOSDevice extends Device {
23  MacOSDevice() : super(
24      'macOS',
25      category: Category.desktop,
26      platformType: PlatformType.macos,
27      ephemeral: false,
28  );
29
30  @override
31  void clearLogs() { }
32
33  @override
34  DeviceLogReader getLogReader({ ApplicationPackage app }) {
35    return _deviceLogReader;
36  }
37  final DesktopLogReader _deviceLogReader = DesktopLogReader();
38
39  // Since the host and target devices are the same, no work needs to be done
40  // to install the application.
41  @override
42  Future<bool> installApp(ApplicationPackage app) async => true;
43
44  // Since the host and target devices are the same, no work needs to be done
45  // to install the application.
46  @override
47  Future<bool> isAppInstalled(ApplicationPackage app) async => true;
48
49  // Since the host and target devices are the same, no work needs to be done
50  // to install the application.
51  @override
52  Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => true;
53
54  @override
55  Future<bool> get isLocalEmulator async => false;
56
57  @override
58  Future<String> get emulatorId async => null;
59
60  @override
61  bool isSupported() => true;
62
63  @override
64  String get name => 'macOS';
65
66  @override
67  DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();
68
69  @override
70  Future<String> get sdkNameAndVersion async => os.name;
71
72  @override
73  Future<LaunchResult> startApp(
74    covariant MacOSApp package, {
75    String mainPath,
76    String route,
77    DebuggingOptions debuggingOptions,
78    Map<String, dynamic> platformArgs,
79    bool prebuiltApplication = false,
80    bool usesTerminalUi = true,
81    bool ipv6 = false,
82  }) async {
83    // Stop any running applications with the same executable.
84    if (!prebuiltApplication) {
85      Cache.releaseLockEarly();
86      await buildMacOS(
87        flutterProject: FlutterProject.current(),
88        buildInfo: debuggingOptions?.buildInfo,
89        targetOverride: mainPath,
90      );
91    }
92
93    // Ensure that the executable is locatable.
94    final String executable = package.executable(debuggingOptions?.buildInfo?.mode);
95    if (executable == null) {
96      printError('Unable to find executable to run');
97      return LaunchResult.failed();
98    }
99
100    // Make sure to call stop app after we've built.
101    await stopApp(package);
102    final Process process = await processManager.start(<String>[
103      executable
104    ]);
105    if (debuggingOptions?.buildInfo?.isRelease == true) {
106      return LaunchResult.succeeded();
107    }
108    _deviceLogReader.initializeProcess(process);
109    final ProtocolDiscovery observatoryDiscovery = ProtocolDiscovery.observatory(_deviceLogReader);
110    try {
111      final Uri observatoryUri = await observatoryDiscovery.uri;
112      // Bring app to foreground.
113      await processManager.run(<String>[
114        'open', package.applicationBundle(debuggingOptions?.buildInfo?.mode),
115      ]);
116      return LaunchResult.succeeded(observatoryUri: observatoryUri);
117    } catch (error) {
118      printError('Error waiting for a debug connection: $error');
119      return LaunchResult.failed();
120    } finally {
121      await observatoryDiscovery.cancel();
122    }
123  }
124
125  // TODO(jonahwilliams): implement using process manager.
126  // currently we rely on killing the isolate taking down the application.
127  @override
128  Future<bool> stopApp(covariant MacOSApp app) async {
129    return killProcess(app.executable(BuildMode.debug));
130  }
131
132  @override
133  Future<TargetPlatform> get targetPlatform async => TargetPlatform.darwin_x64;
134
135  // Since the host and target devices are the same, no work needs to be done
136  // to uninstall the application.
137  @override
138  Future<bool> uninstallApp(ApplicationPackage app) async => true;
139
140  @override
141  bool isSupportedForProject(FlutterProject flutterProject) {
142    return flutterProject.macos.existsSync();
143  }
144}
145
146class MacOSDevices extends PollingDeviceDiscovery {
147  MacOSDevices() : super('macOS devices');
148
149  @override
150  bool get supportsPlatform => platform.isMacOS;
151
152  @override
153  bool get canListAnything => macOSWorkflow.canListDevices;
154
155  @override
156  Future<List<Device>> pollingGetDevices() async {
157    if (!canListAnything) {
158      return const <Device>[];
159    }
160    return <Device>[
161      MacOSDevice(),
162    ];
163  }
164
165  @override
166  Future<List<String>> getDiagnostics() async => const <String>[];
167}
168