Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library pub.executable; | 5 library pub.executable; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:barback/barback.dart'; | 10 import 'package:barback/barback.dart'; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 /// The executable string is a relative Dart file path using native path | 25 /// The executable string is a relative Dart file path using native path |
| 26 /// separators without a trailing ".dart" extension. It is contained within | 26 /// separators without a trailing ".dart" extension. It is contained within |
| 27 /// [package], which should either be the entrypoint package or an immediate | 27 /// [package], which should either be the entrypoint package or an immediate |
| 28 /// dependency of it. | 28 /// dependency of it. |
| 29 /// | 29 /// |
| 30 /// Arguments from [args] will be passed to the spawned Dart application. | 30 /// Arguments from [args] will be passed to the spawned Dart application. |
| 31 /// | 31 /// |
| 32 /// Returns the exit code of the spawned app. | 32 /// Returns the exit code of the spawned app. |
| 33 Future<int> runExecutable(PubCommand command, Entrypoint entrypoint, | 33 Future<int> runExecutable(PubCommand command, Entrypoint entrypoint, |
| 34 String package, String executable, Iterable<String> args, | 34 String package, String executable, Iterable<String> args, |
| 35 {bool isGlobal: false}) { | 35 {bool isGlobal: false}) async { |
| 36 // Unless the user overrides the verbosity, we want to filter out the | 36 // Unless the user overrides the verbosity, we want to filter out the |
| 37 // normal pub output shown while loading the environment. | 37 // normal pub output shown while loading the environment. |
| 38 if (log.verbosity == log.Verbosity.NORMAL) { | 38 if (log.verbosity == log.Verbosity.NORMAL) { |
| 39 log.verbosity = log.Verbosity.WARNING; | 39 log.verbosity = log.Verbosity.WARNING; |
| 40 } | 40 } |
| 41 | 41 |
| 42 var snapshotPath = p.join(".pub", "bin", package, | 42 var snapshotPath = p.join(".pub", "bin", package, |
| 43 "$executable.dart.snapshot"); | 43 "$executable.dart.snapshot"); |
| 44 if (!isGlobal && fileExists(snapshotPath)) { | 44 if (!isGlobal && fileExists(snapshotPath)) { |
| 45 return _runCachedExecutable(entrypoint, snapshotPath, args); | 45 return _runCachedExecutable(entrypoint, snapshotPath, args); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 57 } else if (package != entrypoint.root.name) { | 57 } else if (package != entrypoint.root.name) { |
| 58 command.usageError( | 58 command.usageError( |
| 59 "Cannot run an executable in a subdirectory of a dependency."); | 59 "Cannot run an executable in a subdirectory of a dependency."); |
| 60 } | 60 } |
| 61 | 61 |
| 62 rootDir = parts.first; | 62 rootDir = parts.first; |
| 63 } else { | 63 } else { |
| 64 executable = p.join("bin", executable); | 64 executable = p.join("bin", executable); |
| 65 } | 65 } |
| 66 | 66 |
| 67 var environment; | |
| 68 // TODO(nweiz): Use [packages] to only load assets from packages that the | 67 // TODO(nweiz): Use [packages] to only load assets from packages that the |
| 69 // executable might load. | 68 // executable might load. |
| 70 return AssetEnvironment.create(entrypoint, BarbackMode.RELEASE, | 69 var environment = await AssetEnvironment.create(entrypoint, |
| 71 useDart2JS: false).then((_environment) { | 70 BarbackMode.RELEASE, useDart2JS: false); |
| 72 environment = _environment; | 71 environment.barback.errors.listen((error) { |
| 72 log.error(log.red("Build error:\n$error")); | |
| 73 }); | |
| 73 | 74 |
| 74 environment.barback.errors.listen((error) { | 75 var server; |
| 75 log.error(log.red("Build error:\n$error")); | 76 if (package == entrypoint.root.name) { |
| 76 }); | 77 // Serve the entire root-most directory containing the entrypoint. That |
| 77 | 78 // ensures that, for example, things like `import '../../utils.dart';` |
| 78 if (package == entrypoint.root.name) { | 79 // will work from within some deeply nested script. |
| 79 // Serve the entire root-most directory containing the entrypoint. That | 80 server = await environment.serveDirectory(rootDir); |
| 80 // ensures that, for example, things like `import '../../utils.dart';` | 81 } else { |
| 81 // will work from within some deeply nested script. | |
| 82 return environment.serveDirectory(rootDir); | |
| 83 } | |
| 84 | |
| 85 // Make sure the dependency exists. | 82 // Make sure the dependency exists. |
| 86 var dep = entrypoint.root.immediateDependencies.firstWhere( | 83 var dep = entrypoint.root.immediateDependencies.firstWhere( |
| 87 (dep) => dep.name == package, orElse: () => null); | 84 (dep) => dep.name == package, orElse: () => null); |
| 88 if (dep == null) { | 85 if (dep == null) { |
| 89 if (environment.graph.packages.containsKey(package)) { | 86 if (environment.graph.packages.containsKey(package)) { |
| 90 dataError('Package "$package" is not an immediate dependency.\n' | 87 dataError('Package "$package" is not an immediate dependency.\n' |
| 91 'Cannot run executables in transitive dependencies.'); | 88 'Cannot run executables in transitive dependencies.'); |
| 92 } else { | 89 } else { |
| 93 dataError('Could not find package "$package". Did you forget to ' | 90 dataError('Could not find package "$package". Did you forget to ' |
| 94 'add a dependency?'); | 91 'add a dependency?'); |
| 95 } | 92 } |
| 96 } | 93 } |
| 97 | 94 |
| 98 // For other packages, always use the "bin" directory. | 95 // For other packages, always use the "bin" directory. |
| 99 return environment.servePackageBinDirectory(package); | 96 server = await environment.servePackageBinDirectory(package); |
| 100 }).then((server) { | 97 } |
| 101 // Try to make sure the entrypoint script exists (or is generated) before | |
| 102 // we spawn the process to run it. | |
| 103 var assetPath = "${p.url.joinAll(p.split(executable))}.dart"; | |
| 104 var id = new AssetId(server.package, assetPath); | |
| 105 return environment.barback.getAssetById(id).then((_) { | |
| 106 var vmArgs = []; | |
| 107 | 98 |
| 108 // Run in checked mode. | 99 // Try to make sure the entrypoint script exists (or is generated) before |
| 109 // TODO(rnystrom): Make this configurable. | 100 // we spawn the process to run it. |
| 110 vmArgs.add("--checked"); | 101 var assetPath = "${p.url.joinAll(p.split(executable))}.dart"; |
| 102 var id = new AssetId(server.package, assetPath); | |
| 103 // TODO(rnystrom): Use try/catch here when | |
| 104 // https://github.com/dart-lang/async_await/issues/4 is fixed. | |
| 105 return environment.barback.getAssetById(id).then((_) async { | |
| 106 var vmArgs = []; | |
| 111 | 107 |
| 112 // Get the URL of the executable, relative to the server's root directory. | 108 // Run in checked mode. |
| 113 var relativePath = p.url.relative(assetPath, | 109 // TODO(rnystrom): Make this configurable. |
| 114 from: p.url.joinAll(p.split(server.rootDirectory))); | 110 vmArgs.add("--checked"); |
| 115 vmArgs.add(server.url.resolve(relativePath).toString()); | |
| 116 vmArgs.addAll(args); | |
| 117 | 111 |
| 118 return Process.start(Platform.executable, vmArgs).then((process) { | 112 // Get the URL of the executable, relative to the server's root directory. |
| 119 // Note: we're not using process.std___.pipe(std___) here because | 113 var relativePath = p.url.relative(assetPath, |
| 120 // that prevents pub from also writing to the output streams. | 114 from: p.url.joinAll(p.split(server.rootDirectory))); |
| 121 process.stderr.listen(stderr.add); | 115 vmArgs.add(server.url.resolve(relativePath).toString()); |
| 122 process.stdout.listen(stdout.add); | 116 vmArgs.addAll(args); |
| 123 stdin.listen(process.stdin.add); | |
| 124 | 117 |
| 125 return process.exitCode; | 118 var process = await Process.start(Platform.executable, vmArgs); |
| 126 }); | 119 // Note: we're not using process.std___.pipe(std___) here because |
| 127 }).catchError((error, stackTrace) { | 120 // that prevents pub from also writing to the output streams. |
| 128 if (error is! AssetNotFoundException) throw error; | 121 process.stderr.listen(stderr.add); |
| 122 process.stdout.listen(stdout.add); | |
| 123 stdin.listen(process.stdin.add); | |
| 129 | 124 |
| 130 var message = "Could not find ${log.bold(executable + ".dart")}"; | 125 return process.exitCode; |
| 131 if (package != entrypoint.root.name) { | 126 }).catchError((error, stackTrace) { |
| 132 message += " in package ${log.bold(server.package)}"; | 127 if (error is! AssetNotFoundException) throw error; |
| 133 } | |
| 134 | 128 |
| 135 log.error("$message."); | 129 var message = "Could not find ${log.bold(executable + ".dart")}"; |
| 136 log.fine(new Chain.forTrace(stackTrace)); | 130 if (package != entrypoint.root.name) { |
| 137 return exit_codes.NO_INPUT; | 131 message += " in package ${log.bold(server.package)}"; |
| 138 }); | 132 } |
| 133 | |
| 134 log.error("$message."); | |
| 135 log.fine(new Chain.forTrace(stackTrace)); | |
| 136 return exit_codes.NO_INPUT; | |
| 139 }); | 137 }); |
| 140 } | 138 } |
| 141 | 139 |
| 142 /// Runs the executable snapshot at [snapshotPath]. | 140 /// Runs the executable snapshot at [snapshotPath]. |
| 143 Future _runCachedExecutable(Entrypoint entrypoint, String snapshotPath, | 141 Future _runCachedExecutable(Entrypoint entrypoint, String snapshotPath, |
| 144 List<String> args) { | 142 List<String> args) async { |
| 145 return syncFuture(() { | 143 // If the snapshot was compiled with a different SDK version, we need to |
| 146 // If the snapshot was compiled with a different SDK version, we need to | 144 // recompile it. |
| 147 // recompile it. | 145 var sdkVersionPath = p.join(".pub", "bin", "sdk-version"); |
| 148 var sdkVersionPath = p.join(".pub", "bin", "sdk-version"); | 146 if (fileExists(sdkVersionPath) && |
| 149 if (fileExists(sdkVersionPath) && | 147 readTextFile(sdkVersionPath) == "${sdk.version}\n") { |
| 150 readTextFile(sdkVersionPath) == "${sdk.version}\n") { | 148 return null; |
| 151 return null; | 149 } |
| 152 } | |
| 153 | 150 |
| 154 log.fine("Precompiled executables are out of date."); | 151 log.fine("Precompiled executables are out of date."); |
| 155 return entrypoint.precompileExecutables(); | 152 await entrypoint.precompileExecutables(); |
| 156 }).then((_) { | |
| 157 var vmArgs = ["--checked", snapshotPath]..addAll(args); | |
| 158 | 153 |
| 159 return Process.start(Platform.executable, vmArgs).then((process) { | 154 // TODO(rnystrom): Use cascade here when async_await compiler supports it. |
|
nweiz
2014/08/29 22:27:39
Link this to an issue.
Bob Nystrom
2014/08/29 23:03:20
Done.
| |
| 160 // Note: we're not using process.std___.pipe(std___) here because | 155 var vmArgs = ["--checked", snapshotPath]; |
| 161 // that prevents pub from also writing to the output streams. | 156 vmArgs.addAll(args); |
| 162 process.stderr.listen(stderr.add); | |
| 163 process.stdout.listen(stdout.add); | |
| 164 stdin.listen(process.stdin.add); | |
| 165 | 157 |
| 166 return process.exitCode; | 158 var process = await Process.start(Platform.executable, vmArgs); |
| 167 }); | 159 // Note: we're not using process.std___.pipe(std___) here because |
| 168 }); | 160 // that prevents pub from also writing to the output streams. |
| 161 process.stderr.listen(stderr.add); | |
| 162 process.stdout.listen(stdout.add); | |
| 163 stdin.listen(process.stdin.add); | |
| 164 | |
| 165 return process.exitCode; | |
| 169 } | 166 } |
| OLD | NEW |