| Index: pkg/front_end/lib/src/codegen/tools.dart
|
| diff --git a/pkg/front_end/lib/src/codegen/tools.dart b/pkg/front_end/lib/src/codegen/tools.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..45d5a23971cdac1597b5b9c3577e21b7de1ce58b
|
| --- /dev/null
|
| +++ b/pkg/front_end/lib/src/codegen/tools.dart
|
| @@ -0,0 +1,221 @@
|
| +// 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: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 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.
|
| + */
|
| + bool check(String pkgPath);
|
| +
|
| + /**
|
| + * Replace the [output] with the correct contents. [pkgPath] is the path to
|
| + * the current package.
|
| + */
|
| + void 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 void checkAll(String pkgPath, String generatorRelPath,
|
| + Iterable<GeneratedContent> targets) {
|
| + bool generateNeeded = false;
|
| + for (GeneratedContent target in targets) {
|
| + if (!target.check(pkgPath)) {
|
| + print(
|
| + '${target.output(pkgPath).absolute} does not 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 void generateAll(String pkgPath, Iterable<GeneratedContent> targets) {
|
| + for (GeneratedContent target in targets) {
|
| + 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
|
| + bool check(String pkgPath) {
|
| + Directory outputDirectory = output(pkgPath);
|
| + Map<String, FileContentsComputer> map = directoryContentsComputer(pkgPath);
|
| + try {
|
| + for (String file in map.keys) {
|
| + FileContentsComputer fileContentsComputer = map[file];
|
| + String expectedContents = 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
|
| + void generate(String pkgPath) {
|
| + 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);
|
| + map.forEach((String file, FileContentsComputer fileContentsComputer) {
|
| + File outputFile = new File(posix.join(outputDirectory.path, file));
|
| + outputFile.writeAsStringSync(fileContentsComputer(pkgPath));
|
| + });
|
| + }
|
| +
|
| + @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);
|
| +
|
| + @override
|
| + bool check(String pkgPath) {
|
| + File outputFile = output(pkgPath);
|
| + String expectedContents = computeContents(pkgPath);
|
| + 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
|
| + void generate(String pkgPath) {
|
| + output(pkgPath).writeAsStringSync(computeContents(pkgPath));
|
| + }
|
| +
|
| + @override
|
| + File output(String pkgPath) =>
|
| + new File(join(pkgPath, joinAll(posix.split(outputPath))));
|
| +}
|
|
|