Skip to content

Commit 6ec18b5

Browse files
authored
add a --no-generate-docs flag that is faster and only displays warnings (#1909)
* basic non-documenting mode works * Basically works now, needs tests * Add a test * dartfmt * Cleanup * Add test for doc generation presence/absence with --quiet * Fix packages output parsing problem
1 parent 737755a commit 6ec18b5

11 files changed

+133
-31
lines changed

bin/dartdoc.dart

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class DartdocProgramOptionContext extends DartdocGeneratorOptionContext
2020
: super(optionSet, dir);
2121

2222
bool get asyncStackTraces => optionSet['asyncStackTraces'].valueAt(context);
23+
bool get generateDocs => optionSet['generateDocs'].valueAt(context);
2324
bool get help => optionSet['help'].valueAt(context);
2425
bool get version => optionSet['version'].valueAt(context);
2526
}
@@ -29,6 +30,10 @@ Future<List<DartdocOption>> createDartdocProgramOptions() async {
2930
new DartdocOptionArgOnly<bool>('asyncStackTraces', false,
3031
help: 'Display coordinated asynchronous stack traces (slow)',
3132
negatable: true),
33+
new DartdocOptionArgOnly<bool>('generateDocs', true,
34+
help:
35+
'Generate docs into the output directory (or only display warnings if false).',
36+
negatable: true),
3237
new DartdocOptionArgOnly<bool>('help', false,
3338
abbr: 'h', help: 'Show command help.', negatable: false),
3439
new DartdocOptionArgOnly<bool>('version', false,
@@ -82,29 +87,23 @@ Future<void> main(List<String> arguments) async {
8287
}
8388
startLogging(config);
8489

85-
Directory outputDir = new Directory(config.output);
86-
logInfo("Generating documentation for '${config.topLevelPackageMeta}' into "
87-
"${outputDir.absolute.path}${Platform.pathSeparator}");
88-
89-
Dartdoc dartdoc = await Dartdoc.withDefaultGenerators(config);
90-
90+
Dartdoc dartdoc = config.generateDocs
91+
? await Dartdoc.withDefaultGenerators(config)
92+
: await Dartdoc.withEmptyGenerator(config);
9193
dartdoc.onCheckProgress.listen(logProgress);
9294
try {
9395
await Chain.capture(() async {
94-
await runZoned(() async {
95-
DartdocResults results = await dartdoc.generateDocs();
96-
logInfo('Success! Docs generated into ${results.outDir.absolute.path}');
97-
},
96+
await runZoned(dartdoc.generateDocs,
9897
zoneSpecification: new ZoneSpecification(
9998
print: (Zone self, ZoneDelegate parent, Zone zone, String line) =>
10099
logPrint(line)));
101100
}, onError: (e, Chain chain) {
102101
if (e is DartdocFailure) {
103-
stderr.writeln('\nGeneration failed: ${e}.');
102+
stderr.writeln('\ndartdoc failed: ${e}.');
104103
exitCode = 1;
105104
return;
106105
} else {
107-
stderr.writeln('\nGeneration failed: ${e}\n${chain.terse}');
106+
stderr.writeln('\ndartdoc failed: ${e}\n${chain.terse}');
108107
exitCode = 255;
109108
return;
110109
}

lib/dartdoc.dart

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ class Dartdoc extends PackageBuilder {
6868
return new Dartdoc._(config, generators);
6969
}
7070

71+
/// An asynchronous factory method that builds
72+
static Future<Dartdoc> withEmptyGenerator(DartdocOptionContext config) async {
73+
List<Generator> generators = await initEmptyGenerators(config);
74+
return new Dartdoc._(config, generators);
75+
}
76+
7177
/// Basic synchronous factory that gives a stripped down Dartdoc that won't
7278
/// use generators. Useful for testing.
7379
factory Dartdoc.withoutGenerators(DartdocOptionContext config) {
@@ -101,7 +107,8 @@ class Dartdoc extends PackageBuilder {
101107
await generator.generate(packageGraph, outputDir.path);
102108
writtenFiles.addAll(generator.writtenFiles.map(pathLib.normalize));
103109
}
104-
if (config.validateLinks) validateLinks(packageGraph, outputDir.path);
110+
if (config.validateLinks && writtenFiles.isNotEmpty)
111+
validateLinks(packageGraph, outputDir.path);
105112
}
106113

107114
int warnings = packageGraph.packageWarningCounter.warningCount;
@@ -122,6 +129,8 @@ class Dartdoc extends PackageBuilder {
122129
}
123130

124131
Future<DartdocResults> generateDocs() async {
132+
logPrint("Documenting ${config.topLevelPackageMeta}...");
133+
125134
DartdocResults dartdocResults = await generateDocsBase();
126135
if (dartdocResults.packageGraph.localPublicLibraries.isEmpty) {
127136
throw new DartdocFailure(
@@ -134,7 +143,8 @@ class Dartdoc extends PackageBuilder {
134143
throw new DartdocFailure(
135144
"dartdoc encountered $errorCount} errors while processing.");
136145
}
137-
146+
logInfo(
147+
'Success! Docs generated into ${dartdocResults.outDir.absolute.path}');
138148
return dartdocResults;
139149
}
140150

lib/src/empty_generator.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
library dartdoc.empty_generator;
2+
3+
import 'dart:async';
4+
5+
import 'package:dartdoc/src/generator.dart';
6+
import 'package:dartdoc/src/model.dart';
7+
import 'package:dartdoc/src/model_utils.dart';
8+
9+
/// A generator that does not generate files, but does traverse the [PackageGraph]
10+
/// and access [ModelElement.documetationAsHtml] for every element as though
11+
/// it were.
12+
class EmptyGenerator extends Generator {
13+
@override
14+
Future generate(PackageGraph _packageGraph, String outputDirectoryPath) {
15+
_onFileCreated.add(_packageGraph.defaultPackage.documentationAsHtml);
16+
for (var package in Set.from([_packageGraph.defaultPackage])
17+
..addAll(_packageGraph.localPackages)) {
18+
for (var category in filterNonDocumented(package.categories)) {
19+
_onFileCreated.add(category.documentationAsHtml);
20+
}
21+
22+
for (Library lib in filterNonDocumented(package.libraries)) {
23+
filterNonDocumented(lib.allModelElements)
24+
.forEach((m) => _onFileCreated.add(m.documentationAsHtml));
25+
}
26+
}
27+
return null;
28+
}
29+
30+
final StreamController<void> _onFileCreated =
31+
new StreamController(sync: true);
32+
33+
@override
34+
35+
/// Implementation fires on each model element processed rather than
36+
/// file creation.
37+
Stream<void> get onFileCreated => _onFileCreated.stream;
38+
39+
@override
40+
Set<String> get writtenFiles => new Set();
41+
}

lib/src/generator.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
library dartdoc.generator;
77

88
import 'dart:async' show Stream, Future;
9-
import 'dart:io' show File;
109

1110
import 'package:dartdoc/src/model.dart' show PackageGraph;
1211

@@ -20,7 +19,7 @@ abstract class Generator {
2019
Future generate(PackageGraph packageGraph, String outputDirectoryPath);
2120

2221
/// Fires when a file is created.
23-
Stream<File> get onFileCreated;
22+
Stream<void> get onFileCreated;
2423

2524
/// Fetches all filenames written by this generator.
2625
Set<String> get writtenFiles;

lib/src/html/html_generator.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:io' show Directory, File;
99
import 'dart:isolate';
1010

1111
import 'package:dartdoc/dartdoc.dart';
12+
import 'package:dartdoc/src/empty_generator.dart';
1213
import 'package:dartdoc/src/generator.dart';
1314
import 'package:dartdoc/src/html/html_generator_instance.dart';
1415
import 'package:dartdoc/src/html/template_data.dart';
@@ -41,11 +42,11 @@ class HtmlGenerator extends Generator {
4142
final HtmlGeneratorOptions _options;
4243
HtmlGeneratorInstance _instance;
4344

44-
final StreamController<File> _onFileCreated =
45+
final StreamController<void> _onFileCreated =
4546
new StreamController(sync: true);
4647

4748
@override
48-
Stream<File> get onFileCreated => _onFileCreated.stream;
49+
Stream<void> get onFileCreated => _onFileCreated.stream;
4950

5051
@override
5152
final Set<String> writtenFiles = new Set<String>();
@@ -131,6 +132,10 @@ class HtmlGeneratorOptions implements HtmlOptions {
131132
: this.toolVersion = toolVersion ?? 'unknown';
132133
}
133134

135+
Future<List<Generator>> initEmptyGenerators(DartdocOptionContext config) async {
136+
return [EmptyGenerator()];
137+
}
138+
134139
/// Initialize and setup the generators.
135140
Future<List<Generator>> initGenerators(GeneratorContext config) async {
136141
// TODO(jcollins-g): Rationalize based on GeneratorContext all the way down

lib/src/logging.dart

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,15 @@ void startLogging(LoggingContext config) {
9696
assert(message.isNotEmpty);
9797

9898
if (record.level < Level.WARNING) {
99-
if (config.showProgress && message.endsWith('...')) {
100-
// Assume there may be more progress to print, so omit the trailing
101-
// newline
102-
writingProgress = true;
103-
stdout.write(message);
104-
} else {
105-
print(message);
99+
if (!config.quiet) {
100+
if (config.showProgress && message.endsWith('...')) {
101+
// Assume there may be more progress to print, so omit the trailing
102+
// newline
103+
writingProgress = true;
104+
stdout.write(message);
105+
} else {
106+
print(message);
107+
}
106108
}
107109
} else {
108110
stderr.writeln(message);
@@ -114,6 +116,7 @@ void startLogging(LoggingContext config) {
114116
abstract class LoggingContext implements DartdocOptionContextBase {
115117
bool get json => optionSet['json'].valueAt(context);
116118
bool get showProgress => optionSet['showProgress'].valueAt(context);
119+
bool get quiet => optionSet['quiet'].valueAt(context);
117120
}
118121

119122
Future<List<DartdocOption>> createLoggingOptions() async {
@@ -124,5 +127,15 @@ Future<List<DartdocOption>> createLoggingOptions() async {
124127
new DartdocOptionArgOnly<bool>('showProgress', false,
125128
help: 'Display progress indications to console stdout',
126129
negatable: false),
130+
new DartdocOptionArgSynth<bool>('quiet',
131+
(DartdocSyntheticOption option, Directory dir) {
132+
if (option.root['generateDocs']?.valueAt(dir) == false) {
133+
return true;
134+
}
135+
return false;
136+
},
137+
abbr: 'q',
138+
negatable: true,
139+
help: 'Only show warnings and errors; silence all other output.'),
127140
];
128141
}

lib/src/model.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3251,7 +3251,8 @@ abstract class ModelElement extends Canonicalization
32513251

32523252
/// Separate from _buildDocumentationLocal for overriding.
32533253
String _buildDocumentationBaseSync() {
3254-
assert(_rawDocs == null, 'reentrant calls to _buildDocumentation* not allowed');
3254+
assert(_rawDocs == null,
3255+
'reentrant calls to _buildDocumentation* not allowed');
32553256
// Do not use the sync method if we need to evaluate tools or templates.
32563257
assert(!isCanonical ||
32573258
!needsPrecacheRegExp.hasMatch(documentationComment ?? ''));
@@ -3271,7 +3272,8 @@ abstract class ModelElement extends Canonicalization
32713272
/// Separate from _buildDocumentationLocal for overriding. Can only be
32723273
/// used as part of [PackageGraph.setUpPackageGraph].
32733274
Future<String> _buildDocumentationBase() async {
3274-
assert(_rawDocs == null, 'reentrant calls to _buildDocumentation* not allowed');
3275+
assert(_rawDocs == null,
3276+
'reentrant calls to _buildDocumentation* not allowed');
32753277
// Do not use the sync method if we need to evaluate tools or templates.
32763278
if (config.dropTextFrom.contains(element.library.name)) {
32773279
_rawDocs = '';

test/dartdoc_test.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,36 @@ void main() {
131131
await Future.wait(CoverageSubprocessLauncher.coverageResults);
132132
});
133133

134+
test('running --no-generate-docs is quiet and does not generate docs',
135+
() async {
136+
Directory outputDir =
137+
await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
138+
List<String> outputLines = [];
139+
await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
140+
[dartdocPath, '--output', outputDir.path, '--no-generate-docs'],
141+
perLine: outputLines.add, workingDirectory: _testPackagePath);
142+
expect(outputLines, isNot(contains(matches('^parsing'))));
143+
expect(outputLines, contains(matches('^ warning:')));
144+
expect(
145+
outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
146+
expect(outputDir.listSync(), isEmpty);
147+
});
148+
149+
test('running --quiet is quiet and does generate docs',
150+
() async {
151+
Directory outputDir =
152+
await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
153+
List<String> outputLines = [];
154+
await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
155+
[dartdocPath, '--output', outputDir.path, '--quiet'],
156+
perLine: outputLines.add, workingDirectory: _testPackagePath);
157+
expect(outputLines, isNot(contains(matches('^parsing'))));
158+
expect(outputLines, contains(matches('^ warning:')));
159+
expect(
160+
outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
161+
expect(outputDir.listSync(), isNotEmpty);
162+
});
163+
134164
test('invalid parameters return non-zero and print a fatal-error',
135165
() async {
136166
List outputLines = [];

test/model_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,8 @@ void main() {
676676
});
677677

678678
test('can be reexported even if the file suffix is not .dart', () {
679-
expect(fakeLibrary.allClasses.map((c) => c.name), contains('MyClassFromADartFile'));
679+
expect(fakeLibrary.allClasses.map((c) => c.name),
680+
contains('MyClassFromADartFile'));
680681
});
681682

682683
test('that is deprecated has a deprecated css class in linkedName', () {

test/src/utils.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,14 @@ class CoverageSubprocessLauncher extends SubprocessLauncher {
160160
'coverage:format_coverage',
161161
'--lcov',
162162
'-v',
163-
'-b', '.',
163+
'-b',
164+
'.',
164165
'--packages=.packages',
165166
'--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}',
166167
'--out=${pathLib.canonicalize(outputFile.path)}',
167168
'--report-on=bin,lib',
168-
'-i', tempDir.path,
169+
'-i',
170+
tempDir.path,
169171
]);
170172
}
171173

tool/travis.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ elif [ "$DARTDOC_BOT" = "packages" ]; then
3434
fi
3535
PACKAGE_NAME=access PACKAGE_VERSION=">=1.0.1+2" pub run grinder build-pub-package
3636
# Negative test for flutter_plugin_tools, make sure right error message is displayed.
37-
PACKAGE_NAME=flutter_plugin_tools PACKAGE_VERSION=">=0.0.14+1" pub run grinder build-pub-package 2>&1 | grep "Generation failed: dartdoc could not find any libraries to document.$"
37+
PACKAGE_NAME=flutter_plugin_tools PACKAGE_VERSION=">=0.0.14+1" pub run grinder build-pub-package 2>&1 | grep "dartdoc failed: dartdoc could not find any libraries to document.$"
3838
PACKAGE_NAME=shelf_exception_handler PACKAGE_VERSION=">=0.2.0" pub run grinder build-pub-package
3939
elif [ "$DARTDOC_BOT" = "sdk-analyzer" ]; then
4040
echo "Running main dartdoc bot against the SDK analyzer"

0 commit comments

Comments
 (0)