| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:async'; |
| 5 import 'dart:io'; | 6 import 'dart:io'; |
| 6 | 7 |
| 7 import 'package:path/path.dart'; | 8 import 'package:path/path.dart'; |
| 8 | 9 |
| 9 /** | 10 /** |
| 10 * Type of functions used to compute the contents of a set of generated files. | 11 * Type of functions used to compute the contents of a set of generated files. |
| 11 * [pkgPath] is the path to the current package. | 12 * [pkgPath] is the path to the current package. |
| 12 */ | 13 */ |
| 13 typedef Map<String, FileContentsComputer> DirectoryContentsComputer( | 14 typedef Map<String, FileContentsComputer> DirectoryContentsComputer( |
| 14 String pkgPath); | 15 String pkgPath); |
| 15 | 16 |
| 16 /** | 17 /** |
| 17 * Type of functions used to compute the contents of a generated file. | 18 * Type of functions used to compute the contents of a generated file. |
| 18 * [pkgPath] is the path to the current package. | 19 * [pkgPath] is the path to the current package. |
| 19 */ | 20 */ |
| 20 typedef String FileContentsComputer(String pkgPath); | 21 typedef Future<String> FileContentsComputer(String pkgPath); |
| 21 | 22 |
| 22 /** | 23 /** |
| 23 * Abstract base class representing behaviors common to generated files and | 24 * Abstract base class representing behaviors common to generated files and |
| 24 * generated directories. | 25 * generated directories. |
| 25 */ | 26 */ |
| 26 abstract class GeneratedContent { | 27 abstract class GeneratedContent { |
| 27 /** | 28 /** |
| 28 * Check whether the [output] has the correct contents, and return true if it | 29 * Check whether the [output] has the correct contents, and return true if it |
| 29 * does. [pkgPath] is the path to the current package. | 30 * does. [pkgPath] is the path to the current package. |
| 30 */ | 31 */ |
| 31 bool check(String pkgPath); | 32 Future<bool> check(String pkgPath); |
| 32 | 33 |
| 33 /** | 34 /** |
| 34 * Replace the [output] with the correct contents. [pkgPath] is the path to | 35 * Replace the [output] with the correct contents. [pkgPath] is the path to |
| 35 * the current package. | 36 * the current package. |
| 36 */ | 37 */ |
| 37 void generate(String pkgPath); | 38 Future<Null> generate(String pkgPath); |
| 38 | 39 |
| 39 /** | 40 /** |
| 40 * Get a [FileSystemEntity] representing the output file or directory. | 41 * Get a [FileSystemEntity] representing the output file or directory. |
| 41 * [pkgPath] is the path to the current package. | 42 * [pkgPath] is the path to the current package. |
| 42 */ | 43 */ |
| 43 FileSystemEntity output(String pkgPath); | 44 FileSystemEntity output(String pkgPath); |
| 44 | 45 |
| 45 /** | 46 /** |
| 46 * Check that all of the [targets] are up to date. If they are not, print | 47 * Check that all of the [targets] are up to date. If they are not, print |
| 47 * out a message instructing the user to regenerate them, and exit with a | 48 * out a message instructing the user to regenerate them, and exit with a |
| 48 * nonzero error code. | 49 * nonzero error code. |
| 49 * | 50 * |
| 50 * [pkgPath] is the path to the current package. [generatorRelPath] is the | 51 * [pkgPath] is the path to the current package. [generatorRelPath] is the |
| 51 * path to a .dart script the user may use to regenerate the targets. | 52 * path to a .dart script the user may use to regenerate the targets. |
| 52 * | 53 * |
| 53 * To avoid mistakes when run on Windows, [generatorRelPath] always uses | 54 * To avoid mistakes when run on Windows, [generatorRelPath] always uses |
| 54 * POSIX directory separators. | 55 * POSIX directory separators. |
| 55 */ | 56 */ |
| 56 static void checkAll(String pkgPath, String generatorRelPath, | 57 static Future<Null> checkAll(String pkgPath, String generatorRelPath, |
| 57 Iterable<GeneratedContent> targets) { | 58 Iterable<GeneratedContent> targets) async { |
| 58 bool generateNeeded = false; | 59 bool generateNeeded = false; |
| 59 for (GeneratedContent target in targets) { | 60 for (GeneratedContent target in targets) { |
| 60 if (!target.check(pkgPath)) { | 61 bool ok = await target.check(pkgPath); |
| 62 if (!ok) { |
| 61 print( | 63 print( |
| 62 '${target.output(pkgPath).absolute} does not have expected contents.
'); | 64 '${target.output(pkgPath).absolute} does not have expected contents.
'); |
| 63 generateNeeded = true; | 65 generateNeeded = true; |
| 64 } | 66 } |
| 65 } | 67 } |
| 66 if (generateNeeded) { | 68 if (generateNeeded) { |
| 67 print('Please regenerate using:'); | 69 print('Please regenerate using:'); |
| 68 String executable = Platform.executable; | 70 String executable = Platform.executable; |
| 69 String packageRoot = ''; | 71 String packageRoot = ''; |
| 70 if (Platform.packageRoot != null) { | 72 if (Platform.packageRoot != null) { |
| 71 packageRoot = ' --package-root=${Platform.packageRoot}'; | 73 packageRoot = ' --package-root=${Platform.packageRoot}'; |
| 72 } | 74 } |
| 73 String generateScript = | 75 String generateScript = |
| 74 join(pkgPath, joinAll(posix.split(generatorRelPath))); | 76 join(pkgPath, joinAll(posix.split(generatorRelPath))); |
| 75 print(' $executable$packageRoot $generateScript'); | 77 print(' $executable$packageRoot $generateScript'); |
| 76 exit(1); | 78 exit(1); |
| 77 } else { | 79 } else { |
| 78 print('All generated files up to date.'); | 80 print('All generated files up to date.'); |
| 79 } | 81 } |
| 80 } | 82 } |
| 81 | 83 |
| 82 /** | 84 /** |
| 83 * Regenerate all of the [targets]. [pkgPath] is the path to the current | 85 * Regenerate all of the [targets]. [pkgPath] is the path to the current |
| 84 * package. | 86 * package. |
| 85 */ | 87 */ |
| 86 static void generateAll(String pkgPath, Iterable<GeneratedContent> targets) { | 88 static Future<Null> generateAll( |
| 89 String pkgPath, Iterable<GeneratedContent> targets) async { |
| 87 print("Generating..."); | 90 print("Generating..."); |
| 88 for (GeneratedContent target in targets) { | 91 for (GeneratedContent target in targets) { |
| 89 target.generate(pkgPath); | 92 await target.generate(pkgPath); |
| 90 } | 93 } |
| 91 } | 94 } |
| 92 } | 95 } |
| 93 | 96 |
| 94 /** | 97 /** |
| 95 * Class representing a single output directory (either generated code or | 98 * Class representing a single output directory (either generated code or |
| 96 * generated HTML). No other content should exist in the directory. | 99 * generated HTML). No other content should exist in the directory. |
| 97 */ | 100 */ |
| 98 class GeneratedDirectory extends GeneratedContent { | 101 class GeneratedDirectory extends GeneratedContent { |
| 99 /** | 102 /** |
| 100 * The path to the directory that will have the generated content. | 103 * The path to the directory that will have the generated content. |
| 101 */ | 104 */ |
| 102 final String outputDirPath; | 105 final String outputDirPath; |
| 103 | 106 |
| 104 /** | 107 /** |
| 105 * Callback function that computes the directory contents. | 108 * Callback function that computes the directory contents. |
| 106 */ | 109 */ |
| 107 final DirectoryContentsComputer directoryContentsComputer; | 110 final DirectoryContentsComputer directoryContentsComputer; |
| 108 | 111 |
| 109 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); | 112 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); |
| 110 | 113 |
| 111 @override | 114 @override |
| 112 bool check(String pkgPath) { | 115 Future<bool> check(String pkgPath) async { |
| 113 Directory outputDirectory = output(pkgPath); | 116 Directory outputDirectory = output(pkgPath); |
| 114 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath); | 117 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath); |
| 115 try { | 118 try { |
| 116 for (String file in map.keys) { | 119 for (String file in map.keys) { |
| 117 FileContentsComputer fileContentsComputer = map[file]; | 120 FileContentsComputer fileContentsComputer = map[file]; |
| 118 String expectedContents = fileContentsComputer(pkgPath); | 121 String expectedContents = await fileContentsComputer(pkgPath); |
| 119 File outputFile = new File(posix.join(outputDirectory.path, file)); | 122 File outputFile = new File(posix.join(outputDirectory.path, file)); |
| 120 String actualContents = outputFile.readAsStringSync(); | 123 String actualContents = outputFile.readAsStringSync(); |
| 121 // Normalize Windows line endings to Unix line endings so that the | 124 // Normalize Windows line endings to Unix line endings so that the |
| 122 // comparison doesn't fail on Windows. | 125 // comparison doesn't fail on Windows. |
| 123 actualContents = actualContents.replaceAll('\r\n', '\n'); | 126 actualContents = actualContents.replaceAll('\r\n', '\n'); |
| 124 if (expectedContents != actualContents) { | 127 if (expectedContents != actualContents) { |
| 125 return false; | 128 return false; |
| 126 } | 129 } |
| 127 } | 130 } |
| 128 int nonHiddenFileCount = 0; | 131 int nonHiddenFileCount = 0; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 142 } catch (e) { | 145 } catch (e) { |
| 143 // There was a problem reading the file (most likely because it didn't | 146 // There was a problem reading the file (most likely because it didn't |
| 144 // exist). Treat that the same as if the file doesn't have the expected | 147 // exist). Treat that the same as if the file doesn't have the expected |
| 145 // contents. | 148 // contents. |
| 146 return false; | 149 return false; |
| 147 } | 150 } |
| 148 return true; | 151 return true; |
| 149 } | 152 } |
| 150 | 153 |
| 151 @override | 154 @override |
| 152 void generate(String pkgPath) { | 155 Future<Null> generate(String pkgPath) async { |
| 153 Directory outputDirectory = output(pkgPath); | 156 Directory outputDirectory = output(pkgPath); |
| 154 try { | 157 try { |
| 155 // delete the contents of the directory (and the directory itself) | 158 // delete the contents of the directory (and the directory itself) |
| 156 outputDirectory.deleteSync(recursive: true); | 159 outputDirectory.deleteSync(recursive: true); |
| 157 } catch (e) { | 160 } catch (e) { |
| 158 // Error caught while trying to delete the directory, this can happen if | 161 // Error caught while trying to delete the directory, this can happen if |
| 159 // it didn't yet exist. | 162 // it didn't yet exist. |
| 160 } | 163 } |
| 161 // re-create the empty directory | 164 // re-create the empty directory |
| 162 outputDirectory.createSync(recursive: true); | 165 outputDirectory.createSync(recursive: true); |
| 163 | 166 |
| 164 // generate all of the files in the directory | 167 // generate all of the files in the directory |
| 165 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath); | 168 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath); |
| 166 map.forEach((String file, FileContentsComputer fileContentsComputer) { | 169 for (String file in map.keys) { |
| 170 FileContentsComputer fileContentsComputer = map[file]; |
| 167 File outputFile = new File(posix.join(outputDirectory.path, file)); | 171 File outputFile = new File(posix.join(outputDirectory.path, file)); |
| 168 print(' ${outputFile.path}'); | 172 print(' ${outputFile.path}'); |
| 169 outputFile.writeAsStringSync(fileContentsComputer(pkgPath)); | 173 String contents = await fileContentsComputer(pkgPath); |
| 170 }); | 174 outputFile.writeAsStringSync(contents); |
| 175 } |
| 171 } | 176 } |
| 172 | 177 |
| 173 @override | 178 @override |
| 174 Directory output(String pkgPath) => | 179 Directory output(String pkgPath) => |
| 175 new Directory(join(pkgPath, joinAll(posix.split(outputDirPath)))); | 180 new Directory(join(pkgPath, joinAll(posix.split(outputDirPath)))); |
| 176 } | 181 } |
| 177 | 182 |
| 178 /** | 183 /** |
| 179 * Class representing a single output file (either generated code or generated | 184 * Class representing a single output file (either generated code or generated |
| 180 * HTML). | 185 * HTML). |
| 181 */ | 186 */ |
| 182 class GeneratedFile extends GeneratedContent { | 187 class GeneratedFile extends GeneratedContent { |
| 183 /** | 188 /** |
| 184 * The output file to which generated output should be written, relative to | 189 * The output file to which generated output should be written, relative to |
| 185 * the "tool/spec" directory. This filename uses the posix path separator | 190 * the "tool/spec" directory. This filename uses the posix path separator |
| 186 * ('/') regardless of the OS. | 191 * ('/') regardless of the OS. |
| 187 */ | 192 */ |
| 188 final String outputPath; | 193 final String outputPath; |
| 189 | 194 |
| 190 /** | 195 /** |
| 191 * Callback function which computes the file. | 196 * Callback function which computes the file. |
| 192 */ | 197 */ |
| 193 final FileContentsComputer computeContents; | 198 final FileContentsComputer computeContents; |
| 194 | 199 |
| 195 GeneratedFile(this.outputPath, this.computeContents); | 200 GeneratedFile(this.outputPath, this.computeContents); |
| 196 | 201 |
| 197 bool get isDartFile => outputPath.endsWith('.dart'); | 202 bool get isDartFile => outputPath.endsWith('.dart'); |
| 198 | 203 |
| 199 @override | 204 @override |
| 200 bool check(String pkgPath) { | 205 Future<bool> check(String pkgPath) async { |
| 201 File outputFile = output(pkgPath); | 206 File outputFile = output(pkgPath); |
| 202 String expectedContents = computeContents(pkgPath); | 207 String expectedContents = await computeContents(pkgPath); |
| 203 if (isDartFile) { | 208 if (isDartFile) { |
| 204 expectedContents = DartFormat.formatText(expectedContents); | 209 expectedContents = DartFormat.formatText(expectedContents); |
| 205 } | 210 } |
| 206 try { | 211 try { |
| 207 String actualContents = outputFile.readAsStringSync(); | 212 String actualContents = outputFile.readAsStringSync(); |
| 208 // Normalize Windows line endings to Unix line endings so that the | 213 // Normalize Windows line endings to Unix line endings so that the |
| 209 // comparison doesn't fail on Windows. | 214 // comparison doesn't fail on Windows. |
| 210 actualContents = actualContents.replaceAll('\r\n', '\n'); | 215 actualContents = actualContents.replaceAll('\r\n', '\n'); |
| 211 return expectedContents == actualContents; | 216 return expectedContents == actualContents; |
| 212 } catch (e) { | 217 } catch (e) { |
| 213 // There was a problem reading the file (most likely because it didn't | 218 // There was a problem reading the file (most likely because it didn't |
| 214 // exist). Treat that the same as if the file doesn't have the expected | 219 // exist). Treat that the same as if the file doesn't have the expected |
| 215 // contents. | 220 // contents. |
| 216 return false; | 221 return false; |
| 217 } | 222 } |
| 218 } | 223 } |
| 219 | 224 |
| 220 @override | 225 @override |
| 221 void generate(String pkgPath) { | 226 Future<Null> generate(String pkgPath) async { |
| 222 File outputFile = output(pkgPath); | 227 File outputFile = output(pkgPath); |
| 223 print(' ${outputFile.path}'); | 228 print(' ${outputFile.path}'); |
| 224 outputFile.writeAsStringSync(computeContents(pkgPath)); | 229 String contents = await computeContents(pkgPath); |
| 230 outputFile.writeAsStringSync(contents); |
| 225 if (isDartFile) { | 231 if (isDartFile) { |
| 226 DartFormat.formatFile(outputFile); | 232 DartFormat.formatFile(outputFile); |
| 227 } | 233 } |
| 228 } | 234 } |
| 229 | 235 |
| 230 @override | 236 @override |
| 231 File output(String pkgPath) => | 237 File output(String pkgPath) => |
| 232 new File(join(pkgPath, joinAll(posix.split(outputPath)))); | 238 new File(join(pkgPath, joinAll(posix.split(outputPath)))); |
| 233 } | 239 } |
| 234 | 240 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 253 } | 259 } |
| 254 | 260 |
| 255 static String formatText(String text) { | 261 static String formatText(String text) { |
| 256 File file = new File(join(Directory.systemTemp.path, 'gen.dart')); | 262 File file = new File(join(Directory.systemTemp.path, 'gen.dart')); |
| 257 file.writeAsStringSync(text); | 263 file.writeAsStringSync(text); |
| 258 ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]); | 264 ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]); |
| 259 if (result.exitCode != 0) throw result.stderr; | 265 if (result.exitCode != 0) throw result.stderr; |
| 260 return file.readAsStringSync(); | 266 return file.readAsStringSync(); |
| 261 } | 267 } |
| 262 } | 268 } |
| OLD | NEW |