From 50840544acbbb0479e57982749b4a6a11aab81fe Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 11 Dec 2018 17:22:18 -0800 Subject: [PATCH 01/14] First try at enabling coveralls again for dartdoc --- .gitignore | 1 + README.md | 2 ++ lib/src/io_utils.dart | 68 ++++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 1 + tool/grind.dart | 7 +++-- tool/install_travis.sh | 1 + tool/travis.sh | 4 +++ 7 files changed, 82 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9a076ca277..a144cd77ce 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .settings/ build/ doc/ +lcov.info packages pub.dartlang.org/ testing/test_package/doc diff --git a/README.md b/README.md index f42227486e..7225a024aa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # dartdoc [![Build Status](https://travis-ci.org/dart-lang/dartdoc.svg?branch=master)](https://travis-ci.org/dart-lang/dartdoc) +[![Coverage Status](https://coveralls.io/repos/github/dart-lang/dartdoc/badge.svg?branch=master)](https://coveralls.io/github/dart-lang/dartdoc?branch=master) + Use `dartdoc` to generate HTML documentaton for your Dart package. diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index 79fc42ad75..2926b15bb7 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -9,6 +9,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:dartdoc/src/tuple.dart'; import 'package:path/path.dart' as pathLib; /// Return a resolved path including the home directory in place of tilde @@ -116,6 +117,73 @@ class MultiFutureTracker { Future wait() async => await _waitUntil(0); } +/// Keeps track of coverage data automatically for any processes run by this +/// [CoverageSubprocessLauncher]. Requires that these be dart processes. +class CoverageSubprocessLauncher extends SubprocessLauncher { + CoverageSubprocessLauncher(String context, [Map environment]) + : super(context, environment); + + static int nextObservatoryPort = 9292; + + /// Set this to true to enable coverage runs. + static bool coverageEnabled = false; + /// A list of all coverage results picked up by all launchers. + static List>>> coverageResults = []; + + + static Directory _tempDir; + static Directory get tempDir => _tempDir ??= Directory.systemTemp.createTempSync('dartdoc_coverage_data'); + + int _observatoryPort; + // TODO(jcollins-g): use ephemeral ports + int get observatoryPort => _observatoryPort ??= nextObservatoryPort++; + + String _outCoverageFilename; + String get outCoverageFilename => _outCoverageFilename ??= pathLib.join(tempDir.path, 'coverage.out.${observatoryPort}'); + + /// Call once all coverage runs have been generated by calling runStreamed + /// on all [CoverageSubprocessLaunchers]. + static Future generateCoverageToFile(File outputFile) async { + if (!coverageEnabled) return Future.value(null); + var currentCoverageResults = coverageResults; + coverageResults = []; + var launcher = SubprocessLauncher('format_coverage'); + /// Wait for all coverage runs to finish. + await Future.wait(currentCoverageResults.map((t) => t.item2)); + + return launcher.runStreamed('pub', ['run', 'coverage:format_coverage', + '--lcov', + '--out=${pathLib.canonicalize(outputFile.path)}', + '--report-on=bin,lib', + '-i' + ]..addAll(currentCoverageResults.map((t) => t.item1))); + } + + @override + Future> runStreamed(String executable, List arguments, {String workingDirectory}) { + assert(executable == Platform.executable, 'Must use dart executable for tracking coverage'); + + if (coverageEnabled) { + arguments = ['--enable-vm-service=${observatoryPort}', + '--pause-isolates-on-exit']..addAll(arguments); + } + + Future> results = super.runStreamed(executable, arguments, workingDirectory: workingDirectory); + + if (coverageEnabled) { + coverageResults.add(new Tuple2(outCoverageFilename, + super.runStreamed('pub', ['run', 'coverage:collect_coverage', + '--wait-paused', + '--resume-isolates', + '--port=${observatoryPort}', + '--out=${outCoverageFilename}', + ]))); + } + return results; + } +} + + class SubprocessLauncher { final String context; final Map environment; diff --git a/pubspec.yaml b/pubspec.yaml index a5e7482b67..0e14685774 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dev_dependencies: build: ^1.0.1 build_runner: ^1.0.0 build_version: ^1.0.0 + coverage: any dhttpd: ^3.0.0 glob: ^1.1.5 grinder: ^0.8.2 diff --git a/tool/grind.dart b/tool/grind.dart index 42eef12c3e..05cdd6f22f 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -848,9 +848,10 @@ List get testFiles => new Directory('test') Future testDart2() async { List parameters = ['--enable-asserts']; + CoverageSubprocessLauncher.coverageEnabled = Platform.environment.containsKey('COVERAGE_TOKEN'); for (File dartFile in testFiles) { await testFutures.addFutureFromClosure(() => - new SubprocessLauncher('dart2-${pathLib.basename(dartFile.path)}') + new CoverageSubprocessLauncher('dart2-${pathLib.basename(dartFile.path)}') .runStreamed( Platform.resolvedExecutable, [] @@ -859,7 +860,7 @@ Future testDart2() async { } for (File dartFile in binFiles) { - await testFutures.addFutureFromClosure(() => new SubprocessLauncher( + await testFutures.addFutureFromClosure(() => new CoverageSubprocessLauncher( 'dart2-bin-${pathLib.basename(dartFile.path)}-help') .runStreamed( Platform.resolvedExecutable, @@ -868,6 +869,8 @@ Future testDart2() async { ..add(dartFile.path) ..add('--help'))); } + + return await CoverageSubprocessLauncher.generateCoverageToFile(new File('lcov.info')); } @Task('Generate docs for dartdoc') diff --git a/tool/install_travis.sh b/tool/install_travis.sh index c3bdc15b8e..fd97a969f4 100755 --- a/tool/install_travis.sh +++ b/tool/install_travis.sh @@ -9,6 +9,7 @@ set -x if uname | grep -q Linux ; then sudo apt-get install -y gdb + gem install coveralls-lcov fi exit 0 diff --git a/tool/travis.sh b/tool/travis.sh index 4bdc78b734..45a7a1323c 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -38,4 +38,8 @@ elif [ "$DARTDOC_BOT" = "sdk-analyzer" ]; then else echo "Running main dartdoc bot" pub run grinder buildbot + if [ -n "$COVERAGE_TOKEN" ] && [${DART_VERSION} != "2.1.0"]; then + # Only attempt to upload coverage data for dev builds. + coverage-lcov lcov.info + fi fi From 39151024c70919c7e1f6be3764bee7b377aa07d1 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 11 Dec 2018 17:22:29 -0800 Subject: [PATCH 02/14] dartfmt --- lib/src/io_utils.dart | 58 +++++++++++++++++++++++++++---------------- tool/grind.dart | 20 ++++++++------- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index 2926b15bb7..c35baed5dd 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -127,19 +127,21 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { /// Set this to true to enable coverage runs. static bool coverageEnabled = false; + /// A list of all coverage results picked up by all launchers. static List>>> coverageResults = []; - static Directory _tempDir; - static Directory get tempDir => _tempDir ??= Directory.systemTemp.createTempSync('dartdoc_coverage_data'); + static Directory get tempDir => + _tempDir ??= Directory.systemTemp.createTempSync('dartdoc_coverage_data'); int _observatoryPort; // TODO(jcollins-g): use ephemeral ports int get observatoryPort => _observatoryPort ??= nextObservatoryPort++; String _outCoverageFilename; - String get outCoverageFilename => _outCoverageFilename ??= pathLib.join(tempDir.path, 'coverage.out.${observatoryPort}'); + String get outCoverageFilename => _outCoverageFilename ??= + pathLib.join(tempDir.path, 'coverage.out.${observatoryPort}'); /// Call once all coverage runs have been generated by calling runStreamed /// on all [CoverageSubprocessLaunchers]. @@ -148,42 +150,54 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { var currentCoverageResults = coverageResults; coverageResults = []; var launcher = SubprocessLauncher('format_coverage'); + /// Wait for all coverage runs to finish. await Future.wait(currentCoverageResults.map((t) => t.item2)); - return launcher.runStreamed('pub', ['run', 'coverage:format_coverage', - '--lcov', - '--out=${pathLib.canonicalize(outputFile.path)}', - '--report-on=bin,lib', - '-i' - ]..addAll(currentCoverageResults.map((t) => t.item1))); + return launcher.runStreamed( + 'pub', + [ + 'run', + 'coverage:format_coverage', + '--lcov', + '--out=${pathLib.canonicalize(outputFile.path)}', + '--report-on=bin,lib', + '-i' + ]..addAll(currentCoverageResults.map((t) => t.item1))); } @override - Future> runStreamed(String executable, List arguments, {String workingDirectory}) { - assert(executable == Platform.executable, 'Must use dart executable for tracking coverage'); + Future> runStreamed(String executable, List arguments, + {String workingDirectory}) { + assert(executable == Platform.executable, + 'Must use dart executable for tracking coverage'); if (coverageEnabled) { - arguments = ['--enable-vm-service=${observatoryPort}', - '--pause-isolates-on-exit']..addAll(arguments); + arguments = [ + '--enable-vm-service=${observatoryPort}', + '--pause-isolates-on-exit' + ]..addAll(arguments); } - Future> results = super.runStreamed(executable, arguments, workingDirectory: workingDirectory); + Future> results = super + .runStreamed(executable, arguments, workingDirectory: workingDirectory); if (coverageEnabled) { - coverageResults.add(new Tuple2(outCoverageFilename, - super.runStreamed('pub', ['run', 'coverage:collect_coverage', - '--wait-paused', - '--resume-isolates', - '--port=${observatoryPort}', - '--out=${outCoverageFilename}', - ]))); + coverageResults.add(new Tuple2( + outCoverageFilename, + super.runStreamed('pub', [ + 'run', + 'coverage:collect_coverage', + '--wait-paused', + '--resume-isolates', + '--port=${observatoryPort}', + '--out=${outCoverageFilename}', + ]))); } return results; } } - class SubprocessLauncher { final String context; final Map environment; diff --git a/tool/grind.dart b/tool/grind.dart index 05cdd6f22f..4d653b03cd 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -848,15 +848,16 @@ List get testFiles => new Directory('test') Future testDart2() async { List parameters = ['--enable-asserts']; - CoverageSubprocessLauncher.coverageEnabled = Platform.environment.containsKey('COVERAGE_TOKEN'); + CoverageSubprocessLauncher.coverageEnabled = + Platform.environment.containsKey('COVERAGE_TOKEN'); for (File dartFile in testFiles) { - await testFutures.addFutureFromClosure(() => - new CoverageSubprocessLauncher('dart2-${pathLib.basename(dartFile.path)}') - .runStreamed( - Platform.resolvedExecutable, - [] - ..addAll(parameters) - ..add(dartFile.path))); + await testFutures.addFutureFromClosure(() => new CoverageSubprocessLauncher( + 'dart2-${pathLib.basename(dartFile.path)}') + .runStreamed( + Platform.resolvedExecutable, + [] + ..addAll(parameters) + ..add(dartFile.path))); } for (File dartFile in binFiles) { @@ -870,7 +871,8 @@ Future testDart2() async { ..add('--help'))); } - return await CoverageSubprocessLauncher.generateCoverageToFile(new File('lcov.info')); + return await CoverageSubprocessLauncher.generateCoverageToFile( + new File('lcov.info')); } @Task('Generate docs for dartdoc') From fddc2651a1ceef975da13a268380c67ac0330b03 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 11 Dec 2018 17:42:07 -0800 Subject: [PATCH 03/14] syntax error in travis.sh --- tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/travis.sh b/tool/travis.sh index 45a7a1323c..9c74f6a2ef 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -38,7 +38,7 @@ elif [ "$DARTDOC_BOT" = "sdk-analyzer" ]; then else echo "Running main dartdoc bot" pub run grinder buildbot - if [ -n "$COVERAGE_TOKEN" ] && [${DART_VERSION} != "2.1.0"]; then + if [ -n "$COVERAGE_TOKEN" ] && [ ${DART_VERSION} != "2.1.0" ] && uname | grep -q Linux ; then # Only attempt to upload coverage data for dev builds. coverage-lcov lcov.info fi From 8ef76fa4016bdf7700fb7acf8a4956ca79b42531 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 09:47:08 -0800 Subject: [PATCH 04/14] add quotes --- tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/travis.sh b/tool/travis.sh index 9c74f6a2ef..850c2154d6 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -38,7 +38,7 @@ elif [ "$DARTDOC_BOT" = "sdk-analyzer" ]; then else echo "Running main dartdoc bot" pub run grinder buildbot - if [ -n "$COVERAGE_TOKEN" ] && [ ${DART_VERSION} != "2.1.0" ] && uname | grep -q Linux ; then + if [ -n "$COVERAGE_TOKEN" ] && [ "${DART_VERSION}" != "2.1.0" ] && uname | grep -q Linux ; then # Only attempt to upload coverage data for dev builds. coverage-lcov lcov.info fi From 8c4884dea17fd0ba66f7fee3382917ffc57a8433 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 10:02:16 -0800 Subject: [PATCH 05/14] Fix coverage runner --- tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/travis.sh b/tool/travis.sh index 850c2154d6..25663e0742 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -40,6 +40,6 @@ else pub run grinder buildbot if [ -n "$COVERAGE_TOKEN" ] && [ "${DART_VERSION}" != "2.1.0" ] && uname | grep -q Linux ; then # Only attempt to upload coverage data for dev builds. - coverage-lcov lcov.info + coverage-lcov --repo-token="${COVERAGE_TOKEN}" lcov.info fi fi From 8595476e15d1a07b3fcaf77d1602449fba00a104 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 10:30:25 -0800 Subject: [PATCH 06/14] coveralls installation problem fix? --- tool/install_travis.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tool/install_travis.sh b/tool/install_travis.sh index fd97a969f4..91ff42c2e7 100755 --- a/tool/install_travis.sh +++ b/tool/install_travis.sh @@ -8,8 +8,10 @@ set -x if uname | grep -q Linux ; then + sudo apt-get update sudo apt-get install -y gdb - gem install coveralls-lcov + sudo gem install coveralls-lcov + coveralls-lcov --help fi exit 0 From 0e885839679b7c696b73b63a5f44c87429cc4326 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 10:48:35 -0800 Subject: [PATCH 07/14] coveralls is named coveralls --- tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/travis.sh b/tool/travis.sh index 25663e0742..f477298143 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -40,6 +40,6 @@ else pub run grinder buildbot if [ -n "$COVERAGE_TOKEN" ] && [ "${DART_VERSION}" != "2.1.0" ] && uname | grep -q Linux ; then # Only attempt to upload coverage data for dev builds. - coverage-lcov --repo-token="${COVERAGE_TOKEN}" lcov.info + coveralls-lcov --repo-token="${COVERAGE_TOKEN}" lcov.info fi fi From 043316cae0f1cb88a6fc130c5636d9af1e28ad17 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 11:30:52 -0800 Subject: [PATCH 08/14] Use relative package paths and otherwise fix up the format run --- lib/src/io_utils.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index c35baed5dd..8b401b411c 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -160,6 +160,10 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { 'run', 'coverage:format_coverage', '--lcov', + '-v', + '-b', '.', + '--package-root=.', + '--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}', '--out=${pathLib.canonicalize(outputFile.path)}', '--report-on=bin,lib', '-i' From e4dae4d3ed43c8f987745a0577e41b86989a762e Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 11:31:43 -0800 Subject: [PATCH 09/14] Set up DART_VERSION correctly --- tool/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/travis.sh b/tool/travis.sh index f477298143..9b8e5de874 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -9,6 +9,7 @@ set -ex # add globally activated packages to the path export PATH="$PATH":"~/.pub-cache/bin" +DART_VERSION=`dart --version 2>&1 | awk '{print $4}'` if [ "$DARTDOC_BOT" = "sdk-docs" ]; then # Build the SDK docs @@ -22,7 +23,6 @@ elif [ "$DARTDOC_BOT" = "flutter" ]; then pub run grinder validate-flutter-docs elif [ "$DARTDOC_BOT" = "packages" ]; then echo "Running packages dartdoc bot" - DART_VERSION=`dart --version 2>&1 | awk '{print $4}'` if [ ${DART_VERSION} != 2.0.0 ] ; then PACKAGE_NAME=angular PACKAGE_VERSION=">=5.1.0" DARTDOC_PARAMS="--include=angular,angular.security" pub run grinder build-pub-package else From 12316a073f3f6427fb9e091b2ac803faa7439090 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 12:41:32 -0800 Subject: [PATCH 10/14] Work around dart-lang/coverage#239 --- lib/src/io_utils.dart | 6 +- tool/format_coverage.dart | 232 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 tool/format_coverage.dart diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index 8b401b411c..59e2880a7e 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -141,7 +141,7 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { String _outCoverageFilename; String get outCoverageFilename => _outCoverageFilename ??= - pathLib.join(tempDir.path, 'coverage.out.${observatoryPort}'); + pathLib.join(tempDir.path, 'dart-cov-0-${observatoryPort}.json'); /// Call once all coverage runs have been generated by calling runStreamed /// on all [CoverageSubprocessLaunchers]. @@ -166,8 +166,8 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { '--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}', '--out=${pathLib.canonicalize(outputFile.path)}', '--report-on=bin,lib', - '-i' - ]..addAll(currentCoverageResults.map((t) => t.item1))); + '-i', tempDir.path, + ]); } @override diff --git a/tool/format_coverage.dart b/tool/format_coverage.dart new file mode 100644 index 0000000000..4e6512907f --- /dev/null +++ b/tool/format_coverage.dart @@ -0,0 +1,232 @@ +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:coverage/coverage.dart'; +import 'package:path/path.dart' as p; + +/// [Environment] stores gathered arguments information. +class Environment { + String sdkRoot; + String pkgRoot; + String packagesPath; + String baseDirectory; + String input; + IOSink output; + List reportOn; + String bazelWorkspace; + bool bazel; + int workers; + bool prettyPrint; + bool lcov; + bool expectMarkers; + bool verbose; +} + +Future main(List arguments) async { + final env = parseArgs(arguments); + + List files = filesToProcess(env.input); + if (env.verbose) { + print('Environment:'); + print(' # files: ${files.length}'); + print(' # workers: ${env.workers}'); + print(' sdk-root: ${env.sdkRoot}'); + print(' package-root: ${env.pkgRoot}'); + print(' package-spec: ${env.packagesPath}'); + print(' report-on: ${env.reportOn}'); + } + + var clock = new Stopwatch()..start(); + var hitmap = await parseCoverage(files, env.workers); + + // All workers are done. Process the data. + if (env.verbose) { + print('Done creating global hitmap. Took ${clock.elapsedMilliseconds} ms.'); + } + + String output; + var resolver = env.bazel + ? new BazelResolver(workspacePath: env.bazelWorkspace) + : new Resolver( + packagesPath: env.packagesPath, + packageRoot: env.pkgRoot, + sdkRoot: env.sdkRoot); + var loader = new Loader(); + if (env.prettyPrint) { + output = + await new PrettyPrintFormatter(resolver, loader, reportOn: env.reportOn) + .format(hitmap); + } else { + assert(env.lcov); + output = await new LcovFormatter(resolver, + reportOn: env.reportOn, basePath: env.baseDirectory) + .format(hitmap); + } + + env.output.write(output); + await env.output.flush(); + if (env.verbose) { + print('Done flushing output. Took ${clock.elapsedMilliseconds} ms.'); + } + + if (env.verbose) { + if (resolver.failed.length > 0) { + print('Failed to resolve:'); + for (String error in resolver.failed.toSet()) { + print(' $error'); + } + } + if (loader.failed.length > 0) { + print('Failed to load:'); + for (String error in loader.failed.toSet()) { + print(' $error'); + } + } + } + await env.output.close(); +} + +/// Checks the validity of the provided arguments. Does not initialize actual +/// processing. +Environment parseArgs(List arguments) { + final env = new Environment(); + var parser = new ArgParser(); + + parser.addOption('sdk-root', abbr: 's', help: 'path to the SDK root'); + parser.addOption('package-root', abbr: 'p', help: 'path to the package root'); + parser.addOption('packages', help: 'path to the package spec file'); + parser.addOption('in', abbr: 'i', help: 'input(s): may be file or directory'); + parser.addOption('out', + abbr: 'o', defaultsTo: 'stdout', help: 'output: may be file or stdout'); + parser.addMultiOption('report-on', + help: 'which directories or files to report coverage on'); + parser.addOption('workers', + abbr: 'j', defaultsTo: '1', help: 'number of workers'); + parser.addOption('bazel-workspace', + defaultsTo: '', help: 'Bazel workspace directory'); + parser.addOption('base-directory', + abbr: 'b', + help: 'the base directory relative to which source paths are output'); + parser.addFlag('bazel', + defaultsTo: false, help: 'use Bazel-style path resolution'); + parser.addFlag('pretty-print', + abbr: 'r', + negatable: false, + help: 'convert coverage data to pretty print format'); + parser.addFlag('lcov', + abbr: 'l', + negatable: false, + help: 'convert coverage data to lcov format'); + parser.addFlag('verbose', + abbr: 'v', negatable: false, help: 'verbose output'); + parser.addFlag('help', abbr: 'h', negatable: false, help: 'show this help'); + + var args = parser.parse(arguments); + + void printUsage() { + print('Usage: dart format_coverage.dart [OPTION...]\n'); + print(parser.usage); + } + + void fail(String msg) { + print('\n$msg\n'); + printUsage(); + exit(1); + } + + if (args['help']) { + printUsage(); + exit(0); + } + + env.sdkRoot = args['sdk-root']; + if (env.sdkRoot != null) { + env.sdkRoot = p.normalize(p.join(p.absolute(env.sdkRoot), 'lib')); + if (!FileSystemEntity.isDirectorySync(env.sdkRoot)) { + fail('Provided SDK root "${args["sdk-root"]}" is not a valid SDK ' + 'top-level directory'); + } + } + + if (args['package-root'] != null && args['packages'] != null) { + fail('Only one of --package-root or --packages may be specified.'); + } + + env.packagesPath = args['packages']; + if (env.packagesPath != null) { + if (!FileSystemEntity.isFileSync(env.packagesPath)) { + fail('Package spec "${args["packages"]}" not found, or not a file.'); + } + } + + env.pkgRoot = args['package-root']; + if (env.pkgRoot != null) { + env.pkgRoot = p.absolute(p.normalize(args['package-root'])); + if (!FileSystemEntity.isDirectorySync(env.pkgRoot)) { + fail('Package root "${args["package-root"]}" is not a directory.'); + } + } + + if (args['in'] == null) fail('No input files given.'); + env.input = p.absolute(p.normalize(args['in'])); + if (!FileSystemEntity.isDirectorySync(env.input) && + !FileSystemEntity.isFileSync(env.input)) { + fail('Provided input "${args["in"]}" is neither a directory nor a file.'); + } + + if (args['out'] == 'stdout') { + env.output = stdout; + } else { + var outpath = p.absolute(p.normalize(args['out'])); + var outfile = new File(outpath)..createSync(recursive: true); + env.output = outfile.openWrite(); + } + + env.reportOn = args['report-on'].isNotEmpty ? args['report-on'] : null; + + env.bazel = args['bazel']; + env.bazelWorkspace = args['bazel-workspace']; + if (env.bazelWorkspace.isNotEmpty && !env.bazel) { + stderr.writeln('warning: ignoring --bazel-workspace: --bazel not set'); + } + + if (args['base-directory'] != null) { + env.baseDirectory = p.absolute(args['base-directory']); + } + + env.lcov = args['lcov']; + if (args['pretty-print'] && env.lcov) { + fail('Choose one of pretty-print or lcov output'); + } + // Use pretty-print either explicitly or by default. + env.prettyPrint = !env.lcov; + + try { + env.workers = int.parse('${args["workers"]}'); + } catch (e) { + fail('Invalid worker count: $e'); + } + + env.verbose = args['verbose']; + return env; +} + +/// Given an absolute path absPath, this function returns a [List] of files +/// are contained by it if it is a directory, or a [List] containing the file if +/// it is a file. +List filesToProcess(String absPath) { + var filePattern = new RegExp(r'^dart-cov-\d+-\d+.json$'); + if (FileSystemEntity.isDirectorySync(absPath)) { + return new Directory(absPath) + .listSync(recursive: true) + .whereType() + .where((e) => filePattern.hasMatch(p.basename(e.path))) + .toList(); + } + return [new File(absPath)]; +} From 642d7b1b7e3b16ad76b8481e3314d341c2700c32 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 13:13:24 -0800 Subject: [PATCH 11/14] Don't try to run coverage on sdk-analyzer passes --- tool/travis.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tool/travis.sh b/tool/travis.sh index 9b8e5de874..c26fcef0e6 100755 --- a/tool/travis.sh +++ b/tool/travis.sh @@ -34,6 +34,7 @@ elif [ "$DARTDOC_BOT" = "packages" ]; then PACKAGE_NAME=shelf_exception_handler PACKAGE_VERSION=">=0.2.0" pub run grinder build-pub-package elif [ "$DARTDOC_BOT" = "sdk-analyzer" ]; then echo "Running main dartdoc bot against the SDK analyzer" + unset COVERAGE_TOKEN DARTDOC_GRIND_STEP=buildbot-no-publish pub run grinder test-with-analyzer-sdk else echo "Running main dartdoc bot" From e3e0100f850587bf9fa7692af6664e6aee88ae1c Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 14:04:54 -0800 Subject: [PATCH 12/14] Add workarounds for bugs --- bin/dartdoc.dart | 39 ++++++++++++++++++++++++++------------- lib/src/io_utils.dart | 5 ++--- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index 2b70ffab9d..3626038747 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -38,7 +38,7 @@ Future> createDartdocProgramOptions() async { /// Analyzes Dart files and generates a representation of included libraries, /// classes, and members. Uses the current directory to look for libraries. -void main(List arguments) async { +Future main(List arguments) async { DartdocOptionSet optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ createDartdocOptions, @@ -52,17 +52,27 @@ void main(List arguments) async { } on FormatException catch (e) { stderr.writeln(' fatal error: ${e.message}'); stderr.writeln(''); - _printUsageAndExit(optionSet.argParser, exitCode: 64); + _printUsage(optionSet.argParser); + // Do not use exit() as this bypasses --pause-isolates-on-exit + // TODO(jcollins-g): use exit once dart-lang/sdk#31747 is fixed. + exitCode = 64; + return; } on DartdocOptionError catch (e) { stderr.writeln(' fatal error: ${e.message}'); stderr.writeln(''); - _printUsageAndExit(optionSet.argParser, exitCode: 64); + _printUsage(optionSet.argParser); + exitCode = 64; + return; } if (optionSet['help'].valueAt(Directory.current)) { - _printHelpAndExit(optionSet.argParser); + _printHelp(optionSet.argParser); + exitCode = 0; + return; } if (optionSet['version'].valueAt(Directory.current)) { - _printVersionAndExit(optionSet.argParser); + _printVersion(optionSet.argParser); + exitCode = 0; + return; } DartdocProgramOptionContext config = @@ -88,34 +98,37 @@ void main(List arguments) async { }, onError: (e, Chain chain) { if (e is DartdocFailure) { stderr.writeln('\nGeneration failed: ${e}.'); - exit(1); + exitCode = 1; + return; } else { stderr.writeln('\nGeneration failed: ${e}\n${chain.terse}'); - exit(255); + exitCode = 255; + return; } }, when: config.asyncStackTraces); } finally { // Clear out any cached tool snapshots and temporary directories. + // ignore: unawaited_futures SnapshotCache.instance.dispose(); + // ignore: unawaited_futures ToolTempFileTracker.instance.dispose(); } + exitCode = 0; + return; } /// Print help if we are passed the help option. -void _printHelpAndExit(ArgParser parser, {int exitCode: 0}) { +void _printHelp(ArgParser parser) { print('Generate HTML documentation for Dart libraries.\n'); - _printUsageAndExit(parser, exitCode: exitCode); } /// Print usage information on invalid command lines. -void _printUsageAndExit(ArgParser parser, {int exitCode: 0}) { +void _printUsage(ArgParser parser) { print('Usage: dartdoc [OPTIONS]\n'); print(parser.usage); - exit(exitCode); } /// Print version information. -void _printVersionAndExit(ArgParser parser) { +void _printVersion(ArgParser parser) { print('dartdoc version: ${dartdocVersion}'); - exit(exitCode); } diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index 59e2880a7e..aa36b2c726 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -155,10 +155,9 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { await Future.wait(currentCoverageResults.map((t) => t.item2)); return launcher.runStreamed( - 'pub', + Platform.executable, [ - 'run', - 'coverage:format_coverage', + 'tool/format_coverage.dart', '--lcov', '-v', '-b', '.', From 6b53804f43ec96667234b691d69238e80a851e79 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 12 Dec 2018 14:19:01 -0800 Subject: [PATCH 13/14] Drop almost everything from travis config to try to speed this up --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index c7ca622541..f74c7551e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,18 @@ language: dart sudo: false dart: - - stable + #- stable - "dev/raw/latest" env: - - DARTDOC_BOT=sdk-analyzer + #- DARTDOC_BOT=sdk-analyzer - DARTDOC_BOT=main - - DARTDOC_BOT=flutter - - DARTDOC_BOT=packages - - DARTDOC_BOT=sdk-docs + #- DARTDOC_BOT=flutter + #- DARTDOC_BOT=packages + #- DARTDOC_BOT=sdk-docs script: ./tool/travis.sh os: - - osx + #- osx - linux install: From 628f71813f7ba76e2102b9e46b4d1fffb3b7bff7 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 13 Dec 2018 09:25:17 -0800 Subject: [PATCH 14/14] use packages flag instead of package-root --- lib/src/io_utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index aa36b2c726..507bd0e612 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -161,7 +161,7 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { '--lcov', '-v', '-b', '.', - '--package-root=.', + '--packages=.packages', '--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}', '--out=${pathLib.canonicalize(outputFile.path)}', '--report-on=bin,lib',