Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
.settings/
build/
doc/
lcov.info
packages
pub.dartlang.org/
testing/test_package/doc
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
39 changes: 26 additions & 13 deletions bin/dartdoc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Future<List<DartdocOption>> 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<String> arguments) async {
Future<void> main(List<String> arguments) async {
DartdocOptionSet optionSet =
await DartdocOptionSet.fromOptionGenerators('dartdoc', [
createDartdocOptions,
Expand All @@ -52,17 +52,27 @@ void main(List<String> 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 =
Expand All @@ -88,34 +98,37 @@ void main(List<String> 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);
}
83 changes: 83 additions & 0 deletions lib/src/io_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -116,6 +117,88 @@ class MultiFutureTracker<T> {
Future<void> 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<String, String> 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<Tuple2<String, Future<Iterable<Map>>>> 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, 'dart-cov-0-${observatoryPort}.json');

/// Call once all coverage runs have been generated by calling runStreamed
/// on all [CoverageSubprocessLaunchers].
static Future<void> 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(Platform.executable, [
'tool/format_coverage.dart', // TODO(jcollins-g): use pub after dart-lang/coverage#240 is landed
'--lcov',
'-v',
'-b', '.',
'--packages=.packages',
'--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}',
'--out=${pathLib.canonicalize(outputFile.path)}',
'--report-on=bin,lib',
'-i', tempDir.path,
]);
}

@override
Future<Iterable<Map>> runStreamed(String executable, List<String> 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<Iterable<Map>> 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<String, String> environment;
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ dev_dependencies:
build: ^1.0.1
build_runner: ^1.0.0
build_version: ^1.0.0
coverage: any
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you intending to let this float?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

dhttpd: ^3.0.0
glob: ^1.1.5
grinder: ^0.8.2
Expand Down
Loading