diff --git a/.gitignore b/.gitignore index 26e9525be..79f51c3d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -packages -/*/build/ -.pub/ -pubspec.lock - -# Files generated by dart tools .dart_tool -doc/ +.packages +pubspec.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..009f41650 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,32 @@ +# Created with https://github.com/dart-lang/mono_repo +language: dart + +jobs: + include: + - stage: analyzer_and_format + script: ./tool/travis.sh dartfmt + env: PKG="example" + dart: dev + - stage: analyzer_and_format + script: ./tool/travis.sh dartanalyzer + env: PKG="example" + dart: dev + - stage: analyzer_and_format + script: ./tool/travis.sh dartfmt + env: PKG="webdev" + dart: dev + - stage: analyzer_and_format + script: ./tool/travis.sh dartanalyzer + env: PKG="webdev" + dart: dev + +stages: + - analyzer_and_format + +# Only building master means that we don't run two builds for each pull request. +branches: + only: [master] + +cache: + directories: + - $HOME/.pub-cache diff --git a/example/.mono_repo.yml b/example/.mono_repo.yml new file mode 100644 index 000000000..77bede62c --- /dev/null +++ b/example/.mono_repo.yml @@ -0,0 +1,10 @@ +# See https://github.com/dart-lang/mono_repo for details +dart: + - dev + +stages: + - analyzer_and_format: + - dartfmt + - dartanalyzer: --fatal-infos --fatal-warnings . +# - unit_test: +# - test diff --git a/webdev/example/lib/app_component.css b/example/lib/app_component.css similarity index 100% rename from webdev/example/lib/app_component.css rename to example/lib/app_component.css diff --git a/webdev/example/lib/app_component.dart b/example/lib/app_component.dart similarity index 56% rename from webdev/example/lib/app_component.dart rename to example/lib/app_component.dart index faf444f0c..feac3bfdb 100644 --- a/webdev/example/lib/app_component.dart +++ b/example/lib/app_component.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'package:angular/angular.dart'; import 'src/hello_world/hello_world.dart'; diff --git a/webdev/example/lib/app_component.html b/example/lib/app_component.html similarity index 100% rename from webdev/example/lib/app_component.html rename to example/lib/app_component.html diff --git a/webdev/example/lib/src/hello_world/hello_world.css b/example/lib/src/hello_world/hello_world.css similarity index 100% rename from webdev/example/lib/src/hello_world/hello_world.css rename to example/lib/src/hello_world/hello_world.css diff --git a/example/lib/src/hello_world/hello_world.dart b/example/lib/src/hello_world/hello_world.dart new file mode 100644 index 000000000..a17e4f738 --- /dev/null +++ b/example/lib/src/hello_world/hello_world.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/angular.dart'; + +@Component( + selector: 'hello-world', + styleUrls: const ['hello_world.css'], + templateUrl: 'hello_world.html', +) +class HelloWorldComponent { + // Nothing here. +} diff --git a/example/lib/src/hello_world/hello_world.html b/example/lib/src/hello_world/hello_world.html new file mode 100644 index 000000000..88990aa19 --- /dev/null +++ b/example/lib/src/hello_world/hello_world.html @@ -0,0 +1 @@ +
Hello World
diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 000000000..b45240ced --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,12 @@ +name: webdev_example_app +description: A web app example for webdev CLI. + +environment: + sdk: ">=2.0.0-dev.32.0 <2.0.0" + +dependencies: + angular: ^5.0.0-alpha+8 + +dev_dependencies: + build_runner: ^0.8.0 + build_web_compilers: ^0.3.4 diff --git a/webdev/example/web/index.html b/example/web/index.html similarity index 68% rename from webdev/example/web/index.html rename to example/web/index.html index c7fe29810..0799eec25 100644 --- a/webdev/example/web/index.html +++ b/example/web/index.html @@ -4,8 +4,7 @@ webdev example - - + diff --git a/example/web/main.dart b/example/web/main.dart new file mode 100644 index 000000000..51e09c9bd --- /dev/null +++ b/example/web/main.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:angular/experimental.dart'; + +// ignore: uri_has_not_been_generated +import 'package:webdev_example_app/app_component.template.dart' as ng; + +main() { + // ignore: argument_type_not_assignable + bootstrapFactory(ng.AppComponentNgFactory); +} diff --git a/webdev/example/web/styles.css b/example/web/styles.css similarity index 100% rename from webdev/example/web/styles.css rename to example/web/styles.css diff --git a/tool/travis.sh b/tool/travis.sh new file mode 100755 index 000000000..2e8091aa2 --- /dev/null +++ b/tool/travis.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Created with https://github.com/dart-lang/mono_repo + +if [ -z "$PKG" ]; then + echo -e '\033[31mPKG environment variable must be set!\033[0m' + exit 1 +fi + +if [ "$#" == "0" ]; then + echo -e '\033[31mAt least one task argument must be provided!\033[0m' + exit 1 +fi + +pushd $PKG +pub upgrade || exit $? + +EXIT_CODE=0 + +while (( "$#" )); do + TASK=$1 + case $TASK in + dartanalyzer) echo + echo -e '\033[1mTASK: dartanalyzer\033[22m' + echo -e 'dartanalyzer --fatal-infos --fatal-warnings .' + dartanalyzer --fatal-infos --fatal-warnings . || EXIT_CODE=$? + ;; + dartfmt) echo + echo -e '\033[1mTASK: dartfmt\033[22m' + echo -e 'dartfmt -n --set-exit-if-changed .' + dartfmt -n --set-exit-if-changed . || EXIT_CODE=$? + ;; + *) echo -e "\033[31mNot expecting TASK '${TASK}'. Error!\033[0m" + EXIT_CODE=1 + ;; + esac + + shift +done + +exit $EXIT_CODE diff --git a/webdev/.mono_repo.yml b/webdev/.mono_repo.yml new file mode 100644 index 000000000..77bede62c --- /dev/null +++ b/webdev/.mono_repo.yml @@ -0,0 +1,10 @@ +# See https://github.com/dart-lang/mono_repo for details +dart: + - dev + +stages: + - analyzer_and_format: + - dartfmt + - dartanalyzer: --fatal-infos --fatal-warnings . +# - unit_test: +# - test diff --git a/webdev/bin/webdev.dart b/webdev/bin/webdev.dart index 6c28c16fa..d88116ca4 100644 --- a/webdev/bin/webdev.dart +++ b/webdev/bin/webdev.dart @@ -1,7 +1,22 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'dart:async'; +import 'dart:io'; -import 'package:webdev/webdev.dart'; +import 'package:args/command_runner.dart'; +import 'package:io/ansi.dart'; +import 'package:io/io.dart'; +import 'package:webdev/src/webdev_command_runner.dart'; Future main(List args) async { - await webdevCommandRunner().run(args); + try { + await webdevCommandRunner().run(args); + } on UsageException catch (e) { + print(yellow.wrap(e.message)); + print(' '); + print(e.usage); + exitCode = ExitCode.usage.code; + } } diff --git a/webdev/example/lib/src/hello_world/hello_world.dart b/webdev/example/lib/src/hello_world/hello_world.dart deleted file mode 100644 index f67367f4a..000000000 --- a/webdev/example/lib/src/hello_world/hello_world.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:angular/angular.dart'; - -@Component( - selector: 'hello-world', - styleUrls: const ['hello_world.css'], - templateUrl: 'hello_world.html', -) -class HelloWorldComponent { - // Nothing here. -} diff --git a/webdev/example/lib/src/hello_world/hello_world.html b/webdev/example/lib/src/hello_world/hello_world.html deleted file mode 100644 index e5b22f94a..000000000 --- a/webdev/example/lib/src/hello_world/hello_world.html +++ /dev/null @@ -1 +0,0 @@ -
Hello World
diff --git a/webdev/example/pubspec.yaml b/webdev/example/pubspec.yaml deleted file mode 100644 index 5e4f3719d..000000000 --- a/webdev/example/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: webdev_example_app -description: A web app example for webdev CLI. -version: 0.0.1 - -environment: - sdk: ">=2.0.0-dev.3.0 <2.0.0" - -dependencies: - angular: ^5.0.0-alpha+3 - browser: ^0.10.0 - -dev_dependencies: - webdev: - 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 - ############################################################################## - -dependency_overrides: - # Necessary with angular: ^5.0.0-alpha+1 dependency. - analyzer: ^0.31.0-alpha.1 diff --git a/webdev/example/web/main.dart b/webdev/example/web/main.dart deleted file mode 100644 index 78477ff34..000000000 --- a/webdev/example/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:angular/angular.dart'; -import 'package:webdev_example_app/app_component.dart'; -import 'main.template.dart' as ng; - -main() { - bootstrapStatic(AppComponent, [/*providers*/], ng.initReflector); -} diff --git a/webdev/lib/src/command/build_command.dart b/webdev/lib/src/command/build_command.dart index ac1b646ca..d98c5fbe3 100644 --- a/webdev/lib/src/command/build_command.dart +++ b/webdev/lib/src/command/build_command.dart @@ -1,6 +1,8 @@ -import 'dart:async'; -import 'dart:isolate'; +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'build_runner_command_base.dart'; /// Command to execute pub run build_runner build. @@ -12,12 +14,5 @@ class BuildCommand extends BuildRunnerCommandBase { final description = 'Run builders to build a package.'; @override - 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; - } + Future run() => runCore('build'); } diff --git a/webdev/lib/src/command/build_runner_command_base.dart b/webdev/lib/src/command/build_runner_command_base.dart index 88f2fc0eb..a03bace6a 100644 --- a/webdev/lib/src/command/build_runner_command_base.dart +++ b/webdev/lib/src/command/build_runner_command_base.dart @@ -1,7 +1,13 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'dart:async'; import 'dart:io'; +import 'dart:isolate'; import 'package:args/command_runner.dart'; +import 'package:stack_trace/stack_trace.dart'; /// Extend to get a command with the arguments common to all build_runner /// commands. @@ -19,13 +25,97 @@ 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()); + Future runCore(String command) async { + final arguments = [command]..addAll(argResults.arguments); + + // Heavily inspired by dart-lang/build @ 0c77443dd7 + // /build_runner/bin/build_runner.dart#L58-L85 + var exitPort = new ReceivePort(); + var errorPort = new ReceivePort(); + var messagePort = new ReceivePort(); + var errorListener = errorPort.listen((e) { + stderr.writeln('\n\nYou have hit a bug in build_runner'); + stderr.writeln('Please file an issue with reproduction steps at ' + 'https://github.com/dart-lang/build/issues\n\n'); + final error = e[0]; + final trace = e[1] as String; + stderr.writeln(error); + stderr.writeln(new Trace.parse(trace).terse); + if (exitCode == 0) exitCode = 1; + }); + await Isolate.spawnUri( + await _buildRunnerScript(), arguments, messagePort.sendPort, + onExit: exitPort.sendPort, + onError: errorPort.sendPort, + automaticPackageResolution: true); + StreamSubscription exitCodeListener; + exitCodeListener = messagePort.listen((isolateExitCode) { + if (isolateExitCode is! int) { + throw new StateError( + 'Bad response from isolate, expected an exit code but got ' + '$isolateExitCode'); + } + exitCode = isolateExitCode as int; + exitCodeListener.cancel(); + exitCodeListener = null; + }); + await exitPort.first; + await errorListener.cancel(); + await exitCodeListener?.cancel(); } } + +Future _buildRunnerScript() async { + var dataUri = new Uri.dataFromString(_bootstrapScript); + + var messagePort = new ReceivePort(); + var exitPort = new ReceivePort(); + var errorPort = new ReceivePort(); + + await Isolate.spawnUri(dataUri, [], messagePort.sendPort, + onExit: exitPort.sendPort, + onError: errorPort.sendPort, + errorsAreFatal: true, + packageConfig: new Uri.file('.packages')); + + var allErrorsFuture = errorPort.forEach((error) { + var errorList = error as List; + var message = errorList[0] as String; + var stack = new StackTrace.fromString(errorList[1] as String); + + stderr.writeln(message); + stderr.writeln(stack); + }); + + var items = await Future.wait([ + messagePort.toList(), + allErrorsFuture, + exitPort.first.whenComplete(() { + messagePort.close(); + errorPort.close(); + }) + ]); + + var messages = items[0] as List; + if (messages.isEmpty) { + throw new StateError('An error occurred while running booting.'); + } + + assert(messages.length == 1); + return new Uri.file(messages.single as String); +} + +const _bootstrapScript = r''' +import 'dart:io'; +import 'dart:isolate'; + +import 'package:build_runner/build_script_generate.dart'; +import 'package:path/path.dart' as p; + +void main(List args, [SendPort sendPort]) async { + var buildScript = await generateBuildScript(); + var scriptFile = new File(scriptLocation)..createSync(recursive: true); + scriptFile.writeAsStringSync(buildScript); + sendPort.send(p.absolute(scriptLocation)); +} +'''; diff --git a/webdev/lib/src/command/serve_command.dart b/webdev/lib/src/command/serve_command.dart index a8ba022b7..790d52b97 100644 --- a/webdev/lib/src/command/serve_command.dart +++ b/webdev/lib/src/command/serve_command.dart @@ -1,5 +1,8 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'dart:async'; -import 'dart:isolate'; import 'build_runner_command_base.dart'; @@ -12,21 +15,21 @@ class ServeCommand extends BuildRunnerCommandBase { final description = 'Run a local web development server and a file system' ' watcher that re-builds on changes.'; + @override + String get invocation => '${super.invocation} [[:]]...'; + ServeCommand() { // TODO(nshahan) Expose more args passed to build_runner serve. // build_runner might expose args for use in wrapping scripts like this one. argParser ..addOption('hostname', - defaultsTo: 'localhost', help: 'Specify the hostname to serve on.'); + help: 'Specify the hostname to serve on', defaultsTo: 'localhost') + ..addFlag('log-requests', + defaultsTo: false, + negatable: false, + help: 'Enables logging for each request to the server.'); } @override - 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; - } + Future run() => runCore('serve'); } diff --git a/webdev/lib/src/webdev_command_runner.dart b/webdev/lib/src/webdev_command_runner.dart index 1dbdd4133..c2a7c02b5 100644 --- a/webdev/lib/src/webdev_command_runner.dart +++ b/webdev/lib/src/webdev_command_runner.dart @@ -1,3 +1,7 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + import 'package:args/command_runner.dart'; import 'command/build_command.dart'; diff --git a/webdev/lib/webdev.dart b/webdev/lib/webdev.dart deleted file mode 100644 index 97ed18291..000000000 --- a/webdev/lib/webdev.dart +++ /dev/null @@ -1 +0,0 @@ -export 'src/webdev_command_runner.dart'; diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 5796813f4..eadcaa2df 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -2,17 +2,15 @@ name: webdev description: A CLI for Dart web development. author: Dart Team homepage: https://github.com/dart-lang/webdev +version: 0.1.0-dev environment: - sdk: ">=2.0.0-dev.3.0 <2.0.0" + sdk: ">=2.0.0-dev.32.0 <2.0.0" 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 + io: ^0.3.2+1 + stack_trace: ^1.9.2 -dev_dependencies: - test: "^0.12.0" +executables: + webdev: