mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 14:13:09 +00:00
Move codegen/tools.dart to package:analyzer
Change-Id: Iab61e0dfcdd0969d1bf35e27c13c336a944d14e6 Reviewed-on: https://dart-review.googlesource.com/c/77780 Commit-Queue: Peter von der Ahé <ahe@google.com> Auto-Submit: Peter von der Ahé <ahe@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
This commit is contained in:
parent
fd9a2cb510
commit
eb0ec965e3
|
@ -4,7 +4,7 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import 'generate_all.dart';
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Code generation for the file "AnalysisServer.java".
|
||||
*/
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
|
||||
import 'api.dart';
|
||||
import 'codegen_java.dart';
|
||||
|
@ -113,7 +112,7 @@ class CodegenAnalysisServer extends CodegenJavaVisitor {
|
|||
String methodName = '${request.domainName}_${request.method}';
|
||||
publicMethod(methodName, () {
|
||||
docComment(toHtmlVisitor.collectHtml(() {
|
||||
toHtmlVisitor.write('{@code ${request.longMethod }}');
|
||||
toHtmlVisitor.write('{@code ${request.longMethod}}');
|
||||
toHtmlVisitor.translateHtml(request.html);
|
||||
toHtmlVisitor.javadocParams(request.params);
|
||||
if (request.deprecated) {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'api.dart';
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Tools for Java code generation.
|
||||
*/
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
|
||||
import 'api.dart';
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Code generation for the file "AnalysisServer.java".
|
||||
*/
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
|
||||
import 'api.dart';
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
|
||||
import 'api.dart';
|
||||
import 'from_html.dart';
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
|
||||
import 'api.dart';
|
||||
import 'codegen_dart.dart';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import 'codegen_analysis_server.dart' as codegen_analysis_server;
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'dart:convert';
|
|||
|
||||
import 'package:analyzer/src/codegen/html.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
|
||||
import 'api.dart';
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
*/
|
||||
library analyzer.src.codegen.tools;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:analyzer/src/codegen/html.dart';
|
||||
import 'package:analyzer/src/codegen/text_formatter.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
export 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
final RegExp trailingSpacesInLineRegExp = new RegExp(r' +$', multiLine: true);
|
||||
final RegExp trailingWhitespaceRegExp = new RegExp(r'[\n ]+$');
|
||||
|
@ -383,3 +386,265 @@ class _HtmlCodeGeneratorState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of functions used to compute the contents of a set of generated files.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
typedef Map<String, FileContentsComputer> DirectoryContentsComputer(
|
||||
String pkgPath);
|
||||
|
||||
/**
|
||||
* Type of functions used to compute the contents of a generated file.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
typedef Future<String> FileContentsComputer(String pkgPath);
|
||||
|
||||
/**
|
||||
* Abstract base class representing behaviors common to generated files and
|
||||
* generated directories.
|
||||
*/
|
||||
abstract class GeneratedContent {
|
||||
/**
|
||||
* Check whether the [output] has the correct contents, and return true if it
|
||||
* does. [pkgPath] is the path to the current package.
|
||||
*/
|
||||
Future<bool> check(String pkgPath);
|
||||
|
||||
/**
|
||||
* Replace the [output] with the correct contents. [pkgPath] is the path to
|
||||
* the current package.
|
||||
*/
|
||||
Future<Null> generate(String pkgPath);
|
||||
|
||||
/**
|
||||
* Get a [FileSystemEntity] representing the output file or directory.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
FileSystemEntity output(String pkgPath);
|
||||
|
||||
/**
|
||||
* Check that all of the [targets] are up to date. If they are not, print
|
||||
* out a message instructing the user to regenerate them, and exit with a
|
||||
* nonzero error code.
|
||||
*
|
||||
* [pkgPath] is the path to the current package. [generatorRelPath] is the
|
||||
* path to a .dart script the user may use to regenerate the targets.
|
||||
*
|
||||
* To avoid mistakes when run on Windows, [generatorRelPath] always uses
|
||||
* POSIX directory separators.
|
||||
*/
|
||||
static Future<Null> checkAll(String pkgPath, String generatorRelPath,
|
||||
Iterable<GeneratedContent> targets) async {
|
||||
bool generateNeeded = false;
|
||||
for (GeneratedContent target in targets) {
|
||||
bool ok = await target.check(pkgPath);
|
||||
if (!ok) {
|
||||
print("${target.output(pkgPath).absolute}"
|
||||
" doesn't have expected contents.");
|
||||
generateNeeded = true;
|
||||
}
|
||||
}
|
||||
if (generateNeeded) {
|
||||
print('Please regenerate using:');
|
||||
String executable = Platform.executable;
|
||||
String packageRoot = '';
|
||||
// ignore: deprecated_member_use
|
||||
if (Platform.packageRoot != null) {
|
||||
// ignore: deprecated_member_use
|
||||
packageRoot = ' --package-root=${Platform.packageRoot}';
|
||||
}
|
||||
String generateScript =
|
||||
join(pkgPath, joinAll(posix.split(generatorRelPath)));
|
||||
print(' $executable$packageRoot $generateScript');
|
||||
exit(1);
|
||||
} else {
|
||||
print('All generated files up to date.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate all of the [targets]. [pkgPath] is the path to the current
|
||||
* package.
|
||||
*/
|
||||
static Future<Null> generateAll(
|
||||
String pkgPath, Iterable<GeneratedContent> targets) async {
|
||||
print("Generating...");
|
||||
for (GeneratedContent target in targets) {
|
||||
await target.generate(pkgPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a single output directory (either generated code or
|
||||
* generated HTML). No other content should exist in the directory.
|
||||
*/
|
||||
class GeneratedDirectory extends GeneratedContent {
|
||||
/**
|
||||
* The path to the directory that will have the generated content.
|
||||
*/
|
||||
final String outputDirPath;
|
||||
|
||||
/**
|
||||
* Callback function that computes the directory contents.
|
||||
*/
|
||||
final DirectoryContentsComputer directoryContentsComputer;
|
||||
|
||||
GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer);
|
||||
|
||||
@override
|
||||
Future<bool> check(String pkgPath) async {
|
||||
Directory outputDirectory = output(pkgPath);
|
||||
Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
|
||||
try {
|
||||
for (String file in map.keys) {
|
||||
FileContentsComputer fileContentsComputer = map[file];
|
||||
String expectedContents = await fileContentsComputer(pkgPath);
|
||||
File outputFile = new File(posix.join(outputDirectory.path, file));
|
||||
String actualContents = outputFile.readAsStringSync();
|
||||
// Normalize Windows line endings to Unix line endings so that the
|
||||
// comparison doesn't fail on Windows.
|
||||
actualContents = actualContents.replaceAll('\r\n', '\n');
|
||||
if (expectedContents != actualContents) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int nonHiddenFileCount = 0;
|
||||
outputDirectory
|
||||
.listSync(recursive: false, followLinks: false)
|
||||
.forEach((FileSystemEntity fileSystemEntity) {
|
||||
if (fileSystemEntity is File &&
|
||||
!basename(fileSystemEntity.path).startsWith('.')) {
|
||||
nonHiddenFileCount++;
|
||||
}
|
||||
});
|
||||
if (nonHiddenFileCount != map.length) {
|
||||
// The number of files generated doesn't match the number we expected to
|
||||
// generate.
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
// There was a problem reading the file (most likely because it didn't
|
||||
// exist). Treat that the same as if the file doesn't have the expected
|
||||
// contents.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Null> generate(String pkgPath) async {
|
||||
Directory outputDirectory = output(pkgPath);
|
||||
try {
|
||||
// delete the contents of the directory (and the directory itself)
|
||||
outputDirectory.deleteSync(recursive: true);
|
||||
} catch (e) {
|
||||
// Error caught while trying to delete the directory, this can happen if
|
||||
// it didn't yet exist.
|
||||
}
|
||||
// re-create the empty directory
|
||||
outputDirectory.createSync(recursive: true);
|
||||
|
||||
// generate all of the files in the directory
|
||||
Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
|
||||
for (String file in map.keys) {
|
||||
FileContentsComputer fileContentsComputer = map[file];
|
||||
File outputFile = new File(posix.join(outputDirectory.path, file));
|
||||
print(' ${outputFile.path}');
|
||||
String contents = await fileContentsComputer(pkgPath);
|
||||
outputFile.writeAsStringSync(contents);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Directory output(String pkgPath) =>
|
||||
new Directory(join(pkgPath, joinAll(posix.split(outputDirPath))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a single output file (either generated code or generated
|
||||
* HTML).
|
||||
*/
|
||||
class GeneratedFile extends GeneratedContent {
|
||||
/**
|
||||
* The output file to which generated output should be written, relative to
|
||||
* the "tool/spec" directory. This filename uses the posix path separator
|
||||
* ('/') regardless of the OS.
|
||||
*/
|
||||
final String outputPath;
|
||||
|
||||
/**
|
||||
* Callback function which computes the file.
|
||||
*/
|
||||
final FileContentsComputer computeContents;
|
||||
|
||||
GeneratedFile(this.outputPath, this.computeContents);
|
||||
|
||||
bool get isDartFile => outputPath.endsWith('.dart');
|
||||
|
||||
@override
|
||||
Future<bool> check(String pkgPath) async {
|
||||
File outputFile = output(pkgPath);
|
||||
String expectedContents = await computeContents(pkgPath);
|
||||
if (isDartFile) {
|
||||
expectedContents = DartFormat.formatText(expectedContents);
|
||||
}
|
||||
try {
|
||||
String actualContents = outputFile.readAsStringSync();
|
||||
// Normalize Windows line endings to Unix line endings so that the
|
||||
// comparison doesn't fail on Windows.
|
||||
actualContents = actualContents.replaceAll('\r\n', '\n');
|
||||
return expectedContents == actualContents;
|
||||
} catch (e) {
|
||||
// There was a problem reading the file (most likely because it didn't
|
||||
// exist). Treat that the same as if the file doesn't have the expected
|
||||
// contents.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Null> generate(String pkgPath) async {
|
||||
File outputFile = output(pkgPath);
|
||||
print(' ${outputFile.path}');
|
||||
String contents = await computeContents(pkgPath);
|
||||
outputFile.writeAsStringSync(contents);
|
||||
if (isDartFile) {
|
||||
DartFormat.formatFile(outputFile);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
File output(String pkgPath) =>
|
||||
new File(join(pkgPath, joinAll(posix.split(outputPath))));
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class for invoking dartfmt.
|
||||
*/
|
||||
class DartFormat {
|
||||
static String get _dartfmtPath {
|
||||
String binName = Platform.isWindows ? 'dartfmt.bat' : 'dartfmt';
|
||||
for (var loc in [binName, join('dart-sdk', 'bin', binName)]) {
|
||||
var candidatePath = join(dirname(Platform.resolvedExecutable), loc);
|
||||
if (new File(candidatePath).existsSync()) {
|
||||
return candidatePath;
|
||||
}
|
||||
}
|
||||
throw new StateError('Could not find dartfmt executable');
|
||||
}
|
||||
|
||||
static void formatFile(File file) {
|
||||
ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]);
|
||||
if (result.exitCode != 0) throw result.stderr;
|
||||
}
|
||||
|
||||
static String formatText(String text) {
|
||||
File file = new File(join(Directory.systemTemp.path, 'gen.dart'));
|
||||
file.writeAsStringSync(text);
|
||||
ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]);
|
||||
if (result.exitCode != 0) throw result.stderr;
|
||||
return file.readAsStringSync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/testing/package_root.dart' as pkgRoot;
|
||||
import 'package:path/path.dart';
|
||||
import 'package:yaml/yaml.dart' show loadYaml;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
library analyzer.tool.summary.check_test;
|
||||
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/testing/package_root.dart' as package_root;
|
||||
import 'package:path/path.dart';
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ library analyzer.tool.summary.generate;
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/fasta/scanner/string_scanner.dart';
|
||||
import 'package:front_end/src/scanner/token.dart' show Token;
|
||||
import 'package:front_end/src/testing/package_root.dart' as package_root;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
library analyzer.tool.task_dependency_graph.check_test;
|
||||
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/testing/package_root.dart' as package_root;
|
||||
import 'package:path/path.dart';
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ import 'package:analyzer/src/generated/source_io.dart';
|
|||
import 'package:analyzer/src/source/package_map_resolver.dart';
|
||||
import 'package:front_end/src/api_prototype/byte_store.dart';
|
||||
import 'package:front_end/src/base/performance_logger.dart';
|
||||
import 'package:front_end/src/codegen/tools.dart';
|
||||
import 'package:analyzer/src/codegen/tools.dart';
|
||||
import 'package:front_end/src/testing/package_root.dart' as package_root;
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path/path.dart';
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart';
|
||||
|
||||
/**
|
||||
* Type of functions used to compute the contents of a set of generated files.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
typedef Map<String, FileContentsComputer> DirectoryContentsComputer(
|
||||
String pkgPath);
|
||||
|
||||
/**
|
||||
* Type of functions used to compute the contents of a generated file.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
typedef Future<String> FileContentsComputer(String pkgPath);
|
||||
|
||||
/**
|
||||
* Abstract base class representing behaviors common to generated files and
|
||||
* generated directories.
|
||||
*/
|
||||
abstract class GeneratedContent {
|
||||
/**
|
||||
* Check whether the [output] has the correct contents, and return true if it
|
||||
* does. [pkgPath] is the path to the current package.
|
||||
*/
|
||||
Future<bool> check(String pkgPath);
|
||||
|
||||
/**
|
||||
* Replace the [output] with the correct contents. [pkgPath] is the path to
|
||||
* the current package.
|
||||
*/
|
||||
Future<Null> generate(String pkgPath);
|
||||
|
||||
/**
|
||||
* Get a [FileSystemEntity] representing the output file or directory.
|
||||
* [pkgPath] is the path to the current package.
|
||||
*/
|
||||
FileSystemEntity output(String pkgPath);
|
||||
|
||||
/**
|
||||
* Check that all of the [targets] are up to date. If they are not, print
|
||||
* out a message instructing the user to regenerate them, and exit with a
|
||||
* nonzero error code.
|
||||
*
|
||||
* [pkgPath] is the path to the current package. [generatorRelPath] is the
|
||||
* path to a .dart script the user may use to regenerate the targets.
|
||||
*
|
||||
* To avoid mistakes when run on Windows, [generatorRelPath] always uses
|
||||
* POSIX directory separators.
|
||||
*/
|
||||
static Future<Null> checkAll(String pkgPath, String generatorRelPath,
|
||||
Iterable<GeneratedContent> targets) async {
|
||||
bool generateNeeded = false;
|
||||
for (GeneratedContent target in targets) {
|
||||
bool ok = await target.check(pkgPath);
|
||||
if (!ok) {
|
||||
print("${target.output(pkgPath).absolute}"
|
||||
" doesn't have expected contents.");
|
||||
generateNeeded = true;
|
||||
}
|
||||
}
|
||||
if (generateNeeded) {
|
||||
print('Please regenerate using:');
|
||||
String executable = Platform.executable;
|
||||
String packageRoot = '';
|
||||
if (Platform.packageRoot != null) {
|
||||
packageRoot = ' --package-root=${Platform.packageRoot}';
|
||||
}
|
||||
String generateScript =
|
||||
join(pkgPath, joinAll(posix.split(generatorRelPath)));
|
||||
print(' $executable$packageRoot $generateScript');
|
||||
exit(1);
|
||||
} else {
|
||||
print('All generated files up to date.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate all of the [targets]. [pkgPath] is the path to the current
|
||||
* package.
|
||||
*/
|
||||
static Future<Null> generateAll(
|
||||
String pkgPath, Iterable<GeneratedContent> targets) async {
|
||||
print("Generating...");
|
||||
for (GeneratedContent target in targets) {
|
||||
await target.generate(pkgPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a single output directory (either generated code or
|
||||
* generated HTML). No other content should exist in the directory.
|
||||
*/
|
||||
class GeneratedDirectory extends GeneratedContent {
|
||||
/**
|
||||
* The path to the directory that will have the generated content.
|
||||
*/
|
||||
final String outputDirPath;
|
||||
|
||||
/**
|
||||
* Callback function that computes the directory contents.
|
||||
*/
|
||||
final DirectoryContentsComputer directoryContentsComputer;
|
||||
|
||||
GeneratedDirectory(this.outputDirPath, this.directoryContentsComputer);
|
||||
|
||||
@override
|
||||
Future<bool> check(String pkgPath) async {
|
||||
Directory outputDirectory = output(pkgPath);
|
||||
Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
|
||||
try {
|
||||
for (String file in map.keys) {
|
||||
FileContentsComputer fileContentsComputer = map[file];
|
||||
String expectedContents = await fileContentsComputer(pkgPath);
|
||||
File outputFile = new File(posix.join(outputDirectory.path, file));
|
||||
String actualContents = outputFile.readAsStringSync();
|
||||
// Normalize Windows line endings to Unix line endings so that the
|
||||
// comparison doesn't fail on Windows.
|
||||
actualContents = actualContents.replaceAll('\r\n', '\n');
|
||||
if (expectedContents != actualContents) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int nonHiddenFileCount = 0;
|
||||
outputDirectory
|
||||
.listSync(recursive: false, followLinks: false)
|
||||
.forEach((FileSystemEntity fileSystemEntity) {
|
||||
if (fileSystemEntity is File &&
|
||||
!basename(fileSystemEntity.path).startsWith('.')) {
|
||||
nonHiddenFileCount++;
|
||||
}
|
||||
});
|
||||
if (nonHiddenFileCount != map.length) {
|
||||
// The number of files generated doesn't match the number we expected to
|
||||
// generate.
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
// There was a problem reading the file (most likely because it didn't
|
||||
// exist). Treat that the same as if the file doesn't have the expected
|
||||
// contents.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Null> generate(String pkgPath) async {
|
||||
Directory outputDirectory = output(pkgPath);
|
||||
try {
|
||||
// delete the contents of the directory (and the directory itself)
|
||||
outputDirectory.deleteSync(recursive: true);
|
||||
} catch (e) {
|
||||
// Error caught while trying to delete the directory, this can happen if
|
||||
// it didn't yet exist.
|
||||
}
|
||||
// re-create the empty directory
|
||||
outputDirectory.createSync(recursive: true);
|
||||
|
||||
// generate all of the files in the directory
|
||||
Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
|
||||
for (String file in map.keys) {
|
||||
FileContentsComputer fileContentsComputer = map[file];
|
||||
File outputFile = new File(posix.join(outputDirectory.path, file));
|
||||
print(' ${outputFile.path}');
|
||||
String contents = await fileContentsComputer(pkgPath);
|
||||
outputFile.writeAsStringSync(contents);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Directory output(String pkgPath) =>
|
||||
new Directory(join(pkgPath, joinAll(posix.split(outputDirPath))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a single output file (either generated code or generated
|
||||
* HTML).
|
||||
*/
|
||||
class GeneratedFile extends GeneratedContent {
|
||||
/**
|
||||
* The output file to which generated output should be written, relative to
|
||||
* the "tool/spec" directory. This filename uses the posix path separator
|
||||
* ('/') regardless of the OS.
|
||||
*/
|
||||
final String outputPath;
|
||||
|
||||
/**
|
||||
* Callback function which computes the file.
|
||||
*/
|
||||
final FileContentsComputer computeContents;
|
||||
|
||||
GeneratedFile(this.outputPath, this.computeContents);
|
||||
|
||||
bool get isDartFile => outputPath.endsWith('.dart');
|
||||
|
||||
@override
|
||||
Future<bool> check(String pkgPath) async {
|
||||
File outputFile = output(pkgPath);
|
||||
String expectedContents = await computeContents(pkgPath);
|
||||
if (isDartFile) {
|
||||
expectedContents = DartFormat.formatText(expectedContents);
|
||||
}
|
||||
try {
|
||||
String actualContents = outputFile.readAsStringSync();
|
||||
// Normalize Windows line endings to Unix line endings so that the
|
||||
// comparison doesn't fail on Windows.
|
||||
actualContents = actualContents.replaceAll('\r\n', '\n');
|
||||
return expectedContents == actualContents;
|
||||
} catch (e) {
|
||||
// There was a problem reading the file (most likely because it didn't
|
||||
// exist). Treat that the same as if the file doesn't have the expected
|
||||
// contents.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Null> generate(String pkgPath) async {
|
||||
File outputFile = output(pkgPath);
|
||||
print(' ${outputFile.path}');
|
||||
String contents = await computeContents(pkgPath);
|
||||
outputFile.writeAsStringSync(contents);
|
||||
if (isDartFile) {
|
||||
DartFormat.formatFile(outputFile);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
File output(String pkgPath) =>
|
||||
new File(join(pkgPath, joinAll(posix.split(outputPath))));
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class for invoking dartfmt.
|
||||
*/
|
||||
class DartFormat {
|
||||
static String get _dartfmtPath {
|
||||
String binName = Platform.isWindows ? 'dartfmt.bat' : 'dartfmt';
|
||||
for (var loc in [binName, join('dart-sdk', 'bin', binName)]) {
|
||||
var candidatePath = join(dirname(Platform.resolvedExecutable), loc);
|
||||
if (new File(candidatePath).existsSync()) {
|
||||
return candidatePath;
|
||||
}
|
||||
}
|
||||
throw new StateError('Could not find dartfmt executable');
|
||||
}
|
||||
|
||||
static void formatFile(File file) {
|
||||
ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]);
|
||||
if (result.exitCode != 0) throw result.stderr;
|
||||
}
|
||||
|
||||
static String formatText(String text) {
|
||||
File file = new File(join(Directory.systemTemp.path, 'gen.dart'));
|
||||
file.writeAsStringSync(text);
|
||||
ProcessResult result = Process.runSync(_dartfmtPath, ['-w', file.path]);
|
||||
if (result.exitCode != 0) throw result.stderr;
|
||||
return file.readAsStringSync();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue