From f7d07abacffdbcd1d0e1b9f84cb87c49bf58d8f7 Mon Sep 17 00:00:00 2001 From: Nicholas Shahan Date: Wed, 17 Jan 2018 14:34:56 -0800 Subject: [PATCH 1/2] Try getting dependencies if needed to run `pub run build_runner` --- webdev/bin/webdev.dart | 6 ++ webdev/example/pubspec.yaml | 18 ++++- webdev/lib/src/command/build_command.dart | 6 +- .../command/build_runner_command_base.dart | 80 ++++++++++++++++++- webdev/lib/src/command/serve_command.dart | 6 +- webdev/pubspec.yaml | 17 +++- 6 files changed, 115 insertions(+), 18 deletions(-) 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..69ec14596 100644 --- a/webdev/example/pubspec.yaml +++ b/webdev/example/pubspec.yaml @@ -14,12 +14,22 @@ 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.5+1 ############################################################################## dependency_overrides: # Necessary with angular: ^5.0.0-alpha+1 dependency. analyzer: ^0.31.0-alpha.1 + ############################################################################## + # Temporary until updated packages are published. + build: + git: + url: https://github.com/dart-lang/build.git + ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 + path: build + build_runner: + git: + url: https://github.com/dart-lang/build.git + ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 + path: build_runner + ############################################################################## 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..326ce8ec6 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,82 @@ abstract class BuildRunnerCommandBase extends Command { help: 'Enables verbose logging.'); } - Future get buildRunnerScript async { + /// 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 { + var exitPort = new ReceivePort(); + try { + await Isolate.spawnUri(await _buildRunnerScript, arguments, null, + onExit: exitPort.sendPort, automaticPackageResolution: true); + await exitPort.first; + } on _PubDependenciesError catch (_) { + exitPort.close(); + } + } + + Future get _buildRunnerScript async { + return await logTimedAsync( + _logger, 'Generating build script', _runBuildRunnerGenerate); + } + + /// Generates a build script and returns it's location. + /// + /// Will attempt to run `pub get` or `pub update` if needed. + Future _runBuildRunnerGenerate() 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()); + var result = await Process.run(executable, arguments); + + if (_needPubGet(result)) { + _logger.warning('Generating build script failed.'); + result = await logTimedAsync(_logger, 'Getting dependencies', _runPubGet); + + // Try running build_runner again. + result = await Process.run(executable, arguments); + + if (_needPubGet(result)) { + _logger.warning('Getting dependencies failed.'); + result = await logTimedAsync( + _logger, 'Upgrading dependencies', _runPubUpgrade); + + if (result.exitCode != 0) { + _logger.severe( + 'Could not retrieve dependencies. webdev must be able to run `pub' + ' get`.' + '\nPlease fix the dependencies and retry.' + '\n\n${result.stderr}'); + throw new _PubDependenciesError(); + } + + // Try running build_runner one last time. + result = await Process.run(executable, arguments); + } + } + + return new Uri.file(result.stdout.toString().trim()); + } + + /// Checks [result] for errors to see if a `pub get` is needed. + bool _needPubGet(ProcessResult result) => + result.exitCode != 0 && + result.stderr.toString().contains('please run "pub get"'); + + /// Runs `pub get` as a Process. + Future _runPubGet() async { + return await Process.run('pub', ['get', '--no-precompile']); + } + + /// Runs `pub upgrade` as a Process. + Future _runPubUpgrade() async { + return await Process.run('pub', ['upgrade', '--no-precompile']); } } + +/// Private error class used to report back an error when attempting to run +/// `pub get` and `pub upgrade`. +class _PubDependenciesError extends Error {} 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..ed0cc0e87 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -12,7 +12,22 @@ dependencies: git: url: https://github.com/dart-lang/build.git path: build_runner - build_web_compilers: ^0.1.1 + build_web_compilers: ^0.2.0 dev_dependencies: test: "^0.12.0" + +################################################################################ +# Temporary until updated packages are published. +dependency_overrides: + build: + git: + url: https://github.com/dart-lang/build.git + ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 + path: build + build_runner: + git: + url: https://github.com/dart-lang/build.git + ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 + path: build_runner +################################################################################ From a9044f345a391886ef2e61a8defd9d3ecf9f2ca2 Mon Sep 17 00:00:00 2001 From: Nicholas Shahan Date: Mon, 22 Jan 2018 11:35:55 -0800 Subject: [PATCH 2/2] Allow errors from the isolate to print Based on https://github.com/dart-lang/build/commit/400b58d and https://github.com/dart-lang/build/commit/35e6c62 --- webdev/example/pubspec.yaml | 17 +-- .../command/build_runner_command_base.dart | 102 +++++++++--------- webdev/pubspec.yaml | 20 +--- 3 files changed, 57 insertions(+), 82 deletions(-) diff --git a/webdev/example/pubspec.yaml b/webdev/example/pubspec.yaml index 69ec14596..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,22 +14,9 @@ dev_dependencies: path: ../ ############################################################################## # Temporary until build_runner exposes a function to generate it's script. - build_runner: ^0.7.5+1 + build_runner: ^0.7.7 ############################################################################## dependency_overrides: # Necessary with angular: ^5.0.0-alpha+1 dependency. analyzer: ^0.31.0-alpha.1 - ############################################################################## - # Temporary until updated packages are published. - build: - git: - url: https://github.com/dart-lang/build.git - ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 - path: build - build_runner: - git: - url: https://github.com/dart-lang/build.git - ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 - path: build_runner - ############################################################################## diff --git a/webdev/lib/src/command/build_runner_command_base.dart b/webdev/lib/src/command/build_runner_command_base.dart index 326ce8ec6..2708b16e3 100644 --- a/webdev/lib/src/command/build_runner_command_base.dart +++ b/webdev/lib/src/command/build_runner_command_base.dart @@ -29,77 +29,83 @@ abstract class BuildRunnerCommandBase extends Command { /// 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 { - await Isolate.spawnUri(await _buildRunnerScript, arguments, null, - onExit: exitPort.sendPort, automaticPackageResolution: true); - await exitPort.first; - } on _PubDependenciesError catch (_) { - exitPort.close(); + exitCode = await messagePort.first as int; + } on StateError catch (_) { + if (exitCode == 0) exitCode = 1; } - } - - Future get _buildRunnerScript async { - return await logTimedAsync( - _logger, 'Generating build script', _runBuildRunnerGenerate); + await exitPort.first; + await errorListener.cancel(); } /// Generates a build script and returns it's location. /// - /// Will attempt to run `pub get` or `pub update` if needed. - Future _runBuildRunnerGenerate() 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']; - var result = await Process.run(executable, arguments); - - if (_needPubGet(result)) { + /// 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); - // Try running build_runner again. - result = await Process.run(executable, arguments); - - if (_needPubGet(result)) { + if (result.exitCode != 0) { _logger.warning('Getting dependencies failed.'); result = await logTimedAsync( _logger, 'Upgrading dependencies', _runPubUpgrade); if (result.exitCode != 0) { - _logger.severe( - 'Could not retrieve dependencies. webdev must be able to run `pub' - ' get`.' - '\nPlease fix the dependencies and retry.' - '\n\n${result.stderr}'); - throw new _PubDependenciesError(); + _logger.severe('Upgrading dependencies failed'); + return result; } - - // Try running build_runner one last time. - result = await Process.run(executable, arguments); } + + // Try running build_runner again. + result = await logTimedAsync( + _logger, 'Generating build script', _runGenerateBuildScript); } - return new Uri.file(result.stdout.toString().trim()); + return result; } - /// Checks [result] for errors to see if a `pub get` is needed. - bool _needPubGet(ProcessResult result) => - result.exitCode != 0 && - result.stderr.toString().contains('please run "pub get"'); + /// 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() async { - return await Process.run('pub', ['get', '--no-precompile']); - } + Future _runPubGet() => + Process.run('pub', ['get', '--no-precompile']); /// Runs `pub upgrade` as a Process. - Future _runPubUpgrade() async { - return await Process.run('pub', ['upgrade', '--no-precompile']); - } + Future _runPubUpgrade() => + Process.run('pub', ['upgrade', '--no-precompile']); } - -/// Private error class used to report back an error when attempting to run -/// `pub get` and `pub upgrade`. -class _PubDependenciesError extends Error {} diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index ed0cc0e87..434febd49 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -8,26 +8,8 @@ environment: dependencies: args: ^1.2.0 - build_runner: - git: - url: https://github.com/dart-lang/build.git - path: build_runner + build_runner: ^0.7.7 build_web_compilers: ^0.2.0 dev_dependencies: test: "^0.12.0" - -################################################################################ -# Temporary until updated packages are published. -dependency_overrides: - build: - git: - url: https://github.com/dart-lang/build.git - ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 - path: build - build_runner: - git: - url: https://github.com/dart-lang/build.git - ref: ffbba7fc74a1262c958a63fb31c146995f0a3a99 - path: build_runner -################################################################################