executable.dart 7.13 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8
import 'dart:async';
import 'dart:io';

import 'package:args/command_runner.dart';
9
import 'package:stack_trace/stack_trace.dart';
10

11
import 'src/base/common.dart';
12 13
import 'src/base/context.dart';
import 'src/base/logger.dart';
14
import 'src/base/process.dart';
Devon Carew's avatar
Devon Carew committed
15
import 'src/base/utils.dart';
Hixie's avatar
Hixie committed
16
import 'src/commands/analyze.dart';
17
import 'src/commands/build.dart';
18
import 'src/commands/channel.dart';
19
import 'src/commands/config.dart';
20
import 'src/commands/create.dart';
Devon Carew's avatar
Devon Carew committed
21
import 'src/commands/daemon.dart';
22
import 'src/commands/devices.dart';
23
import 'src/commands/doctor.dart';
yjbanov's avatar
yjbanov committed
24
import 'src/commands/drive.dart';
25
import 'src/commands/format.dart';
26 27
import 'src/commands/install.dart';
import 'src/commands/logs.dart';
28
import 'src/commands/setup.dart';
29
import 'src/commands/packages.dart';
30
import 'src/commands/precache.dart';
31
import 'src/commands/run.dart';
Devon Carew's avatar
Devon Carew committed
32
import 'src/commands/screenshot.dart';
33
import 'src/commands/stop.dart';
34
import 'src/commands/test.dart';
35
import 'src/commands/trace.dart';
36
import 'src/commands/update_packages.dart';
37
import 'src/commands/upgrade.dart';
38
import 'src/devfs.dart';
39
import 'src/device.dart';
40
import 'src/doctor.dart';
Devon Carew's avatar
Devon Carew committed
41
import 'src/globals.dart';
42
import 'src/hot.dart';
43
import 'src/runner/flutter_command_runner.dart';
44 45 46

/// Main entry point for commands.
///
47
/// This function is intended to be used from the `flutter` command line tool.
48
Future<Null> main(List<String> args) async {
Devon Carew's avatar
Devon Carew committed
49
  bool verbose = args.contains('-v') || args.contains('--verbose');
50 51
  bool help = args.contains('-h') || args.contains('--help') ||
      (args.isNotEmpty && args.first == 'help') || (args.length == 1 && verbose);
52
  bool verboseHelp = help && verbose;
Devon Carew's avatar
Devon Carew committed
53

Devon Carew's avatar
Devon Carew committed
54 55 56 57 58 59
  if (verboseHelp) {
    // Remove the verbose option; for help, users don't need to see verbose logs.
    args = new List<String>.from(args);
    args.removeWhere((String option) => option == '-v' || option == '--verbose');
  }

60
  FlutterCommandRunner runner = new FlutterCommandRunner(verboseHelp: verboseHelp)
61 62
    ..addCommand(new AnalyzeCommand(verboseHelp: verboseHelp))
    ..addCommand(new BuildCommand(verboseHelp: verboseHelp))
63
    ..addCommand(new ChannelCommand())
64
    ..addCommand(new ConfigCommand())
65
    ..addCommand(new CreateCommand())
66
    ..addCommand(new DaemonCommand(hidden: !verboseHelp))
67
    ..addCommand(new DevicesCommand())
68
    ..addCommand(new DoctorCommand())
yjbanov's avatar
yjbanov committed
69
    ..addCommand(new DriveCommand())
70
    ..addCommand(new FormatCommand())
71 72
    ..addCommand(new InstallCommand())
    ..addCommand(new LogsCommand())
73
    ..addCommand(new PackagesCommand())
74
    ..addCommand(new PrecacheCommand())
75
    ..addCommand(new RunCommand(verboseHelp: verboseHelp))
Devon Carew's avatar
Devon Carew committed
76
    ..addCommand(new ScreenshotCommand())
77
    ..addCommand(new SetupCommand(hidden: !verboseHelp))
78
    ..addCommand(new StopCommand())
79
    ..addCommand(new TestCommand())
80
    ..addCommand(new TraceCommand())
81
    ..addCommand(new UpdatePackagesCommand(hidden: !verboseHelp))
82
    ..addCommand(new UpgradeCommand());
83

84
  return Chain.capture/*<Future<Null>>*/(() async {
85
    // Initialize globals.
86 87 88 89 90 91 92 93
    if (context[Logger] == null)
      context[Logger] = new StdoutLogger();
    if (context[DeviceManager] == null)
      context[DeviceManager] = new DeviceManager();
    if (context[DevFSConfig] == null)
      context[DevFSConfig] = new DevFSConfig();
    if (context[Doctor] == null)
      context[Doctor] = new Doctor();
94 95
    if (context[HotRunnerConfig] == null)
      context[HotRunnerConfig] = new HotRunnerConfig();
96

97 98
    await runner.run(args);
    _exit(0);
99
  }, onError: (dynamic error, Chain chain) {
100
    if (error is UsageException) {
Devon Carew's avatar
Devon Carew committed
101 102
      stderr.writeln(error.message);
      stderr.writeln();
103 104 105 106
      stderr.writeln(
        "Run 'flutter -h' (or 'flutter <command> -h') for available "
        "flutter commands and options."
      );
107
      // Argument error exit code.
108
      _exit(64);
109
    } else if (error is ToolExit) {
110 111
      if (error.message != null)
        stderr.writeln(error.message);
112 113 114 115 116
      if (verbose) {
        stderr.writeln();
        stderr.writeln(chain.terse.toString());
        stderr.writeln();
      }
117
      _exit(error.exitCode ?? 1);
118
    } else if (error is ProcessExit) {
119
      // We've caught an exit code.
120
      _exit(error.exitCode);
121
    } else {
Devon Carew's avatar
Devon Carew committed
122 123
      // We've crashed; emit a log report.
      stderr.writeln();
124

125 126
      flutterUsage.sendException(error, chain);

127 128
      if (isRunningOnBot) {
        // Print the stack trace on the bots - don't write a crash report.
129
        stderr.writeln('$error');
130
        stderr.writeln(chain.terse.toString());
131
        _exit(1);
132
      } else {
133 134 135 136 137
        if (error is String)
          stderr.writeln('Oops; flutter has exited unexpectedly: "$error".');
        else
          stderr.writeln('Oops; flutter has exited unexpectedly.');

138 139 140 141 142 143 144
        _createCrashReport(args, error, chain).then((File file) {
          stderr.writeln(
              'Crash report written to ${file.path};\n'
              'please let us know at https://github.com/flutter/flutter/issues.'
          );
          _exit(1);
        });
145
      }
146
    }
147
  });
148
}
Devon Carew's avatar
Devon Carew committed
149

