| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /// This script generates Mojo bindings for a Dart package. See README.md for | |
| 6 /// details. | |
| 7 | |
| 8 library generate; | |
| 9 | |
| 10 import 'dart:async'; | |
| 11 import 'dart:convert'; | |
| 12 import 'dart:io'; | |
| 13 | |
| 14 import 'package:args/args.dart' as args; | |
| 15 import 'package:path/path.dart' as path; | |
| 16 | |
| 17 part 'src/options.dart'; | |
| 18 part 'src/utils.dart'; | |
| 19 | |
| 20 bool errorOnDuplicate; | |
| 21 bool verbose; | |
| 22 bool dryRun; | |
| 23 Map<String, String> duplicateDetection; | |
| 24 | |
| 25 /// Searches for .mojom.dart files under [mojomDirectory] and copies them to | |
| 26 /// [data.currentPackage]. | |
| 27 copyAction(PackageIterData data, Directory mojomDirectory) async { | |
| 28 await for (var mojom in mojomDirectory.list(recursive: true)) { | |
| 29 if (mojom is! File) continue; | |
| 30 if (!isMojomDart(mojom.path)) continue; | |
| 31 if (verbose) print("Found $mojom"); | |
| 32 | |
| 33 final relative = path.relative(mojom.path, from: mojomDirectory.path); | |
| 34 final dest = path.join(data.currentPackage.path, relative); | |
| 35 final destDirectory = new Directory(path.dirname(dest)); | |
| 36 | |
| 37 if (errorOnDuplicate && duplicateDetection.containsKey(dest)) { | |
| 38 String original = duplicateDetection[dest]; | |
| 39 throw new GenerationError( | |
| 40 'Conflict: Both ${original} and ${mojom.path} supply ${dest}'); | |
| 41 } | |
| 42 duplicateDetection[dest] = mojom.path; | |
| 43 | |
| 44 if (verbose || dryRun) { | |
| 45 print('Copying $mojom to $dest'); | |
| 46 } | |
| 47 | |
| 48 if (!dryRun) { | |
| 49 final File source = new File(mojom.path); | |
| 50 if (verbose) print("Ensuring $destDirectory exists"); | |
| 51 await destDirectory.create(recursive: true); | |
| 52 source.copy(dest); | |
| 53 } | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 /// Searches for .mojom files under [mojomDirectory], generates .mojom.dart | |
| 58 /// files for them, and copies them to the 'mojom' package. | |
| 59 generateAction(GenerateIterData data, Directory mojomDirectory) async { | |
| 60 final packageRoot = data.currentPackage.parent; | |
| 61 await for (var mojom in mojomDirectory.list(recursive: true)) { | |
| 62 if (mojom is! File) continue; | |
| 63 if (!isMojom(mojom.path)) continue; | |
| 64 if (verbose) print("Found $mojom"); | |
| 65 | |
| 66 final script = path.join( | |
| 67 data.mojoSdk.path, 'tools', 'bindings', 'mojom_bindings_generator.py'); | |
| 68 final sdkInc = path.normalize(path.join(data.mojoSdk.path, '..', '..')); | |
| 69 final outputDir = await data.currentPackage.createTemp(); | |
| 70 final output = outputDir.path; | |
| 71 final arguments = [ | |
| 72 '--use_bundled_pylibs', | |
| 73 '-g', | |
| 74 'dart', | |
| 75 '-o', | |
| 76 output, | |
| 77 // TODO(zra): Are other include paths needed? | |
| 78 '-I', | |
| 79 sdkInc, | |
| 80 '-I', | |
| 81 mojomDirectory.path, | |
| 82 mojom.path | |
| 83 ]; | |
| 84 | |
| 85 if (verbose || dryRun) { | |
| 86 print('Generating $mojom'); | |
| 87 print('$script ${arguments.join(" ")}'); | |
| 88 } | |
| 89 if (!dryRun) { | |
| 90 final result = await Process.run(script, arguments); | |
| 91 if (result.exitCode != 0) { | |
| 92 throw new GenerationError("$script failed:\n${result.stderr}"); | |
| 93 } | |
| 94 | |
| 95 // Generated .mojom.dart is under $output/dart-pkg/$PACKAGE/lib/$X | |
| 96 // Move $X to $PACKAGE_ROOT/$PACKAGE/$X | |
| 97 final generatedDirName = path.join(output, 'dart-pkg'); | |
| 98 final generatedDir = new Directory(generatedDirName); | |
| 99 await for (var genpack in generatedDir.list()) { | |
| 100 if (genpack is! Directory) continue; | |
| 101 var libDir = new Directory(path.join(genpack.path, 'lib')); | |
| 102 var name = path.relative(genpack.path, from: generatedDirName); | |
| 103 var copyData = new GenerateIterData(data.mojoSdk); | |
| 104 copyData.currentPackage = | |
| 105 new Directory(path.join(packageRoot.path, name)); | |
| 106 await copyAction(copyData, libDir); | |
| 107 } | |
| 108 | |
| 109 await outputDir.delete(recursive: true); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 /// In each package, look for a file named .mojoms. Populate a package's | |
| 115 /// mojom directory with the downloaded mojoms, creating the directory if | |
| 116 /// needed. The .mojoms file should be formatted as follows: | |
| 117 /// ''' | |
| 118 /// root: https://www.example.com/mojoms | |
| 119 /// path/to/some/mojom1.mojom | |
| 120 /// path/to/some/other/mojom2.mojom | |
| 121 /// | |
| 122 /// root: https://www.example-two.com/mojoms | |
| 123 /// path/to/example/two/mojom1.mojom | |
| 124 /// ... | |
| 125 /// | |
| 126 /// Lines beginning with '#' are ignored. | |
| 127 downloadAction(GenerateIterData _, Directory packageDirectory) async { | |
| 128 var mojomsPath = path.join(packageDirectory.path, '.mojoms'); | |
| 129 var mojomsFile = new File(mojomsPath); | |
| 130 if (!await mojomsFile.exists()) return; | |
| 131 if (verbose) print("Found .mojoms file: $mojomsPath"); | |
| 132 | |
| 133 Directory mojomsDir; | |
| 134 var httpClient = new HttpClient(); | |
| 135 int repoCount = 0; | |
| 136 int mojomCount = 0; | |
| 137 String repoRoot; | |
| 138 for (String line in await mojomsFile.readAsLines()) { | |
| 139 line = line.trim(); | |
| 140 if (line.isEmpty || line.startsWith('#')) continue; | |
| 141 | |
| 142 if (line.startsWith('root:')) { | |
| 143 if ((mojomsDir != null) && (mojomCount == 0)) { | |
| 144 throw new DownloadError("root with no mojoms: $repoRoot"); | |
| 145 } | |
| 146 mojomCount = 0; | |
| 147 var rootWords = line.split(" "); | |
| 148 if (rootWords.length != 2) { | |
| 149 throw new DownloadError("Malformed root: $line"); | |
| 150 } | |
| 151 repoRoot = rootWords[1]; | |
| 152 if (verbose) print("Found repo root: $repoRoot"); | |
| 153 if (!repoRoot.startsWith('http://') && !repoRoot.startsWith('https://')) { | |
| 154 throw new DownloadError( | |
| 155 'Mojom repo "root" should be an http or https URL: $line'); | |
| 156 } | |
| 157 mojomsDir = new Directory(path.join( | |
| 158 packageDirectory.parent.path, 'mojm.repo.$repoCount', 'mojom')); | |
| 159 await mojomsDir.create(recursive: true); | |
| 160 repoCount++; | |
| 161 } else { | |
| 162 if (mojomsDir == null) { | |
| 163 throw new DownloadError('Malformed .mojoms file: $mojomsPath'); | |
| 164 } | |
| 165 String url = "$repoRoot/$line"; | |
| 166 if (verbose) print("Found $url"); | |
| 167 String fileString = await getUrl(httpClient, url); | |
| 168 if (verbose) print("Downloaded $url"); | |
| 169 String filePath = path.join(mojomsDir.path, line); | |
| 170 var file = new File(filePath); | |
| 171 if (!await file.exists()) { | |
| 172 await file.create(recursive: true); | |
| 173 await file.writeAsString(fileString); | |
| 174 if (verbose) print("Wrote $filePath"); | |
| 175 } | |
| 176 mojomCount++; | |
| 177 } | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 /// The "mojom" entry in [packages] is a symbolic link to the mojom package in | |
| 182 /// the global pub cache directory. Because we might need to write package | |
| 183 /// specific .mojom.dart files into the mojom package, we need to make a local | |
| 184 /// copy of it. | |
| 185 copyMojomPackage(Directory packages) async { | |
| 186 var link = new Link(path.join(packages.path, "mojom")); | |
| 187 if (!await link.exists()) { | |
| 188 // If the "mojom" entry in packages is not a symbolic link, then do nothing. | |
| 189 return; | |
| 190 } | |
| 191 | |
| 192 var realpath = await link.resolveSymbolicLinks(); | |
| 193 var realDir = new Directory(realpath); | |
| 194 var mojomDir = new Directory(path.join(packages.path, "mojom")); | |
| 195 | |
| 196 await link.delete(); | |
| 197 await mojomDir.create(); | |
| 198 await for (var file in realDir.list(recursive: true)) { | |
| 199 if (file is File) { | |
| 200 var relative = path.relative(file.path, from: realDir.path); | |
| 201 var destPath = path.join(mojomDir.path, relative); | |
| 202 var destDir = new Directory(path.dirname(destPath)); | |
| 203 await destDir.create(recursive: true); | |
| 204 await file.copy(path.join(mojomDir.path, relative)); | |
| 205 } | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 main(List<String> arguments) async { | |
| 210 var options = await parseArguments(arguments); | |
| 211 duplicateDetection = new Map<String, String>(); | |
| 212 errorOnDuplicate = options.errorOnDuplicate; | |
| 213 verbose = options.verbose; | |
| 214 dryRun = options.dryRun; | |
| 215 | |
| 216 // mojoms without a DartPackage annotation, and pregenerated mojoms from | |
| 217 // [options.additionalDirs] will go into the mojom package, so we make a local | |
| 218 // copy of it so we don't pollute the global pub cache. | |
| 219 // | |
| 220 // TODO(zra): Fail if a mojom has no DartPackage annotation, and remove the | |
| 221 // need for [options.additionalDirs]. | |
| 222 if (!dryRun) { | |
| 223 await copyMojomPackage(options.packages); | |
| 224 } | |
| 225 | |
| 226 // Download .mojom files. These will be picked up by the generation step | |
| 227 // below. | |
| 228 if (options.download) { | |
| 229 await packageDirIter(options.packages, null, downloadAction); | |
| 230 } | |
| 231 | |
| 232 // Generate mojom files. | |
| 233 if (options.generate) { | |
| 234 await mojomDirIter(options.packages, new GenerateIterData(options.mojoSdk), | |
| 235 generateAction); | |
| 236 } | |
| 237 | |
| 238 // TODO(zra): As mentioned above, this should go away. | |
| 239 // Copy pregenerated files from specified external directories into the | |
| 240 // mojom package. | |
| 241 final data = new GenerateIterData(options.mojoSdk); | |
| 242 data.currentPackage = options.mojomPackage; | |
| 243 for (var mojomDir in options.additionalDirs) { | |
| 244 await copyAction(data, mojomDir); | |
| 245 if (options.generate) { | |
| 246 await generateAction(data, mojomDir); | |
| 247 } | |
| 248 } | |
| 249 } | |
| OLD | NEW |