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

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

Issue 1428673004: Rework codegen tools to avoid relying on CWD; integrate with task model graph. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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 | pkg/analyzer/tool/task_dependency_graph/check_test.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 (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 /** 5 /**
6 * Tools for generating code in analyzer and analysis server. 6 * Tools for generating code in analyzer and analysis server.
7 */ 7 */
8 library analyzer.src.codegen.tools; 8 library analyzer.src.codegen.tools;
9 9
10 import 'dart:io'; 10 import 'dart:io';
11 11
12 import 'package:html/dom.dart' as dom; 12 import 'package:html/dom.dart' as dom;
13 import 'package:path/path.dart'; 13 import 'package:path/path.dart';
14 14
15 import 'html.dart'; 15 import 'html.dart';
16 import 'text_formatter.dart'; 16 import 'text_formatter.dart';
17 17
18 final RegExp trailingSpacesInLineRegExp = new RegExp(r' +$', multiLine: true);
18 final RegExp trailingWhitespaceRegExp = new RegExp(r'[\n ]+$'); 19 final RegExp trailingWhitespaceRegExp = new RegExp(r'[\n ]+$');
19 final RegExp trailingSpacesInLineRegExp = new RegExp(r' +$', multiLine: true);
20 20
21 /** 21 /**
22 * Join the given strings using camelCase. If [doCapitalize] is true, the first 22 * Join the given strings using camelCase. If [doCapitalize] is true, the first
23 * part will be capitalized as well. 23 * part will be capitalized as well.
24 */ 24 */
25 String camelJoin(List<String> parts, {bool doCapitalize: false}) { 25 String camelJoin(List<String> parts, {bool doCapitalize: false}) {
26 List<String> upcasedParts = <String>[]; 26 List<String> upcasedParts = <String>[];
27 for (int i = 0; i < parts.length; i++) { 27 for (int i = 0; i < parts.length; i++) {
28 if (i == 0 && !doCapitalize) { 28 if (i == 0 && !doCapitalize) {
29 upcasedParts.add(parts[i]); 29 upcasedParts.add(parts[i]);
30 } else { 30 } else {
31 upcasedParts.add(capitalize(parts[i])); 31 upcasedParts.add(capitalize(parts[i]));
32 } 32 }
33 } 33 }
34 return upcasedParts.join(); 34 return upcasedParts.join();
35 } 35 }
36 36
37 /** 37 /**
38 * Capitalize and return the passed String. 38 * Capitalize and return the passed String.
39 */ 39 */
40 String capitalize(String string) { 40 String capitalize(String string) {
41 return string[0].toUpperCase() + string.substring(1); 41 return string[0].toUpperCase() + string.substring(1);
42 } 42 }
43 43
44 /** 44 /**
45 * Type of functions used to compute the contents of a set of generated files. 45 * Type of functions used to compute the contents of a set of generated files.
46 * [pkgPath] is the path to the current package.
46 */ 47 */
47 typedef Map<String, FileContentsComputer> DirectoryContentsComputer(); 48 typedef Map<String, FileContentsComputer> DirectoryContentsComputer(
49 String pkgPath);
48 50
49 /** 51 /**
50 * Type of functions used to compute the contents of a generated file. 52 * Type of functions used to compute the contents of a generated file.
53 * [pkgPath] is the path to the current package.
51 */ 54 */
52 typedef String FileContentsComputer(); 55 typedef String FileContentsComputer(String pkgPath);
53 56
54 /** 57 /**
55 * Mixin class for generating code. 58 * Mixin class for generating code.
56 */ 59 */
57 class CodeGenerator { 60 class CodeGenerator {
58 _CodeGeneratorState _state; 61 _CodeGeneratorState _state;
59 62
60 /** 63 /**
61 * Settings that specialize code generation behavior for a given 64 * Settings that specialize code generation behavior for a given
62 * programming language. 65 * programming language.
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 CodeGeneratorSettings( 257 CodeGeneratorSettings(
255 {this.languageName: 'java', 258 {this.languageName: 'java',
256 this.lineCommentLineLeader: '// ', 259 this.lineCommentLineLeader: '// ',
257 this.docCommentStartMarker: '/**', 260 this.docCommentStartMarker: '/**',
258 this.docCommentLineLeader: ' * ', 261 this.docCommentLineLeader: ' * ',
259 this.docCommentEndMarker: ' */', 262 this.docCommentEndMarker: ' */',
260 this.commentLineLength: 99, 263 this.commentLineLength: 99,
261 this.indent: ' '}); 264 this.indent: ' '});
262 } 265 }
263 266
267 /**
268 * Abstract base class representing behaviors common to generated files and
269 * generated directories.
270 */
264 abstract class GeneratedContent { 271 abstract class GeneratedContent {
265 FileSystemEntity get outputFile; 272 /**
266 bool check(); 273 * Check whether the [output] has the correct contents, and return true if it
267 void generate(); 274 * does. [pkgPath] is the path to the current package.
275 */
276 bool check(String pkgPath);
277
278 /**
279 * Replace the [output] with the correct contents. [pkgPath] is the path to
280 * the current package.
281 */
282 void generate(String pkgPath);
283
284 /**
285 * Get a [FileSystemEntity] representing the output file or directory.
286 * [pkgPath] is the path to the current package.
287 */
288 FileSystemEntity output(String pkgPath);
268 } 289 }
269 290
270 /** 291 /**
271 * Class representing a single output directory (either generated code or 292 * Class representing a single output directory (either generated code or
272 * generated HTML). No other content should exist in the directory. 293 * generated HTML). No other content should exist in the directory.
273 */ 294 */
274 class GeneratedDirectory extends GeneratedContent { 295 class GeneratedDirectory extends GeneratedContent {
275 /** 296 /**
276 * The path to the directory that will have the generated content. 297 * The path to the directory that will have the generated content.
277 */ 298 */
278 final String outputDirPath; 299 final String outputDirPath;
279 300
280 /** 301 /**
281 * Callback function that computes the directory contents. 302 * Callback function that computes the directory contents.
282 */ 303 */
283 final DirectoryContentsComputer directoryContentsComputer; 304 final DirectoryContentsComputer directoryContentsComputer;
284 305
285 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer); 306 GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer);
286 307
287 /**
288 * Get a Directory object representing the output directory.
289 */
290 Directory get outputFile =>
291 new Directory(joinAll(posix.split(outputDirPath)));
292
293 /**
294 * Check whether the directory has the correct contents, and return true if it
295 * does.
296 */
297 @override 308 @override
298 bool check() { 309 bool check(String pkgPath) {
299 Map<String, FileContentsComputer> map = directoryContentsComputer(); 310 Directory outputDirectory = output(pkgPath);
311 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
300 try { 312 try {
301 for (String file in map.keys) { 313 for (String file in map.keys) {
302 FileContentsComputer fileContentsComputer = map[file]; 314 FileContentsComputer fileContentsComputer = map[file];
303 String expectedContents = fileContentsComputer(); 315 String expectedContents = fileContentsComputer(pkgPath);
304 File outputFile = 316 File outputFile = new File(posix.join(outputDirectory.path, file));
305 new File(joinAll(posix.split(posix.join(outputDirPath, file))));
306 String actualContents = outputFile.readAsStringSync(); 317 String actualContents = outputFile.readAsStringSync();
307 // Normalize Windows line endings to Unix line endings so that the 318 // Normalize Windows line endings to Unix line endings so that the
308 // comparison doesn't fail on Windows. 319 // comparison doesn't fail on Windows.
309 actualContents = actualContents.replaceAll('\r\n', '\n'); 320 actualContents = actualContents.replaceAll('\r\n', '\n');
310 if (expectedContents != actualContents) { 321 if (expectedContents != actualContents) {
311 return false; 322 return false;
312 } 323 }
313 } 324 }
314 int nonHiddenFileCount = 0; 325 int nonHiddenFileCount = 0;
315 outputFile 326 outputDirectory
316 .listSync(recursive: false, followLinks: false) 327 .listSync(recursive: false, followLinks: false)
317 .forEach((FileSystemEntity fileSystemEntity) { 328 .forEach((FileSystemEntity fileSystemEntity) {
318 if (fileSystemEntity is File && 329 if (fileSystemEntity is File &&
319 !basename(fileSystemEntity.path).startsWith('.')) { 330 !basename(fileSystemEntity.path).startsWith('.')) {
320 nonHiddenFileCount++; 331 nonHiddenFileCount++;
321 } 332 }
322 }); 333 });
323 if (nonHiddenFileCount != map.length) { 334 if (nonHiddenFileCount != map.length) {
324 // The number of files generated doesn't match the number we expected to 335 // The number of files generated doesn't match the number we expected to
325 // generate. 336 // generate.
326 return false; 337 return false;
327 } 338 }
328 } catch (e) { 339 } catch (e) {
329 // There was a problem reading the file (most likely because it didn't 340 // There was a problem reading the file (most likely because it didn't
330 // exist). Treat that the same as if the file doesn't have the expected 341 // exist). Treat that the same as if the file doesn't have the expected
331 // contents. 342 // contents.
332 return false; 343 return false;
333 } 344 }
334 return true; 345 return true;
335 } 346 }
336 347
337 /**
338 * Replace the directory with the correct contents. [spec] is the "tool/spec"
339 * directory. If [spec] is unspecified, it is assumed to be the directory
340 * containing Platform.executable.
341 */
342 @override 348 @override
343 void generate() { 349 void generate(String pkgPath) {
350 Directory outputDirectory = output(pkgPath);
344 try { 351 try {
345 // delete the contents of the directory (and the directory itself) 352 // delete the contents of the directory (and the directory itself)
346 outputFile.deleteSync(recursive: true); 353 outputDirectory.deleteSync(recursive: true);
347 } catch (e) { 354 } catch (e) {
348 // Error caught while trying to delete the directory, this can happen if 355 // Error caught while trying to delete the directory, this can happen if
349 // it didn't yet exist. 356 // it didn't yet exist.
350 } 357 }
351 // re-create the empty directory 358 // re-create the empty directory
352 outputFile.createSync(recursive: true); 359 outputDirectory.createSync(recursive: true);
353 360
354 // generate all of the files in the directory 361 // generate all of the files in the directory
355 Map<String, FileContentsComputer> map = directoryContentsComputer(); 362 Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
356 map.forEach((String file, FileContentsComputer fileContentsComputer) { 363 map.forEach((String file, FileContentsComputer fileContentsComputer) {
357 File outputFile = new File(joinAll(posix.split(outputDirPath + file))); 364 File outputFile = new File(posix.join(outputDirectory.path, file));
358 outputFile.writeAsStringSync(fileContentsComputer()); 365 outputFile.writeAsStringSync(fileContentsComputer(pkgPath));
359 }); 366 });
360 } 367 }
368
369 @override
370 Directory output(String pkgPath) =>
371 new Directory(join(pkgPath, joinAll(posix.split(outputDirPath))));
361 } 372 }
362 373
363 /** 374 /**
364 * Class representing a single output file (either generated code or generated 375 * Class representing a single output file (either generated code or generated
365 * HTML). 376 * HTML).
366 */ 377 */
367 class GeneratedFile extends GeneratedContent { 378 class GeneratedFile extends GeneratedContent {
368 /** 379 /**
369 * The output file to which generated output should be written, relative to 380 * The output file to which generated output should be written, relative to
370 * the "tool/spec" directory. This filename uses the posix path separator 381 * the "tool/spec" directory. This filename uses the posix path separator
371 * ('/') regardless of the OS. 382 * ('/') regardless of the OS.
372 */ 383 */
373 final String outputPath; 384 final String outputPath;
374 385
375 /** 386 /**
376 * Callback function which computes the file. 387 * Callback function which computes the file.
377 */ 388 */
378 final FileContentsComputer computeContents; 389 final FileContentsComputer computeContents;
379 390
380 GeneratedFile(this.outputPath, this.computeContents); 391 GeneratedFile(this.outputPath, this.computeContents);
381 392
382 /**
383 * Get a File object representing the output file.
384 */
385 File get outputFile => new File(joinAll(posix.split(outputPath)));
386
387 /**
388 * Check whether the file has the correct contents, and return true if it
389 * does.
390 */
391 @override 393 @override
392 bool check() { 394 bool check(String pkgPath) {
393 String expectedContents = computeContents(); 395 File outputFile = output(pkgPath);
396 String expectedContents = computeContents(pkgPath);
394 try { 397 try {
395 String actualContents = outputFile.readAsStringSync(); 398 String actualContents = outputFile.readAsStringSync();
396 // Normalize Windows line endings to Unix line endings so that the 399 // Normalize Windows line endings to Unix line endings so that the
397 // comparison doesn't fail on Windows. 400 // comparison doesn't fail on Windows.
398 actualContents = actualContents.replaceAll('\r\n', '\n'); 401 actualContents = actualContents.replaceAll('\r\n', '\n');
399 return expectedContents == actualContents; 402 return expectedContents == actualContents;
400 } catch (e) { 403 } catch (e) {
401 // There was a problem reading the file (most likely because it didn't 404 // There was a problem reading the file (most likely because it didn't
402 // exist). Treat that the same as if the file doesn't have the expected 405 // exist). Treat that the same as if the file doesn't have the expected
403 // contents. 406 // contents.
404 return false; 407 return false;
405 } 408 }
406 } 409 }
407 410
408 /** 411 @override
409 * Replace the file with the correct contents. [spec] is the "tool/spec" 412 void generate(String pkgPath) {
410 * directory. If [spec] is unspecified, it is assumed to be the directory 413 output(pkgPath).writeAsStringSync(computeContents(pkgPath));
411 * containing Platform.executable.
412 */
413 void generate() {
414 outputFile.writeAsStringSync(computeContents());
415 } 414 }
415
416 @override
417 File output(String pkgPath) =>
418 new File(join(pkgPath, joinAll(posix.split(outputPath))));
416 } 419 }
417 420
418 /** 421 /**
419 * Mixin class for generating HTML representations of code that are suitable 422 * Mixin class for generating HTML representations of code that are suitable
420 * for enclosing inside a <pre> element. 423 * for enclosing inside a <pre> element.
421 */ 424 */
422 abstract class HtmlCodeGenerator { 425 abstract class HtmlCodeGenerator {
423 _HtmlCodeGeneratorState _state; 426 _HtmlCodeGeneratorState _state;
424 427
425 /** 428 /**
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 if (lines.last.isEmpty) { 551 if (lines.last.isEmpty) {
549 lines.removeLast(); 552 lines.removeLast();
550 buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); 553 buffer.add(new dom.Text(lines.join('\n$indent') + '\n'));
551 indentNeeded = true; 554 indentNeeded = true;
552 } else { 555 } else {
553 buffer.add(new dom.Text(lines.join('\n$indent'))); 556 buffer.add(new dom.Text(lines.join('\n$indent')));
554 indentNeeded = false; 557 indentNeeded = false;
555 } 558 }
556 } 559 }
557 } 560 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/tool/task_dependency_graph/check_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698