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 |