2019-11-27 23:04:02 +00:00
|
|
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
2016-05-01 22:52:51 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
|
2018-02-05 17:31:18 +00:00
|
|
|
import 'package:args/args.dart';
|
2017-02-10 17:55:58 +00:00
|
|
|
import 'package:intl/intl.dart';
|
2016-05-01 22:52:51 +00:00
|
|
|
import 'package:path/path.dart' as path;
|
2018-11-10 01:51:25 +00:00
|
|
|
import 'package:process/process.dart';
|
2016-05-01 22:52:51 +00:00
|
|
|
|
2020-07-28 22:26:33 +00:00
|
|
|
import 'dartdoc_checker.dart';
|
|
|
|
|
2018-10-23 20:50:24 +00:00
|
|
|
const String kDocsRoot = 'dev/docs';
|
|
|
|
const String kPublishRoot = '$kDocsRoot/doc';
|
2018-11-10 01:51:25 +00:00
|
|
|
const String kSnippetsRoot = 'dev/snippets';
|
2016-05-16 15:28:58 +00:00
|
|
|
|
2020-07-30 21:11:23 +00:00
|
|
|
const String kDummyPackageName = 'Flutter';
|
|
|
|
const String kPlatformIntegrationPackageName = 'platform_integration';
|
|
|
|
|
2016-05-01 22:52:51 +00:00
|
|
|
/// This script expects to run with the cwd as the root of the flutter repo. It
|
|
|
|
/// will generate documentation for the packages in `//packages/` and write the
|
|
|
|
/// documentation to `//dev/docs/doc/api/`.
|
2016-08-29 23:20:18 +00:00
|
|
|
///
|
2016-05-16 15:28:58 +00:00
|
|
|
/// This script also updates the index.html file so that it can be placed
|
2021-01-08 00:28:12 +00:00
|
|
|
/// at the root of api.flutter.dev. We are keeping the files inside of
|
|
|
|
/// api.flutter.dev/flutter for now, so we need to manipulate paths
|
2016-05-16 15:28:58 +00:00
|
|
|
/// a bit. See https://github.com/flutter/flutter/issues/3900 for more info.
|
2017-05-11 16:42:08 +00:00
|
|
|
///
|
|
|
|
/// This will only work on UNIX systems, not Windows. It requires that 'git' be
|
|
|
|
/// in your path. It requires that 'flutter' has been run previously. It uses
|
|
|
|
/// the version of Dart downloaded by the 'flutter' tool in this repository and
|
|
|
|
/// will crash if that is absent.
|
2018-10-04 16:44:23 +00:00
|
|
|
Future<void> main(List<String> arguments) async {
|
2018-02-05 17:31:18 +00:00
|
|
|
final ArgParser argParser = _createArgsParser();
|
|
|
|
final ArgResults args = argParser.parse(arguments);
|
2019-12-05 21:34:06 +00:00
|
|
|
if (args['help'] as bool) {
|
2018-02-05 17:31:18 +00:00
|
|
|
print ('Usage:');
|
|
|
|
print (argParser.usage);
|
|
|
|
exit(0);
|
|
|
|
}
|
2016-05-01 22:52:51 +00:00
|
|
|
// If we're run from the `tools` dir, set the cwd to the repo root.
|
|
|
|
if (path.basename(Directory.current.path) == 'tools')
|
|
|
|
Directory.current = Directory.current.parent.parent;
|
|
|
|
|
2018-01-18 15:59:06 +00:00
|
|
|
final ProcessResult flutter = Process.runSync('flutter', <String>[]);
|
2018-09-12 06:29:29 +00:00
|
|
|
final File versionFile = File('version');
|
2018-01-18 15:59:06 +00:00
|
|
|
if (flutter.exitCode != 0 || !versionFile.existsSync())
|
2018-09-12 06:29:29 +00:00
|
|
|
throw Exception('Failed to determine Flutter version.');
|
2018-01-18 15:59:06 +00:00
|
|
|
final String version = versionFile.readAsStringSync();
|
2017-06-20 18:27:37 +00:00
|
|
|
|
2016-05-01 22:52:51 +00:00
|
|
|
// Create the pubspec.yaml file.
|
2018-09-12 06:29:29 +00:00
|
|
|
final StringBuffer buf = StringBuffer();
|
2020-07-30 21:11:23 +00:00
|
|
|
buf.writeln('name: $kDummyPackageName');
|
2019-04-05 18:39:30 +00:00
|
|
|
buf.writeln('homepage: https://flutter.dev');
|
2020-04-22 23:33:01 +00:00
|
|
|
// TODO(dnfield): Re-factor for proper versioning, https://github.com/flutter/flutter/issues/55409
|
2019-06-21 00:59:37 +00:00
|
|
|
buf.writeln('version: 0.0.0');
|
2020-11-09 18:02:10 +00:00
|
|
|
buf.writeln('environment:');
|
|
|
|
buf.writeln(" sdk: '>=2.10.0 <3.0.0'");
|
2018-01-18 15:59:06 +00:00
|
|
|
buf.writeln('dependencies:');
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final String package in findPackageNames()) {
|
2016-05-01 22:52:51 +00:00
|
|
|
buf.writeln(' $package:');
|
2016-09-23 03:39:35 +00:00
|
|
|
buf.writeln(' sdk: flutter');
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
2020-07-30 21:11:23 +00:00
|
|
|
buf.writeln(' $kPlatformIntegrationPackageName: 0.0.1');
|
2017-02-10 00:12:09 +00:00
|
|
|
buf.writeln('dependency_overrides:');
|
2020-07-30 21:11:23 +00:00
|
|
|
buf.writeln(' $kPlatformIntegrationPackageName:');
|
|
|
|
buf.writeln(' path: $kPlatformIntegrationPackageName');
|
2018-10-23 20:50:24 +00:00
|
|
|
File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString());
|
2016-05-01 22:52:51 +00:00
|
|
|
|
|
|
|
// Create the library file.
|
2018-10-23 20:50:24 +00:00
|
|
|
final Directory libDir = Directory('$kDocsRoot/lib');
|
2016-05-01 22:52:51 +00:00
|
|
|
libDir.createSync();
|
|
|
|
|
2018-09-12 06:29:29 +00:00
|
|
|
final StringBuffer contents = StringBuffer('library temp_doc;\n\n');
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final String libraryRef in libraryRefs()) {
|
2020-02-11 19:58:27 +00:00
|
|
|
contents.writeln("import 'package:$libraryRef';");
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
2018-10-23 20:50:24 +00:00
|
|
|
File('$kDocsRoot/lib/temp_doc.dart').writeAsStringSync(contents.toString());
|
2016-05-01 22:52:51 +00:00
|
|
|
|
2017-12-05 22:46:39 +00:00
|
|
|
final String flutterRoot = Directory.current.path;
|
|
|
|
final Map<String, String> pubEnvironment = <String, String>{
|
|
|
|
'FLUTTER_ROOT': flutterRoot,
|
|
|
|
};
|
|
|
|
|
|
|
|
// If there's a .pub-cache dir in the flutter root, use that.
|
|
|
|
final String pubCachePath = '$flutterRoot/.pub-cache';
|
2018-09-12 06:29:29 +00:00
|
|
|
if (Directory(pubCachePath).existsSync()) {
|
2017-12-05 22:46:39 +00:00
|
|
|
pubEnvironment['PUB_CACHE'] = pubCachePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
final String pubExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/pub';
|
|
|
|
|
2016-05-01 22:52:51 +00:00
|
|
|
// Run pub.
|
2018-11-10 01:51:25 +00:00
|
|
|
ProcessWrapper process = ProcessWrapper(await Process.start(
|
2017-12-05 22:46:39 +00:00
|
|
|
pubExecutable,
|
2017-05-11 16:42:08 +00:00
|
|
|
<String>['get'],
|
2018-10-23 20:50:24 +00:00
|
|
|
workingDirectory: kDocsRoot,
|
2017-12-05 22:46:39 +00:00
|
|
|
environment: pubEnvironment,
|
2018-11-10 01:51:25 +00:00
|
|
|
));
|
2017-07-28 22:44:38 +00:00
|
|
|
printStream(process.stdout, prefix: 'pub:stdout: ');
|
|
|
|
printStream(process.stderr, prefix: 'pub:stderr: ');
|
2018-11-10 01:51:25 +00:00
|
|
|
final int code = await process.done;
|
2016-05-01 22:52:51 +00:00
|
|
|
if (code != 0)
|
|
|
|
exit(code);
|
|
|
|
|
2019-06-21 00:59:37 +00:00
|
|
|
createFooter('$kDocsRoot/lib/', version);
|
2018-10-23 20:50:24 +00:00
|
|
|
copyAssets();
|
2018-12-11 17:53:33 +00:00
|
|
|
createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml');
|
2018-10-23 20:50:24 +00:00
|
|
|
cleanOutSnippets();
|
2017-02-10 17:55:58 +00:00
|
|
|
|
2019-09-17 14:23:44 +00:00
|
|
|
final List<String> dartdocBaseArgs = <String>[
|
|
|
|
'global',
|
|
|
|
'run',
|
2019-12-05 21:34:06 +00:00
|
|
|
if (args['checked'] as bool) '-c',
|
2019-09-17 14:23:44 +00:00
|
|
|
'dartdoc',
|
|
|
|
];
|
2018-02-05 17:31:18 +00:00
|
|
|
|
2017-04-19 17:00:18 +00:00
|
|
|
// Verify which version of dartdoc we're using.
|
2017-05-11 16:42:08 +00:00
|
|
|
final ProcessResult result = Process.runSync(
|
2017-12-05 22:46:39 +00:00
|
|
|
pubExecutable,
|
2019-06-27 19:23:16 +00:00
|
|
|
<String>[...dartdocBaseArgs, '--version'],
|
2018-10-23 20:50:24 +00:00
|
|
|
workingDirectory: kDocsRoot,
|
2017-12-05 22:46:39 +00:00
|
|
|
environment: pubEnvironment,
|
2017-05-11 16:42:08 +00:00
|
|
|
);
|
2018-01-18 15:59:06 +00:00
|
|
|
print('\n${result.stdout}flutter version: $version\n');
|
2017-04-19 17:00:18 +00:00
|
|
|
|
2020-07-30 21:11:23 +00:00
|
|
|
// Dartdoc warnings and errors in these packages are considered fatal.
|
|
|
|
// All packages owned by flutter should be in the list.
|
|
|
|
// TODO(goderbauer): Figure out how to add 'dart:ui'.
|
|
|
|
final List<String> flutterPackages = <String>[
|
|
|
|
kDummyPackageName,
|
|
|
|
kPlatformIntegrationPackageName,
|
|
|
|
...findPackageNames(),
|
2020-08-03 17:46:04 +00:00
|
|
|
];
|
2020-07-30 21:11:23 +00:00
|
|
|
|
2016-08-29 23:20:18 +00:00
|
|
|
// Generate the documentation.
|
2018-05-04 00:47:50 +00:00
|
|
|
// We don't need to exclude flutter_tools in this list because it's not in the
|
|
|
|
// recursive dependencies of the package defined at dev/docs/pubspec.yaml
|
2019-06-27 19:23:16 +00:00
|
|
|
final List<String> dartdocArgs = <String>[
|
|
|
|
...dartdocBaseArgs,
|
2019-09-17 14:23:44 +00:00
|
|
|
'--allow-tools',
|
2019-12-05 21:34:06 +00:00
|
|
|
if (args['json'] as bool) '--json',
|
|
|
|
if (args['validate-links'] as bool) '--validate-links' else '--no-validate-links',
|
2019-09-17 14:23:44 +00:00
|
|
|
'--link-to-source-excludes', '../../bin/cache',
|
|
|
|
'--link-to-source-root', '../..',
|
|
|
|
'--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%',
|
2018-10-23 20:50:24 +00:00
|
|
|
'--inject-html',
|
2020-03-19 21:56:03 +00:00
|
|
|
'--use-base-href',
|
2016-05-01 22:52:51 +00:00
|
|
|
'--header', 'styles.html',
|
|
|
|
'--header', 'analytics.html',
|
2019-03-01 23:42:43 +00:00
|
|
|
'--header', 'survey.html',
|
2018-10-23 20:50:24 +00:00
|
|
|
'--header', 'snippets.html',
|
2018-12-11 17:53:33 +00:00
|
|
|
'--header', 'opensearch.html',
|
2017-05-25 16:42:55 +00:00
|
|
|
'--footer-text', 'lib/footer.html',
|
2020-07-30 21:11:23 +00:00
|
|
|
'--allow-warnings-in-packages', flutterPackages.join(','),
|
2017-12-08 16:08:49 +00:00
|
|
|
'--exclude-packages',
|
2018-10-23 20:50:24 +00:00
|
|
|
<String>[
|
|
|
|
'analyzer',
|
|
|
|
'args',
|
|
|
|
'barback',
|
|
|
|
'cli_util',
|
|
|
|
'csslib',
|
|
|
|
'flutter_goldens',
|
2018-11-10 01:51:25 +00:00
|
|
|
'flutter_goldens_client',
|
2018-10-23 20:50:24 +00:00
|
|
|
'front_end',
|
|
|
|
'fuchsia_remote_debug_protocol',
|
|
|
|
'glob',
|
|
|
|
'html',
|
|
|
|
'http_multi_server',
|
|
|
|
'io',
|
|
|
|
'isolate',
|
|
|
|
'js',
|
|
|
|
'kernel',
|
|
|
|
'logging',
|
|
|
|
'mime',
|
|
|
|
'mockito',
|
|
|
|
'node_preamble',
|
|
|
|
'plugin',
|
|
|
|
'shelf',
|
|
|
|
'shelf_packages_handler',
|
|
|
|
'shelf_static',
|
|
|
|
'shelf_web_socket',
|
|
|
|
'utf',
|
|
|
|
'watcher',
|
|
|
|
'yaml',
|
|
|
|
].join(','),
|
2017-12-08 16:08:49 +00:00
|
|
|
'--exclude',
|
2018-10-23 20:50:24 +00:00
|
|
|
<String>[
|
2020-11-20 19:18:07 +00:00
|
|
|
'dart:io/network_policy.dart', // dart-lang/dartdoc#2437
|
2018-10-23 20:50:24 +00:00
|
|
|
'package:Flutter/temp_doc.dart',
|
|
|
|
'package:http/browser_client.dart',
|
|
|
|
'package:intl/intl_browser.dart',
|
|
|
|
'package:matcher/mirror_matchers.dart',
|
|
|
|
'package:quiver/io.dart',
|
|
|
|
'package:quiver/mirrors.dart',
|
|
|
|
'package:vm_service_client/vm_service_client.dart',
|
|
|
|
'package:web_socket_channel/html.dart',
|
|
|
|
].join(','),
|
2016-05-01 22:52:51 +00:00
|
|
|
'--favicon=favicon.ico',
|
2020-07-30 21:11:23 +00:00
|
|
|
'--package-order', 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver',
|
2017-07-28 22:44:38 +00:00
|
|
|
'--auto-include-dependencies',
|
2019-06-27 19:23:16 +00:00
|
|
|
];
|
2016-05-01 22:52:51 +00:00
|
|
|
|
2018-03-30 19:19:44 +00:00
|
|
|
String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg;
|
2018-10-23 20:50:24 +00:00
|
|
|
print('Executing: (cd $kDocsRoot ; $pubExecutable ${dartdocArgs.map<String>(quote).join(' ')})');
|
2018-03-30 19:19:44 +00:00
|
|
|
|
2018-11-10 01:51:25 +00:00
|
|
|
process = ProcessWrapper(await Process.start(
|
2017-12-05 22:46:39 +00:00
|
|
|
pubExecutable,
|
2018-02-05 17:31:18 +00:00
|
|
|
dartdocArgs,
|
2018-10-23 20:50:24 +00:00
|
|
|
workingDirectory: kDocsRoot,
|
2017-12-05 22:46:39 +00:00
|
|
|
environment: pubEnvironment,
|
2018-11-10 01:51:25 +00:00
|
|
|
));
|
2019-12-05 21:34:06 +00:00
|
|
|
printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ',
|
|
|
|
filter: args['verbose'] as bool ? const <Pattern>[] : <Pattern>[
|
2018-09-12 06:29:29 +00:00
|
|
|
RegExp(r'^generating docs for library '), // unnecessary verbosity
|
|
|
|
RegExp(r'^pars'), // unnecessary verbosity
|
2017-07-28 22:44:38 +00:00
|
|
|
],
|
|
|
|
);
|
2019-12-05 21:34:06 +00:00
|
|
|
printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ',
|
|
|
|
filter: args['verbose'] as bool ? const <Pattern>[] : <Pattern>[
|
2018-09-12 06:29:29 +00:00
|
|
|
RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control
|
2017-07-28 22:44:38 +00:00
|
|
|
],
|
|
|
|
);
|
2018-11-10 01:51:25 +00:00
|
|
|
final int exitCode = await process.done;
|
2016-05-16 15:28:58 +00:00
|
|
|
|
|
|
|
if (exitCode != 0)
|
|
|
|
exit(exitCode);
|
|
|
|
|
2016-11-09 23:16:13 +00:00
|
|
|
sanityCheckDocs();
|
2020-07-28 22:26:33 +00:00
|
|
|
checkForUnresolvedDirectives('$kPublishRoot/api');
|
2016-11-09 23:16:13 +00:00
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
createIndexAndCleanup();
|
|
|
|
}
|
|
|
|
|
2018-02-05 17:31:18 +00:00
|
|
|
ArgParser _createArgsParser() {
|
2018-09-12 06:29:29 +00:00
|
|
|
final ArgParser parser = ArgParser();
|
2018-02-05 17:31:18 +00:00
|
|
|
parser.addFlag('help', abbr: 'h', negatable: false,
|
|
|
|
help: 'Show command help.');
|
|
|
|
parser.addFlag('verbose', negatable: true, defaultsTo: true,
|
|
|
|
help: 'Whether to report all error messages (on) or attempt to '
|
|
|
|
'filter out some known false positives (off). Shut this off '
|
|
|
|
'locally if you want to address Flutter-specific issues.');
|
|
|
|
parser.addFlag('checked', abbr: 'c', negatable: true,
|
|
|
|
help: 'Run dartdoc in checked mode.');
|
|
|
|
parser.addFlag('json', negatable: true,
|
|
|
|
help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.');
|
2018-02-27 22:39:42 +00:00
|
|
|
parser.addFlag('validate-links', negatable: true,
|
|
|
|
help: 'Display warnings for broken links generated by dartdoc (slow)');
|
2018-02-05 17:31:18 +00:00
|
|
|
return parser;
|
|
|
|
}
|
|
|
|
|
2018-09-12 06:29:29 +00:00
|
|
|
final RegExp gitBranchRegexp = RegExp(r'^## (.*)');
|
2018-08-17 21:10:33 +00:00
|
|
|
|
2018-12-11 17:53:33 +00:00
|
|
|
String getBranchName() {
|
|
|
|
final ProcessResult gitResult = Process.runSync('git', <String>['status', '-b', '--porcelain']);
|
|
|
|
if (gitResult.exitCode != 0)
|
|
|
|
throw 'git status exit with non-zero exit code: ${gitResult.exitCode}';
|
|
|
|
final Match gitBranchMatch = gitBranchRegexp.firstMatch(
|
2019-12-05 21:34:06 +00:00
|
|
|
(gitResult.stdout as String).trim().split('\n').first);
|
2018-12-11 17:53:33 +00:00
|
|
|
return gitBranchMatch == null ? '' : gitBranchMatch.group(1).split('...').first;
|
|
|
|
}
|
|
|
|
|
2019-02-04 22:40:22 +00:00
|
|
|
String gitRevision() {
|
2017-10-13 20:31:32 +00:00
|
|
|
const int kGitRevisionLength = 10;
|
|
|
|
|
2018-12-11 17:53:33 +00:00
|
|
|
final ProcessResult gitResult = Process.runSync('git', <String>['rev-parse', 'HEAD']);
|
2018-01-18 15:59:06 +00:00
|
|
|
if (gitResult.exitCode != 0)
|
2018-08-17 21:10:33 +00:00
|
|
|
throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}';
|
2019-12-05 21:34:06 +00:00
|
|
|
final String gitRevision = (gitResult.stdout as String).trim();
|
2018-08-17 21:10:33 +00:00
|
|
|
|
2019-02-04 22:40:22 +00:00
|
|
|
return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision;
|
|
|
|
}
|
2017-02-10 17:55:58 +00:00
|
|
|
|
2019-06-21 00:59:37 +00:00
|
|
|
void createFooter(String footerPath, String version) {
|
2018-09-12 06:29:29 +00:00
|
|
|
final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
|
2019-02-04 22:40:22 +00:00
|
|
|
final String gitBranch = getBranchName();
|
2019-06-21 00:59:37 +00:00
|
|
|
final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch';
|
|
|
|
File('${footerPath}footer.html').writeAsStringSync('<script src="footer.js"></script>');
|
|
|
|
File('$kPublishRoot/api/footer.js')
|
|
|
|
..createSync(recursive: true)
|
2020-02-20 09:16:28 +00:00
|
|
|
..writeAsStringSync('''
|
|
|
|
(function() {
|
2019-06-21 05:08:52 +00:00
|
|
|
var span = document.querySelector('footer>span');
|
|
|
|
if (span) {
|
|
|
|
span.innerText = 'Flutter $version • $timestamp • ${gitRevision()} $gitBranchOut';
|
|
|
|
}
|
|
|
|
var sourceLink = document.querySelector('a.source-link');
|
|
|
|
if (sourceLink) {
|
|
|
|
sourceLink.href = sourceLink.href.replace('/master/', '/${gitRevision()}/');
|
|
|
|
}
|
|
|
|
})();
|
2019-06-21 00:59:37 +00:00
|
|
|
''');
|
2017-02-10 17:55:58 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 17:53:33 +00:00
|
|
|
/// Generates an OpenSearch XML description that can be used to add a custom
|
|
|
|
/// search for Flutter API docs to the browser. Unfortunately, it has to know
|
|
|
|
/// the URL to which site to search, so we customize it here based upon the
|
|
|
|
/// branch name.
|
|
|
|
void createSearchMetadata(String templatePath, String metadataPath) {
|
|
|
|
final String template = File(templatePath).readAsStringSync();
|
|
|
|
final String branch = getBranchName();
|
|
|
|
final String metadata = template.replaceAll(
|
|
|
|
'{SITE_URL}',
|
2021-01-08 00:28:12 +00:00
|
|
|
branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/',
|
2018-12-11 17:53:33 +00:00
|
|
|
);
|
|
|
|
Directory(path.dirname(metadataPath)).create(recursive: true);
|
|
|
|
File(metadataPath).writeAsStringSync(metadata);
|
|
|
|
}
|
|
|
|
|
2018-10-23 20:50:24 +00:00
|
|
|
/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if
|
|
|
|
/// specified, for each source/destination file pair.
|
|
|
|
///
|
|
|
|
/// Creates `destDir` if needed.
|
2021-03-04 16:59:17 +00:00
|
|
|
void copyDirectorySync(Directory srcDir, Directory destDir, [void Function(File srcFile, File destFile) onFileCopied]) {
|
2018-10-23 20:50:24 +00:00
|
|
|
if (!srcDir.existsSync())
|
|
|
|
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
|
|
|
|
|
|
|
|
if (!destDir.existsSync())
|
|
|
|
destDir.createSync(recursive: true);
|
|
|
|
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final FileSystemEntity entity in srcDir.listSync()) {
|
2018-10-23 20:50:24 +00:00
|
|
|
final String newPath = path.join(destDir.path, path.basename(entity.path));
|
|
|
|
if (entity is File) {
|
|
|
|
final File newFile = File(newPath);
|
|
|
|
entity.copySync(newPath);
|
|
|
|
onFileCopied?.call(entity, newFile);
|
|
|
|
} else if (entity is Directory) {
|
|
|
|
copyDirectorySync(entity, Directory(newPath));
|
|
|
|
} else {
|
|
|
|
throw Exception('${entity.path} is neither File nor Directory');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void copyAssets() {
|
|
|
|
final Directory assetsDir = Directory(path.join(kPublishRoot, 'assets'));
|
|
|
|
if (assetsDir.existsSync()) {
|
|
|
|
assetsDir.deleteSync(recursive: true);
|
|
|
|
}
|
|
|
|
copyDirectorySync(
|
|
|
|
Directory(path.join(kDocsRoot, 'assets')),
|
|
|
|
Directory(path.join(kPublishRoot, 'assets')),
|
|
|
|
(File src, File dest) => print('Copied ${src.path} to ${dest.path}'));
|
|
|
|
}
|
|
|
|
|
2018-12-11 17:53:33 +00:00
|
|
|
/// Clean out any existing snippets so that we don't publish old files from
|
|
|
|
/// previous runs accidentally.
|
2018-10-23 20:50:24 +00:00
|
|
|
void cleanOutSnippets() {
|
|
|
|
final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets'));
|
|
|
|
if (snippetsDir.existsSync()) {
|
|
|
|
snippetsDir
|
|
|
|
..deleteSync(recursive: true)
|
|
|
|
..createSync(recursive: true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-09 23:16:13 +00:00
|
|
|
void sanityCheckDocs() {
|
2018-03-30 19:19:44 +00:00
|
|
|
final List<String> canaries = <String>[
|
2018-10-23 20:50:24 +00:00
|
|
|
'$kPublishRoot/assets/overrides.css',
|
|
|
|
'$kPublishRoot/api/dart-io/File-class.html',
|
|
|
|
'$kPublishRoot/api/dart-ui/Canvas-class.html',
|
|
|
|
'$kPublishRoot/api/dart-ui/Canvas/drawRect.html',
|
|
|
|
'$kPublishRoot/api/flutter_driver/FlutterDriver/FlutterDriver.connectedTo.html',
|
|
|
|
'$kPublishRoot/api/flutter_test/WidgetTester/pumpWidget.html',
|
|
|
|
'$kPublishRoot/api/material/Material-class.html',
|
|
|
|
'$kPublishRoot/api/material/Tooltip-class.html',
|
|
|
|
'$kPublishRoot/api/widgets/Widget-class.html',
|
2016-11-09 23:16:13 +00:00
|
|
|
];
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final String canary in canaries) {
|
2018-09-12 06:29:29 +00:00
|
|
|
if (!File(canary).existsSync())
|
|
|
|
throw Exception('Missing "$canary", which probably means the documentation failed to build correctly.');
|
2016-11-09 23:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
/// Creates a custom index.html because we try to maintain old
|
|
|
|
/// paths. Cleanup unused index.html files no longer needed.
|
|
|
|
void createIndexAndCleanup() {
|
2018-10-23 20:50:24 +00:00
|
|
|
print('\nCreating a custom index.html in $kPublishRoot/index.html');
|
2016-05-16 20:05:13 +00:00
|
|
|
removeOldFlutterDocsDir();
|
2016-05-16 15:28:58 +00:00
|
|
|
renameApiDir();
|
|
|
|
copyIndexToRootOfDocs();
|
|
|
|
addHtmlBaseToIndex();
|
2018-03-30 19:19:44 +00:00
|
|
|
changePackageToSdkInTitlebar();
|
2016-05-16 15:28:58 +00:00
|
|
|
putRedirectInOldIndexLocation();
|
2019-01-08 10:38:59 +00:00
|
|
|
writeSnippetsIndexFile();
|
2016-05-16 15:28:58 +00:00
|
|
|
print('\nDocs ready to go!');
|
|
|
|
}
|
|
|
|
|
2016-05-16 20:05:13 +00:00
|
|
|
void removeOldFlutterDocsDir() {
|
|
|
|
try {
|
2018-10-23 20:50:24 +00:00
|
|
|
Directory('$kPublishRoot/flutter').deleteSync(recursive: true);
|
2018-08-17 20:17:23 +00:00
|
|
|
} on FileSystemException {
|
2016-05-16 20:05:13 +00:00
|
|
|
// If the directory does not exist, that's OK.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
void renameApiDir() {
|
2018-10-23 20:50:24 +00:00
|
|
|
Directory('$kPublishRoot/api').renameSync('$kPublishRoot/flutter');
|
2016-05-16 15:28:58 +00:00
|
|
|
}
|
|
|
|
|
2016-07-23 05:21:04 +00:00
|
|
|
void copyIndexToRootOfDocs() {
|
2018-10-23 20:50:24 +00:00
|
|
|
File('$kPublishRoot/flutter/index.html').copySync('$kPublishRoot/index.html');
|
2016-05-16 15:28:58 +00:00
|
|
|
}
|
|
|
|
|
2018-03-30 19:19:44 +00:00
|
|
|
void changePackageToSdkInTitlebar() {
|
2018-10-23 20:50:24 +00:00
|
|
|
final File indexFile = File('$kPublishRoot/index.html');
|
2018-03-30 19:19:44 +00:00
|
|
|
String indexContents = indexFile.readAsStringSync();
|
|
|
|
indexContents = indexContents.replaceFirst(
|
2019-04-05 18:39:30 +00:00
|
|
|
'<li><a href="https://flutter.dev">Flutter package</a></li>',
|
|
|
|
'<li><a href="https://flutter.dev">Flutter SDK</a></li>',
|
2018-03-30 19:19:44 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
indexFile.writeAsStringSync(indexContents);
|
|
|
|
}
|
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
void addHtmlBaseToIndex() {
|
2018-10-23 20:50:24 +00:00
|
|
|
final File indexFile = File('$kPublishRoot/index.html');
|
2016-05-16 15:28:58 +00:00
|
|
|
String indexContents = indexFile.readAsStringSync();
|
2017-07-28 22:44:38 +00:00
|
|
|
indexContents = indexContents.replaceFirst(
|
|
|
|
'</title>\n',
|
|
|
|
'</title>\n <base href="./flutter/">\n',
|
|
|
|
);
|
2017-02-10 00:12:09 +00:00
|
|
|
indexContents = indexContents.replaceAll(
|
|
|
|
'href="Android/Android-library.html"',
|
2017-07-28 22:44:38 +00:00
|
|
|
'href="/javadoc/"',
|
2017-02-10 00:12:09 +00:00
|
|
|
);
|
2017-06-26 10:15:24 +00:00
|
|
|
indexContents = indexContents.replaceAll(
|
|
|
|
'href="iOS/iOS-library.html"',
|
2017-07-28 22:44:38 +00:00
|
|
|
'href="/objcdoc/"',
|
2017-06-26 10:15:24 +00:00
|
|
|
);
|
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
indexFile.writeAsStringSync(indexContents);
|
|
|
|
}
|
|
|
|
|
|
|
|
void putRedirectInOldIndexLocation() {
|
2018-02-01 06:51:26 +00:00
|
|
|
const String metaTag = '<meta http-equiv="refresh" content="0;URL=../index.html">';
|
2018-10-23 20:50:24 +00:00
|
|
|
File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag);
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
|
|
|
|
2019-01-08 10:38:59 +00:00
|
|
|
|
|
|
|
void writeSnippetsIndexFile() {
|
|
|
|
final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets'));
|
|
|
|
if (snippetsDir.existsSync()) {
|
|
|
|
const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' ');
|
|
|
|
final Iterable<File> files = snippetsDir
|
|
|
|
.listSync()
|
|
|
|
.whereType<File>()
|
|
|
|
.where((File file) => path.extension(file.path) == '.json');
|
|
|
|
// Combine all the metadata into a single JSON array.
|
|
|
|
final Iterable<String> fileContents = files.map((File file) => file.readAsStringSync());
|
|
|
|
final List<dynamic> metadataObjects = fileContents.map<dynamic>(json.decode).toList();
|
|
|
|
final String jsonArray = jsonEncoder.convert(metadataObjects);
|
|
|
|
File('$kPublishRoot/snippets/index.json').writeAsStringSync(jsonArray);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-16 15:28:58 +00:00
|
|
|
List<String> findPackageNames() {
|
2018-10-01 19:29:08 +00:00
|
|
|
return findPackages().map<String>((FileSystemEntity file) => path.basename(file.path)).toList();
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 17:00:10 +00:00
|
|
|
/// Finds all packages in the Flutter SDK
|
2019-12-05 21:34:06 +00:00
|
|
|
List<Directory> findPackages() {
|
2018-09-12 06:29:29 +00:00
|
|
|
return Directory('packages')
|
2016-05-01 22:52:51 +00:00
|
|
|
.listSync()
|
2016-11-15 20:35:50 +00:00
|
|
|
.where((FileSystemEntity entity) {
|
|
|
|
if (entity is! Directory)
|
|
|
|
return false;
|
2018-09-12 06:29:29 +00:00
|
|
|
final File pubspec = File('${entity.path}/pubspec.yaml');
|
2020-12-17 22:47:45 +00:00
|
|
|
if (!pubspec.existsSync()) {
|
|
|
|
print("Unexpected package '${entity.path}' found in packages directory");
|
|
|
|
return false;
|
|
|
|
}
|
2016-11-15 20:35:50 +00:00
|
|
|
// TODO(ianh): Use a real YAML parser here
|
|
|
|
return !pubspec.readAsStringSync().contains('nodoc: true');
|
2016-05-01 22:52:51 +00:00
|
|
|
})
|
2018-07-13 17:35:23 +00:00
|
|
|
.cast<Directory>()
|
2016-05-01 22:52:51 +00:00
|
|
|
.toList();
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:00:10 +00:00
|
|
|
/// Returns import or on-disk paths for all libraries in the Flutter SDK.
|
2018-10-11 20:27:43 +00:00
|
|
|
Iterable<String> libraryRefs() sync* {
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final Directory dir in findPackages()) {
|
2017-03-04 02:06:08 +00:00
|
|
|
final String dirName = path.basename(dir.path);
|
2020-01-07 15:32:04 +00:00
|
|
|
for (final FileSystemEntity file in Directory('${dir.path}/lib').listSync()) {
|
2017-01-11 17:00:10 +00:00
|
|
|
if (file is File && file.path.endsWith('.dart')) {
|
2018-10-11 20:27:43 +00:00
|
|
|
yield '$dirName/${path.basename(file.path)}';
|
|
|
|
}
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
|
|
|
}
|
2017-02-10 00:12:09 +00:00
|
|
|
|
|
|
|
// Add a fake package for platform integration APIs.
|
2020-07-30 21:11:23 +00:00
|
|
|
yield '$kPlatformIntegrationPackageName/android.dart';
|
|
|
|
yield '$kPlatformIntegrationPackageName/ios.dart';
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|
|
|
|
|
2018-06-05 06:50:40 +00:00
|
|
|
void printStream(Stream<List<int>> stream, { String prefix = '', List<Pattern> filter = const <Pattern>[] }) {
|
2017-07-28 22:44:38 +00:00
|
|
|
assert(prefix != null);
|
|
|
|
assert(filter != null);
|
2016-05-01 22:52:51 +00:00
|
|
|
stream
|
2018-10-01 19:29:08 +00:00
|
|
|
.transform<String>(utf8.decoder)
|
|
|
|
.transform<String>(const LineSplitter())
|
2017-07-28 22:44:38 +00:00
|
|
|
.listen((String line) {
|
|
|
|
if (!filter.any((Pattern pattern) => line.contains(pattern)))
|
|
|
|
print('$prefix$line'.trim());
|
|
|
|
});
|
2016-05-01 22:52:51 +00:00
|
|
|
}
|