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
diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart
index 830624b..930eba0 100644
--- a/bin/dartdoc.dart
+++ b/bin/dartdoc.dart
@@ -20,6 +20,7 @@
: super(optionSet, dir);
bool get asyncStackTraces => optionSet['asyncStackTraces'].valueAt(context);
+ bool get generateDocs => optionSet['generateDocs'].valueAt(context);
bool get help => optionSet['help'].valueAt(context);
bool get version => optionSet['version'].valueAt(context);
}
@@ -29,6 +30,10 @@
new DartdocOptionArgOnly<bool>('asyncStackTraces', false,
help: 'Display coordinated asynchronous stack traces (slow)',
negatable: true),
+ new DartdocOptionArgOnly<bool>('generateDocs', true,
+ help:
+ 'Generate docs into the output directory (or only display warnings if false).',
+ negatable: true),
new DartdocOptionArgOnly<bool>('help', false,
abbr: 'h', help: 'Show command help.', negatable: false),
new DartdocOptionArgOnly<bool>('version', false,
@@ -82,29 +87,23 @@
}
startLogging(config);
- Directory outputDir = new Directory(config.output);
- logInfo("Generating documentation for '${config.topLevelPackageMeta}' into "
- "${outputDir.absolute.path}${Platform.pathSeparator}");
-
- Dartdoc dartdoc = await Dartdoc.withDefaultGenerators(config);
-
+ Dartdoc dartdoc = config.generateDocs
+ ? await Dartdoc.withDefaultGenerators(config)
+ : await Dartdoc.withEmptyGenerator(config);
dartdoc.onCheckProgress.listen(logProgress);
try {
await Chain.capture(() async {
- await runZoned(() async {
- DartdocResults results = await dartdoc.generateDocs();
- logInfo('Success! Docs generated into ${results.outDir.absolute.path}');
- },
+ await runZoned(dartdoc.generateDocs,
zoneSpecification: new ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) =>
logPrint(line)));
}, onError: (e, Chain chain) {
if (e is DartdocFailure) {
- stderr.writeln('\nGeneration failed: ${e}.');
+ stderr.writeln('\ndartdoc failed: ${e}.');
exitCode = 1;
return;
} else {
- stderr.writeln('\nGeneration failed: ${e}\n${chain.terse}');
+ stderr.writeln('\ndartdoc failed: ${e}\n${chain.terse}');
exitCode = 255;
return;
}
diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart
index f2abfdf..b428213 100644
--- a/lib/dartdoc.dart
+++ b/lib/dartdoc.dart
@@ -68,6 +68,12 @@
return new Dartdoc._(config, generators);
}
+ /// An asynchronous factory method that builds
+ static Future<Dartdoc> withEmptyGenerator(DartdocOptionContext config) async {
+ List<Generator> generators = await initEmptyGenerators(config);
+ return new Dartdoc._(config, generators);
+ }
+
/// Basic synchronous factory that gives a stripped down Dartdoc that won't
/// use generators. Useful for testing.
factory Dartdoc.withoutGenerators(DartdocOptionContext config) {
@@ -101,7 +107,8 @@
await generator.generate(packageGraph, outputDir.path);
writtenFiles.addAll(generator.writtenFiles.map(pathLib.normalize));
}
- if (config.validateLinks) validateLinks(packageGraph, outputDir.path);
+ if (config.validateLinks && writtenFiles.isNotEmpty)
+ validateLinks(packageGraph, outputDir.path);
}
int warnings = packageGraph.packageWarningCounter.warningCount;
@@ -122,6 +129,8 @@
}
Future<DartdocResults> generateDocs() async {
+ logPrint("Documenting ${config.topLevelPackageMeta}...");
+
DartdocResults dartdocResults = await generateDocsBase();
if (dartdocResults.packageGraph.localPublicLibraries.isEmpty) {
throw new DartdocFailure(
@@ -134,7 +143,8 @@
throw new DartdocFailure(
"dartdoc encountered $errorCount} errors while processing.");
}
-
+ logInfo(
+ 'Success! Docs generated into ${dartdocResults.outDir.absolute.path}');
return dartdocResults;
}
diff --git a/lib/src/empty_generator.dart b/lib/src/empty_generator.dart
new file mode 100644
index 0000000..476dd67
--- /dev/null
+++ b/lib/src/empty_generator.dart
@@ -0,0 +1,41 @@
+library dartdoc.empty_generator;
+
+import 'dart:async';
+
+import 'package:dartdoc/src/generator.dart';
+import 'package:dartdoc/src/model.dart';
+import 'package:dartdoc/src/model_utils.dart';
+
+/// A generator that does not generate files, but does traverse the [PackageGraph]
+/// and access [ModelElement.documetationAsHtml] for every element as though
+/// it were.
+class EmptyGenerator extends Generator {
+ @override
+ Future generate(PackageGraph _packageGraph, String outputDirectoryPath) {
+ _onFileCreated.add(_packageGraph.defaultPackage.documentationAsHtml);
+ for (var package in Set.from([_packageGraph.defaultPackage])
+ ..addAll(_packageGraph.localPackages)) {
+ for (var category in filterNonDocumented(package.categories)) {
+ _onFileCreated.add(category.documentationAsHtml);
+ }
+
+ for (Library lib in filterNonDocumented(package.libraries)) {
+ filterNonDocumented(lib.allModelElements)
+ .forEach((m) => _onFileCreated.add(m.documentationAsHtml));
+ }
+ }
+ return null;
+ }
+
+ final StreamController<void> _onFileCreated =
+ new StreamController(sync: true);
+
+ @override
+
+ /// Implementation fires on each model element processed rather than
+ /// file creation.
+ Stream<void> get onFileCreated => _onFileCreated.stream;
+
+ @override
+ Set<String> get writtenFiles => new Set();
+}
diff --git a/lib/src/generator.dart b/lib/src/generator.dart
index 20dd037..bd35988 100644
--- a/lib/src/generator.dart
+++ b/lib/src/generator.dart
@@ -6,7 +6,6 @@
library dartdoc.generator;
import 'dart:async' show Stream, Future;
-import 'dart:io' show File;
import 'package:dartdoc/src/model.dart' show PackageGraph;
@@ -20,7 +19,7 @@
Future generate(PackageGraph packageGraph, String outputDirectoryPath);
/// Fires when a file is created.
- Stream<File> get onFileCreated;
+ Stream<void> get onFileCreated;
/// Fetches all filenames written by this generator.
Set<String> get writtenFiles;
diff --git a/lib/src/html/html_generator.dart b/lib/src/html/html_generator.dart
index f706060..aac3023 100644
--- a/lib/src/html/html_generator.dart
+++ b/lib/src/html/html_generator.dart
@@ -9,6 +9,7 @@
import 'dart:isolate';
import 'package:dartdoc/dartdoc.dart';
+import 'package:dartdoc/src/empty_generator.dart';
import 'package:dartdoc/src/generator.dart';
import 'package:dartdoc/src/html/html_generator_instance.dart';
import 'package:dartdoc/src/html/template_data.dart';
@@ -41,11 +42,11 @@
final HtmlGeneratorOptions _options;
HtmlGeneratorInstance _instance;
- final StreamController<File> _onFileCreated =
+ final StreamController<void> _onFileCreated =
new StreamController(sync: true);
@override
- Stream<File> get onFileCreated => _onFileCreated.stream;
+ Stream<void> get onFileCreated => _onFileCreated.stream;
@override
final Set<String> writtenFiles = new Set<String>();
@@ -131,6 +132,10 @@
: this.toolVersion = toolVersion ?? 'unknown';
}
+Future<List<Generator>> initEmptyGenerators(DartdocOptionContext config) async {
+ return [EmptyGenerator()];
+}
+
/// Initialize and setup the generators.
Future<List<Generator>> initGenerators(GeneratorContext config) async {
// TODO(jcollins-g): Rationalize based on GeneratorContext all the way down
diff --git a/lib/src/logging.dart b/lib/src/logging.dart
index c52b05f..ae67052 100644
--- a/lib/src/logging.dart
+++ b/lib/src/logging.dart
@@ -96,13 +96,15 @@
assert(message.isNotEmpty);
if (record.level < Level.WARNING) {
- if (config.showProgress && message.endsWith('...')) {
- // Assume there may be more progress to print, so omit the trailing
- // newline
- writingProgress = true;
- stdout.write(message);
- } else {
- print(message);
+ if (!config.quiet) {
+ if (config.showProgress && message.endsWith('...')) {
+ // Assume there may be more progress to print, so omit the trailing
+ // newline
+ writingProgress = true;
+ stdout.write(message);
+ } else {
+ print(message);
+ }
}
} else {
stderr.writeln(message);
@@ -114,6 +116,7 @@
abstract class LoggingContext implements DartdocOptionContextBase {
bool get json => optionSet['json'].valueAt(context);
bool get showProgress => optionSet['showProgress'].valueAt(context);
+ bool get quiet => optionSet['quiet'].valueAt(context);
}
Future<List<DartdocOption>> createLoggingOptions() async {
@@ -124,5 +127,15 @@
new DartdocOptionArgOnly<bool>('showProgress', false,
help: 'Display progress indications to console stdout',
negatable: false),
+ new DartdocOptionArgSynth<bool>('quiet',
+ (DartdocSyntheticOption option, Directory dir) {
+ if (option.root['generateDocs']?.valueAt(dir) == false) {
+ return true;
+ }
+ return false;
+ },
+ abbr: 'q',
+ negatable: true,
+ help: 'Only show warnings and errors; silence all other output.'),
];
}
diff --git a/lib/src/model.dart b/lib/src/model.dart
index 44c7199..9bfe5fe 100644
--- a/lib/src/model.dart
+++ b/lib/src/model.dart
@@ -3251,7 +3251,8 @@
/// Separate from _buildDocumentationLocal for overriding.
String _buildDocumentationBaseSync() {
- assert(_rawDocs == null, 'reentrant calls to _buildDocumentation* not allowed');
+ assert(_rawDocs == null,
+ 'reentrant calls to _buildDocumentation* not allowed');
// Do not use the sync method if we need to evaluate tools or templates.
assert(!isCanonical ||
!needsPrecacheRegExp.hasMatch(documentationComment ?? ''));
@@ -3271,7 +3272,8 @@
/// Separate from _buildDocumentationLocal for overriding. Can only be
/// used as part of [PackageGraph.setUpPackageGraph].
Future<String> _buildDocumentationBase() async {
- assert(_rawDocs == null, 'reentrant calls to _buildDocumentation* not allowed');
+ assert(_rawDocs == null,
+ 'reentrant calls to _buildDocumentation* not allowed');
// Do not use the sync method if we need to evaluate tools or templates.
if (config.dropTextFrom.contains(element.library.name)) {
_rawDocs = '';
diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart
index f9282ec..70b7cd1 100644
--- a/test/dartdoc_test.dart
+++ b/test/dartdoc_test.dart
@@ -131,6 +131,36 @@
await Future.wait(CoverageSubprocessLauncher.coverageResults);
});
+ test('running --no-generate-docs is quiet and does not generate docs',
+ () async {
+ Directory outputDir =
+ await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
+ List<String> outputLines = [];
+ await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
+ [dartdocPath, '--output', outputDir.path, '--no-generate-docs'],
+ perLine: outputLines.add, workingDirectory: _testPackagePath);
+ expect(outputLines, isNot(contains(matches('^parsing'))));
+ expect(outputLines, contains(matches('^ warning:')));
+ expect(
+ outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
+ expect(outputDir.listSync(), isEmpty);
+ });
+
+ test('running --quiet is quiet and does generate docs',
+ () async {
+ Directory outputDir =
+ await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
+ List<String> outputLines = [];
+ await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
+ [dartdocPath, '--output', outputDir.path, '--quiet'],
+ perLine: outputLines.add, workingDirectory: _testPackagePath);
+ expect(outputLines, isNot(contains(matches('^parsing'))));
+ expect(outputLines, contains(matches('^ warning:')));
+ expect(
+ outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
+ expect(outputDir.listSync(), isNotEmpty);
+ });
+
test('invalid parameters return non-zero and print a fatal-error',
() async {
List outputLines = [];
diff --git a/test/model_test.dart b/test/model_test.dart
index c7452b9..ff7ea0f 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -676,7 +676,8 @@
});
test('can be reexported even if the file suffix is not .dart', () {
- expect(fakeLibrary.allClasses.map((c) => c.name), contains('MyClassFromADartFile'));
+ expect(fakeLibrary.allClasses.map((c) => c.name),
+ contains('MyClassFromADartFile'));
});
test('that is deprecated has a deprecated css class in linkedName', () {
diff --git a/test/src/utils.dart b/test/src/utils.dart
index 637bccc..acfcad0 100644
--- a/test/src/utils.dart
+++ b/test/src/utils.dart
@@ -160,12 +160,14 @@
'coverage:format_coverage',
'--lcov',
'-v',
- '-b', '.',
+ '-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,
+ '-i',
+ tempDir.path,
]);
}
diff --git a/tool/travis.sh b/tool/travis.sh
index f3d2a03..3b96e36 100755
--- a/tool/travis.sh
+++ b/tool/travis.sh
@@ -34,7 +34,7 @@
fi
PACKAGE_NAME=access PACKAGE_VERSION=">=1.0.1+2" pub run grinder build-pub-package
# Negative test for flutter_plugin_tools, make sure right error message is displayed.
- 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.$"
+ 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.$"
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"