Skip to content

Try getting dependencies if needed to run pub run build_runner #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions webdev/bin/webdev.dart
Original file line number Diff line number Diff line change
@@ -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<String> 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();
}
18 changes: 14 additions & 4 deletions webdev/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
##############################################################################
6 changes: 1 addition & 5 deletions webdev/lib/src/command/build_command.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:isolate';

import 'build_runner_command_base.dart';

Expand All @@ -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);
}
}
87 changes: 84 additions & 3 deletions webdev/lib/src/command/build_runner_command_base.dart
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -19,13 +24,89 @@ abstract class BuildRunnerCommandBase extends Command {
help: 'Enables verbose logging.');
}

Future<Uri> 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<String> arguments) async {
var exitPort = new ReceivePort();
var errorPort = new ReceivePort();
var errorListener =
errorPort.listen((e) => stderr.writeAll(e as List, '\n'));
try {
await Isolate.spawnUri(await _buildRunnerScript, arguments, null,
onExit: exitPort.sendPort,
onError: errorPort.sendPort,
automaticPackageResolution: true);
await exitPort.first;
} on _PubDependenciesError catch (_) {
exitPort.close();
} finally {
await errorListener.cancel();
}
}

Future<Uri> 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<Uri> _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<ProcessResult> _runPubGet() async {
return await Process.run('pub', ['get', '--no-precompile']);
}

/// Runs `pub upgrade` as a Process.
Future<ProcessResult> _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 {}
6 changes: 1 addition & 5 deletions webdev/lib/src/command/serve_command.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:isolate';

import 'build_runner_command_base.dart';

Expand All @@ -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);
}
}
17 changes: 16 additions & 1 deletion webdev/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
################################################################################