150
Future<File> _createCrashReport(List<String> args, dynamic error, Chain chain) async {
Devon Carew's avatar
Devon Carew committed
151
  File crashFile = getUniqueFile(Directory.current, 'flutter', 'log');
Devon Carew's avatar
Devon Carew committed
152

153
  StringBuffer buffer = new StringBuffer();
Devon Carew's avatar
Devon Carew committed
154

155
  buffer.writeln('Flutter crash report; please file at https://github.com/flutter/flutter/issues.\n');
Devon Carew's avatar
Devon Carew committed
156

157 158
  buffer.writeln('## command\n');
  buffer.writeln('flutter ${args.join(' ')}\n');
Devon Carew's avatar
Devon Carew committed
159

160 161 162
  buffer.writeln('## exception\n');
  buffer.writeln('$error\n');
  buffer.writeln('```\n${chain.terse}```\n');
Devon Carew's avatar
Devon Carew committed
163

164
  buffer.writeln('## flutter doctor\n');
165
  buffer.writeln('```\n${await _doctorText()}```');
Devon Carew's avatar
Devon Carew committed
166

167 168 169 170 171 172 173 174 175 176 177 178
  try {
    crashFile.writeAsStringSync(buffer.toString());
  } on FileSystemException catch (_) {
    // Fallback to the system temporary directory.
    crashFile = getUniqueFile(Directory.systemTemp, 'flutter', 'log');
    try {
      crashFile.writeAsStringSync(buffer.toString());
    } on FileSystemException catch (e) {
      printError('Could not write crash report to disk: $e');
      printError(buffer.toString());
    }
  }
Devon Carew's avatar
Devon Carew committed
179 180 181 182

  return crashFile;
}

183
Future<String> _doctorText() async {
Devon Carew's avatar
Devon Carew committed
184 185 186 187 188 189
  try {
    BufferLogger logger = new BufferLogger();
    AppContext appContext = new AppContext();

    appContext[Logger] = logger;

190
    await appContext.runInZone(() => doctor.diagnose());
Devon Carew's avatar
Devon Carew committed
191 192

    return logger.statusText;
193
  } catch (error, trace) {
194
    return 'encountered exception: $error\n\n${trace.toString().trim()}\n';
Devon Carew's avatar
Devon Carew committed
195 196
  }
}
197 198

Future<Null> _exit(int code) async {
199 200 201
  if (flutterUsage.isFirstRun)
    flutterUsage.printUsage();

202 203 204 205 206 207 208 209
  // Send any last analytics calls that are in progress without overly delaying
  // the tool's exit (we wait a maximum of 250ms).
  if (flutterUsage.enabled) {
    Stopwatch stopwatch = new Stopwatch()..start();
    await flutterUsage.ensureAnalyticsSent();
    printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms');
  }

210 211 212
  // Run shutdown hooks before flushing logs
  await runShutdownHooks();

213
  // Give the task / timer queue one cycle through before we hard exit.
214
  Timer.run(() {
Ian Hickson's avatar
Ian Hickson committed
215
    printTrace('exiting with code $code');
216 217 218
    exit(code);
  });
}