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

Side by Side Diff: pkg/front_end/lib/src/codegen/tools.dart

Issue 2742333005: Move some of analyzer's code generation utilities into front_end. (Closed)
Patch Set: Created 3 years, 9 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:io';
6
7 import 'package:path/path.dart';
8
9 /**
10 * Type of functions used to compute the contents of a set of generated files.
11 * [pkgPath] is the path to the current package.
12 */
13 typedef Map<String, FileContentsComputer> DirectoryContentsComputer(
14 String pkgPath);
15
16 /**
17 * Type of functions used to compute the contents of a generated file.
18 * [pkgPath] is the path to the current package.
19 */
20 typedef String FileContentsComputer(String pkgPath);
21
22 /**
23 * Abstract base class representing behaviors common to generated files and
24 * generated directories.
25 */
26 abstract class GeneratedContent {
27 /**
28 * Check whether the [output] has the correct contents, and return true if it
29 * does. [pkgPath] is the path to the current package.
30 */
31 bool check(String pkgPath);
32
33 /**
34 * Replace the [output] with the correct contents. [pkgPath] is the path to
35 * the current package.
36 */
37 void generate(String pkgPath);
38
39 /**
40 * Get a [FileSystemEntity] representing the output file or directory.
41 * [pkgPath] is the path to the current package.
42 */
43 FileSystemEntity output(String pkgPath);
44
45 /**
46 * 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 * nonzero error code.
49 *
50 * [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 *
53 * To avoid mistakes when run on Windows, [generatorRelPath] always uses
54 * POSIX directory separators.
55 */
56 static void checkAll(String pkgPath, String generatorRelPath,
57 Iterable<GeneratedContent> targets) {
58 bool generateNeeded = false;
59 for (GeneratedContent target in targets) {
60 if (!target.check(pkgPath)) {
61 print(
62 '${target.output(pkgPath).absolute} does not have expected contents. ');
63 generateNeeded = true;
64 }
65 }
66 if (generateNeeded) {
67 print('Please regenerate using:');
68 String executable = Platform.executable;
69 String packageRoot = '';
70 if (Platform.packageRoot != null) {
71 packageRoot = ' --package-root=${Platform.packageRoot}';
72 }
73 String generateScript =
74 join(pkgPath, joinAll(posix.split(generatorRelPath)));
75 print(' $executable$packageRoot $generateScript');
76 exit(1);
77 } else {
78 print('All generated files up to date.');
79 }
80 }
81
82 /**
83 * Regenerate all of the [targets]. [pkgPath] is the path to the current
84 * package.
85 */
86 static void generateAll(String pkgPath, Iterable<GeneratedContent> targets) {
87 for (GeneratedContent target in targets) {
88 target.generate(pkgPath);
89 }
90 }
91 }
92
93 /**
94 * Class representing a single output directory (either generated code or
95 * generated HTML). No other content should exist in the directory.
96 */
97 class GeneratedDirectory extends GeneratedContent {
98 /**
99 * The path to the directory that will have the generated content.
100 */
101 final String outputDirPath;
102
103 /**
104 * Callback function that computes the directory contents.
105 */
106 final DirectoryContentsComputer directoryContentsComputer;
107
108 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer);
109
110 @override
111 bool check(String pkgPath) {
112 Directory outputDirectory = output(pkgPath);
113 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
114 try {
115 for (String file in map.keys) {
116 FileContentsComputer fileContentsComputer = map[file];
117 String expectedContents = fileContentsComputer(pkgPath);
118 File outputFile = new File(posix.join(outputDirectory.path, file));
119 String actualContents = outputFile.readAsStringSync();
120 // Normalize Windows line endings to Unix line endings so that the
121 // comparison doesn't fail on Windows.
122 actualContents = actualContents.replaceAll('\r\n', '\n');
123 if (expectedContents != actualContents) {
124 return false;
125 }
126 }
127 int nonHiddenFileCount = 0;
128 outputDirectory
129 .listSync(recursive: false, followLinks: false)
130 .forEach((FileSystemEntity fileSystemEntity) {
131 if (fileSystemEntity is File &&
132 !basename(fileSystemEntity.path).startsWith('.')) {
133 nonHiddenFileCount++;
134 }
135 });
136 if (nonHiddenFileCount != map.length) {
137 // The number of files generated doesn't match the number we expected to
138 // generate.
139 return false;
140 }
141 } catch (e) {
142 // There was a problem reading the file (most likely because it didn't
143 // exist). Treat that the same as if the file doesn't have the expected
144 // contents.
145 return false;
146 }
147 return true;
148 }
149
150 @override
151 void generate(String pkgPath) {
152 Directory outputDirectory = output(pkgPath);
153 try {
154 // delete the contents of the directory (and the directory itself)
155 outputDirectory.deleteSync(recursive: true);
156 } catch (e) {
157 // Error caught while trying to delete the directory, this can happen if
158 // it didn't yet exist.
159 }
160 // re-create the empty directory
161 outputDirectory.createSync(recursive: true);
162
163 // generate all of the files in the directory
164 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
165 map.forEach((String file, FileContentsComputer fileContentsComputer) {
166 File outputFile = new File(posix.join(outputDirectory.path, file));
167 outputFile.writeAsStringSync(fileContentsComputer(pkgPath));
168 });
169 }
170
171 @override
172 Directory output(String pkgPath) =>
173 new Directory(join(pkgPath, joinAll(posix.split(outputDirPath))));
174 }
175
176 /**
177 * Class representing a single output file (either generated code or generated
178 * HTML).
179 */
180 class GeneratedFile extends GeneratedContent {
181 /**
182 * The output file to which generated output should be written, relative to
183 * the "tool/spec" directory. This filename uses the posix path separator
184 * ('/') regardless of the OS.
185 */
186 final String outputPath;
187
188 /**
189 * Callback function which computes the file.
190 */
191 final FileContentsComputer computeContents;
192
193 GeneratedFile(this.outputPath, this.computeContents);
194
195 @override
196 bool check(String pkgPath) {
197 File outputFile = output(pkgPath);
198 String expectedContents = computeContents(pkgPath);
199 try {
200 String actualContents = outputFile.readAsStringSync();
201 // Normalize Windows line endings to Unix line endings so that the
202 // comparison doesn't fail on Windows.
203 actualContents = actualContents.replaceAll('\r\n', '\n');
204 return expectedContents == actualContents;
205 } catch (e) {
206 // There was a problem reading the file (most likely because it didn't
207 // exist). Treat that the same as if the file doesn't have the expected
208 // contents.
209 return false;
210 }
211 }
212
213 @override
214 void generate(String pkgPath) {
215 output(pkgPath).writeAsStringSync(computeContents(pkgPath));
216 }
217
218 @override
219 File output(String pkgPath) =>
220 new File(join(pkgPath, joinAll(posix.split(outputPath))));
221 }
OLDNEW
« no previous file with comments | « pkg/analyzer_plugin/tool/spec/to_html.dart ('k') | pkg/front_end/test/subpackage_relationships_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698