diff --git a/webdev/bin/webdev.dart b/webdev/bin/webdev.dart index 6c28c16fa..484a4b412 100644 --- a/webdev/bin/webdev.dart +++ b/webdev/bin/webdev.dart @@ -1,7 +1,13 @@ import 'dart:async'; import 'package:webdev/webdev.dart'; +import 'package:build_runner/src/logging/std_io_logging.dart'; +import 'package:logging/logging.dart'; Future main(List args) async { + // TODO(nshahan) See if build_runner wants to expose their listener. + // Using log listener from build_runner to match output format. + final logListener = Logger.root.onRecord.listen(stdIOLogListener); await webdevCommandRunner().run(args); + await logListener?.cancel(); } diff --git a/webdev/example/pubspec.yaml b/webdev/example/pubspec.yaml index 5e4f3719d..6c4f93988 100644 --- a/webdev/example/pubspec.yaml +++ b/webdev/example/pubspec.yaml @@ -6,7 +6,7 @@ environment: sdk: ">=2.0.0-dev.3.0 <2.0.0" dependencies: - angular: ^5.0.0-alpha+3 + angular: ^5.0.0-alpha+4 browser: ^0.10.0 dev_dependencies: @@ -14,10 +14,7 @@ dev_dependencies: path: ../ ############################################################################## # Temporary until build_runner exposes a function to generate it's script. - build_runner: - git: - url: https://github.com/dart-lang/build.git - path: build_runner + build_runner: ^0.7.7 ############################################################################## dependency_overrides: diff --git a/webdev/lib/src/command/build_command.dart b/webdev/lib/src/command/build_command.dart index ac1b646ca..7f71059e7 100644 --- a/webdev/lib/src/command/build_command.dart +++ b/webdev/lib/src/command/build_command.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:isolate'; import 'build_runner_command_base.dart'; @@ -15,9 +14,6 @@ class BuildCommand extends BuildRunnerCommandBase { Future run() async { final arguments = ['build']; arguments.addAll(argResults.arguments); - var exitPort = new ReceivePort(); - await Isolate.spawnUri(await buildRunnerScript, arguments, null, - onExit: exitPort.sendPort, automaticPackageResolution: true); - await exitPort.first; + await runBuildRunner(arguments); } } diff --git a/webdev/lib/src/command/build_runner_command_base.dart b/webdev/lib/src/command/build_runner_command_base.dart index 88f2fc0eb..2708b16e3 100644 --- a/webdev/lib/src/command/build_runner_command_base.dart +++ b/webdev/lib/src/command/build_runner_command_base.dart @@ -1,7 +1,12 @@ import 'dart:async'; import 'dart:io'; +import 'dart:isolate'; import 'package:args/command_runner.dart'; +import 'package:build_runner/src/logging/logging.dart'; +import 'package:logging/logging.dart'; + +var _logger = new Logger('webdev'); /// Extend to get a command with the arguments common to all build_runner /// commands. @@ -19,13 +24,88 @@ abstract class BuildRunnerCommandBase extends Command { help: 'Enables verbose logging.'); } - Future get buildRunnerScript async { - // TODO(nshahan) build_runner will expose this as a function call that will - // be imported to avoid running a binary in a transitive dependency with - // pub run. - final executable = 'pub'; - final arguments = ['run', 'build_runner', 'generate-build-script']; - final results = await Process.run(executable, arguments); - return new Uri.file(results.stdout.toString().trim()); + /// Runs `pub run build_runner` with [arguments] as an isolate. + /// + /// Attempts to run `pub get` and `pub upgrade` if needed and will retry + /// running build_runner after. + Future runBuildRunner(List arguments) async { + final result = await _runBuildRunnerGenerate(); + + if (result.exitCode != 0) { + print(result.exitCode); + _logger.severe('Unable to run `pub get` and `pub run build_runner`.' + '\nPlease fix the dependencies and retry.' + '\n\n${result.stderr}'); + return; + } + + var exitPort = new ReceivePort(); + var errorPort = new ReceivePort(); + var messagePort = new ReceivePort(); + var errorListener = errorPort.listen((e) { + stderr.writeAll(e as List, '\n'); + if (exitCode == 0) exitCode = 1; + }); + await Isolate.spawnUri(_scriptPath(result), arguments, messagePort.sendPort, + onExit: exitPort.sendPort, + onError: errorPort.sendPort, + automaticPackageResolution: true); + try { + exitCode = await messagePort.first as int; + } on StateError catch (_) { + if (exitCode == 0) exitCode = 1; + } + await exitPort.first; + await errorListener.cancel(); + } + + /// Generates a build script and returns it's location. + /// + /// Will attempt to get dependencies if needed. + Future _runBuildRunnerGenerate() async { + var result = await logTimedAsync( + _logger, 'Generating build script', _runGenerateBuildScript); + + if (result.exitCode != 0) { + _logger.warning('Generating build script failed.'); + result = await logTimedAsync(_logger, 'Getting dependencies', _runPubGet); + + if (result.exitCode != 0) { + _logger.warning('Getting dependencies failed.'); + result = await logTimedAsync( + _logger, 'Upgrading dependencies', _runPubUpgrade); + + if (result.exitCode != 0) { + _logger.severe('Upgrading dependencies failed'); + return result; + } + } + + // Try running build_runner again. + result = await logTimedAsync( + _logger, 'Generating build script', _runGenerateBuildScript); + } + + return result; } + + /// Parses the generated script path from the the results of running + /// `build_runner generate-build-script`.` + Uri _scriptPath(ProcessResult result) => + new Uri.file(result.stdout.toString().trim()); + + /// Runs `build_runner generate-build-script` as a Process. + Future _runGenerateBuildScript() => + // TODO(nshahan) build_runner will expose this as a function call that + // will be imported to avoid running a binary in a transitive dependency + // with pub run. + Process.run('pub', ['run', 'build_runner', 'generate-build-script']); + + /// Runs `pub get` as a Process. + Future _runPubGet() => + Process.run('pub', ['get', '--no-precompile']); + + /// Runs `pub upgrade` as a Process. + Future _runPubUpgrade() => + Process.run('pub', ['upgrade', '--no-precompile']); } diff --git a/webdev/lib/src/command/serve_command.dart b/webdev/lib/src/command/serve_command.dart index a8ba022b7..5e74d21ec 100644 --- a/webdev/lib/src/command/serve_command.dart +++ b/webdev/lib/src/command/serve_command.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:isolate'; import 'build_runner_command_base.dart'; @@ -24,9 +23,6 @@ class ServeCommand extends BuildRunnerCommandBase { Future run() async { final arguments = ['serve']; arguments.addAll(argResults.arguments); - var exitPort = new ReceivePort(); - await Isolate.spawnUri(await buildRunnerScript, arguments, null, - onExit: exitPort.sendPort, automaticPackageResolution: true); - await exitPort.first; + await runBuildRunner(arguments); } } diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 5796813f4..434febd49 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -8,11 +8,8 @@ environment: dependencies: args: ^1.2.0 - build_runner: - git: - url: https://github.com/dart-lang/build.git - path: build_runner - build_web_compilers: ^0.1.1 + build_runner: ^0.7.7 + build_web_compilers: ^0.2.0 dev_dependencies: test: "^0.12.0"