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 |