Chromium Code Reviews| Index: sdk/lib/_internal/pub/lib/src/command/run.dart |
| diff --git a/sdk/lib/_internal/pub/lib/src/command/run.dart b/sdk/lib/_internal/pub/lib/src/command/run.dart |
| index 73b62be8b425e433c0ab2575ae089b1623b2aa3a..5973ca78bc1ae743f63126694358719fba37edaf 100644 |
| --- a/sdk/lib/_internal/pub/lib/src/command/run.dart |
| +++ b/sdk/lib/_internal/pub/lib/src/command/run.dart |
| @@ -39,6 +39,8 @@ class RunCommand extends PubCommand { |
| } |
| var environment; |
| + var package = entrypoint.root.name; |
| + var rootDir; |
| var scriptPath; |
| var args; |
| return AssetEnvironment.create(entrypoint, BarbackMode.RELEASE, |
| @@ -55,40 +57,64 @@ class RunCommand extends PubCommand { |
| var script = commandOptions.rest[0]; |
| args = commandOptions.rest.skip(1).toList(); |
| + // A command like "foo:bar" runs the "bar" script from the "foo" package. |
| + // If there is no colon prefix, default to the root package. |
| + if (script.contains(":")) { |
|
Sean Eagan
2014/06/20 12:42:38
Instead of inventing a syntax for this:
pub r
Bob Nystrom
2014/06/20 17:35:27
My hunch is that this will be a very common use ca
|
| + var components = split1(script, ":"); |
| + package = components[0]; |
| + script = components[1]; |
| + |
| + var dep = entrypoint.root.immediateDependencies.firstWhere( |
| + (dep) => dep.name == package, orElse: () => null); |
| + if (dep == null) { |
| + if (environment.graph.packages.containsKey(package)) { |
| + dataError('Package "$package" is not an immediate dependency.\n' |
| + 'Cannot run executables in transitive dependencies.'); |
| + } else { |
| + dataError('Could not find package "$package". Did you forget to ' |
| + 'add a dependency?'); |
| + } |
| + } |
| + } |
| + |
| // If the command has a path separator, then it's a path relative to the |
| // root of the package. Otherwise, it's implicitly understood to be in |
| // "bin". |
| - var rootDir; |
| var parts = path.split(script); |
| if (parts.length > 1) { |
| - scriptPath = "$script.dart"; |
| + if (package != entrypoint.root.name) { |
| + usageError("Can not run an executable in a subdirectory of a " |
| + "dependency."); |
| + } |
| + |
| + scriptPath = "${path.url.joinAll(parts.skip(1))}.dart"; |
| rootDir = parts.first; |
| } else { |
| - scriptPath = "bin/$script.dart"; |
| + scriptPath = "$script.dart"; |
| rootDir = "bin"; |
| } |
| - // Serve the entire root-most directory containing the entrypoint. That |
| - // ensures that, for example, things like `import '../../utils.dart';` |
| - // will work from within some deeply nested script. |
| - return environment.serveDirectory(rootDir); |
| + if (package == entrypoint.root.name) { |
| + // Serve the entire root-most directory containing the entrypoint. That |
| + // ensures that, for example, things like `import '../../utils.dart';` |
| + // will work from within some deeply nested script. |
| + return environment.serveDirectory(rootDir); |
| + } else { |
| + // For other packages, always use the "bin" directory. |
| + return environment.servePackageBinDirectory(package); |
| + } |
| }).then((server) { |
| // Try to make sure the entrypoint script exists (or is generated) before |
| // we spawn the process to run it. |
| return environment.barback.getAssetById( |
| - new AssetId(entrypoint.root.name, scriptPath)).then((_) { |
| - return environment.getUrlsForAssetPath(scriptPath).then((urls) { |
| - // Should only be bound to one port. |
| - assert(urls.length == 1); |
| - |
| - // Run in checked mode. |
| - // TODO(rnystrom): Make this configurable. |
| - args.insert(0, "--checked"); |
| - |
| - // The URL to the Dart entrypoint comes before the script arguments. |
| - args.insert(1, urls[0].toString()); |
| - return Process.start(Platform.executable, args); |
| - }).then((process) { |
| + new AssetId(package, path.url.join(rootDir, scriptPath))).then((_) { |
| + |
| + // Run in checked mode. |
| + // TODO(rnystrom): Make this configurable. |
| + var mode = "--checked"; |
| + args = [mode, server.url.resolve(scriptPath).toString()]..addAll(args); |
| + |
| + return Process.start(Platform.executable, args).then((process) { |
| // Note: we're not using process.std___.pipe(std___) here because |
| // that prevents pub from also writing to the output streams. |
| process.stderr.listen(stderr.add); |
| @@ -100,7 +126,12 @@ class RunCommand extends PubCommand { |
| }).catchError((error, stackTrace) { |
| if (error is! AssetNotFoundException) throw error; |
| - log.error("Could not find $scriptPath."); |
| + var message = "Could not find ${path.join(rootDir, scriptPath)}"; |
| + if (package != entrypoint.root.name) { |
| + message += " in package $package"; |
| + } |
| + |
| + log.error("$message."); |
| log.fine(new Chain.forTrace(stackTrace)); |
| return flushThenExit(exit_codes.NO_INPUT); |
| }); |