| // Copyright (c) 2020, 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:convert' show jsonDecode, jsonEncode; | |
| import 'dart:io' show Directory, File, Platform, Process, exitCode; | |
| import 'package:args/args.dart' show ArgParser; | |
| import 'package:path/path.dart' show absolute; | |
| import 'package:yaml/yaml.dart' show loadYaml; | |
| const _dartdocDir = 'dartdoc-dir'; | |
| const _markdownBefore = 'before'; | |
| const _markdownAfter = 'after'; | |
| const _sdk = 'sdk'; | |
| const _help = 'help'; | |
| void main(List<String> arguments) { | |
| final parser = ArgParser() | |
| ..addSeparator('Usage: dartdoc-compare.dart [OPTIONS] <dart-package>') | |
| ..addOption(_dartdocDir, help: 'Directory of the dartdoc package') | |
| ..addOption(_markdownBefore, help: "Markdown package 'before' ref") | |
| ..addOption( | |
| _markdownAfter, | |
| defaultsTo: 'HEAD', | |
| help: "Markdown package 'after' ref (or 'local')", | |
| ) | |
| ..addFlag(_sdk, negatable: false, help: 'Is the package the SDK?') | |
| ..addFlag(_help, abbr: 'h', hide: true); | |
| final options = parser.parse(arguments); | |
| if (options[_help] as bool) { | |
| print(parser.usage); | |
| exitCode = 0; | |
| return; | |
| } | |
| if (options[_dartdocDir] == null || options[_markdownBefore] == null) { | |
| print( | |
| 'Invalid arguments: Options --$_dartdocDir and --$_markdownBefore ' | |
| 'must be specified', | |
| ); | |
| print(parser.usage); | |
| exitCode = 1; | |
| return; | |
| } | |
| final comparer = DartdocCompare( | |
| options[_dartdocDir] as String, | |
| options[_markdownBefore] as String, | |
| options[_markdownAfter] as String, | |
| absolute(options[_dartdocDir] as String, 'bin/dartdoc.dart'), | |
| absolute(options[_dartdocDir] as String, 'pubspec.yaml'), | |
| options[_sdk] as bool, | |
| ); | |
| String? path; | |
| if (comparer.sdk) { | |
| if (options.rest.isNotEmpty) { | |
| path = options.rest.single; | |
| } | |
| } else { | |
| path = options.rest.single; | |
| } | |
| if (comparer.compare(path)) { | |
| exitCode = 0; | |
| } else { | |
| exitCode = 1; | |
| } | |
| } | |
| class DartdocCompare { | |
| final String dartdocDir; | |
| final String markdownBefore; | |
| final String markdownAfter; | |
| final String dartdocBin; | |
| final String dartdocPubspecPath; | |
| final bool sdk; | |
| final String markdownPath = File(Platform.script.path).parent.parent.path; | |
| DartdocCompare( | |
| this.dartdocDir, | |
| this.markdownBefore, | |
| this.markdownAfter, | |
| this.dartdocBin, | |
| this.dartdocPubspecPath, | |
| this.sdk, | |
| ); | |
| bool compare(String? package) { | |
| // Generate docs with Markdown "Before". | |
| final outBefore = _runDartdoc(markdownBefore, package); | |
| // Generate docs with Markdown "After". | |
| final outAfter = _runDartdoc(markdownAfter, package); | |
| // Compare outputs | |
| final diffOptions = ['-r', '-B', outBefore, outAfter]; | |
| final result = Process.runSync('diff', diffOptions, runInShell: true); | |
| final nlines = '\n'.allMatches(result.stdout as String).length; | |
| print('Diff lines: $nlines'); | |
| print('diff ${diffOptions.join(" ")}'); | |
| return result.exitCode == 0; | |
| } | |
| String _runDartdoc(String markdownRef, String? path) { | |
| print('=========================================================='); | |
| print('Running dartdoc for $markdownRef...'); | |
| print('=========================================================='); | |
| _doInPath(dartdocDir, () { | |
| final returnCode = _updateDartdocPubspec(markdownRef); | |
| if (returnCode != 0) { | |
| throw Exception("Could not update dartdoc's pubspec!"); | |
| } | |
| }); | |
| return _doInPath(path, () { | |
| if (!sdk) { | |
| _system('pub', ['upgrade']); | |
| } | |
| final out = Directory.systemTemp.createTempSync( | |
| 'dartdoc-compare-${markdownRef}__', | |
| ); | |
| const cmd = 'dart'; | |
| final args = [dartdocBin, '--output=${out.path}']; | |
| if (sdk) { | |
| args.add('--sdk-docs'); | |
| } | |
| print('Command: $cmd ${args.join(' ')}'); | |
| final startTime = DateTime.now(); | |
| _system(cmd, args); | |
| final endTime = DateTime.now(); | |
| final duration = endTime.difference(startTime).inSeconds; | |
| print('dartdoc generation for $markdownRef took $duration seconds.'); | |
| print(''); | |
| return out.path; | |
| }); | |
| } | |
| int _updateDartdocPubspec(String markdownRef) { | |
| var dartdocPubspec = | |
| loadYaml(File(dartdocPubspecPath).readAsStringSync()) as Map; | |
| // make modifiable copy | |
| dartdocPubspec = jsonDecode(jsonEncode(dartdocPubspec)) as Map; | |
| final dependencies = dartdocPubspec['dependencies'] as Map; | |
| if (markdownRef == 'local') { | |
| dependencies['markdown'] = {'path': markdownPath}; | |
| } else { | |
| dependencies['markdown'] = { | |
| 'git': { | |
| 'url': 'git://github.com/dart-lang/markdown.git', | |
| 'ref': markdownRef, | |
| }, | |
| }; | |
| } | |
| File(dartdocPubspecPath).writeAsStringSync(jsonEncode(dartdocPubspec)); | |
| return _system('pub', ['upgrade']); | |
| } | |
| } | |
| int _system(String cmd, List<String> args) { | |
| final result = Process.runSync(cmd, args); | |
| print(result.stdout); | |
| print(result.stderr); | |
| return result.exitCode; | |
| } | |
| T _doInPath<T>(String? path, T Function() f) { | |
| if (path == null) { | |
| return f(); | |
| } | |
| final former = Directory.current.path; | |
| Directory.current = path; | |
| try { | |
| return f(); | |
| } finally { | |
| Directory.current = former; | |
| } | |
| } |