## Description This re-lands #132353 with some additional options for keeping around the staging directory, so that the recipe for publishing docs can give those options and have the staging directory left around for deploying to the website. Reverted in #132613 ## Related Issues - https://flutter-review.googlesource.com/c/recipes/+/49580
This commit is contained in:
parent
d19fb632ec
commit
ced3e76626
205
dev/bots/docs.sh
205
dev/bots/docs.sh
@ -16,102 +16,13 @@ function script_location() {
|
||||
cd -P "$(dirname "$script_location")" >/dev/null && pwd
|
||||
}
|
||||
|
||||
function generate_docs() {
|
||||
# Install and activate dartdoc.
|
||||
# When updating to a new dartdoc version, please also update
|
||||
# `dartdoc_options.yaml` to include newly introduced error and warning types.
|
||||
"$DART" pub global activate dartdoc 6.3.0
|
||||
|
||||
# Install and activate the snippets tool, which resides in the
|
||||
# assets-for-api-docs repo:
|
||||
# https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
|
||||
"$DART" pub global activate snippets 0.3.1
|
||||
|
||||
# This script generates a unified doc set, and creates
|
||||
# a custom index.html, placing everything into dev/docs/doc.
|
||||
(cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get)
|
||||
(cd "$FLUTTER_ROOT/dev/tools" && "$DART" pub get)
|
||||
(cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/dartdoc.dart")
|
||||
(cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/java_and_objc_doc.dart")
|
||||
}
|
||||
|
||||
# Zip up the docs so people can download them for offline usage.
|
||||
function create_offline_zip() {
|
||||
# Must be run from "$FLUTTER_ROOT/dev/docs"
|
||||
echo "$(date): Zipping Flutter offline docs archive."
|
||||
rm -rf flutter.docs.zip doc/offline
|
||||
(cd ./doc; zip -r -9 -q ../flutter.docs.zip .)
|
||||
}
|
||||
|
||||
# Generate the docset for Flutter docs for use with Dash, Zeal, and Velocity.
|
||||
function create_docset() {
|
||||
# Must be run from "$FLUTTER_ROOT/dev/docs"
|
||||
# Must have dashing installed: go get -u github.com/technosophos/dashing
|
||||
# Dashing produces a LOT of log output (~30MB), so we redirect it, and just
|
||||
# show the end of it if there was a problem.
|
||||
echo "$(date): Building Flutter docset."
|
||||
rm -rf flutter.docset
|
||||
# If dashing gets stuck, Cirrus will time out the build after an hour, and we
|
||||
# never get to see the logs. Thus, we run it in the background and tail the logs
|
||||
# while we wait for it to complete.
|
||||
dashing_log=/tmp/dashing.log
|
||||
dashing build --source ./doc --config ./dashing.json > $dashing_log 2>&1 &
|
||||
dashing_pid=$!
|
||||
wait $dashing_pid && \
|
||||
cp ./doc/flutter/static-assets/favicon.png ./flutter.docset/icon.png && \
|
||||
"$DART" --disable-dart-dev --enable-asserts ./dashing_postprocess.dart && \
|
||||
tar cf flutter.docset.tar.gz --use-compress-program="gzip --best" flutter.docset
|
||||
if [[ $? -ne 0 ]]; then
|
||||
>&2 echo "Dashing docset generation failed"
|
||||
tail -200 $dashing_log
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function deploy_docs() {
|
||||
case "$LUCI_BRANCH" in
|
||||
master)
|
||||
echo "$(date): Updating $LUCI_BRANCH docs: https://master-api.flutter.dev/"
|
||||
# Disable search indexing on the master staging site so searches get only
|
||||
# the stable site.
|
||||
echo -e "User-agent: *\nDisallow: /" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt"
|
||||
;;
|
||||
stable)
|
||||
echo "$(date): Updating $LUCI_BRANCH docs: https://api.flutter.dev/"
|
||||
# Enable search indexing on the master staging site so searches get only
|
||||
# the stable site.
|
||||
echo -e "# All robots welcome!" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt"
|
||||
;;
|
||||
*)
|
||||
>&2 echo "Docs deployment cannot be run on the $LUCI_BRANCH branch."
|
||||
exit 0
|
||||
esac
|
||||
}
|
||||
|
||||
# Move the offline archives into place, after all the processing of the doc
|
||||
# directory is done. This avoids the tools recursively processing the archives
|
||||
# as part of their process.
|
||||
function move_offline_into_place() {
|
||||
# Must be run from "$FLUTTER_ROOT/dev/docs"
|
||||
echo "$(date): Moving offline data into place."
|
||||
mkdir -p doc/offline
|
||||
mv flutter.docs.zip doc/offline/flutter.docs.zip
|
||||
du -sh doc/offline/flutter.docs.zip
|
||||
if [[ "$LUCI_BRANCH" == "stable" ]]; then
|
||||
echo -e "<entry>\n <version>${FLUTTER_VERSION_STRING}</version>\n <url>https://api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml
|
||||
else
|
||||
echo -e "<entry>\n <version>${FLUTTER_VERSION_STRING}</version>\n <url>https://master-api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml
|
||||
fi
|
||||
mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz
|
||||
du -sh doc/offline/flutter.docset.tar.gz
|
||||
}
|
||||
|
||||
# So that users can run this script from anywhere and it will work as expected.
|
||||
SCRIPT_LOCATION="$(script_location)"
|
||||
# Sets the Flutter root to be "$(script_location)/../..": This script assumes
|
||||
# that it resides two directory levels down from the root, so if that changes,
|
||||
# then this line will need to as well.
|
||||
FLUTTER_ROOT="$(dirname "$(dirname "$SCRIPT_LOCATION")")"
|
||||
export FLUTTER_ROOT
|
||||
|
||||
echo "$(date): Running docs.sh"
|
||||
|
||||
@ -124,31 +35,115 @@ FLUTTER_BIN="$FLUTTER_ROOT/bin"
|
||||
DART_BIN="$FLUTTER_ROOT/bin/cache/dart-sdk/bin"
|
||||
FLUTTER="$FLUTTER_BIN/flutter"
|
||||
DART="$DART_BIN/dart"
|
||||
export PATH="$FLUTTER_BIN:$DART_BIN:$PATH"
|
||||
PATH="$FLUTTER_BIN:$DART_BIN:$PATH"
|
||||
|
||||
# Make sure dart is installed by invoking Flutter to download it.
|
||||
# This also creates the 'version' file.
|
||||
FLUTTER_VERSION=$("$FLUTTER" --version --machine)
|
||||
# Make sure dart is installed by invoking Flutter to download it if it is missing.
|
||||
# Also make sure the flutter command is ready to run before capturing output from
|
||||
# it: if it has to rebuild itself or something, it'll spoil our JSON output.
|
||||
"$FLUTTER" > /dev/null 2>&1
|
||||
FLUTTER_VERSION="$("$FLUTTER" --version --machine)"
|
||||
export FLUTTER_VERSION
|
||||
FLUTTER_VERSION_STRING=$(cat "$FLUTTER_ROOT/version")
|
||||
|
||||
# If the pub cache directory exists in the root, then use that.
|
||||
FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache"
|
||||
if [[ -d "$FLUTTER_PUB_CACHE" ]]; then
|
||||
# This has to be exported, because pub interprets setting it to the empty
|
||||
# string in the same way as setting it to ".".
|
||||
export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}"
|
||||
PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}"
|
||||
export PUB_CACHE
|
||||
fi
|
||||
|
||||
function usage() {
|
||||
echo "Usage: $(basename "${BASH_SOURCE[0]}") [--keep-temp] [--output <output.zip>]"
|
||||
echo ""
|
||||
echo " --keep-staging Do not delete the staging directory created while generating"
|
||||
echo " docs. Normally the script deletes the staging directory after"
|
||||
echo " generating the output ZIP file."
|
||||
echo " --output <output.zip> specifies where the output ZIP file containing the documentation"
|
||||
echo " data will be written."
|
||||
echo " --staging-dir <directory> specifies where the temporary output files will be written while"
|
||||
echo " generating docs. This directory will be deleted after generation"
|
||||
echo " unless --keep-staging is also specified."
|
||||
echo ""
|
||||
}
|
||||
|
||||
function parse_args() {
|
||||
local arg
|
||||
local args=()
|
||||
STAGING_DIR=
|
||||
KEEP_STAGING=0
|
||||
DESTINATION="$FLUTTER_ROOT/dev/docs/api_docs.zip"
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--staging-dir)
|
||||
STAGING_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
--keep-staging)
|
||||
KEEP_STAGING=1
|
||||
;;
|
||||
--output)
|
||||
DESTINATION="$2"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
args=("${args[@]}" "$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [[ -z $STAGING_DIR ]]; then
|
||||
STAGING_DIR=$(mktemp -d /tmp/dartdoc.XXXXX)
|
||||
fi
|
||||
DOC_DIR="$STAGING_DIR/doc"
|
||||
if [[ ${#args[@]} != 0 ]]; then
|
||||
>&2 echo "ERROR: Unknown arguments: ${args[@]}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function generate_docs() {
|
||||
# Install and activate dartdoc.
|
||||
# When updating to a new dartdoc version, please also update
|
||||
# `dartdoc_options.yaml` to include newly introduced error and warning types.
|
||||
"$DART" pub global activate dartdoc 6.3.0
|
||||
|
||||
# Install and activate the snippets tool, which resides in the
|
||||
# assets-for-api-docs repo:
|
||||
# https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
|
||||
"$DART" pub global activate snippets 0.4.0
|
||||
|
||||
# This script generates a unified doc set, and creates
|
||||
# a custom index.html, placing everything into DOC_DIR.
|
||||
|
||||
# Make sure that create_api_docs.dart has all the dependencies it needs.
|
||||
(cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get)
|
||||
(cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/create_api_docs.dart" --output-dir="$DOC_DIR")
|
||||
}
|
||||
|
||||
function main() {
|
||||
echo "Writing docs build temporary output to $DOC_DIR"
|
||||
mkdir -p "$DOC_DIR"
|
||||
generate_docs
|
||||
# Skip publishing docs for PRs and release candidate branches
|
||||
if [[ -n "$LUCI_CI" && -z "$LUCI_PR" ]]; then
|
||||
(cd "$FLUTTER_ROOT/dev/docs"; create_offline_zip)
|
||||
(cd "$FLUTTER_ROOT/dev/docs"; create_docset)
|
||||
(cd "$FLUTTER_ROOT/dev/docs"; move_offline_into_place)
|
||||
deploy_docs
|
||||
# If the destination isn't an absolute path, make it into one.
|
||||
if ! [[ "$DESTINATION" =~ ^/ ]]; then
|
||||
DESTINATION="$PWD/$DESTINATION"
|
||||
fi
|
||||
# Zip up doc directory and write the output to the destination.
|
||||
(cd "$STAGING_DIR"; zip -r -9 -q "$DESTINATION" ./doc)
|
||||
if [[ $KEEP_STAGING -eq 1 ]]; then
|
||||
echo "Staging documentation output left in $STAGING_DIR"
|
||||
else
|
||||
echo "Removing staging documentation output from $STAGING_DIR"
|
||||
rm -rf "$STAGING_DIR"
|
||||
fi
|
||||
echo "Wrote docs ZIP file to $DESTINATION"
|
||||
}
|
||||
|
||||
# Zip docs
|
||||
cd "$FLUTTER_ROOT/dev/docs"
|
||||
zip -r api_docs.zip doc
|
||||
parse_args "$@"
|
||||
main
|
||||
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. 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';
|
||||
|
||||
/// This changes the DocSetPlatformFamily key to be "dartlang" instead of the
|
||||
/// name of the package (usually "flutter").
|
||||
///
|
||||
/// This is so that the IntelliJ plugin for Dash will be able to go directly to
|
||||
/// the docs for a symbol from a keystroke. Without this, flutter isn't part
|
||||
/// of the list of package names it searches. After this, it finds the flutter
|
||||
/// docs because they're declared here to be part of the "dartlang" family of
|
||||
/// docs.
|
||||
///
|
||||
/// Dashing doesn't have a way to configure this, so we modify the Info.plist
|
||||
/// directly to make the change.
|
||||
void main(List<String> args) {
|
||||
final File infoPlist = File('flutter.docset/Contents/Info.plist');
|
||||
String contents = infoPlist.readAsStringSync();
|
||||
|
||||
// Since I didn't want to add the XML package as a dependency just for this,
|
||||
// I just used a regular expression to make this simple change.
|
||||
final RegExp findRe = RegExp(r'(\s*<key>DocSetPlatformFamily</key>\s*<string>)[^<]+(</string>)', multiLine: true);
|
||||
contents = contents.replaceAllMapped(findRe, (Match match) {
|
||||
return '${match.group(1)}dartlang${match.group(2)}';
|
||||
});
|
||||
infoPlist.writeAsStringSync(contents);
|
||||
}
|
1141
dev/tools/create_api_docs.dart
Normal file
1141
dev/tools/create_api_docs.dart
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,606 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. 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:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'dartdoc_checker.dart';
|
||||
|
||||
const String kDocsRoot = 'dev/docs';
|
||||
const String kPublishRoot = '$kDocsRoot/doc';
|
||||
|
||||
const String kDummyPackageName = 'Flutter';
|
||||
const String kPlatformIntegrationPackageName = 'platform_integration';
|
||||
|
||||
/// 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/`.
|
||||
///
|
||||
/// This script also updates the index.html file so that it can be placed
|
||||
/// 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
|
||||
/// a bit. See https://github.com/flutter/flutter/issues/3900 for more info.
|
||||
///
|
||||
/// 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.
|
||||
Future<void> main(List<String> arguments) async {
|
||||
final ArgParser argParser = _createArgsParser();
|
||||
final ArgResults args = argParser.parse(arguments);
|
||||
if (args['help'] as bool) {
|
||||
print ('Usage:');
|
||||
print (argParser.usage);
|
||||
exit(0);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
final ProcessResult flutter = Process.runSync('flutter', <String>[]);
|
||||
final File versionFile = File('version');
|
||||
if (flutter.exitCode != 0 || !versionFile.existsSync()) {
|
||||
throw Exception('Failed to determine Flutter version.');
|
||||
}
|
||||
final String version = versionFile.readAsStringSync();
|
||||
|
||||
// Create the pubspec.yaml file.
|
||||
final StringBuffer buf = StringBuffer();
|
||||
buf.writeln('name: $kDummyPackageName');
|
||||
buf.writeln('homepage: https://flutter.dev');
|
||||
buf.writeln('version: 0.0.0');
|
||||
buf.writeln('environment:');
|
||||
buf.writeln(" sdk: '>=3.0.0-0 <4.0.0'");
|
||||
buf.writeln('dependencies:');
|
||||
for (final String package in findPackageNames()) {
|
||||
buf.writeln(' $package:');
|
||||
buf.writeln(' sdk: flutter');
|
||||
}
|
||||
buf.writeln(' $kPlatformIntegrationPackageName: 0.0.1');
|
||||
buf.writeln('dependency_overrides:');
|
||||
buf.writeln(' $kPlatformIntegrationPackageName:');
|
||||
buf.writeln(' path: $kPlatformIntegrationPackageName');
|
||||
File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString());
|
||||
|
||||
// Create the library file.
|
||||
final Directory libDir = Directory('$kDocsRoot/lib');
|
||||
libDir.createSync();
|
||||
|
||||
final StringBuffer contents = StringBuffer('library temp_doc;\n\n');
|
||||
for (final String libraryRef in libraryRefs()) {
|
||||
contents.writeln("import 'package:$libraryRef';");
|
||||
}
|
||||
File('$kDocsRoot/lib/temp_doc.dart').writeAsStringSync(contents.toString());
|
||||
|
||||
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';
|
||||
if (Directory(pubCachePath).existsSync()) {
|
||||
pubEnvironment['PUB_CACHE'] = pubCachePath;
|
||||
}
|
||||
|
||||
final String dartExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/dart';
|
||||
|
||||
// Run pub.
|
||||
ProcessWrapper process = ProcessWrapper(await runPubProcess(
|
||||
dartBinaryPath: dartExecutable,
|
||||
arguments: <String>['get'],
|
||||
workingDirectory: kDocsRoot,
|
||||
environment: pubEnvironment,
|
||||
));
|
||||
printStream(process.stdout, prefix: 'pub:stdout: ');
|
||||
printStream(process.stderr, prefix: 'pub:stderr: ');
|
||||
final int code = await process.done;
|
||||
if (code != 0) {
|
||||
exit(code);
|
||||
}
|
||||
|
||||
createFooter('$kDocsRoot/lib/', version);
|
||||
copyAssets();
|
||||
createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml');
|
||||
cleanOutSnippets();
|
||||
|
||||
final List<String> dartdocBaseArgs = <String>[
|
||||
'global',
|
||||
'run',
|
||||
if (args['checked'] as bool) '--enable-asserts',
|
||||
'dartdoc',
|
||||
];
|
||||
|
||||
// Verify which version of snippets and dartdoc we're using.
|
||||
final ProcessResult snippetsResult = Process.runSync(
|
||||
dartExecutable,
|
||||
<String>[
|
||||
'pub',
|
||||
'global',
|
||||
'list',
|
||||
],
|
||||
workingDirectory: kDocsRoot,
|
||||
environment: pubEnvironment,
|
||||
stdoutEncoding: utf8,
|
||||
);
|
||||
print('');
|
||||
final Iterable<RegExpMatch> versionMatches = RegExp(r'^(?<name>snippets|dartdoc) (?<version>[^\s]+)', multiLine: true)
|
||||
.allMatches(snippetsResult.stdout as String);
|
||||
for (final RegExpMatch match in versionMatches) {
|
||||
print('${match.namedGroup('name')} version: ${match.namedGroup('version')}');
|
||||
}
|
||||
|
||||
print('flutter version: $version\n');
|
||||
|
||||
// Dartdoc warnings and errors in these packages are considered fatal.
|
||||
// All packages owned by flutter should be in the list.
|
||||
final List<String> flutterPackages = <String>[
|
||||
kDummyPackageName,
|
||||
kPlatformIntegrationPackageName,
|
||||
...findPackageNames(),
|
||||
// TODO(goderbauer): Figure out how to only include `dart:ui` of `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278.
|
||||
// 'sky_engine',
|
||||
];
|
||||
|
||||
// Generate the documentation.
|
||||
// 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
|
||||
final List<String> dartdocArgs = <String>[
|
||||
...dartdocBaseArgs,
|
||||
'--allow-tools',
|
||||
if (args['json'] as bool) '--json',
|
||||
if (args['validate-links'] as bool) '--validate-links' else '--no-validate-links',
|
||||
'--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%',
|
||||
'--inject-html',
|
||||
'--use-base-href',
|
||||
'--header', 'styles.html',
|
||||
'--header', 'analytics.html',
|
||||
'--header', 'survey.html',
|
||||
'--header', 'snippets.html',
|
||||
'--header', 'opensearch.html',
|
||||
'--footer-text', 'lib/footer.html',
|
||||
'--allow-warnings-in-packages', flutterPackages.join(','),
|
||||
'--exclude-packages',
|
||||
<String>[
|
||||
'analyzer',
|
||||
'args',
|
||||
'barback',
|
||||
'csslib',
|
||||
'flutter_goldens',
|
||||
'flutter_goldens_client',
|
||||
'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(','),
|
||||
'--exclude',
|
||||
<String>[
|
||||
'dart:io/network_policy.dart', // dart-lang/dartdoc#2437
|
||||
'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(','),
|
||||
'--favicon=favicon.ico',
|
||||
'--package-order', 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver',
|
||||
'--auto-include-dependencies',
|
||||
];
|
||||
|
||||
String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg;
|
||||
print('Executing: (cd $kDocsRoot ; $dartExecutable ${dartdocArgs.map<String>(quote).join(' ')})');
|
||||
|
||||
process = ProcessWrapper(await runPubProcess(
|
||||
dartBinaryPath: dartExecutable,
|
||||
arguments: dartdocArgs,
|
||||
workingDirectory: kDocsRoot,
|
||||
environment: pubEnvironment,
|
||||
));
|
||||
printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ',
|
||||
filter: args['verbose'] as bool ? const <Pattern>[] : <Pattern>[
|
||||
RegExp(r'^Generating docs for library '), // unnecessary verbosity
|
||||
],
|
||||
);
|
||||
printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ',
|
||||
filter: args['verbose'] as bool ? const <Pattern>[] : <Pattern>[
|
||||
RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control
|
||||
],
|
||||
);
|
||||
final int exitCode = await process.done;
|
||||
|
||||
if (exitCode != 0) {
|
||||
exit(exitCode);
|
||||
}
|
||||
|
||||
sanityCheckDocs();
|
||||
checkForUnresolvedDirectives('$kPublishRoot/api');
|
||||
|
||||
createIndexAndCleanup();
|
||||
}
|
||||
|
||||
ArgParser _createArgsParser() {
|
||||
final ArgParser parser = ArgParser();
|
||||
parser.addFlag('help', abbr: 'h', negatable: false,
|
||||
help: 'Show command help.');
|
||||
parser.addFlag('verbose', 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',
|
||||
help: 'Run dartdoc with asserts enabled.');
|
||||
parser.addFlag('json',
|
||||
help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.');
|
||||
parser.addFlag('validate-links',
|
||||
help: 'Display warnings for broken links generated by dartdoc (slow)');
|
||||
return parser;
|
||||
}
|
||||
|
||||
final RegExp gitBranchRegexp = RegExp(r'^## (.*)');
|
||||
|
||||
/// Get the name of the release branch.
|
||||
///
|
||||
/// On LUCI builds, the git HEAD is detached, so first check for the env
|
||||
/// variable "LUCI_BRANCH"; if it is not set, fall back to calling git.
|
||||
String getBranchName({
|
||||
@visibleForTesting
|
||||
Platform platform = const LocalPlatform(),
|
||||
@visibleForTesting
|
||||
ProcessManager processManager = const LocalProcessManager(),
|
||||
}) {
|
||||
final String? luciBranch = platform.environment['LUCI_BRANCH'];
|
||||
if (luciBranch != null && luciBranch.trim().isNotEmpty) {
|
||||
return luciBranch.trim();
|
||||
}
|
||||
final ProcessResult gitResult = processManager.runSync(<String>['git', 'status', '-b', '--porcelain']);
|
||||
if (gitResult.exitCode != 0) {
|
||||
throw 'git status exit with non-zero exit code: ${gitResult.exitCode}';
|
||||
}
|
||||
final RegExpMatch? gitBranchMatch = gitBranchRegexp.firstMatch(
|
||||
(gitResult.stdout as String).trim().split('\n').first);
|
||||
return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first;
|
||||
}
|
||||
|
||||
String gitRevision() {
|
||||
const int kGitRevisionLength = 10;
|
||||
|
||||
final ProcessResult gitResult = Process.runSync('git', <String>['rev-parse', 'HEAD']);
|
||||
if (gitResult.exitCode != 0) {
|
||||
throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}';
|
||||
}
|
||||
final String gitRevision = (gitResult.stdout as String).trim();
|
||||
|
||||
return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision;
|
||||
}
|
||||
|
||||
void createFooter(String footerPath, String version) {
|
||||
final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
|
||||
final String gitBranch = getBranchName();
|
||||
final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch';
|
||||
File('${footerPath}footer.html').writeAsStringSync('<script src="footer.js"></script>');
|
||||
File('$kPublishRoot/api/footer.js')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('''
|
||||
(function() {
|
||||
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()}/');
|
||||
}
|
||||
})();
|
||||
''');
|
||||
}
|
||||
|
||||
/// 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}',
|
||||
branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/',
|
||||
);
|
||||
Directory(path.dirname(metadataPath)).create(recursive: true);
|
||||
File(metadataPath).writeAsStringSync(metadata);
|
||||
}
|
||||
|
||||
/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if
|
||||
/// specified, for each source/destination file pair.
|
||||
///
|
||||
/// Creates `destDir` if needed.
|
||||
void copyDirectorySync(Directory srcDir, Directory destDir, [void Function(File srcFile, File destFile)? onFileCopied]) {
|
||||
if (!srcDir.existsSync()) {
|
||||
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
|
||||
}
|
||||
|
||||
if (!destDir.existsSync()) {
|
||||
destDir.createSync(recursive: true);
|
||||
}
|
||||
|
||||
for (final FileSystemEntity entity in srcDir.listSync()) {
|
||||
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}'));
|
||||
}
|
||||
|
||||
/// Clean out any existing snippets so that we don't publish old files from
|
||||
/// previous runs accidentally.
|
||||
void cleanOutSnippets() {
|
||||
final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets'));
|
||||
if (snippetsDir.existsSync()) {
|
||||
snippetsDir
|
||||
..deleteSync(recursive: true)
|
||||
..createSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
void _sanityCheckExample(String fileString, String regExpString) {
|
||||
final File file = File(fileString);
|
||||
if (file.existsSync()) {
|
||||
final RegExp regExp = RegExp(regExpString, dotAll: true);
|
||||
final String contents = file.readAsStringSync();
|
||||
if (!regExp.hasMatch(contents)) {
|
||||
throw Exception("Missing example code matching '$regExpString' in ${file.path}.");
|
||||
}
|
||||
} else {
|
||||
throw Exception(
|
||||
"Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a sanity check by running a test.
|
||||
void sanityCheckDocs([Platform platform = const LocalPlatform()]) {
|
||||
final List<String> canaries = <String>[
|
||||
'$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',
|
||||
'$kPublishRoot/api/widgets/Listener-class.html',
|
||||
];
|
||||
for (final String canary in canaries) {
|
||||
if (!File(canary).existsSync()) {
|
||||
throw Exception('Missing "$canary", which probably means the documentation failed to build correctly.');
|
||||
}
|
||||
}
|
||||
// Make sure at least one example of each kind includes source code.
|
||||
|
||||
// Check a "sample" example, any one will do.
|
||||
_sanityCheckExample(
|
||||
'$kPublishRoot/api/widgets/showGeneralDialog.html',
|
||||
r'\s*<pre\s+id="longSnippet1".*<code\s+class="language-dart">\s*import 'package:flutter/material.dart';',
|
||||
);
|
||||
|
||||
// Check a "snippet" example, any one will do.
|
||||
_sanityCheckExample(
|
||||
'$kPublishRoot/api/widgets/ModalRoute/barrierColor.html',
|
||||
r'\s*<pre.*id="sample-code">.*Color\s+get\s+barrierColor.*</pre>',
|
||||
);
|
||||
|
||||
// Check a "dartpad" example, any one will do, and check for the correct URL
|
||||
// arguments.
|
||||
// Just use "master" for any branch other than the LUCI_BRANCH.
|
||||
final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim();
|
||||
final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master';
|
||||
final List<String> argumentRegExps = <String>[
|
||||
r'split=\d+',
|
||||
r'run=true',
|
||||
r'sample_id=widgets\.Listener\.\d+',
|
||||
'sample_channel=$expectedBranch',
|
||||
'channel=$expectedBranch',
|
||||
];
|
||||
for (final String argumentRegExp in argumentRegExps) {
|
||||
_sanityCheckExample(
|
||||
'$kPublishRoot/api/widgets/Listener-class.html',
|
||||
r'\s*<iframe\s+class="snippet-dartpad"\s+src="'
|
||||
r'https:\/\/dartpad.dev\/embed-flutter.html\?.*?\b'
|
||||
'$argumentRegExp'
|
||||
r'\b.*">\s*<\/iframe>',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a custom index.html because we try to maintain old
|
||||
/// paths. Cleanup unused index.html files no longer needed.
|
||||
void createIndexAndCleanup() {
|
||||
print('\nCreating a custom index.html in $kPublishRoot/index.html');
|
||||
removeOldFlutterDocsDir();
|
||||
renameApiDir();
|
||||
copyIndexToRootOfDocs();
|
||||
addHtmlBaseToIndex();
|
||||
changePackageToSdkInTitlebar();
|
||||
putRedirectInOldIndexLocation();
|
||||
writeSnippetsIndexFile();
|
||||
print('\nDocs ready to go!');
|
||||
}
|
||||
|
||||
void removeOldFlutterDocsDir() {
|
||||
try {
|
||||
Directory('$kPublishRoot/flutter').deleteSync(recursive: true);
|
||||
} on FileSystemException {
|
||||
// If the directory does not exist, that's OK.
|
||||
}
|
||||
}
|
||||
|
||||
void renameApiDir() {
|
||||
Directory('$kPublishRoot/api').renameSync('$kPublishRoot/flutter');
|
||||
}
|
||||
|
||||
void copyIndexToRootOfDocs() {
|
||||
File('$kPublishRoot/flutter/index.html').copySync('$kPublishRoot/index.html');
|
||||
}
|
||||
|
||||
void changePackageToSdkInTitlebar() {
|
||||
final File indexFile = File('$kPublishRoot/index.html');
|
||||
String indexContents = indexFile.readAsStringSync();
|
||||
indexContents = indexContents.replaceFirst(
|
||||
'<li><a href="https://flutter.dev">Flutter package</a></li>',
|
||||
'<li><a href="https://flutter.dev">Flutter SDK</a></li>',
|
||||
);
|
||||
|
||||
indexFile.writeAsStringSync(indexContents);
|
||||
}
|
||||
|
||||
void addHtmlBaseToIndex() {
|
||||
final File indexFile = File('$kPublishRoot/index.html');
|
||||
String indexContents = indexFile.readAsStringSync();
|
||||
indexContents = indexContents.replaceFirst(
|
||||
'</title>\n',
|
||||
'</title>\n <base href="./flutter/">\n',
|
||||
);
|
||||
indexContents = indexContents.replaceAll(
|
||||
'href="Android/Android-library.html"',
|
||||
'href="/javadoc/"',
|
||||
);
|
||||
indexContents = indexContents.replaceAll(
|
||||
'href="iOS/iOS-library.html"',
|
||||
'href="/objcdoc/"',
|
||||
);
|
||||
|
||||
indexFile.writeAsStringSync(indexContents);
|
||||
}
|
||||
|
||||
void putRedirectInOldIndexLocation() {
|
||||
const String metaTag = '<meta http-equiv="refresh" content="0;URL=../index.html">';
|
||||
File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> findPackageNames() {
|
||||
return findPackages().map<String>((FileSystemEntity file) => path.basename(file.path)).toList();
|
||||
}
|
||||
|
||||
/// Finds all packages in the Flutter SDK
|
||||
List<Directory> findPackages() {
|
||||
return Directory('packages')
|
||||
.listSync()
|
||||
.where((FileSystemEntity entity) {
|
||||
if (entity is! Directory) {
|
||||
return false;
|
||||
}
|
||||
final File pubspec = File('${entity.path}/pubspec.yaml');
|
||||
if (!pubspec.existsSync()) {
|
||||
print("Unexpected package '${entity.path}' found in packages directory");
|
||||
return false;
|
||||
}
|
||||
// TODO(ianh): Use a real YAML parser here
|
||||
return !pubspec.readAsStringSync().contains('nodoc: true');
|
||||
})
|
||||
.cast<Directory>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// Returns import or on-disk paths for all libraries in the Flutter SDK.
|
||||
Iterable<String> libraryRefs() sync* {
|
||||
for (final Directory dir in findPackages()) {
|
||||
final String dirName = path.basename(dir.path);
|
||||
for (final FileSystemEntity file in Directory('${dir.path}/lib').listSync()) {
|
||||
if (file is File && file.path.endsWith('.dart')) {
|
||||
yield '$dirName/${path.basename(file.path)}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a fake package for platform integration APIs.
|
||||
yield '$kPlatformIntegrationPackageName/android.dart';
|
||||
yield '$kPlatformIntegrationPackageName/ios.dart';
|
||||
}
|
||||
|
||||
void printStream(Stream<List<int>> stream, { String prefix = '', List<Pattern> filter = const <Pattern>[] }) {
|
||||
stream
|
||||
.transform<String>(utf8.decoder)
|
||||
.transform<String>(const LineSplitter())
|
||||
.listen((String line) {
|
||||
if (!filter.any((Pattern pattern) => line.contains(pattern))) {
|
||||
print('$prefix$line'.trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<Process> runPubProcess({
|
||||
required String dartBinaryPath,
|
||||
required List<String> arguments,
|
||||
String? workingDirectory,
|
||||
Map<String, String>? environment,
|
||||
@visibleForTesting
|
||||
ProcessManager processManager = const LocalProcessManager(),
|
||||
}) {
|
||||
return processManager.start(
|
||||
<Object>[dartBinaryPath, 'pub', ...arguments],
|
||||
workingDirectory: workingDirectory,
|
||||
environment: environment,
|
||||
);
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. 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 'dart:math';
|
||||
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
const String kDocRoot = 'dev/docs/doc';
|
||||
|
||||
/// This script downloads an archive of Javadoc and objc doc for the engine from
|
||||
/// the artifact store and extracts them to the location used for Dartdoc.
|
||||
Future<void> main(List<String> args) async {
|
||||
final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim();
|
||||
String engineRealm = File('bin/internal/engine.realm').readAsStringSync().trim();
|
||||
if (engineRealm.isNotEmpty) {
|
||||
engineRealm = '$engineRealm/';
|
||||
}
|
||||
|
||||
final String javadocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/android-javadoc.zip';
|
||||
generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html');
|
||||
|
||||
final String objcdocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip';
|
||||
generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html');
|
||||
}
|
||||
|
||||
/// Fetches the zip archive at the specified url.
|
||||
///
|
||||
/// Returns null if the archive fails to download after [maxTries] attempts.
|
||||
Future<Archive?> fetchArchive(String url, int maxTries) async {
|
||||
List<int>? responseBytes;
|
||||
for (int i = 0; i < maxTries; i++) {
|
||||
final http.Response response = await http.get(Uri.parse(url));
|
||||
if (response.statusCode == 200) {
|
||||
responseBytes = response.bodyBytes;
|
||||
break;
|
||||
}
|
||||
stderr.writeln('Failed attempt ${i+1} to fetch $url.');
|
||||
|
||||
// On failure print a short snipped from the body in case it's helpful.
|
||||
final int bodyLength = min(1024, response.body.length);
|
||||
stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}');
|
||||
sleep(const Duration(seconds: 1));
|
||||
}
|
||||
return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes);
|
||||
}
|
||||
|
||||
Future<void> generateDocs(String url, String docName, String checkFile) async {
|
||||
const int maxTries = 5;
|
||||
final Archive? archive = await fetchArchive(url, maxTries);
|
||||
if (archive == null) {
|
||||
stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final Directory output = Directory('$kDocRoot/$docName');
|
||||
print('Extracting $docName to ${output.path}');
|
||||
output.createSync(recursive: true);
|
||||
|
||||
for (final ArchiveFile af in archive) {
|
||||
if (!af.name.endsWith('/')) {
|
||||
final File file = File('${output.path}/${af.name}');
|
||||
file.createSync(recursive: true);
|
||||
file.writeAsBytesSync(af.content as List<int>);
|
||||
}
|
||||
}
|
||||
|
||||
/// If object then copy files to old location if the archive is using the new location.
|
||||
final bool exists = Directory('$kDocRoot/$docName/objectc_docs').existsSync();
|
||||
if (exists) {
|
||||
copyFolder(Directory('$kDocRoot/$docName/objectc_docs'), Directory('$kDocRoot/$docName/'));
|
||||
}
|
||||
|
||||
final File testFile = File('${output.path}/$checkFile');
|
||||
if (!testFile.existsSync()) {
|
||||
print('Expected file ${testFile.path} not found');
|
||||
exit(1);
|
||||
}
|
||||
print('$docName ready to go!');
|
||||
}
|
||||
|
||||
/// Copies the files in a directory recursively to a new location.
|
||||
void copyFolder(Directory source, Directory destination) {
|
||||
source.listSync()
|
||||
.forEach((FileSystemEntity entity) {
|
||||
if (entity is Directory) {
|
||||
final Directory newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path)));
|
||||
newDirectory.createSync();
|
||||
copyFolder(entity.absolute, newDirectory);
|
||||
} else if (entity is File) {
|
||||
entity.copySync(path.join(destination.path, path.basename(entity.path)));
|
||||
}
|
||||
});
|
||||
}
|
@ -12,6 +12,7 @@ dependencies:
|
||||
meta: 1.9.1
|
||||
path: 1.8.3
|
||||
process: 4.2.4
|
||||
pub_semver: 2.1.4
|
||||
|
||||
async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
@ -45,7 +46,6 @@ dev_dependencies:
|
||||
node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||
|
197
dev/tools/test/create_api_docs_test.dart
Normal file
197
dev/tools/test/create_api_docs_test.dart
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../../../packages/flutter_tools/test/src/fake_process_manager.dart';
|
||||
import '../create_api_docs.dart' as apidocs;
|
||||
import '../examples_smoke_test.dart';
|
||||
|
||||
void main() {
|
||||
test('getBranchName does not call git if env LUCI_BRANCH provided', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'LUCI_BRANCH': branchName,
|
||||
},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['flutter', '--version', '--machine'],
|
||||
stdout: testVersionInfo,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(
|
||||
apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(),
|
||||
branchName,
|
||||
);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
test('getBranchName calls git if env LUCI_BRANCH not provided', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['flutter', '--version', '--machine'],
|
||||
stdout: testVersionInfo,
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '-b', '--porcelain'],
|
||||
stdout: '## $branchName',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(
|
||||
apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(),
|
||||
branchName,
|
||||
);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
test('getBranchName calls git if env LUCI_BRANCH is empty', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'LUCI_BRANCH': '',
|
||||
},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['flutter', '--version', '--machine'],
|
||||
stdout: testVersionInfo,
|
||||
),
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '-b', '--porcelain'],
|
||||
stdout: '## $branchName',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(
|
||||
apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(),
|
||||
branchName,
|
||||
);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
test("runPubProcess doesn't use the pub binary", () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FLUTTER_ROOT': '/flutter',
|
||||
},
|
||||
);
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['/flutter/bin/dart', 'pub', '--one', '--two'],
|
||||
),
|
||||
],
|
||||
);
|
||||
apidocs.FlutterInformation.instance =
|
||||
apidocs.FlutterInformation(platform: platform, processManager: processManager);
|
||||
|
||||
apidocs.runPubProcess(
|
||||
arguments: <String>['--one', '--two'],
|
||||
processManager: processManager,
|
||||
filesystem: filesystem,
|
||||
);
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
group('FlutterInformation', () {
|
||||
late FakeProcessManager fakeProcessManager;
|
||||
late FakePlatform fakePlatform;
|
||||
late MemoryFileSystem memoryFileSystem;
|
||||
late apidocs.FlutterInformation flutterInformation;
|
||||
|
||||
void setUpWithEnvironment(Map<String, String> environment) {
|
||||
fakePlatform = FakePlatform(environment: environment);
|
||||
flutterInformation = apidocs.FlutterInformation(
|
||||
filesystem: memoryFileSystem,
|
||||
processManager: fakeProcessManager,
|
||||
platform: fakePlatform,
|
||||
);
|
||||
apidocs.FlutterInformation.instance = flutterInformation;
|
||||
}
|
||||
|
||||
setUp(() {
|
||||
fakeProcessManager = FakeProcessManager.empty();
|
||||
memoryFileSystem = MemoryFileSystem();
|
||||
setUpWithEnvironment(<String, String>{});
|
||||
});
|
||||
|
||||
test('calls out to flutter if FLUTTER_VERSION is not set', () async {
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['flutter', '--version', '--machine'], stdout: testVersionInfo));
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo));
|
||||
final Map<String, dynamic> info = flutterInformation.getFlutterInformation();
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
expect(info['frameworkVersion'], equals(Version.parse('2.5.0')));
|
||||
});
|
||||
test("doesn't call out to flutter if FLUTTER_VERSION is set", () async {
|
||||
setUpWithEnvironment(<String, String>{
|
||||
'FLUTTER_VERSION': testVersionInfo,
|
||||
});
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo));
|
||||
final Map<String, dynamic> info = flutterInformation.getFlutterInformation();
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
expect(info['frameworkVersion'], equals(Version.parse('2.5.0')));
|
||||
});
|
||||
test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async {
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['flutter', '--version', '--machine'], stdout: testVersionInfo));
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo));
|
||||
final Directory root = flutterInformation.getFlutterRoot();
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
expect(root.path, equals('/home/user/flutter'));
|
||||
});
|
||||
test("getFlutterRoot doesn't call out to flutter if FLUTTER_ROOT is set", () async {
|
||||
setUpWithEnvironment(<String, String>{'FLUTTER_ROOT': '/home/user/flutter'});
|
||||
final Directory root = flutterInformation.getFlutterRoot();
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
expect(root.path, equals('/home/user/flutter'));
|
||||
});
|
||||
test('parses version properly', () async {
|
||||
fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo;
|
||||
fakeProcessManager.addCommand(
|
||||
const FakeCommand(command: <Pattern>['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo));
|
||||
final Map<String, dynamic> info = flutterInformation.getFlutterInformation();
|
||||
expect(info['frameworkVersion'], isNotNull);
|
||||
expect(info['frameworkVersion'], equals(Version.parse('2.5.0')));
|
||||
expect(info['dartSdkVersion'], isNotNull);
|
||||
expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev')));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const String branchName = 'stable';
|
||||
const String testVersionInfo = '''
|
||||
{
|
||||
"frameworkVersion": "2.5.0",
|
||||
"channel": "$branchName",
|
||||
"repositoryUrl": "git@github.com:flutter/flutter.git",
|
||||
"frameworkRevision": "0000000000000000000000000000000000000000",
|
||||
"frameworkCommitDate": "2021-07-28 13:03:40 -0700",
|
||||
"engineRevision": "0000000000000000000000000000000000000001",
|
||||
"dartSdkVersion": "2.14.0 (build 2.14.0-360.0.dev)",
|
||||
"flutterRoot": "/home/user/flutter"
|
||||
}
|
||||
''';
|
@ -1,98 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:platform/platform.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../../../packages/flutter_tools/test/src/fake_process_manager.dart';
|
||||
import '../dartdoc.dart' show getBranchName, runPubProcess;
|
||||
|
||||
void main() {
|
||||
const String branchName = 'stable';
|
||||
test('getBranchName does not call git if env LUCI_BRANCH provided', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'LUCI_BRANCH': branchName,
|
||||
},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.empty();
|
||||
|
||||
expect(
|
||||
getBranchName(
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
),
|
||||
branchName,
|
||||
);
|
||||
});
|
||||
|
||||
test('getBranchName calls git if env LUCI_BRANCH not provided', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '-b', '--porcelain'],
|
||||
stdout: '## $branchName',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(
|
||||
getBranchName(
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
),
|
||||
branchName,
|
||||
);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
test('getBranchName calls git if env LUCI_BRANCH is empty', () {
|
||||
final Platform platform = FakePlatform(
|
||||
environment: <String, String>{
|
||||
'LUCI_BRANCH': '',
|
||||
},
|
||||
);
|
||||
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['git', 'status', '-b', '--porcelain'],
|
||||
stdout: '## $branchName',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(
|
||||
getBranchName(
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
),
|
||||
branchName,
|
||||
);
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
||||
test("runPubProcess doesn't use the pub binary", () {
|
||||
final ProcessManager processManager = FakeProcessManager.list(
|
||||
<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['dart', 'pub', '--one', '--two'],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
runPubProcess(
|
||||
dartBinaryPath: 'dart',
|
||||
arguments: <String>['--one', '--two'],
|
||||
processManager: processManager,
|
||||
);
|
||||
|
||||
expect(processManager, hasNoRemainingExpectations);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user