Revert "Reorganize and clarify API doc generator" (#132613)
Reverts flutter/flutter#132353 Educated guess that this is causing the docs failures: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8772644466113801713/+/u/Docs/Deploy_docs/Firebase_deploy/stdout
This commit is contained in:
parent
375538873d
commit
909400dc4d
200
dev/bots/docs.sh
200
dev/bots/docs.sh
@ -16,13 +16,102 @@ 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"
|
||||
|
||||
@ -35,106 +124,31 @@ FLUTTER_BIN="$FLUTTER_ROOT/bin"
|
||||
DART_BIN="$FLUTTER_ROOT/bin/cache/dart-sdk/bin"
|
||||
FLUTTER="$FLUTTER_BIN/flutter"
|
||||
DART="$DART_BIN/dart"
|
||||
PATH="$FLUTTER_BIN:$DART_BIN:$PATH"
|
||||
export PATH="$FLUTTER_BIN:$DART_BIN:$PATH"
|
||||
|
||||
# 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)"
|
||||
# Make sure dart is installed by invoking Flutter to download it.
|
||||
# This also creates the 'version' file.
|
||||
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 ".".
|
||||
PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}"
|
||||
export PUB_CACHE
|
||||
export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}"
|
||||
fi
|
||||
|
||||
OUTPUT_DIR=$(mktemp -d /tmp/dartdoc.XXXXX)
|
||||
DOC_DIR="$OUTPUT_DIR/doc"
|
||||
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
|
||||
fi
|
||||
|
||||
function usage() {
|
||||
echo "Usage: $(basename "${BASH_SOURCE[0]}") [--keep-temp] [--output <output.zip>]"
|
||||
echo ""
|
||||
echo " --keep-temp Do not delete the temporary output directory created while generating docs."
|
||||
echo " Normally the script deletes the temporary directory after generating the"
|
||||
echo " output ZIP file."
|
||||
echo " --output <output.zip> specifies where the output ZIP file containing the documentation data"
|
||||
echo " will be written."
|
||||
echo ""
|
||||
}
|
||||
|
||||
function parse_args() {
|
||||
local arg
|
||||
local args=()
|
||||
KEEP_TEMP=0
|
||||
DESTINATION="$FLUTTER_ROOT/dev/docs/api_docs.zip"
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--keep-temp)
|
||||
KEEP_TEMP=1
|
||||
;;
|
||||
--output)
|
||||
DESTINATION="$2"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
args=("${args[@]}" "$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
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
|
||||
# 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 "$OUTPUT_DIR"; zip -r -9 -q "$DESTINATION" ./doc)
|
||||
if [[ $KEEP_TMP == 1 ]]; then
|
||||
echo "Temporary document generation output left in $OUTPUT_DIR"
|
||||
else
|
||||
echo "Removing Temporary document generation output from $OUTPUT_DIR"
|
||||
rm -rf "$OUTPUT_DIR"
|
||||
fi
|
||||
echo "Wrote docs ZIP file to $DESTINATION"
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
main
|
||||
# Zip docs
|
||||
cd "$FLUTTER_ROOT/dev/docs"
|
||||
zip -r api_docs.zip doc
|
||||
|
29
dev/docs/dashing_postprocess.dart
Normal file
29
dev/docs/dashing_postprocess.dart
Normal file
@ -0,0 +1,29 @@
|
||||
// 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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
606
dev/tools/dartdoc.dart
Normal file
606
dev/tools/dartdoc.dart
Normal file
@ -0,0 +1,606 @@
|
||||
// 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,
|
||||
);
|
||||
}
|
97
dev/tools/java_and_objc_doc.dart
Normal file
97
dev/tools/java_and_objc_doc.dart
Normal file
@ -0,0 +1,97 @@
|
||||
// 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,7 +12,6 @@ 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"
|
||||
@ -46,6 +45,7 @@ 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"
|
||||
|
@ -1,195 +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: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;
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
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"
|
||||
}
|
||||
''';
|
98
dev/tools/test/dartdoc_test.dart
Normal file
98
dev/tools/test/dartdoc_test.dart
Normal file
@ -0,0 +1,98 @@
|
||||
// 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