Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Unified Diff: sdk/lib/_internal/pub/lib/src/command/serve.dart

Issue 167103003: Support serving from multiple directories using "pub serve". (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/pub/lib/src/command/serve.dart
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index a03bdd9904d967b2992395de588b146178c9a413..f7d91cb9635233321deccb7c867b9929bfa64108 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -5,8 +5,10 @@
library pub.command.serve;
import 'dart:async';
+import 'dart:math' as math;
import 'package:barback/barback.dart';
+import 'package:path/path.dart' as p;
import '../barback/build_environment.dart';
import '../barback/pub_package_provider.dart';
@@ -20,8 +22,12 @@ final _arrow = getSpecial('\u2192', '=>');
/// Handles the `serve` pub command.
class ServeCommand extends PubCommand {
- String get description => "Run a local web development server.";
- String get usage => "pub serve";
+ String get description =>
+ 'Run a local web development server.\n\n'
+ 'By default, this serves "web/" and "test/", but an explicit list of \n'
+ 'directories to serve can be provided as well.';
+ String get usage => "pub serve [directories...]";
+ final takesArguments = true;
PubPackageProvider _provider;
@@ -35,7 +41,7 @@ class ServeCommand extends PubCommand {
ServeCommand() {
commandParser.addOption('port', defaultsTo: '8080',
- help: 'The port to listen on.');
+ help: 'The base port to listen on.');
// A hidden option for the tests to work around a bug in some of the OS X
// bots where "localhost" very rarely resolves to the IPv4 loopback address
@@ -66,24 +72,26 @@ class ServeCommand extends PubCommand {
WatcherType.POLLING : WatcherType.AUTO;
return BuildEnvironment.create(entrypoint, hostname, port, mode,
- watcherType, ["web"].toSet(),
+ watcherType, _directoriesToServe,
useDart2JS: useDart2JS).then((environment) {
// In release mode, strip out .dart files since all relevant ones have
// been compiled to JavaScript already.
if (mode == BarbackMode.RELEASE) {
- environment.server.allowAsset = (url) => !url.path.endsWith(".dart");
+ for (var server in environment.servers) {
+ server.allowAsset = (url) => !url.path.endsWith(".dart");
+ }
}
/// This completer is used to keep pub running (by not completing) and
/// to pipe fatal errors to pub's top-level error-handling machinery.
var completer = new Completer();
- environment.server.barback.errors.listen((error) {
+ environment.barback.errors.listen((error) {
log.error(log.red("Build error:\n$error"));
});
- environment.server.barback.results.listen((result) {
+ environment.barback.results.listen((result) {
if (result.succeeded) {
// TODO(rnystrom): Report using growl/inotify-send where available.
log.message("Build completed ${log.green('successfully')}");
@@ -95,28 +103,79 @@ class ServeCommand extends PubCommand {
if (!completer.isCompleted) completer.completeError(error, stackTrace);
});
- environment.server.results.listen((result) {
- if (result.isSuccess) {
- log.message("${log.green('GET')} ${result.url.path} $_arrow "
- "${result.id}");
- return;
- }
-
- var msg = "${log.red('GET')} ${result.url.path} $_arrow";
- var error = result.error.toString();
- if (error.contains("\n")) {
- log.message("$msg\n${prefixLines(error)}");
- } else {
- log.message("$msg $error");
- }
- }, onError: (error, [stackTrace]) {
- if (!completer.isCompleted) completer.completeError(error, stackTrace);
- });
-
- log.message("Serving ${entrypoint.root.name} "
- "on http://$hostname:${environment.server.port}");
+ var directoryLength = environment.servers
+ .map((server) => server.rootDirectory.length)
+ .reduce(math.max);
+ for (var server in environment.servers) {
+ // Add three characters to account for "[", "/", and "]".
+ var directoryPrefix = log.gray(
+ padRight("[${server.rootDirectory}/]", directoryLength + 3));
Bob Nystrom 2014/02/19 00:36:52 Nit, but I think I'd prefer not showing the "/" he
nweiz 2014/02/19 01:25:58 Done.
+ server.results.listen((result) {
+ if (result.isSuccess) {
+ log.message("$directoryPrefix ${log.green('GET')} "
+ "${result.url.path} $_arrow ${result.id}");
+ return;
+ }
+
+ var msg = "$directoryPrefix ${log.red('GET')} ${result.url.path} "
+ "$_arrow";
+ var error = result.error.toString();
+ if (error.contains("\n")) {
+ log.message("$msg\n${prefixLines(error)}");
+ } else {
+ log.message("$msg $error");
+ }
+ }, onError: (error, [stackTrace]) {
+ if (completer.isCompleted) return;
+ completer.completeError(error, stackTrace);
+ });
+
+ log.message("Serving ${entrypoint.root.name} "
+ "${padRight(server.rootDirectory + '/', directoryLength + 1)} "
+ "on ${log.bold('http://$hostname:${server.port}')}");
+ }
return completer.future;
});
}
+
+ /// Returns the set of directories that will be served from servers exposed to
+ /// the user.
Bob Nystrom 2014/02/19 00:36:52 Document that it may throw a UsageException if the
nweiz 2014/02/19 01:25:58 Done.
+ Set<String> get _directoriesToServe {
+ if (commandOptions.rest.isEmpty) {
+ var directories = ['web', 'test'].where(dirExists).toSet();
+ if (directories.isNotEmpty) return directories;
+ usageError('Neither "web/" nor "test/" exist to serve from.');
+ }
+
+ var directories = commandOptions.rest.map(p.normalize).toSet();
+ var invalid = directories.where((dir) => !isBeneath(dir, '.'));
+ if (invalid.isNotEmpty) {
+ usageError("${_directorySentence(invalid, "isn't", "aren't")} in this "
+ "package.");
+ }
+
+ var nonExistent = directories.where((dir) => !dirExists(dir));
+ if (nonExistent.isNotEmpty) {
+ usageError("${_directorySentence(nonExistent, "doesn't", "don't")} "
+ "exist.");
+ }
+
+ return directories;
+ }
+
+ /// Converts a list of [directoryNames] to a sentence.
+ ///
+ /// After the list of directories, [singularVerb] will be used if there is
+ /// only one directory and [pluralVerb] will be used if there are more than
+ /// one.
+ String _directorySentence(Iterable<String> directoryNames,
+ String singularVerb, String pluralVerb) {
+ var directories = pluralize('Directory', directoryNames.length,
+ plural: 'Directories');
+ var names = toSentence(ordered(directoryNames).map((dir) => '"$dir/"'));
+ var verb = pluralize(singularVerb, directoryNames.length,
+ plural: pluralVerb);
+ return "$directories $names $verb";
+ }
}

Powered by Google App Engine
This is Rietveld 408576698