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

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: Address comments 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 directory with the downloaded mojoms, creating the directory if
103 /// needed. The .mojoms file should be formatted as follows:
104 /// '''
105 /// root: https://www.example.com/mojoms
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 line = line.trim();
127 if (line.isEmpty || line.startsWith('#')) continue;
128
129 if (line.startsWith('root:')) {
130 if ((mojomsDir != null) && (mojomCount == 0)) {
131 throw new DownloadError("root with no mojoms: $repoRoot");
132 }
133 mojomCount = 0;
134 var rootWords = line.split(" ");
135 if (rootWords.length != 2) {
136 throw new DownloadError("Malformed root: $line");
137 }
138 repoRoot = rootWords[1];
139 if (verbose) print("Found repo root: $repoRoot");
140 if (!repoRoot.startsWith('http://') &&
141 !repoRoot.startsWith('https://')) {
142 throw new DownloadError(
143 'Mojom repo "root" should be an http or https URL: $line');
144 }
145 mojomsDir = new Directory(path.join(
146 packageDirectory.parent.path, 'mojm.repo.$repoCount', 'mojom'));
147 await mojomsDir.create(recursive: true);
148 repoCount++;
149 } else {
150 if (mojomsDir == null) {
151 throw new DownloadError('Malformed .mojoms file: $mojomsPath');
152 }
153 String url = "$repoRoot/$line";
154 if (verbose) print("Found $url");
155 String fileString = await getUrl(httpClient, url);
156 if (verbose) print("Downloaded $url");
157 String filePath = path.join(mojomsDir.path, line);
158 var file = new File(filePath);
159 if (!await file.exists()) {
160 await file.create(recursive: true);
161 await file.writeAsString(fileString);
162 if (verbose) print("Wrote $filePath");
163 }
164 mojomCount++;
165 }
166 }
167 }
153 168
154 /// Ensures that the directories in [additionalPaths] are absolute and exist, 169 /// Ensures that the directories in [additionalPaths] are absolute and exist,
155 /// and creates Directories for them, which are returned. 170 /// and creates Directories for them, which are returned.
156 validateAdditionalDirs(Iterable additionalPaths) async { 171 Future<List<Directory>> validateAdditionalDirs(Iterable additionalPaths) async {
157 var additionalDirs = []; 172 var additionalDirs = [];
158 for (var mojomPath in additionalPaths) { 173 for (var mojomPath in additionalPaths) {
159 final mojomDir = new Directory(mojomPath); 174 final mojomDir = new Directory(mojomPath);
160 if (!mojomDir.isAbsolute) { 175 if (!mojomDir.isAbsolute) {
161 throw new CommandLineError( 176 throw new CommandLineError(
162 "All --additional-mojom-dir parameters must be absolute paths."); 177 "All --additional-mojom-dir parameters must be absolute paths.");
163 } 178 }
164 if (!(await mojomDir.exists())) { 179 if (!(await mojomDir.exists())) {
165 throw new CommandLineError( 180 throw new CommandLineError(
166 "The additional mojom directory $mojomDir must exist"); 181 "The additional mojom directory $mojomDir must exist");
167 } 182 }
168 additionalDirs.add(mojomDir); 183 additionalDirs.add(mojomDir);
169 } 184 }
170 if (verbose) print("additional_mojom_dirs = $additionalDirs"); 185 if (verbose) print("additional_mojom_dirs = $additionalDirs");
171 return additionalDirs; 186 return additionalDirs;
172 } 187 }
173 188
189 class GenerateOptions {
190 final Directory packages;
191 final Directory mojomPackage;
192 final Directory mojoSdk;
193 final List<Directory> additionalDirs;
194 final bool download;
195 final bool generate;
196 GenerateOptions(
197 this.packages, this.mojomPackage, this.mojoSdk, this.additionalDirs,
198 this.download, this.generate);
199 }
174 200
175 main(List<String> arguments) async { 201 Future<GenerateOptions> parseArguments(List<String> arguments) async {
176 final parser = new args.ArgParser() 202 final parser = new args.ArgParser()
177 ..addOption('additional-mojom-dir', 203 ..addOption('additional-mojom-dir',
178 abbr: 'a', 204 abbr: 'a',
179 allowMultiple: true, 205 allowMultiple: true,
180 help: 'Absolute path to an additional directory containing mojom.dart' 206 help: 'Absolute path to an additional directory containing mojom.dart'
181 'files to put in the mojom package. May be specified multiple times.') 207 'files to put in the mojom package. May be specified multiple times.')
182 ..addFlag('dry-run', 208 ..addFlag('download',
183 abbr: 'd', 209 abbr: 'd',
184 defaultsTo: false, 210 defaultsTo: false,
185 help: 'Print the copy operations that would have been run, but' 211 help: 'Searches packages for a .mojoms file, and downloads .mojom files'
186 'do not copy anything.') 212 'as speficied in that file. Implies -g.')
213 ..addFlag('fake',
214 abbr: 'f',
215 defaultsTo: false,
216 help: 'Print the operations that would have been run, but'
217 'do not run anything.')
187 ..addFlag('generate', 218 ..addFlag('generate',
188 abbr: 'g', 219 abbr: 'g',
189 defaultsTo: false, 220 defaultsTo: false,
190 help: 'Generate Dart bindings for .mojom files.') 221 help: 'Generate Dart bindings for .mojom files.')
191 ..addOption('mojo-sdk', 222 ..addOption('mojo-sdk',
192 abbr: 'm', 223 abbr: 'm',
193 defaultsTo: Platform.environment['MOJO_SDK'], 224 defaultsTo: Platform.environment['MOJO_SDK'],
194 help: 'Absolute path to the Mojo SDK, which can also be specified ' 225 help: 'Absolute path to the Mojo SDK, which can also be specified '
195 'with the environment variable MOJO_SDK.') 226 'with the environment variable MOJO_SDK.')
196 ..addOption('package-root', 227 ..addOption('package-root',
197 abbr: 'p', 228 abbr: 'p',
198 defaultsTo: path.join(Directory.current.path, 'packages'), 229 defaultsTo: path.join(Directory.current.path, 'packages'),
199 help: 'An absolute path to an application\'s package root') 230 help: 'An absolute path to an application\'s package root')
200 ..addFlag('verbose', abbr: 'v', defaultsTo: false); 231 ..addFlag('verbose', abbr: 'v', defaultsTo: false);
201 final result = parser.parse(arguments); 232 final result = parser.parse(arguments);
202 verbose = result['verbose']; 233 verbose = result['verbose'];
203 dryRun = result['dry-run']; 234 dryRun = result['fake'];
204 235
205 final packages = new Directory(result['package-root']); 236 final packages = new Directory(result['package-root']);
206 if (!packages.isAbsolute) { 237 if (!packages.isAbsolute) {
207 throw new CommandLineError( 238 throw new CommandLineError(
208 "The --package-root parameter must be an absolute path."); 239 "The --package-root parameter must be an absolute path.");
209 } 240 }
210 if (verbose) print("packages = $packages"); 241 if (verbose) print("packages = $packages");
211 if (!(await packages.exists())) { 242 if (!(await packages.exists())) {
212 throw new CommandLineError( 243 throw new CommandLineError(
213 "The packages directory $packages must exist"); 244 "The packages directory $packages must exist");
214 } 245 }
215 246
216 final mojomPackage = new Directory(path.join(packages.path, 'mojom')); 247 final mojomPackage = new Directory(path.join(packages.path, 'mojom'));
217 if (verbose) print("mojom package = $mojomPackage"); 248 if (verbose) print("mojom package = $mojomPackage");
218 if (!(await mojomPackage.exists())) { 249 if (!(await mojomPackage.exists())) {
219 throw new CommandLineError( 250 throw new CommandLineError(
220 "The mojom package directory $mojomPackage must exist"); 251 "The mojom package directory $mojomPackage must exist");
221 } 252 }
222 253
223 final generate = result['generate']; 254 final download = result['download'];
255 final generate = result['generate'] || download;
224 var mojoSdk = null; 256 var mojoSdk = null;
225 if (generate) { 257 if (generate) {
226 final mojoSdkPath = result['mojo-sdk']; 258 final mojoSdkPath = result['mojo-sdk'];
227 if (mojoSdkPath == null) { 259 if (mojoSdkPath == null) {
228 throw new CommandLineError( 260 throw new CommandLineError(
229 "The Mojo SDK directory must be specified with the --mojo-sdk flag or" 261 "The Mojo SDK directory must be specified with the --mojo-sdk flag or"
230 "the MOJO_SDK environment variable."); 262 "the MOJO_SDK environment variable.");
231 } 263 }
232 mojoSdk = new Directory(mojoSdkPath); 264 mojoSdk = new Directory(mojoSdkPath);
233 if (verbose) print("Mojo SDK = $mojoSdk"); 265 if (verbose) print("Mojo SDK = $mojoSdk");
234 if (!(await mojoSdk.exists())) { 266 if (!(await mojoSdk.exists())) {
235 throw new CommandLineError( 267 throw new CommandLineError(
236 "The specified Mojo SDK directory $mojoSdk must exist."); 268 "The specified Mojo SDK directory $mojoSdk must exist.");
237 } 269 }
238 } 270 }
239 271
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 = 272 final additionalDirs =
247 await validateAdditionalDirs(result['additional-mojom-dir']); 273 await validateAdditionalDirs(result['additional-mojom-dir']);
248 final data = new GenerateIterData(mojoSdk, mojomPackage); 274
249 for (var mojomDir in additionalDirs) { 275 return new GenerateOptions(
276 packages, mojomPackage, mojoSdk, additionalDirs, download, generate);
277 }
278
279 main(List<String> arguments) async {
280 var options = await parseArguments(arguments);
281
282 // Copy any pregenerated files form packages.
283 await mojomDirIter(
284 options.packages,
285 new PackageIterData(options.mojomPackage),
286 copyAction);
287
288 // Download .mojom files. These will be picked up by the generation step
289 // below.
290 if (options.download) {
291 await packageDirIter(options.packages, null, downloadAction);
292 }
293
294 // Generate mojom files.
295 if (options.generate) {
296 await mojomDirIter(
297 options.packages,
298 new GenerateIterData(options.mojoSdk, options.mojomPackage),
299 generateAction);
300 }
301
302 // Copy pregenerated files from specified external directories.
303 final data = new GenerateIterData(options.mojoSdk, options.mojomPackage);
304 for (var mojomDir in options.additionalDirs) {
250 await copyAction(data, mojomDir); 305 await copyAction(data, mojomDir);
251 if (generate) { 306 if (options.generate) {
252 await generateAction(data, mojomDir); 307 await generateAction(data, mojomDir);
253 } 308 }
254 } 309 }
255 } 310 }
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