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

Side by Side Diff: mojo/dart/mojom/lib/generate.dart

Issue 1210253006: Dart: Allows the mojom package's generate script to download .mojoms. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 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 unified diff | Download patch
« no previous file with comments | « no previous file | mojo/dart/mojom/lib/src/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /// This script should be run by every project that consumes Mojom IDL 5 /// This script should be run by every project that consumes Mojom IDL
6 /// interfaces. It populates the 'mojom' package with the generated Dart 6 /// interfaces. It populates the 'mojom' package with the generated Dart
7 /// bindings for the Mojom IDL files. 7 /// bindings for the Mojom IDL files.
8 /// 8 ///
9 /// From a consuming project, it should be invoked as follows: 9 /// From a consuming project, it should be invoked as follows:
10 /// 10 ///
11 /// $ dart packages/mojom/generate.dart [-p package-root] 11 /// $ dart packages/mojom/generate.dart [-p package-root]
12 /// [-a additional-dirs] 12 /// [-a additional-dirs]
13 /// [-m mojo-sdk] 13 /// [-m mojo-sdk]
14 /// [-g] # Generate from .mojom files 14 /// [-g] # Generate from .mojom files
15 /// [-d] # Download from .mojoms files
15 /// [-v] # verbose 16 /// [-v] # verbose
16 /// [-d] # Dry run 17 /// [-f] # Fake (dry) run
18
19 library generate;
17 20
18 import 'dart:async'; 21 import 'dart:async';
22 import 'dart:convert';
19 import 'dart:io'; 23 import 'dart:io';
20 24
21 import 'package:args/args.dart' as args; 25 import 'package:args/args.dart' as args;
22 import 'package:path/path.dart' as path; 26 import 'package:path/path.dart' as path;
23 27
28 part 'src/utils.dart';
29
24 bool verbose; 30 bool verbose;
25 bool dryRun; 31 bool dryRun;
26 32
27 bool isMojomDart(String path) => path.endsWith('.mojom.dart');
28 bool isMojom(String path) => path.endsWith('.mojom');
29
30 /// An Error for problems on the command line.
31 class CommandLineError extends Error {
32 final _msg;
33 CommandLineError(this._msg);
34 toString() => _msg;
35 }
36
37 /// An Error for failures of the bindings generation script.
38 class GenerationError extends Error {
39 final _msg;
40 GenerationError(this._msg);
41 toString() => _msg;
42 }
43
44 /// The base type of data passed to actions for [mojomDirIter].
45 class PackageIterData {
46 final Directory _mojomPackage;
47 PackageIterData(this._mojomPackage);
48 Directory get mojomPackage => _mojomPackage;
49 }
50
51 /// Data for [mojomDirIter] that includes the path to the Mojo SDK for bindings
52 /// generation.
53 class GenerateIterData extends PackageIterData {
54 final Directory _mojoSdk;
55 GenerateIterData(this._mojoSdk, Directory mojomPackage)
56 : super(mojomPackage);
57 Directory get mojoSdk => _mojoSdk;
58 }
59
60 /// The type of action performed by [mojomDirIter].
61 typedef Future MojomAction(PackageIterData data, Directory mojomDirectory);
62
63 /// Iterates over mojom directories of Dart packages, taking some action for
64 /// each.
65 ///
66 /// For each 'mojom' subdirectory of each subdirectory in [packages], runs
67 /// [action] on the subdirectory passing along [data] to [action].
68 mojomDirIter(
69 Directory packages, PackageIterData data, MojomAction action) async {
70 await for (var package in packages.list()) {
71 if (package is Directory) {
72 if (package.path == data.mojomPackage.path) continue;
73 if (verbose) print("package = $package");
74 final mojomDirectory = new Directory(path.join(package.path, 'mojom'));
75 if (verbose) print("looking for = $mojomDirectory");
76 if (await mojomDirectory.exists()) {
77 await action(data, mojomDirectory);
78 } else if (verbose) {
79 print("$mojomDirectory not found");
80 }
81 }
82 }
83 }
84
85
86 /// Searches for .mojom.dart files under [mojomDirectory] and copies them to 33 /// Searches for .mojom.dart files under [mojomDirectory] and copies them to
87 /// the 'mojom' packages. 34 /// the 'mojom' packages.
88 copyAction(PackageIterData data, Directory mojomDirectory) async { 35 copyAction(PackageIterData data, Directory mojomDirectory) async {
89 await for (var mojom in mojomDirectory.list(recursive: true)) { 36 await for (var mojom in mojomDirectory.list(recursive: true)) {
90 if (mojom is! File) continue; 37 if (mojom is! File) continue;
91 if (!isMojomDart(mojom.path)) continue; 38 if (!isMojomDart(mojom.path)) continue;
92 if (verbose) print("Found $mojom"); 39 if (verbose) print("Found $mojom");
93 40
94 final relative = path.relative(mojom.path, from: mojomDirectory.path); 41 final relative = path.relative(mojom.path, from: mojomDirectory.path);
95 final dest = path.join(data.mojomPackage.path, relative); 42 final dest = path.join(data.mojomPackage.path, relative);
96 final destDirectory = new Directory(path.dirname(dest)); 43 final destDirectory = new Directory(path.dirname(dest));
97 44
98 if (verbose || dryRun) { 45 if (verbose || dryRun) {
99 print('Copying $mojom to $dest'); 46 print('Copying $mojom to $dest');
100 } 47 }
101 48
102 if (!dryRun) { 49 if (!dryRun) {
103 final File source = new File(mojom.path); 50 final File source = new File(mojom.path);
104 if (verbose) print("Ensuring $destDirectory exists"); 51 if (verbose) print("Ensuring $destDirectory exists");
105 await destDirectory.create(recursive: true); 52 await destDirectory.create(recursive: true);
106 source.copy(dest); 53 source.copy(dest);
107 } 54 }
108 } 55 }
109 } 56 }
110 57
111
112 /// Searches for .mojom files under [mojomDirectory], generates .mojom.dart 58 /// Searches for .mojom files under [mojomDirectory], generates .mojom.dart
113 /// files for them, and copies them to the 'mojom' package. 59 /// files for them, and copies them to the 'mojom' package.
114 generateAction(GenerateIterData data, Directory mojomDirectory) async { 60 generateAction(GenerateIterData data, Directory mojomDirectory) async {
115 await for (var mojom in mojomDirectory.list(recursive: true)) { 61 await for (var mojom in mojomDirectory.list(recursive: true)) {
116 if (mojom is! File) continue; 62 if (mojom is! File) continue;
117 if (!isMojom(mojom.path)) continue; 63 if (!isMojom(mojom.path)) continue;
118 if (verbose) print("Found $mojom"); 64 if (verbose) print("Found $mojom");
119 65
120 final script = path.join(data.mojoSdk.path, 66 final script = path.join(data.mojoSdk.path,
121 'mojo', 'public', 'tools', 'bindings', 'mojom_bindings_generator.py'); 67 'tools', 'bindings', 'mojom_bindings_generator.py');
68 final sdkInc = path.normalize(path.join(data.mojoSdk.path, '..', '..'));
122 final outputDir = await data.mojomPackage.createTemp(); 69 final outputDir = await data.mojomPackage.createTemp();
123 final output = outputDir.path; 70 final output = outputDir.path;
124 final arguments = [ 71 final arguments = [
125 '--use_bundled_pylibs', 72 '--use_bundled_pylibs',
73 '-g', 'dart',
126 '-o', output, 74 '-o', output,
127 // TODO(zra): Are other include paths needed? 75 // TODO(zra): Are other include paths needed?
128 '-I', data.mojoSdk.path, 76 '-I', sdkInc,
129 '-I', mojomDirectory.path, 77 '-I', mojomDirectory.path,
130 mojom.path]; 78 mojom.path];
131 79
132 if (verbose || dryRun) { 80 if (verbose || dryRun) {
133 print('Generating $mojom'); 81 print('Generating $mojom');
134 print('$script ${arguments.join(" ")}'); 82 print('$script ${arguments.join(" ")}');
135 } 83 }
136 if (!dryRun) { 84 if (!dryRun) {
137 final result = await Process.run(script, arguments); 85 final result = await Process.run(script, arguments);
138 if (result.exitCode != 0) { 86 if (result.exitCode != 0) {
139 throw new GenerationError("$script failed:\n${result.stderr}"); 87 throw new GenerationError("$script failed:\n${result.stderr}");
140 } 88 }
141 // Generated .mojom.dart is under $output/dart-gen/mojom/lib/X 89 // Generated .mojom.dart is under $output/dart-gen/mojom/lib/X
142 // Move X to $mojomPackage. Then rm -rf $output 90 // Move X to $mojomPackage. Then rm -rf $output
143 final generatedDirName = path.join(output, 'dart-gen', 'mojom', 'lib'); 91 final generatedDirName = path.join(output, 'dart-gen', 'mojom', 'lib');
144 final generatedDir = new Directory(generatedDirName); 92 final generatedDir = new Directory(generatedDirName);
145 93
146 await copyAction(data, generatedDir); 94 await copyAction(data, generatedDir);
147 95
148 await outputDir.delete(recursive: true); 96 await outputDir.delete(recursive: true);
149 } 97 }
150 } 98 }
151 } 99 }
152 100
101 /// In each package, look for a file named .mojoms. Populate a package's
102 /// mojom direcoty with the downloaded mojoms, creating the directory if needed.
Cutch 2015/07/20 15:39:09 direcoty -> directory
zra 2015/07/20 21:09:05 Done.
103 /// The .mojoms file should be formatted as follows:
104 /// '''
105 /// root: https://www.example.com/mojoms
Cutch 2015/07/20 15:39:08 Why use a stateful format over a list of uris?
zra 2015/07/20 21:09:05 Related mojoms can import each other. The conventi
106 /// path/to/some/mojom1.mojom
107 /// path/to/some/other/mojom2.mojom
108 ///
109 /// root: https://www.example-two.com/mojoms
110 /// path/to/example/two/mojom1.mojom
111 /// ...
112 ///
113 /// Lines beginning with '#' are ignored.
114 downloadAction(GenerateIterData data, Directory packageDirectory) async {
115 var mojomsPath = path.join(packageDirectory.path, '.mojoms');
116 var mojomsFile = new File(mojomsPath);
117 if (!await mojomsFile.exists()) return;
118 if (verbose) print("Found .mojoms file: $mojomsPath");
119
120 Directory mojomsDir;
121 var httpClient = new HttpClient();
122 int repoCount = 0;
123 int mojomCount = 0;
124 String repoRoot;
125 for (String line in await mojomsFile.readAsLines()) {
126 if (line.isEmpty || line.startsWith('#')) continue;
Cutch 2015/07/20 15:39:08 strip leading whitespace?
zra 2015/07/20 21:09:05 Done.
127
128 if (line.startsWith('root:')) {
129 if ((mojomsDir != null) && (mojomCount == 0)) {
130 throw new DownloadError("root with no mojoms: $repoRoot");
131 }
132 mojomCount = 0;
133 var rootWords = line.split(" ");
134 if (rootWords.length != 2) {
135 throw new DownloadError("Malformed root: $line");
136 }
137 repoRoot = rootWords[1];
138 if (verbose) print("Found repo root: $repoRoot");
139 if (!repoRoot.startsWith('https://')) {
Cutch 2015/07/20 15:39:08 What if I want to use http?
zra 2015/07/20 21:09:05 Removed restriction as discussed.
140 throw new DownloadError(
141 'Mojom repo "root" should be an https URL: $line');
142 }
143 mojomsDir = new Directory(path.join(
144 packageDirectory.parent.path, 'mojm.repo.$repoCount', 'mojom'));
145 await mojomsDir.create(recursive: true);
146 repoCount++;
147 } else {
148 if (mojomsDir == null) {
149 throw new DownloadError('Malformed .mojoms file: $mojomsPath');
150 }
151 String url = "$repoRoot/$line";
152 if (verbose) print("Found $url");
153 String fileString = await getUrl(httpClient, url);
154 if (verbose) print("Downloaded $url");
155 String filePath = path.join(mojomsDir.path, line);
156 var file = new File(filePath);
157 if (!await file.exists()) {
158 await file.create(recursive: true);
159 await file.writeAsString(fileString);
160 if (verbose) print("Wrote $filePath");
161 }
162 mojomCount++;
163 }
164 }
165 }
153 166
154 /// Ensures that the directories in [additionalPaths] are absolute and exist, 167 /// Ensures that the directories in [additionalPaths] are absolute and exist,
155 /// and creates Directories for them, which are returned. 168 /// and creates Directories for them, which are returned.
156 validateAdditionalDirs(Iterable additionalPaths) async { 169 Future<List<Directory>> validateAdditionalDirs(Iterable additionalPaths) async {
157 var additionalDirs = []; 170 var additionalDirs = [];
158 for (var mojomPath in additionalPaths) { 171 for (var mojomPath in additionalPaths) {
159 final mojomDir = new Directory(mojomPath); 172 final mojomDir = new Directory(mojomPath);
160 if (!mojomDir.isAbsolute) { 173 if (!mojomDir.isAbsolute) {
161 throw new CommandLineError( 174 throw new CommandLineError(
162 "All --additional-mojom-dir parameters must be absolute paths."); 175 "All --additional-mojom-dir parameters must be absolute paths.");
163 } 176 }
164 if (!(await mojomDir.exists())) { 177 if (!(await mojomDir.exists())) {
165 throw new CommandLineError( 178 throw new CommandLineError(
166 "The additional mojom directory $mojomDir must exist"); 179 "The additional mojom directory $mojomDir must exist");
167 } 180 }
168 additionalDirs.add(mojomDir); 181 additionalDirs.add(mojomDir);
169 } 182 }
170 if (verbose) print("additional_mojom_dirs = $additionalDirs"); 183 if (verbose) print("additional_mojom_dirs = $additionalDirs");
171 return additionalDirs; 184 return additionalDirs;
172 } 185 }
173 186
187 class GenerateOptions {
188 final Directory packages;
189 final Directory mojomPackage;
190 final Directory mojoSdk;
191 final List<Directory> additionalDirs;
192 final bool download;
193 final bool generate;
194 GenerateOptions(
195 this.packages, this.mojomPackage, this.mojoSdk, this.additionalDirs,
196 this.download, this.generate);
197 }
174 198
175 main(List<String> arguments) async { 199 Future<GenerateOptions> parseArguments(List<String> arguments) async {
176 final parser = new args.ArgParser() 200 final parser = new args.ArgParser()
177 ..addOption('additional-mojom-dir', 201 ..addOption('additional-mojom-dir',
178 abbr: 'a', 202 abbr: 'a',
179 allowMultiple: true, 203 allowMultiple: true,
180 help: 'Absolute path to an additional directory containing mojom.dart' 204 help: 'Absolute path to an additional directory containing mojom.dart'
181 'files to put in the mojom package. May be specified multiple times.') 205 'files to put in the mojom package. May be specified multiple times.')
182 ..addFlag('dry-run', 206 ..addFlag('download',
183 abbr: 'd', 207 abbr: 'd',
184 defaultsTo: false, 208 defaultsTo: false,
185 help: 'Print the copy operations that would have been run, but' 209 help: 'Searches packages for a .mojoms file, and downloads .mojom files'
186 'do not copy anything.') 210 'as speficied in that file. Implies -g.')
211 ..addFlag('fake',
212 abbr: 'f',
213 defaultsTo: false,
214 help: 'Print the operations that would have been run, but'
215 'do not run anything.')
187 ..addFlag('generate', 216 ..addFlag('generate',
188 abbr: 'g', 217 abbr: 'g',
189 defaultsTo: false, 218 defaultsTo: false,
190 help: 'Generate Dart bindings for .mojom files.') 219 help: 'Generate Dart bindings for .mojom files.')
191 ..addOption('mojo-sdk', 220 ..addOption('mojo-sdk',
192 abbr: 'm', 221 abbr: 'm',
193 defaultsTo: Platform.environment['MOJO_SDK'], 222 defaultsTo: Platform.environment['MOJO_SDK'],
194 help: 'Absolute path to the Mojo SDK, which can also be specified ' 223 help: 'Absolute path to the Mojo SDK, which can also be specified '
195 'with the environment variable MOJO_SDK.') 224 'with the environment variable MOJO_SDK.')
196 ..addOption('package-root', 225 ..addOption('package-root',
197 abbr: 'p', 226 abbr: 'p',
198 defaultsTo: path.join(Directory.current.path, 'packages'), 227 defaultsTo: path.join(Directory.current.path, 'packages'),
199 help: 'An absolute path to an application\'s package root') 228 help: 'An absolute path to an application\'s package root')
200 ..addFlag('verbose', abbr: 'v', defaultsTo: false); 229 ..addFlag('verbose', abbr: 'v', defaultsTo: false);
201 final result = parser.parse(arguments); 230 final result = parser.parse(arguments);
202 verbose = result['verbose']; 231 verbose = result['verbose'];
203 dryRun = result['dry-run']; 232 dryRun = result['fake'];
204 233
205 final packages = new Directory(result['package-root']); 234 final packages = new Directory(result['package-root']);
206 if (!packages.isAbsolute) { 235 if (!packages.isAbsolute) {
207 throw new CommandLineError( 236 throw new CommandLineError(
208 "The --package-root parameter must be an absolute path."); 237 "The --package-root parameter must be an absolute path.");
209 } 238 }
210 if (verbose) print("packages = $packages"); 239 if (verbose) print("packages = $packages");
211 if (!(await packages.exists())) { 240 if (!(await packages.exists())) {
212 throw new CommandLineError( 241 throw new CommandLineError(
213 "The packages directory $packages must exist"); 242 "The packages directory $packages must exist");
214 } 243 }
215 244
216 final mojomPackage = new Directory(path.join(packages.path, 'mojom')); 245 final mojomPackage = new Directory(path.join(packages.path, 'mojom'));
217 if (verbose) print("mojom package = $mojomPackage"); 246 if (verbose) print("mojom package = $mojomPackage");
218 if (!(await mojomPackage.exists())) { 247 if (!(await mojomPackage.exists())) {
219 throw new CommandLineError( 248 throw new CommandLineError(
220 "The mojom package directory $mojomPackage must exist"); 249 "The mojom package directory $mojomPackage must exist");
221 } 250 }
222 251
223 final generate = result['generate']; 252 final download = result['download'];
253 final generate = result['generate'] || download;
224 var mojoSdk = null; 254 var mojoSdk = null;
225 if (generate) { 255 if (generate) {
226 final mojoSdkPath = result['mojo-sdk']; 256 final mojoSdkPath = result['mojo-sdk'];
227 if (mojoSdkPath == null) { 257 if (mojoSdkPath == null) {
228 throw new CommandLineError( 258 throw new CommandLineError(
229 "The Mojo SDK directory must be specified with the --mojo-sdk flag or" 259 "The Mojo SDK directory must be specified with the --mojo-sdk flag or"
230 "the MOJO_SDK environment variable."); 260 "the MOJO_SDK environment variable.");
231 } 261 }
232 mojoSdk = new Directory(mojoSdkPath); 262 mojoSdk = new Directory(mojoSdkPath);
233 if (verbose) print("Mojo SDK = $mojoSdk"); 263 if (verbose) print("Mojo SDK = $mojoSdk");
234 if (!(await mojoSdk.exists())) { 264 if (!(await mojoSdk.exists())) {
235 throw new CommandLineError( 265 throw new CommandLineError(
236 "The specified Mojo SDK directory $mojoSdk must exist."); 266 "The specified Mojo SDK directory $mojoSdk must exist.");
237 } 267 }
238 } 268 }
239 269
240 await mojomDirIter(packages, new PackageIterData(mojomPackage), copyAction);
241 if (generate) {
242 await mojomDirIter(packages, new GenerateIterData(mojoSdk, mojomPackage),
243 generateAction);
244 }
245
246 final additionalDirs = 270 final additionalDirs =
247 await validateAdditionalDirs(result['additional-mojom-dir']); 271 await validateAdditionalDirs(result['additional-mojom-dir']);
248 final data = new GenerateIterData(mojoSdk, mojomPackage); 272
249 for (var mojomDir in additionalDirs) { 273 return new GenerateOptions(
274 packages, mojomPackage, mojoSdk, additionalDirs, download, generate);
275 }
276
277 main(List<String> arguments) async {
278 var options = await parseArguments(arguments);
279
280 // Copy any pregenerated files form packages.
281 await mojomDirIter(
282 options.packages,
283 new PackageIterData(options.mojomPackage),
284 copyAction);
285
286 // Download .mojom files. These will be picked up by the generation step
287 // below.
288 if (options.download) {
289 await packageDirIter(options.packages, null, downloadAction);
290 }
291
292 // Generate mojom files.
293 if (options.generate) {
294 await mojomDirIter(
295 options.packages,
296 new GenerateIterData(options.mojoSdk, options.mojomPackage),
297 generateAction);
298 }
299
300 // Copy pregenerated files from specified external directories.
301 final data = new GenerateIterData(options.mojoSdk, options.mojomPackage);
302 for (var mojomDir in options.additionalDirs) {
250 await copyAction(data, mojomDir); 303 await copyAction(data, mojomDir);
251 if (generate) { 304 if (options.generate) {
252 await generateAction(data, mojomDir); 305 await generateAction(data, mojomDir);
253 } 306 }
254 } 307 }
255 } 308 }
OLDNEW
« no previous file with comments | « no previous file | mojo/dart/mojom/lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698