diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index eaa0b4a284..f73248a22a 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -17,7 +17,7 @@ Future main(List arguments) async { // There was an error while parsing options. return; } - final packageBuilder = PubPackageBuilder(config); + final packageBuilder = PubPackageBuilder(config, pubPackageMetaProvider); final dartdoc = config.generateDocs ? await Dartdoc.fromContext(config, packageBuilder) : await Dartdoc.withEmptyGenerator(config, packageBuilder); diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 1b513e3500..016304fedb 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -10,8 +10,9 @@ library dartdoc; import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show exitCode, stderr; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/generator/empty_generator.dart'; import 'package:dartdoc/src/generator/generator.dart'; @@ -41,17 +42,19 @@ const String dartdocVersion = packageVersion; /// Helper class that consolidates option contexts for instantiating generators. class DartdocGeneratorOptionContext extends DartdocOptionContext with GeneratorContext { - DartdocGeneratorOptionContext(DartdocOptionSet optionSet, Directory dir) - : super(optionSet, dir); + DartdocGeneratorOptionContext( + DartdocOptionSet optionSet, Folder dir, ResourceProvider resourceProvider) + : super(optionSet, dir, resourceProvider); } class DartdocFileWriter implements FileWriter { final String outputDir; + ResourceProvider resourceProvider; final Map _fileElementMap = {}; @override final Set writtenFiles = {}; - DartdocFileWriter(this.outputDir); + DartdocFileWriter(this.outputDir, this.resourceProvider); @override void write(String filePath, Object content, @@ -73,10 +76,11 @@ class DartdocFileWriter implements FileWriter { } _fileElementMap[outFile] = element; - var file = File(path.join(outputDir, outFile)); + var file = resourceProvider + .getFile(resourceProvider.pathContext.join(outputDir, outFile)); var parent = file.parent; - if (!parent.existsSync()) { - parent.createSync(recursive: true); + if (!parent.exists) { + parent.create(); } if (content is String) { @@ -100,14 +104,16 @@ class Dartdoc { final PackageBuilder packageBuilder; final DartdocOptionContext config; final Set writtenFiles = {}; - Directory outputDir; + Folder outputDir; // Fires when the self checks make progress. final StreamController _onCheckProgress = StreamController(sync: true); Dartdoc._(this.config, this.generator, this.packageBuilder) { - outputDir = Directory(config.output)..createSync(recursive: true); + outputDir = config.resourceProvider + .getFolder(config.resourceProvider.pathContext.absolute(config.output)) + ..create(); } /// An asynchronous factory method that builds Dartdoc's file writers @@ -182,9 +188,9 @@ class Dartdoc { final generator = this.generator; if (generator != null) { // Create the out directory. - if (!outputDir.existsSync()) outputDir.createSync(recursive: true); + if (!outputDir.exists) outputDir.create(); - var writer = DartdocFileWriter(outputDir.path); + var writer = DartdocFileWriter(outputDir.path, config.resourceProvider); await generator.generate(packageGraph, writer); writtenFiles.addAll(writer.writtenFiles); @@ -225,15 +231,16 @@ class Dartdoc { throw DartdocFailure( 'dartdoc encountered $errorCount errors while processing.'); } - logInfo( - 'Success! Docs generated into ${dartdocResults.outDir.absolute.path}'); + var outDirPath = config.resourceProvider.pathContext + .absolute(dartdocResults.outDir.path); + logInfo('Success! Docs generated into $outDirPath'); return dartdocResults; } finally { // Clear out any cached tool snapshots and temporary directories. // ignore: unawaited_futures - SnapshotCache.instance.dispose(); + SnapshotCache.instance?.dispose(); // ignore: unawaited_futures - ToolTempFileTracker.instance.dispose(); + ToolTempFileTracker.instance?.dispose(); } } @@ -289,35 +296,43 @@ class Dartdoc { var staticAssets = path.joinAll([normalOrigin, 'static-assets', '']); var indexJson = path.joinAll([normalOrigin, 'index.json']); var foundIndexJson = false; - for (var f in Directory(normalOrigin).listSync(recursive: true)) { - if (f is Directory) { - continue; - } - var fullPath = path.normalize(f.path); - if (fullPath.startsWith(staticAssets)) { - continue; - } - if (fullPath == indexJson) { - foundIndexJson = true; - _onCheckProgress.add(fullPath); - continue; - } - if (visited.contains(fullPath)) continue; - var relativeFullPath = path.relative(fullPath, from: normalOrigin); - if (!writtenFiles.contains(relativeFullPath)) { - // This isn't a file we wrote (this time); don't claim we did. - _warn(packageGraph, PackageWarning.unknownFile, fullPath, normalOrigin); - } else { - // Error messages are orphaned by design and do not appear in the search - // index. - if (['__404error.html', 'categories.json'].contains(fullPath)) { - _warn(packageGraph, PackageWarning.orphanedFile, fullPath, - normalOrigin); + + void checkDirectory(Folder dir) { + for (var f in dir.getChildren()) { + if (f is Folder) { + checkDirectory(f); + continue; + } + var fullPath = path.normalize(f.path); + if (fullPath.startsWith(staticAssets)) { + continue; } + if (path.equals(fullPath, indexJson)) { + foundIndexJson = true; + _onCheckProgress.add(fullPath); + continue; + } + if (visited.contains(fullPath)) continue; + var relativeFullPath = path.relative(fullPath, from: normalOrigin); + if (!writtenFiles.contains(relativeFullPath)) { + // This isn't a file we wrote (this time); don't claim we did. + _warn( + packageGraph, PackageWarning.unknownFile, fullPath, normalOrigin); + } else { + // Error messages are orphaned by design and do not appear in the search + // index. + if (['__404error.html', 'categories.json'] + .contains(fullPath)) { + _warn(packageGraph, PackageWarning.orphanedFile, fullPath, + normalOrigin); + } + } + _onCheckProgress.add(fullPath); } - _onCheckProgress.add(fullPath); } + checkDirectory(config.resourceProvider.getFolder(normalOrigin)); + if (!foundIndexJson) { _warn(packageGraph, PackageWarning.brokenLink, indexJson, normalOrigin); _onCheckProgress.add(indexJson); @@ -327,8 +342,8 @@ class Dartdoc { // This is extracted to save memory during the check; be careful not to hang // on to anything referencing the full file and doc tree. Tuple2, String> _getStringLinksAndHref(String fullPath) { - var file = File('$fullPath'); - if (!file.existsSync()) { + var file = config.resourceProvider.getFile('$fullPath'); + if (!file.exists) { return null; } // TODO(srawlins): It is possible that instantiating an HtmlParser using @@ -353,8 +368,8 @@ class Dartdoc { PackageGraph packageGraph, String origin, Set visited) { var fullPath = path.joinAll([origin, 'index.json']); var indexPath = path.joinAll([origin, 'index.html']); - var file = File('$fullPath'); - if (!file.existsSync()) { + var file = config.resourceProvider.getFile('$fullPath'); + if (!file.exists) { return null; } var decoder = JsonDecoder(); @@ -519,7 +534,7 @@ class DartdocFailure { class DartdocResults { final PackageMeta packageMeta; final PackageGraph packageGraph; - final Directory outDir; + final Folder outDir; DartdocResults(this.packageMeta, this.packageGraph, this.outDir); } diff --git a/lib/options.dart b/lib/options.dart index 8c833276c0..50686f214a 100644 --- a/lib/options.dart +++ b/lib/options.dart @@ -1,29 +1,34 @@ import 'dart:async'; -import 'dart:io'; +import 'dart:io' show stderr, exitCode; +import 'package:analyzer/file_system/file_system.dart'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/logging.dart'; class DartdocProgramOptionContext extends DartdocGeneratorOptionContext with LoggingContext { - DartdocProgramOptionContext(DartdocOptionSet optionSet, Directory dir) - : super(optionSet, dir); + DartdocProgramOptionContext( + DartdocOptionSet optionSet, Folder dir, ResourceProvider resourceProvider) + : super(optionSet, dir, resourceProvider); bool get generateDocs => optionSet['generateDocs'].valueAt(context); bool get help => optionSet['help'].valueAt(context); bool get version => optionSet['version'].valueAt(context); } -Future>> createDartdocProgramOptions() async { +Future>> createDartdocProgramOptions( + PackageMetaProvider packageMetaProvider) async { + var resourceProvider = packageMetaProvider.resourceProvider; return [ - DartdocOptionArgOnly('generateDocs', true, + DartdocOptionArgOnly('generateDocs', true, resourceProvider, help: - 'Generate docs into the output directory (or only display warnings if false).', + 'Generate docs into the output directory (or only display warnings ' + 'if false).', negatable: true), - DartdocOptionArgOnly('help', false, + DartdocOptionArgOnly('help', false, resourceProvider, abbr: 'h', help: 'Show command help.', negatable: false), - DartdocOptionArgOnly('version', false, + DartdocOptionArgOnly('version', false, resourceProvider, help: 'Display the version for $programName.', negatable: false), ]; } @@ -33,13 +38,16 @@ Future parseOptions( List arguments, { OptionGenerator additionalOptions, }) async { - var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ - () => createDartdocOptions(packageMetaProvider), - createDartdocProgramOptions, - createLoggingOptions, - createGeneratorOptions, - if (additionalOptions != null) additionalOptions, - ]); + var optionSet = await DartdocOptionSet.fromOptionGenerators( + 'dartdoc', + [ + createDartdocOptions, + createDartdocProgramOptions, + createLoggingOptions, + createGeneratorOptions, + if (additionalOptions != null) additionalOptions, + ], + packageMetaProvider); try { optionSet.parseArguments(arguments); @@ -51,12 +59,12 @@ Future parseOptions( exitCode = 64; return null; } - if (optionSet['help'].valueAt(Directory.current)) { + if (optionSet['help'].valueAtCurrent()) { _printHelp(optionSet.argParser); exitCode = 0; return null; } - if (optionSet['version'].valueAt(Directory.current)) { + if (optionSet['version'].valueAtCurrent()) { _printVersion(optionSet.argParser); exitCode = 0; return null; @@ -64,7 +72,8 @@ Future parseOptions( DartdocProgramOptionContext config; try { - config = DartdocProgramOptionContext(optionSet, null); + config = DartdocProgramOptionContext( + optionSet, null, packageMetaProvider.resourceProvider); } on DartdocOptionError catch (e) { stderr.writeln(' fatal error: ${e.message}'); stderr.writeln(''); diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 523f3b68ee..a2e07cc8fd 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -15,9 +15,10 @@ library dartdoc.dartdoc_options; import 'dart:async'; -import 'dart:io'; +import 'dart:io' show Platform; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/experiment_options.dart'; @@ -26,7 +27,7 @@ import 'package:dartdoc/src/source_linker.dart'; import 'package:dartdoc/src/tool_runner.dart'; import 'package:dartdoc/src/tuple.dart'; import 'package:dartdoc/src/warnings.dart'; -import 'package:path/path.dart' as p; +import 'package:path/path.dart' as p show Context, canonicalize, extension; import 'package:yaml/yaml.dart'; /// Constants to help with type checking, because T is int and so forth @@ -38,10 +39,7 @@ const int _kIntVal = 0; const double _kDoubleVal = 0.0; const bool _kBoolVal = true; -/// Args are computed relative to the current directory at the time the -/// program starts. -final Directory directoryCurrent = Directory.current; -final String directoryCurrentPath = p.canonicalize(Directory.current.path); +typedef ConvertYamlToType = T Function(YamlMap, String, ResourceProvider); class DartdocOptionError extends DartdocFailure { DartdocOptionError(String details) : super(details); @@ -83,8 +81,8 @@ class CategoryConfiguration { return CategoryConfiguration._({}); } - static CategoryConfiguration fromYamlMap( - YamlMap yamlMap, p.Context pathContext) { + static CategoryConfiguration fromYamlMap(YamlMap yamlMap, + String canonicalYamlPath, ResourceProvider resourceProvider) { var newCategoryDefinitions = {}; for (var entry in yamlMap.entries) { var name = entry.key.toString(); @@ -95,9 +93,10 @@ class CategoryConfiguration { displayName = categoryMap['displayName']?.toString(); documentationMarkdown = categoryMap['markdown']?.toString(); if (documentationMarkdown != null) { - documentationMarkdown = - pathContext.canonicalize(documentationMarkdown); - if (!File(documentationMarkdown).existsSync()) { + documentationMarkdown = resourceProvider.pathContext.canonicalize( + resourceProvider.pathContext + .join(canonicalYamlPath, documentationMarkdown)); + if (!resourceProvider.getFile(documentationMarkdown).exists) { throw DartdocFileMissing( 'In categories definition for ${name}, "markdown" resolves to ' 'the missing file $documentationMarkdown'); @@ -143,12 +142,16 @@ class ToolDefinition { /// Creates a ToolDefinition or subclass that is appropriate for the command /// given. factory ToolDefinition.fromCommand( - List command, List setupCommand, String description) { + List command, + List setupCommand, + String description, + ResourceProvider resourceProvider) { assert(command != null); assert(command.isNotEmpty); assert(description != null); if (isDartExecutable(command[0])) { - return DartToolDefinition(command, setupCommand, description); + return DartToolDefinition( + command, setupCommand, description, resourceProvider); } else { return ToolDefinition(command, setupCommand, description); } @@ -190,17 +193,21 @@ class ToolDefinition { class Snapshot { File _snapshotFile; + // TODO(srawlins): Deprecate this public getter; change private field to just + // be the absolute path. File get snapshotFile => _snapshotFile; final Completer _snapshotCompleter = Completer(); - Snapshot(Directory snapshotCache, String toolPath, int serial) { + Snapshot(Folder snapshotCache, String toolPath, int serial, + ResourceProvider resourceProvider) { if (toolPath.endsWith('.snapshot')) { _needsSnapshot = false; - _snapshotFile = File(toolPath); + _snapshotFile = resourceProvider.getFile(toolPath); snapshotCompleted(); } else { - _snapshotFile = - File(p.join(snapshotCache.absolute.path, 'snapshot_$serial')); + _snapshotFile = resourceProvider.getFile(resourceProvider.pathContext + .join(resourceProvider.pathContext.absolute(snapshotCache.path), + 'snapshot_$serial')); } } @@ -227,32 +234,35 @@ class Snapshot { class SnapshotCache { static SnapshotCache _instance; - Directory snapshotCache; + // TODO(srawlins): Make this final. + Folder snapshotCache; + final ResourceProvider _resourceProvider; final Map snapshots = {}; int _serial = 0; - SnapshotCache._() + SnapshotCache._(this._resourceProvider) : snapshotCache = - Directory.systemTemp.createTempSync('dartdoc_snapshot_cache_'); + _resourceProvider.createSystemTemp('dartdoc_snapshot_cache_'); - static SnapshotCache get instance { - _instance ??= SnapshotCache._(); - return _instance; - } + static SnapshotCache get instance => _instance; + + static SnapshotCache createInstance(ResourceProvider resourceProvider) => + _instance ??= SnapshotCache._(resourceProvider); Snapshot getSnapshot(String toolPath) { if (snapshots.containsKey(toolPath)) { return snapshots[toolPath]; } - snapshots[toolPath] = Snapshot(snapshotCache, toolPath, _serial); + snapshots[toolPath] = + Snapshot(snapshotCache, toolPath, _serial, _resourceProvider); _serial++; return snapshots[toolPath]; } - Future dispose() { + void dispose() { _instance = null; - if (snapshotCache != null && snapshotCache.existsSync()) { - return snapshotCache.delete(recursive: true); + if (snapshotCache != null && snapshotCache.exists) { + return snapshotCache.delete(); } return null; } @@ -260,6 +270,8 @@ class SnapshotCache { /// A special kind of tool definition for Dart commands. class DartToolDefinition extends ToolDefinition { + final ResourceProvider _resourceProvider; + /// Takes a list of args to modify, and returns the name of the executable /// to run. If no snapshot file existed, then create one and modify the args /// so that if they are executed with dart, will result in the snapshot being @@ -269,25 +281,26 @@ class DartToolDefinition extends ToolDefinition { assert(args[0] == command.first); // Set up flags to create a new snapshot, if needed, and use the first run // as the training run. + SnapshotCache.createInstance(_resourceProvider); var snapshot = SnapshotCache.instance.getSnapshot(command.first); var snapshotFile = snapshot.snapshotFile; var needsSnapshot = snapshot.needsSnapshot; if (needsSnapshot) { args.insertAll(0, [ - '--snapshot=${snapshotFile.absolute.path}', + '--snapshot=${_resourceProvider.pathContext.absolute(snapshotFile.path)}', '--snapshot_kind=app-jit' ]); } else { await snapshot.snapshotValid(); // replace the first argument with the path to the snapshot. - args[0] = snapshotFile.absolute.path; + args[0] = _resourceProvider.pathContext.absolute(snapshotFile.path); } - return Tuple2(Platform.resolvedExecutable, + return Tuple2(_resourceProvider.resolvedExecutable, needsSnapshot ? snapshot.snapshotCompleted : null); } - DartToolDefinition( - List command, List setupCommand, String description) + DartToolDefinition(List command, List setupCommand, + String description, this._resourceProvider) : super(command, setupCommand, description); } @@ -295,19 +308,23 @@ class DartToolDefinition extends ToolDefinition { class ToolConfiguration { final Map tools; + final ResourceProvider resourceProvider; + ToolRunner _runner; ToolRunner get runner => _runner ??= ToolRunner(this); - ToolConfiguration._(this.tools); + ToolConfiguration._(this.tools, this.resourceProvider); - static ToolConfiguration get empty { - return ToolConfiguration._({}); + static ToolConfiguration empty(ResourceProvider resourceProvider) { + return ToolConfiguration._({}, resourceProvider); } // TODO(jcollins-g): consider caching these. - static ToolConfiguration fromYamlMap(YamlMap yamlMap, p.Context pathContext) { + static ToolConfiguration fromYamlMap(YamlMap yamlMap, + String canonicalYamlPath, ResourceProvider resourceProvider) { var newToolDefinitions = {}; + var pathContext = resourceProvider.pathContext; for (var entry in yamlMap.entries) { var name = entry.key.toString(); var toolMap = entry.value; @@ -362,14 +379,10 @@ class ToolConfiguration { 'At least one of "command" or "${Platform.operatingSystem}" must ' 'be defined for the tool $name.'); } - bool validateExecutable(String executable) { - bool isExecutable(int mode) { - return (0x1 & ((mode >> 6) | (mode >> 3) | mode)) != 0; - } - var executableFile = File(executable); - var exeStat = executableFile.statSync(); - if (exeStat.type == FileSystemEntityType.notFound) { + bool validateExecutable(String executable) { + var executableFile = resourceProvider.getFile(executable); + if (resourceProvider.isNotFound(executableFile)) { throw DartdocOptionError('Command executables must exist. ' 'The file "$executable" does not exist for tool $name.'); } @@ -377,7 +390,7 @@ class ToolConfiguration { var isDartCommand = ToolDefinition.isDartExecutable(executable); // Dart scripts don't need to be executable, because they'll be // executed with the Dart binary. - if (!isDartCommand && !isExecutable(exeStat.mode)) { + if (!isDartCommand && !resourceProvider.isExecutable(executableFile)) { throw DartdocOptionError('Non-Dart commands must be ' 'executable. The file "$executable" for tool $name does not have ' 'execute permission.'); @@ -385,11 +398,14 @@ class ToolConfiguration { return isDartCommand; } - var executable = pathContext.canonicalize(command.removeAt(0)); + var executableRelatvePath = command.removeAt(0); + var executable = pathContext.canonicalize( + pathContext.join(canonicalYamlPath, executableRelatvePath)); validateExecutable(executable); if (setupCommand != null) { - var setupExecutable = - pathContext.canonicalize(setupCommand.removeAt(0)); + var setupExecutableRelativePath = setupCommand.removeAt(0); + var setupExecutable = pathContext.canonicalize( + pathContext.join(canonicalYamlPath, setupExecutableRelativePath)); var isDartSetupCommand = validateExecutable(executable); // Setup commands aren't snapshotted, since they're only run once. setupCommand = (isDartSetupCommand @@ -398,9 +414,9 @@ class ToolConfiguration { setupCommand; } newToolDefinitions[name] = ToolDefinition.fromCommand( - [executable] + command, setupCommand, description); + [executable] + command, setupCommand, description, resourceProvider); } - return ToolConfiguration._(newToolDefinitions); + return ToolConfiguration._(newToolDefinitions, resourceProvider); } } @@ -496,8 +512,10 @@ abstract class DartdocOption { /// and requires that one of [isDir] or [isFile] is set. final bool mustExist; + final ResourceProvider resourceProvider; + DartdocOption(this.name, this.defaultsTo, this.help, this.isDir, this.isFile, - this.mustExist, this._convertYamlToType) { + this.mustExist, this._convertYamlToType, this.resourceProvider) { assert(!(isDir && isFile)); if (isDir || isFile) assert(_isString || _isListString || _isMapString); if (mustExist) { @@ -506,7 +524,7 @@ abstract class DartdocOption { } /// Closure to convert yaml data into some other structure. - T Function(YamlMap, p.Context) _convertYamlToType; + ConvertYamlToType _convertYamlToType; // The choice not to use reflection means there's some ugly type checking, // somewhat more ugly than we'd have to do anyway to automatically convert @@ -573,8 +591,10 @@ abstract class DartdocOption { '${valueWithContext.value.runtimeType}'); } for (var path in resolvedPaths) { - var f = isDir ? Directory(path) : File(path); - if (!f.existsSync()) { + var f = isDir + ? resourceProvider.getFolder(path) + : resourceProvider.getFile(path); + if (!f.exists) { _onMissing(valueWithContext, path); } } @@ -638,14 +658,20 @@ abstract class DartdocOption { /// type. If [mustExist] is true, will throw [DartdocFileMissing] for command /// line parameters and file paths in config files that don't point to /// corresponding files or directories. - T valueAt(Directory dir); + T valueAt(Folder dir); /// Calls [valueAt] with the working directory at the start of the program. - T valueAtCurrent() => valueAt(directoryCurrent); + T valueAtCurrent() => valueAt(_directoryCurrent); + + Folder get _directoryCurrent => + resourceProvider.getFolder(resourceProvider.pathContext.current); + + String get _directoryCurrentPath => resourceProvider.pathContext.current; /// Calls [valueAt] on the directory this element is defined in. - T valueAtElement(Element element) => - valueAt(Directory(p.canonicalize(p.basename(element.source.fullName)))); + T valueAtElement(Element element) => valueAt(resourceProvider.getFolder( + resourceProvider.pathContext.canonicalize( + resourceProvider.pathContext.basename(element.source.fullName)))); /// Adds a DartdocOption to the children of this DartdocOption. void add(DartdocOption option) { @@ -683,21 +709,23 @@ class DartdocOptionFileSynth extends DartdocOption with DartdocSyntheticOption, _DartdocFileOption { bool _parentDirOverridesChild; @override - final T Function(DartdocSyntheticOption, Directory) _compute; + final T Function(DartdocSyntheticOption, Folder) _compute; - DartdocOptionFileSynth(String name, this._compute, + DartdocOptionFileSynth( + String name, this._compute, ResourceProvider resourceprovider, {bool mustExist = false, String help = '', bool isDir = false, bool isFile = false, bool parentDirOverridesChild, - T Function(YamlMap, p.Context) convertYamlToType}) - : super(name, null, help, isDir, isFile, mustExist, convertYamlToType) { + ConvertYamlToType convertYamlToType}) + : super(name, null, help, isDir, isFile, mustExist, convertYamlToType, + resourceprovider) { _parentDirOverridesChild = parentDirOverridesChild; } @override - T valueAt(Directory dir) { + T valueAt(Folder dir) { var result = _valueAtFromFile(dir); if (result?.definingFile != null) { return _handlePathsInContext(result); @@ -729,9 +757,10 @@ class DartdocOptionArgSynth extends DartdocOption bool _splitCommas; @override - final T Function(DartdocSyntheticOption, Directory) _compute; + final T Function(DartdocSyntheticOption, Folder) _compute; - DartdocOptionArgSynth(String name, this._compute, + DartdocOptionArgSynth( + String name, this._compute, ResourceProvider resourceProvider, {String abbr, bool mustExist = false, String help = '', @@ -740,7 +769,8 @@ class DartdocOptionArgSynth extends DartdocOption bool isFile = false, bool negatable = false, bool splitCommas}) - : super(name, null, help, isDir, isFile, mustExist, null) { + : super(name, null, help, isDir, isFile, mustExist, null, + resourceProvider) { _hide = hide; _negatable = negatable; _splitCommas = splitCommas; @@ -754,7 +784,7 @@ class DartdocOptionArgSynth extends DartdocOption } @override - T valueAt(Directory dir) { + T valueAt(Folder dir) { if (_argResults.wasParsed(argName)) { return _valueAtFromArgs(); } @@ -782,23 +812,25 @@ class DartdocOptionArgSynth extends DartdocOption class DartdocOptionSyntheticOnly extends DartdocOption with DartdocSyntheticOption { @override - final T Function(DartdocSyntheticOption, Directory) _compute; + final T Function(DartdocSyntheticOption, Folder) _compute; - DartdocOptionSyntheticOnly(String name, this._compute, + DartdocOptionSyntheticOnly( + String name, this._compute, ResourceProvider resourceProvider, {bool mustExist = false, String help = '', bool isDir = false, bool isFile = false}) - : super(name, null, help, isDir, isFile, mustExist, null); + : super( + name, null, help, isDir, isFile, mustExist, null, resourceProvider); } abstract class DartdocSyntheticOption implements DartdocOption { - T Function(DartdocSyntheticOption, Directory) get _compute; + T Function(DartdocSyntheticOption, Folder) get _compute; @override - T valueAt(Directory dir) => _valueAtFromSynthetic(dir); + T valueAt(Folder dir) => _valueAtFromSynthetic(dir); - T _valueAtFromSynthetic(Directory dir) { + T _valueAtFromSynthetic(Folder dir) { var context = _OptionValueWithContext(_compute(this, dir), dir.path); return _handlePathsInContext(context); } @@ -817,13 +849,14 @@ abstract class DartdocSyntheticOption implements DartdocOption { } } -typedef OptionGenerator = Future>> Function(); +typedef OptionGenerator = Future>> Function( + PackageMetaProvider); /// A [DartdocOption] that only contains other [DartdocOption]s and is not an /// option itself. class DartdocOptionSet extends DartdocOption { - DartdocOptionSet(String name) - : super(name, null, null, false, false, false, null); + DartdocOptionSet(String name, ResourceProvider resourceProvider) + : super(name, null, null, false, false, false, null, resourceProvider); /// Asynchronous factory that is the main entry point to initialize Dartdoc /// options for use. @@ -832,17 +865,20 @@ class DartdocOptionSet extends DartdocOption { /// [optionGenerators] is a sequence of asynchronous functions that return /// [DartdocOption]s that will be added to the new option set. static Future fromOptionGenerators( - String name, Iterable optionGenerators) async { - var optionSet = DartdocOptionSet(name); + String name, + Iterable optionGenerators, + PackageMetaProvider packageMetaProvider) async { + var optionSet = + DartdocOptionSet(name, packageMetaProvider.resourceProvider); for (var generator in optionGenerators) { - optionSet.addAll(await generator()); + optionSet.addAll(await generator(packageMetaProvider)); } return optionSet; } /// [DartdocOptionSet] always has the null value. @override - Null valueAt(Directory dir) => null; + Null valueAt(Folder dir) => null; /// Since we have no value, [_onMissing] does nothing. @override @@ -866,7 +902,8 @@ class DartdocOptionArgOnly extends DartdocOption bool _negatable; bool _splitCommas; - DartdocOptionArgOnly(String name, T defaultsTo, + DartdocOptionArgOnly( + String name, T defaultsTo, ResourceProvider resourceProvider, {String abbr, bool mustExist = false, String help = '', @@ -875,7 +912,8 @@ class DartdocOptionArgOnly extends DartdocOption bool isFile = false, bool negatable = false, bool splitCommas}) - : super(name, defaultsTo, help, isDir, isFile, mustExist, null) { + : super(name, defaultsTo, help, isDir, isFile, mustExist, null, + resourceProvider) { _hide = hide; _negatable = negatable; _splitCommas = splitCommas; @@ -905,7 +943,8 @@ class DartdocOptionArgFile extends DartdocOption bool _parentDirOverridesChild; bool _splitCommas; - DartdocOptionArgFile(String name, T defaultsTo, + DartdocOptionArgFile( + String name, T defaultsTo, ResourceProvider resourceProvider, {String abbr, bool mustExist = false, String help = '', @@ -915,7 +954,8 @@ class DartdocOptionArgFile extends DartdocOption bool negatable = false, bool parentDirOverridesChild = false, bool splitCommas}) - : super(name, defaultsTo, help, isDir, isFile, mustExist, null) { + : super(name, defaultsTo, help, isDir, isFile, mustExist, null, + resourceProvider) { _abbr = abbr; _hide = hide; _negatable = negatable; @@ -936,7 +976,7 @@ class DartdocOptionArgFile extends DartdocOption /// Try to find an explicit argument setting this value, but if not, fall back /// to files finally, the default. @override - T valueAt(Directory dir) { + T valueAt(Folder dir) { var value = _valueAtFromArgs(); value ??= _valueAtFromFiles(dir); value ??= defaultsTo; @@ -963,15 +1003,16 @@ class DartdocOptionFileOnly extends DartdocOption with _DartdocFileOption { bool _parentDirOverridesChild; - DartdocOptionFileOnly(String name, T defaultsTo, + DartdocOptionFileOnly( + String name, T defaultsTo, ResourceProvider resourceProvider, {bool mustExist = false, String help = '', bool isDir = false, bool isFile = false, bool parentDirOverridesChild = false, - T Function(YamlMap, p.Context) convertYamlToType}) + ConvertYamlToType convertYamlToType}) : super(name, defaultsTo, help, isDir, isFile, mustExist, - convertYamlToType) { + convertYamlToType, resourceProvider) { _parentDirOverridesChild = parentDirOverridesChild; } @@ -1003,7 +1044,7 @@ abstract class _DartdocFileOption implements DartdocOption { void _onMissingFromFiles( _OptionValueWithContext valueWithContext, String missingPath) { - var dartdocYaml = p.join( + var dartdocYaml = resourceProvider.pathContext.join( valueWithContext.canonicalDirectoryPath, valueWithContext.definingFile); throw DartdocFileMissing('Field ${fieldName} from ${dartdocYaml}, set to ' '${valueWithContext.value}, resolves to missing path: ' @@ -1014,7 +1055,7 @@ abstract class _DartdocFileOption implements DartdocOption { /// Searches for a value in configuration files relative to [dir], and if not /// found, returns [defaultsTo]. - T valueAt(Directory dir) { + T valueAt(Folder dir) { return _valueAtFromFiles(dir) ?? defaultsTo; } @@ -1022,8 +1063,8 @@ abstract class _DartdocFileOption implements DartdocOption { // The value of this option from files will not change unless files are // modified during execution (not allowed in Dartdoc). - T _valueAtFromFiles(Directory dir) { - var key = p.canonicalize(dir.path); + T _valueAtFromFiles(Folder dir) { + var key = resourceProvider.pathContext.canonicalize(dir.path); if (!__valueAtFromFiles.containsKey(key)) { _OptionValueWithContext valueWithContext; if (parentDirOverridesChild) { @@ -1038,11 +1079,11 @@ abstract class _DartdocFileOption implements DartdocOption { /// Searches all dartdoc_options files through parent directories, starting at /// [dir], for the option and returns one once found. - _OptionValueWithContext _valueAtFromFilesFirstFound(Directory dir) { + _OptionValueWithContext _valueAtFromFilesFirstFound(Folder dir) { _OptionValueWithContext value; while (true) { value = _valueAtFromFile(dir); - if (value != null || p.equals(dir.parent.path, dir.path)) break; + if (value != null || dir.parent == null) break; dir = dir.parent; } return value; @@ -1051,20 +1092,20 @@ abstract class _DartdocFileOption implements DartdocOption { /// Searches all dartdoc_options files for the option, and returns the value /// in the top-most parent directory `dartdoc_options.yaml` file it is /// mentioned in. - _OptionValueWithContext _valueAtFromFilesLastFound(Directory dir) { + _OptionValueWithContext _valueAtFromFilesLastFound(Folder dir) { _OptionValueWithContext value; while (true) { var tmpValue = _valueAtFromFile(dir); if (tmpValue != null) value = tmpValue; - if (p.equals(dir.parent.path, dir.path)) break; dir = dir.parent; + if (dir == null) break; } return value; } /// Returns null if not set in the YAML file in this directory (or its /// parents). - _OptionValueWithContext _valueAtFromFile(Directory dir) { + _OptionValueWithContext _valueAtFromFile(Folder dir) { var yamlFileData = _yamlAtDirectory(dir); var contextPath = yamlFileData.canonicalDirectoryPath; dynamic yamlData = yamlFileData.data; @@ -1090,7 +1131,8 @@ abstract class _DartdocFileOption implements DartdocOption { // _OptionValueWithContext into the return data here, and would not have // that be separate. if (_isMapString && _convertYamlToType == null) { - _convertYamlToType = (YamlMap yamlMap, p.Context pathContext) { + _convertYamlToType = (YamlMap yamlMap, String canonicalYamlPath, + ResourceProvider resourceProvider) { var returnData = {}; for (var entry in yamlMap.entries) { returnData[entry.key.toString()] = entry.value.toString(); @@ -1103,9 +1145,10 @@ abstract class _DartdocFileOption implements DartdocOption { 'Unable to convert yaml to type for option: $fieldName, method not ' 'defined'); } - var canonicalDirectoryPath = p.canonicalize(contextPath); + var canonicalDirectoryPath = + resourceProvider.pathContext.canonicalize(contextPath); returnData = _convertYamlToType( - yamlData, p.Context(current: canonicalDirectoryPath)); + yamlData, canonicalDirectoryPath, resourceProvider); } else if (_isDouble) { if (yamlData is num) { returnData = yamlData.toDouble(); @@ -1121,24 +1164,30 @@ abstract class _DartdocFileOption implements DartdocOption { definingFile: 'dartdoc_options.yaml'); } - _YamlFileData _yamlAtDirectory(Directory dir) { - var canonicalPaths = [p.canonicalize(dir.path)]; + _YamlFileData _yamlAtDirectory(Folder dir) { + var canonicalPaths = [ + resourceProvider.pathContext.canonicalize(dir.path) + ]; if (!_yamlAtCanonicalPathCache.containsKey(canonicalPaths.first)) { - var yamlData = _YamlFileData({}, directoryCurrentPath); - if (dir.existsSync()) { + var yamlData = _YamlFileData({}, _directoryCurrentPath); + if (dir.exists) { File dartdocOptionsFile; while (true) { - dartdocOptionsFile = File(p.join(dir.path, 'dartdoc_options.yaml')); - if (dartdocOptionsFile.existsSync() || - p.equals(dir.parent.path, dir.path)) break; + dartdocOptionsFile = resourceProvider.getFile(resourceProvider + .pathContext + .join(dir.path, 'dartdoc_options.yaml')); + if (dartdocOptionsFile.exists || dir.parent == null) { + break; + } dir = dir.parent; - canonicalPaths.add(p.canonicalize(dir.path)); + canonicalPaths + .add(resourceProvider.pathContext.canonicalize(dir.path)); } - if (dartdocOptionsFile.existsSync()) { + if (dartdocOptionsFile.exists) { yamlData = _YamlFileData( loadYaml(dartdocOptionsFile.readAsStringSync()), - p.canonicalize(dir.path)); + resourceProvider.pathContext.canonicalize(dir.path)); } } canonicalPaths.forEach((p) => _yamlAtCanonicalPathCache[p] = yamlData); @@ -1167,7 +1216,7 @@ abstract class _DartdocArgOption implements DartdocOption { /// valueAt for arguments ignores the [dir] parameter and only uses command /// line arguments and the current working directory to resolve the result. @override - T valueAt(Directory dir) => _valueAtFromArgs() ?? defaultsTo; + T valueAt(Folder dir) => _valueAtFromArgs() ?? defaultsTo; /// For passing in to [int.parse] and [double.parse] `onError'. void _throwErrorForTypes(String value) { @@ -1203,7 +1252,7 @@ abstract class _DartdocArgOption implements DartdocOption { } /// Generates an _OptionValueWithContext using the value of the argument from - /// the [argParser] and the working directory from [directoryCurrent]. + /// the [argParser] and the working directory from [_directoryCurrent]. /// /// Throws [UnsupportedError] if [T] is not a supported type. _OptionValueWithContext _valueAtFromArgsWithContext() { @@ -1234,7 +1283,7 @@ abstract class _DartdocArgOption implements DartdocOption { } else { throw UnsupportedError('Type ${T} is not supported'); } - return _OptionValueWithContext(retval, directoryCurrentPath); + return _OptionValueWithContext(retval, _directoryCurrentPath); } /// The name of this option as a command line argument. @@ -1301,7 +1350,7 @@ abstract class _DartdocArgOption implements DartdocOption { abstract class DartdocOptionContextBase { DartdocOptionSet get optionSet; - Directory get context; + Folder get context; } /// An [DartdocOptionSet] wrapped in nice accessors specific to Dartdoc, which @@ -1318,42 +1367,51 @@ class DartdocOptionContext extends DartdocOptionContextBase @override final DartdocOptionSet optionSet; @override - Directory context; + Folder context; // TODO(jcollins-g): Allow passing in structured data to initialize a // [DartdocOptionContext]'s arguments instead of having to parse strings // via optionSet. /// If [entity] is null, assume this is the initialization case and use /// the inputDir flag to determine the context. - DartdocOptionContext(this.optionSet, FileSystemEntity entity) { - if (entity == null) { - String inputDir = optionSet['inputDir'].valueAt(directoryCurrent) ?? - directoryCurrentPath; - context = Directory(inputDir); + DartdocOptionContext( + this.optionSet, Resource resource, ResourceProvider resourceProvider) { + if (resource == null) { + var current = resourceProvider.pathContext.current; + String inputDir = + optionSet['inputDir'].valueAt(resourceProvider.getFolder(current)) ?? + current; + context = resourceProvider.getFolder(inputDir); } else { - context = Directory( - p.canonicalize(entity is File ? entity.parent.path : entity.path)); + context = resourceProvider.getFolder(resourceProvider.pathContext + .canonicalize( + resource is File ? resource.parent.path : resource.path)); } } /// Build a DartdocOptionContext from an analyzer element (using its source /// location). - factory DartdocOptionContext.fromElement( - DartdocOptionSet optionSet, Element element) { - return DartdocOptionContext(optionSet, File(element.source.fullName)); + factory DartdocOptionContext.fromElement(DartdocOptionSet optionSet, + Element element, ResourceProvider resourceProvider) { + return DartdocOptionContext(optionSet, + resourceProvider.getFile(element.source.fullName), resourceProvider); } /// Build a DartdocOptionContext from an existing [DartdocOptionContext] and a /// new analyzer [Element]. factory DartdocOptionContext.fromContextElement( - DartdocOptionContext optionContext, Element element) { - return DartdocOptionContext.fromElement(optionContext.optionSet, element); + DartdocOptionContext optionContext, + Element element, + ResourceProvider resourceProvider) { + return DartdocOptionContext.fromElement( + optionContext.optionSet, element, resourceProvider); } /// Build a DartdocOptionContext from an existing [DartdocOptionContext]. - factory DartdocOptionContext.fromContext( - DartdocOptionContext optionContext, FileSystemEntity entity) { - return DartdocOptionContext(optionContext.optionSet, entity); + factory DartdocOptionContext.fromContext(DartdocOptionContext optionContext, + Resource resource, ResourceProvider resourceProvider) { + return DartdocOptionContext( + optionContext.optionSet, resource, resourceProvider); } // All values defined in createDartdocOptions should be exposed here. @@ -1420,6 +1478,8 @@ class DartdocOptionContext extends DartdocOptionContextBase bool get sdkDocs => optionSet['sdkDocs'].valueAt(context); + ResourceProvider get resourceProvider => optionSet.resourceProvider; + String get sdkDir => optionSet['sdkDir'].valueAt(context); bool get showUndocumentedCategories => @@ -1451,28 +1511,31 @@ class DartdocOptionContext extends DartdocOptionContextBase Future>> createDartdocOptions( PackageMetaProvider packageMetaProvider, ) async { + var resourceProvider = packageMetaProvider.resourceProvider; return [ - DartdocOptionArgOnly('allowTools', false, + DartdocOptionArgOnly('allowTools', false, resourceProvider, help: 'Execute user-defined tools to fill in @tool directives.', negatable: true), - DartdocOptionArgFile('ambiguousReexportScorerMinConfidence', 0.1, + DartdocOptionArgFile( + 'ambiguousReexportScorerMinConfidence', 0.1, resourceProvider, help: 'Minimum scorer confidence to suppress warning on ambiguous ' 'reexport.'), - DartdocOptionArgOnly('autoIncludeDependencies', false, + DartdocOptionArgOnly( + 'autoIncludeDependencies', false, resourceProvider, help: 'Include all the used libraries into the docs, even the ones not ' 'in the current package or "include-external"', negatable: true), - DartdocOptionArgFile>('categoryOrder', [], + DartdocOptionArgFile>('categoryOrder', [], resourceProvider, help: 'A list of categories (not package names) to place first when ' "grouping symbols on dartdoc's sidebar. Unmentioned categories are " 'sorted after these.'), DartdocOptionFileOnly( - 'categories', CategoryConfiguration.empty, + 'categories', CategoryConfiguration.empty, resourceProvider, convertYamlToType: CategoryConfiguration.fromYamlMap, help: 'A list of all categories, their display names, and markdown ' 'documentation in the order they are to be displayed.'), DartdocOptionSyntheticOnly>('dropTextFrom', - (DartdocSyntheticOption> option, Directory dir) { + (DartdocSyntheticOption> option, Folder dir) { if (option.parent['hideSdkText'].valueAt(dir)) { return [ 'dart.async', @@ -1494,59 +1557,65 @@ Future>> createDartdocOptions( ]; } return []; - }, help: 'Remove text from libraries with the following names.'), - DartdocOptionArgFile('examplePathPrefix', null, + }, resourceProvider, + help: 'Remove text from libraries with the following names.'), + DartdocOptionArgFile('examplePathPrefix', null, resourceProvider, isDir: true, help: 'Prefix for @example paths.\n(defaults to the project root)', mustExist: true), - DartdocOptionArgFile>('exclude', [], + DartdocOptionArgFile>('exclude', [], resourceProvider, help: 'Library names to ignore.', splitCommas: true), - DartdocOptionArgOnly>('excludePackages', [], + DartdocOptionArgOnly>('excludePackages', [], resourceProvider, help: 'Package names to ignore.', splitCommas: true), // This could be a ArgOnly, but trying to not provide too many ways // to set the flutter root. DartdocOptionSyntheticOnly( 'flutterRoot', - (DartdocSyntheticOption option, Directory dir) => + (DartdocSyntheticOption option, Folder dir) => resolveTildePath(Platform.environment['FLUTTER_ROOT']), + resourceProvider, isDir: true, help: 'Root of the Flutter SDK, specified from environment.', mustExist: true), - DartdocOptionArgOnly('hideSdkText', false, + DartdocOptionArgOnly('hideSdkText', false, resourceProvider, hide: true, help: 'Drop all text for SDK components. Helpful for integration ' 'tests for dartdoc, probably not useful for anything else.', negatable: true), - DartdocOptionArgFile>('include', [], + DartdocOptionArgFile>('include', [], resourceProvider, help: 'Library names to generate docs for.', splitCommas: true), - DartdocOptionArgFile>('includeExternal', null, + DartdocOptionArgFile>( + 'includeExternal', null, resourceProvider, isFile: true, help: 'Additional (external) dart files to include; use "dir/fileName", ' 'as in lib/material.dart.', mustExist: true, splitCommas: true), - DartdocOptionArgOnly('includeSource', true, + DartdocOptionArgOnly('includeSource', true, resourceProvider, help: 'Show source code blocks.', negatable: true), - DartdocOptionArgOnly('injectHtml', false, + DartdocOptionArgOnly('injectHtml', false, resourceProvider, help: 'Allow the use of the {@inject-html} directive to inject raw ' 'HTML into dartdoc output.'), - DartdocOptionArgOnly('input', directoryCurrentPath, + DartdocOptionArgOnly( + 'input', resourceProvider.pathContext.current, resourceProvider, isDir: true, help: 'Path to source directory', mustExist: true), DartdocOptionSyntheticOnly('inputDir', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { if (option.parent['sdkDocs'].valueAt(dir)) { return option.parent['sdkDir'].valueAt(dir); } return option.parent['input'].valueAt(dir); - }, + }, resourceProvider, help: 'Path to source directory (with override if --sdk-docs)', isDir: true, mustExist: true), - DartdocOptionSet('linkTo') + DartdocOptionSet('linkTo', resourceProvider) ..addAll([ - DartdocOptionArgOnly>('hosted', + DartdocOptionArgOnly>( + 'hosted', {'pub.dartlang.org': 'https://pub.dev/documentation/%n%/%v%'}, + resourceProvider, help: 'Specify URLs for hosted pub packages'), DartdocOptionArgOnly>( 'sdks', @@ -1554,10 +1623,11 @@ Future>> createDartdocOptions( 'Dart': 'https://api.dart.dev/%b%/%v%', 'Flutter': 'https://api.flutter.dev/flutter', }, + resourceProvider, help: 'Specify URLs for SDKs.', ), DartdocOptionFileSynth('url', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { PackageMeta packageMeta = option.parent.parent['packageMeta'].valueAt(dir); // Prefer SDK check first, then pub cache check. @@ -1573,16 +1643,17 @@ Future>> createDartdocOptions( if (hostMap.containsKey(hostedAt)) return hostMap[hostedAt]; } return ''; - }, help: 'Url to use for this particular package.'), - DartdocOptionArgOnly('remote', true, + }, resourceProvider, help: 'Url to use for this particular package.'), + DartdocOptionArgOnly('remote', true, resourceProvider, help: 'Allow links to be generated for packages outside this one.', negatable: true), ]), - DartdocOptionArgOnly('output', p.join('doc', 'api'), + DartdocOptionArgOnly('output', + resourceProvider.pathContext.join('doc', 'api'), resourceProvider, isDir: true, help: 'Path to output directory.'), DartdocOptionSyntheticOnly( 'packageMeta', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { var packageMeta = packageMetaProvider.fromDir(dir); if (packageMeta == null) { throw DartdocOptionError( @@ -1590,15 +1661,16 @@ Future>> createDartdocOptions( } return packageMeta; }, + resourceProvider, ), - DartdocOptionArgOnly>('packageOrder', [], + DartdocOptionArgOnly>('packageOrder', [], resourceProvider, help: 'A list of package names to place first when grouping libraries in ' 'packages. Unmentioned packages are sorted after these.'), - DartdocOptionArgOnly('sdkDocs', false, + DartdocOptionArgOnly('sdkDocs', false, resourceProvider, help: 'Generate ONLY the docs for the Dart SDK.'), DartdocOptionArgSynth('sdkDir', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { if (!option.parent['sdkDocs'].valueAt(dir) && (option.root['topLevelPackageMeta'].valueAt(dir) as PackageMeta) .requiresFlutter) { @@ -1608,16 +1680,19 @@ Future>> createDartdocOptions( // [PackageBuilder.buildPackageGraph]. return null; } - return p.join(flutterRoot, 'bin', 'cache', 'dart-sdk'); + return resourceProvider.pathContext + .join(flutterRoot, 'bin', 'cache', 'dart-sdk'); } - return defaultSdkDir.absolute.path; - }, help: 'Path to the SDK directory.', isDir: true, mustExist: true), - DartdocOptionArgFile('showUndocumentedCategories', false, + return resourceProvider.defaultSdkDir.path; + }, packageMetaProvider.resourceProvider, + help: 'Path to the SDK directory.', isDir: true, mustExist: true), + DartdocOptionArgFile( + 'showUndocumentedCategories', false, resourceProvider, help: "Label categories that aren't documented", negatable: true), DartdocOptionSyntheticOnly('topLevelPackageMeta', - (DartdocSyntheticOption option, Directory dir) { - var packageMeta = packageMetaProvider - .fromDir(Directory(option.parent['inputDir'].valueAt(dir))); + (DartdocSyntheticOption option, Folder dir) { + var packageMeta = packageMetaProvider.fromDir( + resourceProvider.getFolder(option.parent['inputDir'].valueAt(dir))); if (packageMeta == null) { throw DartdocOptionError( 'Unable to generate documentation: no package found'); @@ -1627,25 +1702,26 @@ Future>> createDartdocOptions( throw DartdocOptionError('Package is invalid: $firstError'); } return packageMeta; - }, help: 'PackageMeta object for the default package.'), - DartdocOptionArgOnly('useCategories', true, + }, resourceProvider, help: 'PackageMeta object for the default package.'), + DartdocOptionArgOnly('useCategories', true, resourceProvider, help: 'Display categories in the sidebar of packages'), - DartdocOptionArgOnly('validateLinks', true, + DartdocOptionArgOnly('validateLinks', true, resourceProvider, help: 'Runs the built-in link checker to display Dart context aware ' 'warnings for broken links (slow)', negatable: true), - DartdocOptionArgOnly('verboseWarnings', true, + DartdocOptionArgOnly('verboseWarnings', true, resourceProvider, help: 'Display extra debugging information and help with warnings.', negatable: true), - DartdocOptionFileOnly('excludeFooterVersion', false, + DartdocOptionFileOnly('excludeFooterVersion', false, resourceProvider, help: 'Excludes the package version number in the footer text'), - DartdocOptionFileOnly('tools', ToolConfiguration.empty, + DartdocOptionFileOnly( + 'tools', ToolConfiguration.empty(resourceProvider), resourceProvider, convertYamlToType: ToolConfiguration.fromYamlMap, help: 'A map of tool names to executable paths. Each executable must ' 'exist. Executables for different platforms are specified by ' 'giving the platform name as a key, and a list of strings as the ' 'command.'), - DartdocOptionArgOnly('useBaseHref', false, + DartdocOptionArgOnly('useBaseHref', false, resourceProvider, help: 'Use in generated files (legacy behavior). This option ' 'is temporary and support will be removed in the future. Use only ' @@ -1654,11 +1730,12 @@ Future>> createDartdocOptions( negatable: false, hide: true), // TODO(jdkoren): Unhide when we have good support for another format. - DartdocOptionArgOnly('format', 'html', hide: true), + DartdocOptionArgOnly('format', 'html', resourceProvider, + hide: true), // TODO(jcollins-g): refactor so there is a single static "create" for // each DartdocOptionContext that traverses the inheritance tree itself. - ...await createExperimentOptions(), + ...await createExperimentOptions(resourceProvider), ...await createPackageWarningOptions(packageMetaProvider), - ...await createSourceLinkerOptions(), + ...await createSourceLinkerOptions(resourceProvider), ]; } diff --git a/lib/src/experiment_options.dart b/lib/src/experiment_options.dart index 8c5b4d4e9a..9a136b0ee5 100644 --- a/lib/src/experiment_options.dart +++ b/lib/src/experiment_options.dart @@ -8,6 +8,7 @@ /// library dartdoc.experiment_options; +import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/src/dart/analysis/experiments.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; @@ -19,10 +20,12 @@ abstract class DartdocExperimentOptionContext // TODO(jcollins-g): Implement YAML parsing for these flags and generation // of [DartdocExperimentOptionContext], once a YAML file is available. -Future>> createExperimentOptions() async { +Future>> createExperimentOptions( + ResourceProvider resourceProvider) async { return [ // TODO(jcollins-g): Consider loading experiment values from dartdoc_options.yaml? - DartdocOptionArgOnly>('enable-experiment', [], + DartdocOptionArgOnly>( + 'enable-experiment', [], resourceProvider, help: 'Enable or disable listed experiments.\n' + ExperimentStatus.knownFeatures.values .where((e) => e.documentation != null) diff --git a/lib/src/generator/generator.dart b/lib/src/generator/generator.dart index ce09ff2572..b77dff3cc0 100644 --- a/lib/src/generator/generator.dart +++ b/lib/src/generator/generator.dart @@ -6,10 +6,11 @@ library dartdoc.generator; import 'dart:async' show Future; -import 'dart:io' show Directory; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/model/model.dart' show PackageGraph; +import 'package:dartdoc/src/package_meta.dart'; import 'package:dartdoc/src/warnings.dart'; abstract class FileWriter { @@ -55,9 +56,11 @@ mixin GeneratorContext on DartdocOptionContextBase { bool get useBaseHref => optionSet['useBaseHref'].valueAt(context); } -Future>> createGeneratorOptions() async { +Future>> createGeneratorOptions( + PackageMetaProvider packageMetaProvider) async { + var resourceProvider = packageMetaProvider.resourceProvider; return [ - DartdocOptionArgFile>('footer', [], + DartdocOptionArgFile>('footer', [], resourceProvider, isFile: true, help: 'Paths to files with content to add to page footers, but possibly ' @@ -66,7 +69,7 @@ Future>> createGeneratorOptions() async { 'to dedicated footer elements, use --footer-text instead.', mustExist: true, splitCommas: true), - DartdocOptionArgFile>('footerText', [], + DartdocOptionArgFile>('footerText', [], resourceProvider, isFile: true, help: 'Paths to files with content to add to page footers (next to the ' 'package name and version).', @@ -74,30 +77,31 @@ Future>> createGeneratorOptions() async { splitCommas: true), DartdocOptionSyntheticOnly( 'addSdkFooter', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { return option.root['topLevelPackageMeta'].valueAt(dir).isSdk; }, + resourceProvider, help: 'Whether the SDK footer text should be added (synthetic)', ), - DartdocOptionArgFile>('header', [], + DartdocOptionArgFile>('header', [], resourceProvider, isFile: true, help: 'Paths to files with content to add to page headers.', splitCommas: true), - DartdocOptionArgOnly('prettyIndexJson', false, + DartdocOptionArgOnly('prettyIndexJson', false, resourceProvider, help: 'Generates `index.json` with indentation and newlines. The file is ' 'larger, but it\'s also easier to diff.', negatable: false), - DartdocOptionArgFile('favicon', null, + DartdocOptionArgFile('favicon', null, resourceProvider, isFile: true, help: 'A path to a favicon for the generated docs.', mustExist: true), - DartdocOptionArgOnly('relCanonicalPrefix', null, + DartdocOptionArgOnly('relCanonicalPrefix', null, resourceProvider, help: 'If provided, add a rel="canonical" prefixed with provided value. ' 'Consider using if building many versions of the docs for public ' 'SEO; learn more at https://goo.gl/gktN6F.'), - DartdocOptionArgOnly('templatesDir', null, + DartdocOptionArgOnly('templatesDir', null, resourceProvider, isDir: true, mustExist: true, hide: true, diff --git a/lib/src/generator/html_generator.dart b/lib/src/generator/html_generator.dart index 5319db9dde..3a38b1495d 100644 --- a/lib/src/generator/html_generator.dart +++ b/lib/src/generator/html_generator.dart @@ -5,7 +5,6 @@ library dartdoc.html_generator; import 'dart:async' show Future; -import 'dart:io' show File; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/generator/dartdoc_generator_backend.dart'; @@ -44,7 +43,8 @@ class HtmlGeneratorBackend extends DartdocGeneratorBackend { await _copyResources(writer); if (options.favicon != null) { // Allow overwrite of favicon. - var bytes = File(options.favicon).readAsBytesSync(); + var bytes = + graph.resourceProvider.getFile(options.favicon).readAsBytesSync(); writer.write(path.join('static-assets', 'favicon.png'), bytes, allowOverwrite: true); } diff --git a/lib/src/io_utils.dart b/lib/src/io_utils.dart index 33a8c6117e..c4a3cfaf18 100644 --- a/lib/src/io_utils.dart +++ b/lib/src/io_utils.dart @@ -6,10 +6,16 @@ library dartdoc.io_utils; import 'dart:async'; -import 'dart:io'; +import 'dart:convert'; +import 'dart:io' as io; +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; +import 'package:dartdoc/src/package_meta.dart'; import 'package:path/path.dart' as path; +Encoding utf8AllowMalformed = Utf8Codec(allowMalformed: true); + /// Return a resolved path including the home directory in place of tilde /// references. String resolveTildePath(String originalPath) { @@ -19,15 +25,75 @@ String resolveTildePath(String originalPath) { String homeDir; - if (Platform.isWindows) { - homeDir = path.absolute(Platform.environment['USERPROFILE']); + if (io.Platform.isWindows) { + homeDir = path.absolute(io.Platform.environment['USERPROFILE']); } else { - homeDir = path.absolute(Platform.environment['HOME']); + homeDir = path.absolute(io.Platform.environment['HOME']); } return path.join(homeDir, originalPath.substring(2)); } +extension ResourceProviderExtensions on ResourceProvider { + Folder createSystemTemp(String prefix) { + if (this is PhysicalResourceProvider) { + return getFolder(io.Directory.systemTemp.createTempSync(prefix).path); + } else { + return getFolder(pathContext.join('/tmp', prefix))..create(); + } + } + + Folder get defaultSdkDir { + if (this is PhysicalResourceProvider) { + var sdkDir = getFile(pathContext.absolute(io.Platform.resolvedExecutable)) + .parent + .parent; + assert(pathContext.equals( + sdkDir.path, PubPackageMeta.sdkDirParent(sdkDir, this).path)); + return sdkDir; + } else { + // TODO(srawlins): Return what is needed for tests. + return null; + } + } + + String get resolvedExecutable { + if (this is PhysicalResourceProvider) { + return io.Platform.resolvedExecutable; + } else { + // TODO(srawlins): Return what is needed for tests. + return null; + } + } + + bool isExecutable(File file) { + if (this is PhysicalResourceProvider) { + var mode = io.File(file.path).statSync().mode; + return (0x1 & ((mode >> 6) | (mode >> 3) | mode)) != 0; + } else { + // TODO(srawlins) + return false; + } + } + + bool isNotFound(File file) { + if (this is PhysicalResourceProvider) { + return io.File(file.path).statSync().type == + io.FileSystemEntityType.notFound; + } else { + return !file.exists; + } + } + + String readAsMalformedAllowedStringSync(File file) { + if (this is PhysicalResourceProvider) { + return io.File(file.path).readAsStringSync(encoding: utf8AllowMalformed); + } else { + return file.readAsStringSync(); + } + } +} + /// Lists the contents of [dir]. /// /// If [recursive] is `true`, lists subdirectory contents (defaults to `false`). @@ -37,8 +103,8 @@ String resolveTildePath(String originalPath) { /// The returned paths are guaranteed to begin with [dir]. Iterable listDir(String dir, {bool recursive = false, - Iterable Function(Directory dir) listDir}) { - listDir ??= (Directory dir) => dir.listSync(); + Iterable Function(io.Directory dir) listDir}) { + listDir ??= (io.Directory dir) => dir.listSync(); return _doList(dir, {}, recursive, listDir); } @@ -47,21 +113,21 @@ Iterable _doList( String dir, Set listedDirectories, bool recurse, - Iterable Function(Directory dir) listDir) sync* { + Iterable Function(io.Directory dir) listDir) sync* { // Avoid recursive symlinks. - var resolvedPath = Directory(dir).resolveSymbolicLinksSync(); + var resolvedPath = io.Directory(dir).resolveSymbolicLinksSync(); if (!listedDirectories.contains(resolvedPath)) { listedDirectories = Set.from(listedDirectories); listedDirectories.add(resolvedPath); - for (var entity in listDir(Directory(dir))) { + for (var entity in listDir(io.Directory(dir))) { // Skip hidden files and directories if (path.basename(entity.path).startsWith('.')) { continue; } yield entity.path; - if (entity is Directory) { + if (entity is io.Directory) { if (recurse) { yield* _doList(entity.path, listedDirectories, recurse, listDir); } diff --git a/lib/src/logging.dart b/lib/src/logging.dart index fbaadd3b08..702c7c48f3 100644 --- a/lib/src/logging.dart +++ b/lib/src/logging.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show stderr, stdout; +import 'package:analyzer/file_system/file_system.dart'; import 'package:cli_util/cli_logging.dart' show Ansi; +import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -130,21 +132,24 @@ abstract class LoggingContext implements DartdocOptionContextBase { bool get quiet => optionSet['quiet'].valueAt(context); } -Future>> createLoggingOptions() async { +Future>> createLoggingOptions( + PackageMetaProvider packageMetaProvider) async { + var resourceProvider = packageMetaProvider.resourceProvider; return [ - DartdocOptionArgOnly('json', false, + DartdocOptionArgOnly('json', false, resourceProvider, help: 'Prints out progress JSON maps. One entry per line.', negatable: true), - DartdocOptionArgOnly('showProgress', Ansi.terminalSupportsAnsi, + DartdocOptionArgOnly( + 'showProgress', Ansi.terminalSupportsAnsi, resourceProvider, help: 'Display progress indications to console stdout.', negatable: true), DartdocOptionArgSynth('quiet', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { if (option.root['generateDocs']?.valueAt(dir) == false) { return true; } return false; - }, + }, resourceProvider, abbr: 'q', negatable: true, help: 'Only show warnings and errors; silence all other output.'), diff --git a/lib/src/model/category.dart b/lib/src/model/category.dart index fd7df304ad..9ae991b3c4 100644 --- a/lib/src/model/category.dart +++ b/lib/src/model/category.dart @@ -2,9 +2,8 @@ // 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:io'; - import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/render/category_renderer.dart'; @@ -179,7 +178,8 @@ class Category extends Nameable File get documentationFile { if (_documentationFile == null) { if (categoryDefinition?.documentationMarkdown != null) { - _documentationFile = File(categoryDefinition.documentationMarkdown); + _documentationFile = _config.resourceProvider + .getFile(categoryDefinition.documentationMarkdown); } } return _documentationFile; diff --git a/lib/src/model/comment_processable.dart b/lib/src/model/comment_processable.dart index b78791e553..72c0395361 100644 --- a/lib/src/model/comment_processable.dart +++ b/lib/src/model/comment_processable.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:args/args.dart'; import 'package:crypto/crypto.dart' as crypto; import 'package:dartdoc/src/model/model.dart'; @@ -74,6 +72,8 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { // Remember, periods are legal in library names. fullyQualifiedName.replaceFirst('${library.fullyQualifiedName}.', ''); + path.Context get pathContext => packageGraph.resourceProvider.pathContext; + @visibleForTesting ModelElementRenderer get modelElementRenderer => packageGraph.rendererFactory.modelElementRenderer; @@ -198,8 +198,9 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { var replacement = match[0]; // default to fully matched string. - var fragmentFile = File(path.join(dirPath, args['file'])); - if (fragmentFile.existsSync()) { + var fragmentFile = packageGraph.resourceProvider.getFile( + pathContext.canonicalize(pathContext.join(dirPath, args['file']))); + if (fragmentFile.exists) { replacement = fragmentFile.readAsStringSync(); if (lang.isNotEmpty) { replacement = replacement.replaceFirst('```', '```$lang'); @@ -234,7 +235,7 @@ mixin CommentProcessable on Documentable, Warnable, Locatable, SourceCodeMixin { // Extract PATH and fix the path separators. var src = results.rest.isEmpty ? '' - : results.rest.first.replaceAll('/', Platform.pathSeparator); + : results.rest.first.replaceAll('/', pathContext.separator); var args = { 'src': src, 'lang': results['lang'], diff --git a/lib/src/model/documentable.dart b/lib/src/model/documentable.dart index 92810d8113..4c63497f41 100644 --- a/lib/src/model/documentable.dart +++ b/lib/src/model/documentable.dart @@ -2,10 +2,9 @@ // 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:io' show File; - +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; -import 'package:dartdoc/src/package_meta.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:path/path.dart' as p; import 'model.dart'; @@ -44,7 +43,10 @@ mixin MarkdownFileDocumentation implements Documentable, Canonicalization { DocumentLocation get documentedWhere; @override - String get documentation => documentationFile?.contents; + String get documentation => documentationFile == null + ? null + : packageGraph.resourceProvider + .readAsMalformedAllowedStringSync(documentationFile); Documentation __documentation; @@ -59,7 +61,10 @@ mixin MarkdownFileDocumentation implements Documentable, Canonicalization { @override bool get hasDocumentation => - documentationFile != null && documentationFile.contents.isNotEmpty; + documentationFile != null && + packageGraph.resourceProvider + .readAsMalformedAllowedStringSync(documentationFile) + .isNotEmpty; @override bool get hasExtendedDocumentation => diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index f571fa03c5..a01f3a5687 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -508,8 +508,8 @@ abstract class ModelElement extends Canonicalization @override DartdocOptionContext get config { - _config ??= - DartdocOptionContext.fromContextElement(packageGraph.config, element); + _config ??= DartdocOptionContext.fromContextElement( + packageGraph.config, element, packageGraph.resourceProvider); return _config; } diff --git a/lib/src/model/package.dart b/lib/src/model/package.dart index de31343afc..a8053e517a 100644 --- a/lib/src/model/package.dart +++ b/lib/src/model/package.dart @@ -2,10 +2,10 @@ // 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:io'; - import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/package_meta.dart'; import 'package:dartdoc/src/warnings.dart'; @@ -111,12 +111,18 @@ class Package extends LibraryContainer @override String get documentation { - return hasDocumentationFile ? documentationFile.contents : null; + return hasDocumentationFile + ? packageGraph.resourceProvider + .readAsMalformedAllowedStringSync(documentationFile) + : null; } @override bool get hasDocumentation => - documentationFile != null && documentationFile.contents.isNotEmpty; + documentationFile != null && + packageGraph.resourceProvider + .readAsMalformedAllowedStringSync(documentationFile) + .isNotEmpty; @override bool get hasExtendedDocumentation => documentation.isNotEmpty; @@ -332,7 +338,9 @@ class Package extends LibraryContainer @override DartdocOptionContext get config { _config ??= DartdocOptionContext.fromContext( - packageGraph.config, Directory(packagePath)); + packageGraph.config, + packageGraph.resourceProvider.getFolder(packagePath), + packageGraph.resourceProvider); return _config; } diff --git a/lib/src/model/package_builder.dart b/lib/src/model/package_builder.dart index 8d90216a79..05337dd74f 100644 --- a/lib/src/model/package_builder.dart +++ b/lib/src/model/package_builder.dart @@ -21,14 +21,14 @@ import 'package:analyzer/src/generated/java_io.dart'; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/generated/source_io.dart'; +import 'package:dartdoc/src/quiver.dart' as quiver; import 'package:analyzer/src/source/package_map_resolver.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/package_meta.dart' - show PackageMeta, pubPackageMetaProvider; -import 'package:dartdoc/src/quiver.dart' as quiver; + show PackageMeta, PackageMetaProvider; import 'package:dartdoc/src/render/renderer_factory.dart'; import 'package:dartdoc/src/special_elements.dart'; import 'package:package_config/discovery.dart' as package_config; @@ -43,8 +43,9 @@ abstract class PackageBuilder { /// A package builder that understands pub package format. class PubPackageBuilder implements PackageBuilder { final DartdocOptionContext config; + final PackageMetaProvider packageMetaProvider; - PubPackageBuilder(this.config); + PubPackageBuilder(this.config, this.packageMetaProvider); @override Future buildPackageGraph() async { @@ -67,7 +68,7 @@ class PubPackageBuilder implements PackageBuilder { sdk, hasEmbedderSdkFiles, rendererFactory, - pubPackageMetaProvider, + packageMetaProvider, ); await getLibraries(newGraph); await newGraph.initializePackageGraph(); @@ -201,6 +202,7 @@ class PubPackageBuilder implements PackageBuilder { /// If [filePath] is not a library, returns null. Future processLibrary(String filePath) async { var name = filePath; + var directoryCurrentPath = config.resourceProvider.pathContext.current; if (name.startsWith(directoryCurrentPath)) { name = name.substring(directoryCurrentPath.length); @@ -243,7 +245,7 @@ class PubPackageBuilder implements PackageBuilder { Set _packageMetasForFiles(Iterable files) { var metas = {}; for (var filename in files) { - metas.add(pubPackageMetaProvider.fromFilename(filename)); + metas.add(packageMetaProvider.fromFilename(filename)); } return metas; } @@ -356,7 +358,8 @@ class PubPackageBuilder implements PackageBuilder { /// therein. Iterable _includeExternalsFrom(Iterable files) sync* { for (var file in files) { - var fileContext = DartdocOptionContext.fromContext(config, File(file)); + var fileContext = DartdocOptionContext.fromContext(config, + config.resourceProvider.getFile(file), config.resourceProvider); if (fileContext.includeExternal != null) { yield* fileContext.includeExternal; } diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index 2870590b7c..4169837181 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/generated/source_io.dart'; @@ -237,6 +238,8 @@ class PackageGraph { /// Map of package name to Package. final Map packageMap = {}; + ResourceProvider get resourceProvider => config.resourceProvider; + final DartSdk sdk; Map _sdkLibrarySources; diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index 7df2de1d13..578014410b 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -5,9 +5,11 @@ library dartdoc.package_meta; import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show Platform, Process; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:path/path.dart' as p; import 'package:yaml/yaml.dart'; @@ -15,13 +17,8 @@ import 'package:yaml/yaml.dart'; import 'logging.dart'; Map _packageMetaCache = {}; -Encoding utf8AllowMalformed = Utf8Codec(allowMalformed: true); -Directory get defaultSdkDir { - var sdkDir = File(Platform.resolvedExecutable).parent.parent; - assert(p.equals(sdkDir.path, PubPackageMeta.sdkDirParent(sdkDir).path)); - return sdkDir; -} +Encoding utf8AllowMalformed = Utf8Codec(allowMalformed: true); class PackageMetaFailure extends DartdocFailure { PackageMetaFailure(String message) : super(message); @@ -39,6 +36,7 @@ final PackageMetaProvider pubPackageMetaProvider = PackageMetaProvider( PubPackageMeta.fromElement, PubPackageMeta.fromFilename, PubPackageMeta.fromDir, + PhysicalResourceProvider.INSTANCE, ); /// Sets the supported way of constructing [PackageMeta] objects. @@ -50,11 +48,20 @@ final PackageMetaProvider pubPackageMetaProvider = PackageMetaProvider( /// By using a different provider, these implementations can control how /// [PackageMeta] objects is built. class PackageMetaProvider { - final PackageMeta Function(LibraryElement, String) fromElement; - final PackageMeta Function(String) fromFilename; - final PackageMeta Function(Directory) fromDir; + final ResourceProvider resourceProvider; + + final PackageMeta Function(LibraryElement, String, ResourceProvider) + _fromElement; + final PackageMeta Function(String, ResourceProvider) _fromFilename; + final PackageMeta Function(Folder, ResourceProvider) _fromDir; + + PackageMeta fromElement(LibraryElement library, String s) => + _fromElement(library, s, resourceProvider); + PackageMeta fromFilename(String s) => _fromFilename(s, resourceProvider); + PackageMeta fromDir(Folder dir) => _fromDir(dir, resourceProvider); - PackageMetaProvider(this.fromElement, this.fromFilename, this.fromDir); + PackageMetaProvider(this._fromElement, this._fromFilename, this._fromDir, + this.resourceProvider); } /// Describes a single package in the context of `dartdoc`. @@ -66,19 +73,23 @@ class PackageMetaProvider { /// Overriding this is typically done by overriding factories as rest of /// `dartdoc` creates this object by calling these static factories. abstract class PackageMeta { - final Directory dir; + final Folder dir; - PackageMeta(this.dir); + final ResourceProvider resourceProvider; + + PackageMeta(this.dir, this.resourceProvider); @override bool operator ==(Object other) { if (other is! PackageMeta) return false; PackageMeta otherMeta = other; - return p.equals(dir.absolute.path, otherMeta.dir.absolute.path); + return resourceProvider.pathContext.equals(dir.path, otherMeta.dir.path); } @override - int get hashCode => p.hash(dir.absolute.path); + int get hashCode => pathContext.hash(pathContext.absolute(dir.path)); + + p.Context get pathContext => resourceProvider.pathContext; /// Returns true if this represents a 'Dart' SDK. A package can be part of /// Dart and Flutter at the same time, but if we are part of a Dart SDK @@ -131,7 +142,8 @@ abstract class PackageMeta { /// Default implementation of [PackageMeta] depends on pub packages. abstract class PubPackageMeta extends PackageMeta { - PubPackageMeta(Directory dir) : super(dir); + PubPackageMeta(Folder dir, ResourceProvider resourceProvider) + : super(dir, resourceProvider); static List> __sdkDirFilePaths; @@ -156,48 +168,58 @@ abstract class PubPackageMeta extends PackageMeta { /// Returns the directory of the SDK if the given directory is inside a Dart /// SDK. Returns null if the directory isn't a subdirectory of the SDK. - static final Map _sdkDirParent = {}; + static final _sdkDirParent = {}; - static Directory sdkDirParent(Directory dir) { + static Folder sdkDirParent(Folder dir, ResourceProvider resourceProvider) { var dirPathCanonical = p.canonicalize(dir.path); if (!_sdkDirParent.containsKey(dirPathCanonical)) { _sdkDirParent[dirPathCanonical] = null; - while (dir.existsSync()) { + while (dir.exists) { if (_sdkDirFilePaths.every((List l) { - return l.any((f) => File(p.join(dir.path, f)).existsSync()); + return l.any((f) => resourceProvider + .getFile(resourceProvider.pathContext.join(dir.path, f)) + .exists); })) { _sdkDirParent[dirPathCanonical] = dir; break; } - if (p.equals(dir.path, dir.parent.path)) break; dir = dir.parent; + if (dir == null) break; } } return _sdkDirParent[dirPathCanonical]; } /// Use this instead of fromDir where possible. - static PubPackageMeta fromElement( - LibraryElement libraryElement, String sdkDir) { + static PubPackageMeta fromElement(LibraryElement libraryElement, + String sdkDir, ResourceProvider resourceProvider) { if (libraryElement.isInSdk) { - return PubPackageMeta.fromDir(Directory(sdkDir)); + return PubPackageMeta.fromDir( + resourceProvider.getFolder(sdkDir), resourceProvider); } return PubPackageMeta.fromDir( - File(p.canonicalize(libraryElement.source.fullName)).parent); + resourceProvider + .getFile(resourceProvider.pathContext + .canonicalize(libraryElement.source.fullName)) + .parent, + resourceProvider); } - static PubPackageMeta fromFilename(String filename) { - return PubPackageMeta.fromDir(File(filename).parent); + static PubPackageMeta fromFilename( + String filename, ResourceProvider resourceProvider) { + return PubPackageMeta.fromDir( + resourceProvider.getFile(filename).parent, resourceProvider); } /// This factory is guaranteed to return the same object for any given /// [dir.absolute.path]. Multiple [dir.absolute.path]s will resolve to the /// same object if they are part of the same package. Returns null /// if the directory is not part of a known package. - static PubPackageMeta fromDir(Directory dir) { - var original = dir.absolute; + static PubPackageMeta fromDir(Folder dir, ResourceProvider resourceProvider) { + var pathContext = resourceProvider.pathContext; + var original = resourceProvider.getFolder(pathContext.absolute(dir.path)); dir = original; - if (!original.existsSync()) { + if (!original.exists) { throw PackageMetaFailure( 'fatal error: unable to locate the input directory at ${original.path}.'); } @@ -205,37 +227,42 @@ abstract class PubPackageMeta extends PackageMeta { if (!_packageMetaCache.containsKey(dir.path)) { PackageMeta packageMeta; // There are pubspec.yaml files inside the SDK. Ignore them. - var parentSdkDir = sdkDirParent(dir); + var parentSdkDir = sdkDirParent(dir, resourceProvider); if (parentSdkDir != null) { - packageMeta = _SdkMeta(parentSdkDir); + packageMeta = _SdkMeta(parentSdkDir, resourceProvider); } else { - while (dir.existsSync()) { - var pubspec = File(p.join(dir.path, 'pubspec.yaml')); - if (pubspec.existsSync()) { - packageMeta = _FilePackageMeta(dir); + while (dir.exists) { + var pubspec = resourceProvider + .getFile(pathContext.join(dir.path, 'pubspec.yaml')); + if (pubspec.exists) { + packageMeta = _FilePackageMeta(dir, resourceProvider); break; } // Allow a package to be at root (possible in a Windows setting with // drive letter mappings). - if (p.equals(dir.path, dir.parent.path)) break; - dir = dir.parent.absolute; + if (dir.parent == null) break; + // TODO(srawlins): or just... `.parent`? + dir = + resourceProvider.getFolder(pathContext.absolute(dir.parent.path)); } } - _packageMetaCache[dir.absolute.path] = packageMeta; + _packageMetaCache[pathContext.absolute(dir.path)] = packageMeta; } - return _packageMetaCache[dir.absolute.path]; + return _packageMetaCache[pathContext.absolute(dir.path)]; } @override String sdkType(String flutterRootPath) { if (flutterRootPath != null) { - var flutterPackages = p.join(flutterRootPath, 'packages'); - var flutterBinCache = p.join(flutterRootPath, 'bin', 'cache'); + var flutterPackages = pathContext.join(flutterRootPath, 'packages'); + var flutterBinCache = pathContext.join(flutterRootPath, 'bin', 'cache'); /// Don't include examples or other non-SDK components as being the /// "Flutter SDK". - if (p.isWithin(flutterPackages, p.canonicalize(dir.absolute.path)) || - p.isWithin(flutterBinCache, p.canonicalize(dir.absolute.path))) { + var canonicalizedDir = pathContext + .canonicalize(resourceProvider.pathContext.absolute(dir.path)); + if (pathContext.isWithin(flutterPackages, canonicalizedDir) || + pathContext.isWithin(flutterBinCache, canonicalizedDir)) { return 'Flutter'; } } @@ -246,24 +273,22 @@ abstract class PubPackageMeta extends PackageMeta { @override String get resolvedDir { - _resolvedDir ??= dir.resolveSymbolicLinksSync(); + _resolvedDir ??= dir.resolveSymbolicLinksSync().path; return _resolvedDir; } } -extension FileContents on File { - String get contents => readAsStringSync(encoding: utf8AllowMalformed); -} - class _FilePackageMeta extends PubPackageMeta { File _readme; File _license; File _changelog; Map _pubspec; - _FilePackageMeta(Directory dir) : super(dir) { - var f = File(p.join(dir.path, 'pubspec.yaml')); - if (f.existsSync()) { + _FilePackageMeta(Folder dir, ResourceProvider resourceProvider) + : super(dir, resourceProvider) { + var f = resourceProvider + .getFile(resourceProvider.pathContext.join(dir.path, 'pubspec.yaml')); + if (f.exists) { _pubspec = loadYaml(f.readAsStringSync()); } else { _pubspec = {}; @@ -286,13 +311,15 @@ class _FilePackageMeta extends PubPackageMeta { // possibly by calculating hosting directly from pubspec.yaml or importing // a pub library to do this. // People could have a pub cache at root with Windows drive mappings. - if (p.split(p.canonicalize(dir.path)).length >= 3) { + if (pathContext.split(pathContext.canonicalize(dir.path)).length >= 3) { var pubCacheRoot = dir.parent.parent.parent.path; - var hosted = p.canonicalize(dir.parent.parent.path); - var hostname = p.canonicalize(dir.parent.path); - if (p.basename(hosted) == 'hosted' && - Directory(p.join(pubCacheRoot, '_temp')).existsSync()) { - _hostedAt = p.basename(hostname); + var hosted = pathContext.canonicalize(dir.parent.parent.path); + var hostname = pathContext.canonicalize(dir.parent.path); + if (pathContext.basename(hosted) == 'hosted' && + resourceProvider + .getFolder(pathContext.join(pubCacheRoot, '_temp')) + .exists) { + _hostedAt = pathContext.basename(hostname); } } } @@ -303,9 +330,9 @@ class _FilePackageMeta extends PubPackageMeta { bool get isSdk => false; @override - bool get needsPubGet => - !(File(p.join(dir.path, '.dart_tool', 'package_config.json')) - .existsSync()); + bool get needsPubGet => !(resourceProvider + .getFile(pathContext.join(dir.path, '.dart_tool', 'package_config.json')) + .exists); @override void runPubGet(String flutterRoot) { @@ -379,8 +406,8 @@ class _FilePackageMeta extends PubPackageMeta { } } -File _locate(Directory dir, List fileNames) { - var files = dir.listSync().whereType().toList(); +File _locate(Folder dir, List fileNames) { + var files = dir.getChildren().whereType().toList(); for (var name in fileNames) { for (var f in files) { @@ -396,8 +423,10 @@ File _locate(Directory dir, List fileNames) { class _SdkMeta extends PubPackageMeta { String sdkReadmePath; - _SdkMeta(Directory dir) : super(dir) { - sdkReadmePath = p.join(dir.path, 'lib', 'api_readme.md'); + _SdkMeta(Folder dir, ResourceProvider resourceProvider) + : super(dir, resourceProvider) { + sdkReadmePath = + resourceProvider.pathContext.join(dir.path, 'lib', 'api_readme.md'); } @override @@ -416,8 +445,9 @@ class _SdkMeta extends PubPackageMeta { @override String get version { - var versionFile = File(p.join(dir.path, 'version')); - if (versionFile.existsSync()) return versionFile.readAsStringSync().trim(); + var versionFile = resourceProvider + .getFile(resourceProvider.pathContext.join(dir.path, 'version')); + if (versionFile.exists) return versionFile.readAsStringSync().trim(); return 'unknown'; } @@ -434,11 +464,13 @@ class _SdkMeta extends PubPackageMeta { @override File getReadmeContents() { - var f = File(p.join(dir.path, 'lib', 'api_readme.md')); - if (!f.existsSync()) { - f = File(p.join(dir.path, 'api_readme.md')); + var f = resourceProvider.getFile( + resourceProvider.pathContext.join(dir.path, 'lib', 'api_readme.md')); + if (!f.exists) { + f = resourceProvider.getFile( + resourceProvider.pathContext.join(dir.path, 'api_readme.md')); } - return f.existsSync() ? f : null; + return f.exists ? f : null; } @override diff --git a/lib/src/source_linker.dart b/lib/src/source_linker.dart index f4dafdbf9a..4bfd715042 100644 --- a/lib/src/source_linker.dart +++ b/lib/src/source_linker.dart @@ -5,6 +5,7 @@ /// A library for getting external source code links for Dartdoc. library dartdoc.source_linker; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:meta/meta.dart'; @@ -29,22 +30,23 @@ abstract class SourceLinkerOptionContext implements DartdocOptionContextBase { optionSet['linkToSource']['uriTemplate'].valueAt(context); } -Future>> createSourceLinkerOptions() async { +Future>> createSourceLinkerOptions( + ResourceProvider resourceProvider) async { return [ - DartdocOptionSet('linkToSource') + DartdocOptionSet('linkToSource', resourceProvider) ..addAll([ - DartdocOptionArgFile>('excludes', [], + DartdocOptionArgFile>('excludes', [], resourceProvider, isDir: true, help: 'A list of directories to exclude from linking to a source code repository.'), // TODO(jcollins-g): Use [DartdocOptionArgSynth], possibly in combination with a repository type and the root directory, and get revision number automatically - DartdocOptionArgOnly('revision', null, + DartdocOptionArgOnly('revision', null, resourceProvider, help: 'Revision number to insert into the URI.'), - DartdocOptionArgFile('root', null, + DartdocOptionArgFile('root', null, resourceProvider, isDir: true, help: 'Path to a local directory that is the root of the repository we link to. All source code files under this directory will be linked.'), - DartdocOptionArgFile('uriTemplate', null, + DartdocOptionArgFile('uriTemplate', null, resourceProvider, help: '''Substitute into this template to generate a uri for an element's source code. Dartdoc dynamically substitutes the following fields into the template: diff --git a/lib/src/tool_runner.dart b/lib/src/tool_runner.dart index b8f7d5374f..c835ac7688 100644 --- a/lib/src/tool_runner.dart +++ b/lib/src/tool_runner.dart @@ -5,10 +5,11 @@ library dartdoc.tool_runner; import 'dart:async'; -import 'dart:io'; +import 'dart:io' show Process, ProcessException; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/io_utils.dart'; -import 'package:path/path.dart' as path; +import 'package:path/path.dart' as p; import 'dartdoc_options.dart'; typedef ToolErrorCallback = void Function(String message); @@ -23,31 +24,37 @@ final MultiFutureTracker _toolTracker = MultiFutureTracker(4); /// /// This will remove any temporary files created by the tool runner. class ToolTempFileTracker { - final Directory temporaryDirectory; + final ResourceProvider resourceProvider; + final Folder temporaryDirectory; - ToolTempFileTracker._() + ToolTempFileTracker._(this.resourceProvider) : temporaryDirectory = - Directory.systemTemp.createTempSync('dartdoc_tools_'); + resourceProvider.createSystemTemp('dartdoc_tools_'); static ToolTempFileTracker _instance; - static ToolTempFileTracker get instance => - _instance ??= ToolTempFileTracker._(); + static ToolTempFileTracker get instance => _instance; + + static ToolTempFileTracker createInstance( + ResourceProvider resourceProvider) => + _instance ??= ToolTempFileTracker._(resourceProvider); int _temporaryFileCount = 0; Future createTemporaryFile() async { _temporaryFileCount++; - var tempFile = File(path.join( - temporaryDirectory.absolute.path, 'input_$_temporaryFileCount')); - await tempFile.create(recursive: true); + // TODO(srawlins): Assume [temporaryDirectory]'s path is always absolute. + var tempFile = resourceProvider.getFile(resourceProvider.pathContext.join( + resourceProvider.pathContext.absolute(temporaryDirectory.path), + 'input_$_temporaryFileCount')); + await tempFile.writeAsStringSync(''); return tempFile; } /// Call once no more files are to be created. Future dispose() async { - if (temporaryDirectory.existsSync()) { - return temporaryDirectory.delete(recursive: true); + if (temporaryDirectory.exists) { + return temporaryDirectory.delete(); } } } @@ -73,7 +80,7 @@ class ToolRunner { String commandPath; if (isDartSetup) { - commandPath = Platform.resolvedExecutable; + commandPath = toolConfiguration.resourceProvider.resolvedExecutable; } else { commandPath = args.removeAt(0); } @@ -95,8 +102,8 @@ class ToolRunner { await Process.run(commandPath, args, environment: environment); if (result.exitCode != 0) { toolErrorCallback('Tool "$name" returned non-zero exit code ' - '(${result.exitCode}) when run as ' - '"${commandString()}" from ${Directory.current}\n' + '(${result.exitCode}) when run as "${commandString()}" from ' + '${pathContext.current}\n' 'Input to $name was:\n' '$content\n' 'Stderr output was:\n${result.stderr}\n'); @@ -155,14 +162,16 @@ class ToolRunner { // file before running the tool synchronously. // Write the content to a temp file. - var tmpFile = await ToolTempFileTracker.instance.createTemporaryFile(); - await tmpFile.writeAsString(content); + var tmpFile = await ToolTempFileTracker.createInstance( + toolConfiguration.resourceProvider) + .createTemporaryFile(); + tmpFile.writeAsStringSync(content); // Substitute the temp filename for the "$INPUT" token, and all of the other // environment variables. Variables are allowed to either be in $(VAR) form, // or $VAR form. var envWithInput = { - 'INPUT': tmpFile.absolute.path, + 'INPUT': pathContext.absolute(tmpFile.path), 'TOOL_COMMAND': toolDefinition.command[0], ...environment, }; @@ -173,8 +182,10 @@ class ToolRunner { // script writer can use this instead of Platform.script if they want to // find out where their script was coming from as an absolute path on the // filesystem. - envWithInput['DART_SNAPSHOT_CACHE'] = - SnapshotCache.instance.snapshotCache.absolute.path; + envWithInput['DART_SNAPSHOT_CACHE'] = pathContext.absolute( + SnapshotCache.createInstance(toolConfiguration.resourceProvider) + .snapshotCache + .path); if (toolDefinition.setupCommand != null) { envWithInput['DART_SETUP_COMMAND'] = toolDefinition.setupCommand[0]; } @@ -216,4 +227,6 @@ class ToolRunner { envWithInput, toolErrorCallback); } } + + p.Context get pathContext => toolConfiguration.resourceProvider.pathContext; } diff --git a/lib/src/warnings.dart b/lib/src/warnings.dart index ade343e762..ef564d6464 100644 --- a/lib/src/warnings.dart +++ b/lib/src/warnings.dart @@ -2,9 +2,8 @@ // 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:io'; - import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/model.dart'; @@ -26,8 +25,9 @@ abstract class PackageWarningOptionContext implements DartdocOptionContextBase { Future>> createPackageWarningOptions( PackageMetaProvider packageMetaProvider, ) async { + var resourceProvider = packageMetaProvider.resourceProvider; return [ - DartdocOptionArgOnly('allowNonLocalWarnings', false, + DartdocOptionArgOnly('allowNonLocalWarnings', false, resourceProvider, negatable: true, help: 'Show warnings from packages we are not documenting locally.'), @@ -35,43 +35,48 @@ Future>> createPackageWarningOptions( // for individual packages are command-line only. This will allow // meta-packages like Flutter to control whether warnings are displayed for // packages they don't control. - DartdocOptionArgOnly>('allowWarningsInPackages', null, + DartdocOptionArgOnly>( + 'allowWarningsInPackages', null, resourceProvider, help: 'Package names to display warnings for (ignore all others if set).'), - DartdocOptionArgOnly>('allowErrorsInPackages', null, + DartdocOptionArgOnly>( + 'allowErrorsInPackages', null, resourceProvider, help: 'Package names to display errors for (ignore all others if set)'), - DartdocOptionArgOnly>('ignoreWarningsInPackages', null, - help: - 'Package names to ignore warnings for. Takes priority over allow-warnings-in-packages'), - DartdocOptionArgOnly>('ignoreErrorsInPackages', null, - help: - 'Package names to ignore errors for. Takes priority over allow-errors-in-packages'), + DartdocOptionArgOnly>( + 'ignoreWarningsInPackages', null, resourceProvider, + help: 'Package names to ignore warnings for. Takes priority over ' + 'allow-warnings-in-packages'), + DartdocOptionArgOnly>( + 'ignoreErrorsInPackages', null, resourceProvider, + help: 'Package names to ignore errors for. Takes priority over ' + 'allow-errors-in-packages'), // Options for globally enabling/disabling warnings and errors across // packages. Loaded from dartdoc_options.yaml, but command line arguments // will override. - DartdocOptionArgFile>('errors', null, - help: - 'Additional warning names to force as errors. Specify an empty list to force defaults (overriding dartdoc_options.yaml)\nDefaults:\n' + - (packageWarningDefinitions.values - .where((d) => - d.defaultWarningMode == PackageWarningMode.error) - .toList() - ..sort()) - .map((d) => ' ${d.warningName}: ${d.shortHelp}') - .join('\n')), - DartdocOptionArgFile>('ignore', null, - help: - 'Additional warning names to ignore. Specify an empty list to force defaults (overriding dartdoc_options.yaml).\nDefaults:\n' + - (packageWarningDefinitions.values - .where((d) => - d.defaultWarningMode == PackageWarningMode.ignore) - .toList() - ..sort()) - .map((d) => ' ${d.warningName}: ${d.shortHelp}') - .join('\n')), - DartdocOptionArgFile>('warnings', null, + DartdocOptionArgFile>('errors', null, resourceProvider, + help: 'Additional warning names to force as errors. Specify an empty ' + 'list to force defaults (overriding dartdoc_options.yaml)\nDefaults:\n' + + (packageWarningDefinitions.values + .where( + (d) => d.defaultWarningMode == PackageWarningMode.error) + .toList() + ..sort()) + .map((d) => ' ${d.warningName}: ${d.shortHelp}') + .join('\n')), + DartdocOptionArgFile>('ignore', null, resourceProvider, + help: 'Additional warning names to ignore. Specify an empty list to ' + 'force defaults (overriding dartdoc_options.yaml).\nDefaults:\n' + + (packageWarningDefinitions.values + .where((d) => + d.defaultWarningMode == PackageWarningMode.ignore) + .toList() + ..sort()) + .map((d) => ' ${d.warningName}: ${d.shortHelp}') + .join('\n')), + DartdocOptionArgFile>('warnings', null, resourceProvider, help: - 'Additional warning names to show as warnings (instead of error or ignore, if not warning by default).\nDefaults:\n' + + 'Additional warning names to show as warnings (instead of error or ' + 'ignore, if not warning by default).\nDefaults:\n' + (packageWarningDefinitions.values .where((d) => d.defaultWarningMode == PackageWarningMode.warn) @@ -82,8 +87,9 @@ Future>> createPackageWarningOptions( // Synthetic option uses a factory to build a PackageWarningOptions from all the above flags. DartdocOptionSyntheticOnly( 'packageWarningOptions', - (DartdocSyntheticOption option, Directory dir) => + (DartdocSyntheticOption option, Folder dir) => PackageWarningOptions.fromOptions(option, dir, packageMetaProvider), + resourceProvider, ), ]; } @@ -317,10 +323,9 @@ class PackageWarningOptions { } } - /// [packageMeta] parameter is for testing. static PackageWarningOptions fromOptions( DartdocSyntheticOption option, - Directory dir, + Folder dir, PackageMetaProvider packageMetaProvider, ) { // First, initialize defaults. diff --git a/test/dartdoc_options_test.dart b/test/dartdoc_options_test.dart index 3054ef6782..1d8a63959e 100644 --- a/test/dartdoc_options_test.dart +++ b/test/dartdoc_options_test.dart @@ -4,9 +4,10 @@ library dartdoc.options_test; -import 'dart:io'; - +import 'package:analyzer/file_system/file_system.dart'; +import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; @@ -18,10 +19,10 @@ class ConvertedOption { ConvertedOption._(this.param1, this.param2, this.myContextPath); - static ConvertedOption fromYamlMap(YamlMap yamlMap, path.Context context) { + static ConvertedOption fromYamlMap(YamlMap yamlMap, String canonicalYamlPath, + ResourceProvider resourceProvider) { String p1; String p2; - var contextPath = context.current; for (var entry in yamlMap.entries) { switch (entry.key.toString()) { @@ -33,20 +34,22 @@ class ConvertedOption { break; } } - return ConvertedOption._(p1, p2, contextPath); + return ConvertedOption._(p1, p2, canonicalYamlPath); } } void main() { + var resourceProvider = pubPackageMetaProvider.resourceProvider; + DartdocOptionSet dartdocOptionSetFiles; DartdocOptionSet dartdocOptionSetArgs; DartdocOptionSet dartdocOptionSetAll; DartdocOptionSet dartdocOptionSetSynthetic; - Directory tempDir; - Directory firstDir; - Directory secondDir; - Directory secondDirFirstSub; - Directory secondDirSecondSub; + Folder tempDir; + Folder firstDir; + Folder secondDir; + Folder secondDirFirstSub; + Folder secondDirSecondSub; File dartdocOptionsOne; File dartdocOptionsTwo; @@ -54,118 +57,145 @@ void main() { File firstExisting; setUpAll(() { - dartdocOptionSetSynthetic = DartdocOptionSet('dartdoc'); - dartdocOptionSetSynthetic - .add(DartdocOptionArgFile('mySpecialInteger', 91)); + dartdocOptionSetSynthetic = DartdocOptionSet('dartdoc', resourceProvider); + dartdocOptionSetSynthetic.add( + DartdocOptionArgFile('mySpecialInteger', 91, resourceProvider)); dartdocOptionSetSynthetic.add( DartdocOptionSyntheticOnly>('vegetableLoader', - (DartdocSyntheticOption> option, Directory dir) { + (DartdocSyntheticOption> option, Folder dir) { if (option.root['mySpecialInteger'].valueAt(dir) > 20) { return ['existing.dart']; } else { return ['not_existing.dart']; } - })); + }, resourceProvider)); dartdocOptionSetSynthetic.add( DartdocOptionSyntheticOnly>('vegetableLoaderChecked', - (DartdocSyntheticOption> option, Directory dir) { + (DartdocSyntheticOption> option, Folder dir) { return option.root['vegetableLoader'].valueAt(dir); - }, isFile: true, mustExist: true)); + }, resourceProvider, isFile: true, mustExist: true)); dartdocOptionSetSynthetic.add(DartdocOptionFileSynth('double', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { return 3.7 + 4.1; - })); + }, resourceProvider)); dartdocOptionSetSynthetic.add( DartdocOptionArgSynth('nonCriticalFileOption', - (DartdocSyntheticOption option, Directory dir) { + (DartdocSyntheticOption option, Folder dir) { return option.root['vegetableLoader'].valueAt(dir).first; - }, isFile: true)); + }, resourceProvider, isFile: true)); - dartdocOptionSetFiles = DartdocOptionSet('dartdoc'); - dartdocOptionSetFiles - .add(DartdocOptionFileOnly>('categoryOrder', [])); - dartdocOptionSetFiles.add(DartdocOptionFileOnly('double', 3.0)); + dartdocOptionSetFiles = DartdocOptionSet('dartdoc', resourceProvider); + dartdocOptionSetFiles.add(DartdocOptionFileOnly>( + 'categoryOrder', [], resourceProvider)); dartdocOptionSetFiles - .add(DartdocOptionFileOnly('mySpecialInteger', 42)); + .add(DartdocOptionFileOnly('double', 3.0, resourceProvider)); + dartdocOptionSetFiles.add( + DartdocOptionFileOnly('mySpecialInteger', 42, resourceProvider)); dartdocOptionSetFiles.add(DartdocOptionFileOnly>( - 'mapOption', {'hello': 'world'})); + 'mapOption', {'hello': 'world'}, resourceProvider)); dartdocOptionSetFiles.add(DartdocOptionFileOnly>( - 'fileOptionList', [], + 'fileOptionList', [], resourceProvider, isFile: true, mustExist: true)); - dartdocOptionSetFiles.add(DartdocOptionFileOnly('fileOption', null, + dartdocOptionSetFiles.add(DartdocOptionFileOnly( + 'fileOption', null, resourceProvider, isFile: true, mustExist: true)); dartdocOptionSetFiles.add(DartdocOptionFileOnly( - 'parentOverride', 'oops', + 'parentOverride', 'oops', resourceProvider, parentDirOverridesChild: true)); dartdocOptionSetFiles.add(DartdocOptionFileOnly( - 'nonCriticalFileOption', null, + 'nonCriticalFileOption', null, resourceProvider, isFile: true)); - dartdocOptionSetFiles.add(DartdocOptionSet('nestedOption') - ..addAll([DartdocOptionFileOnly('flag', false)])); - dartdocOptionSetFiles.add(DartdocOptionFileOnly('dirOption', null, + dartdocOptionSetFiles.add(DartdocOptionSet('nestedOption', resourceProvider) + ..addAll([DartdocOptionFileOnly('flag', false, resourceProvider)])); + dartdocOptionSetFiles.add(DartdocOptionFileOnly( + 'dirOption', null, resourceProvider, isDir: true, mustExist: true)); dartdocOptionSetFiles.add(DartdocOptionFileOnly( - 'nonCriticalDirOption', null, + 'nonCriticalDirOption', null, resourceProvider, isDir: true)); dartdocOptionSetFiles.add(DartdocOptionFileOnly( 'convertThisMap', null, + resourceProvider, convertYamlToType: ConvertedOption.fromYamlMap, )); - dartdocOptionSetArgs = DartdocOptionSet('dartdoc'); - dartdocOptionSetArgs - .add(DartdocOptionArgOnly('cauliflowerSystem', false)); - dartdocOptionSetArgs - .add(DartdocOptionArgOnly('extraSpecial', 'something')); - dartdocOptionSetArgs.add( - DartdocOptionArgOnly>('excludeFiles', ['one', 'two'])); - dartdocOptionSetArgs - .add(DartdocOptionArgOnly('number_of_heads', 3, abbr: 'h')); - dartdocOptionSetArgs - .add(DartdocOptionArgOnly('respawnProbability', 0.2)); - dartdocOptionSetArgs.add(DartdocOptionSet('warn') - ..addAll([DartdocOptionArgOnly('unrecognizedVegetable', false)])); + dartdocOptionSetArgs = DartdocOptionSet('dartdoc', resourceProvider); + dartdocOptionSetArgs.add(DartdocOptionArgOnly( + 'cauliflowerSystem', false, resourceProvider)); + dartdocOptionSetArgs.add(DartdocOptionArgOnly( + 'extraSpecial', 'something', resourceProvider)); + dartdocOptionSetArgs.add(DartdocOptionArgOnly>( + 'excludeFiles', ['one', 'two'], resourceProvider)); + dartdocOptionSetArgs.add(DartdocOptionArgOnly( + 'number_of_heads', 3, resourceProvider, + abbr: 'h')); + dartdocOptionSetArgs.add(DartdocOptionArgOnly( + 'respawnProbability', 0.2, resourceProvider)); + dartdocOptionSetArgs.add(DartdocOptionSet('warn', resourceProvider) + ..addAll([ + DartdocOptionArgOnly( + 'unrecognizedVegetable', false, resourceProvider) + ])); dartdocOptionSetArgs.add(DartdocOptionArgOnly>( - 'aFancyMapVariable', {'hello': 'map world'}, + 'aFancyMapVariable', {'hello': 'map world'}, resourceProvider, splitCommas: true)); - dartdocOptionSetArgs.add(DartdocOptionArgOnly>('filesFlag', [], + dartdocOptionSetArgs.add(DartdocOptionArgOnly>( + 'filesFlag', [], resourceProvider, isFile: true, mustExist: true)); - dartdocOptionSetArgs.add(DartdocOptionArgOnly('singleFile', 'hello', + dartdocOptionSetArgs.add(DartdocOptionArgOnly( + 'singleFile', 'hello', resourceProvider, isFile: true, mustExist: true)); dartdocOptionSetArgs.add(DartdocOptionArgOnly( - 'unimportantFile', 'whatever', + 'unimportantFile', 'whatever', resourceProvider, isFile: true)); - dartdocOptionSetAll = DartdocOptionSet('dartdoc'); - dartdocOptionSetAll - .add(DartdocOptionArgFile>('categoryOrder', [])); - dartdocOptionSetAll.add(DartdocOptionArgFile('mySpecialInteger', 91)); - dartdocOptionSetAll.add(DartdocOptionSet('warn') - ..addAll([DartdocOptionArgFile('unrecognizedVegetable', false)])); + dartdocOptionSetAll = DartdocOptionSet('dartdoc', resourceProvider); + dartdocOptionSetAll.add(DartdocOptionArgFile>( + 'categoryOrder', [], resourceProvider)); + dartdocOptionSetAll.add( + DartdocOptionArgFile('mySpecialInteger', 91, resourceProvider)); + dartdocOptionSetAll.add(DartdocOptionSet('warn', resourceProvider) + ..addAll([ + DartdocOptionArgFile( + 'unrecognizedVegetable', false, resourceProvider) + ])); dartdocOptionSetAll.add(DartdocOptionArgFile>( - 'mapOption', {'hi': 'there'})); - dartdocOptionSetAll - .add(DartdocOptionArgFile('notInAnyFile', 'so there')); - dartdocOptionSetAll.add(DartdocOptionArgFile('fileOption', null, + 'mapOption', {'hi': 'there'}, resourceProvider)); + dartdocOptionSetAll.add(DartdocOptionArgFile( + 'notInAnyFile', 'so there', resourceProvider)); + dartdocOptionSetAll.add(DartdocOptionArgFile( + 'fileOption', null, resourceProvider, isFile: true, mustExist: true)); - tempDir = Directory.systemTemp.createTempSync('options_test'); - firstDir = Directory(path.join(tempDir.path, 'firstDir'))..createSync(); - firstExisting = File(path.join(firstDir.path, 'existing.dart')) - ..createSync(); - secondDir = Directory(path.join(tempDir.path, 'secondDir'))..createSync(); - File(path.join(secondDir.path, 'existing.dart'))..createSync(); - - secondDirFirstSub = Directory(path.join(secondDir.path, 'firstSub')) - ..createSync(); - secondDirSecondSub = Directory(path.join(secondDir.path, 'secondSub')) - ..createSync(); - - dartdocOptionsOne = File(path.join(firstDir.path, 'dartdoc_options.yaml')); - dartdocOptionsTwo = File(path.join(secondDir.path, 'dartdoc_options.yaml')); - dartdocOptionsTwoFirstSub = - File(path.join(secondDirFirstSub.path, 'dartdoc_options.yaml')); + tempDir = resourceProvider.createSystemTemp('options_test'); + firstDir = resourceProvider + .getFolder(resourceProvider.pathContext.join(tempDir.path, 'firstDir')) + ..create(); + firstExisting = resourceProvider.getFile( + resourceProvider.pathContext.join(firstDir.path, 'existing.dart')) + ..writeAsStringSync(''); + secondDir = resourceProvider + .getFolder(resourceProvider.pathContext.join(tempDir.path, 'secondDir')) + ..create(); + resourceProvider.getFile( + resourceProvider.pathContext.join(secondDir.path, 'existing.dart')) + ..writeAsStringSync(''); + + secondDirFirstSub = resourceProvider.getFolder( + resourceProvider.pathContext.join(secondDir.path, 'firstSub')) + ..create(); + secondDirSecondSub = resourceProvider.getFolder( + resourceProvider.pathContext.join(secondDir.path, 'secondSub')) + ..create(); + + dartdocOptionsOne = resourceProvider.getFile(resourceProvider.pathContext + .join(firstDir.path, 'dartdoc_options.yaml')); + dartdocOptionsTwo = resourceProvider.getFile(resourceProvider.pathContext + .join(secondDir.path, 'dartdoc_options.yaml')); + dartdocOptionsTwoFirstSub = resourceProvider.getFile(resourceProvider + .pathContext + .join(secondDirFirstSub.path, 'dartdoc_options.yaml')); dartdocOptionsOne.writeAsStringSync(''' dartdoc: @@ -202,7 +232,7 @@ dartdoc: }); tearDownAll(() { - tempDir.deleteSync(recursive: true); + tempDir.delete(); }); group('new style synthetic option', () { @@ -230,10 +260,15 @@ dartdoc: } on DartdocFileMissing catch (e) { errorMessage = e.message; } + var missingPath = resourceProvider.pathContext.canonicalize( + resourceProvider.pathContext.join( + resourceProvider.pathContext.absolute(tempDir.path), + 'existing.dart')); expect( errorMessage, - equals( - 'Synthetic configuration option vegetableLoaderChecked from , computed as [existing.dart], resolves to missing path: "${path.canonicalize(path.join(tempDir.absolute.path, 'existing.dart'))}"')); + equals('Synthetic configuration option vegetableLoaderChecked from ' + ', computed as [existing.dart], resolves to missing ' + 'path: "$missingPath"')); }); test('file can override synthetic in FileSynth', () { @@ -249,8 +284,7 @@ dartdoc: // Since this is an ArgSynth, it ignores the yaml option and resolves to the CWD expect( dartdocOptionSetSynthetic['nonCriticalFileOption'].valueAt(firstDir), - equals(path - .canonicalize(path.join(Directory.current.path, 'stuff.zip')))); + equals(resourceProvider.pathContext.canonicalize('stuff.zip'))); }); test('ArgSynth defaults to synthetic', () { @@ -274,10 +308,14 @@ dartdoc: } on DartdocFileMissing catch (e) { errorMessage = e.message; } + var missingPath = resourceProvider.pathContext.join( + resourceProvider.pathContext + .canonicalize(resourceProvider.pathContext.current), + 'override-not-existing.dart'); expect( errorMessage, - equals( - 'Argument --file-option, set to override-not-existing.dart, resolves to missing path: "${path.join(path.canonicalize(Directory.current.path), "override-not-existing.dart")}"')); + equals('Argument --file-option, set to override-not-existing.dart, ' + 'resolves to missing path: "$missingPath"')); }); test('validate argument can override missing file', () { @@ -367,18 +405,21 @@ dartdoc: } on DartdocFileMissing catch (e) { errorMessage = e.message; } + var missingPath = resourceProvider.pathContext.join( + resourceProvider.pathContext + .canonicalize(resourceProvider.pathContext.current), + 'not_found.txt'); expect( errorMessage, - equals( - 'Argument --single-file, set to not_found.txt, resolves to missing path: ' - '"${path.join(path.canonicalize(Directory.current.path), 'not_found.txt')}"')); + equals('Argument --single-file, set to not_found.txt, resolves to ' + 'missing path: "$missingPath"')); }); test('DartdocOptionArgOnly checks file existence on multi-options', () { String errorMessage; dartdocOptionSetArgs.parseArguments([ '--files-flag', - firstExisting.absolute.path, + resourceProvider.pathContext.absolute(firstExisting.path), '--files-flag', 'other_not_found.txt' ]); @@ -387,11 +428,16 @@ dartdoc: } on DartdocFileMissing catch (e) { errorMessage = e.message; } + var missingPath = resourceProvider.pathContext.join( + resourceProvider.pathContext + .canonicalize(resourceProvider.pathContext.current), + 'other_not_found.txt'); expect( errorMessage, - equals( - 'Argument --files-flag, set to [${firstExisting.absolute.path}, other_not_found.txt], resolves to missing path: ' - '"${path.join(path.canonicalize(Directory.current.path), "other_not_found.txt")}"')); + equals('Argument --files-flag, set to ' + '[${resourceProvider.pathContext.absolute(firstExisting.path)}, ' + 'other_not_found.txt], resolves to missing path: ' + '"$missingPath"')); }); test( @@ -401,7 +447,9 @@ dartdoc: .parseArguments(['--unimportant-file', 'this-will-never-exist']); expect( dartdocOptionSetArgs['unimportantFile'].valueAt(tempDir), - equals(path.join(path.canonicalize(Directory.current.path), + equals(resourceProvider.pathContext.join( + resourceProvider.pathContext + .canonicalize(resourceProvider.pathContext.current), 'this-will-never-exist'))); }); diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index fac044c10f..d466973b7c 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -5,9 +5,11 @@ library dartdoc.dartdoc_test; import 'dart:async'; -import 'dart:io'; +import 'dart:io' show Platform; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/dartdoc.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/tuple.dart'; @@ -17,67 +19,86 @@ import 'package:test/test.dart'; import 'src/utils.dart'; -final Directory _testPackageDir = Directory('testing/test_package'); - -final _testPackageBadDir = Directory('testing/test_package_bad'); -final _testPackageMinimumDir = Directory('testing/test_package_minimum'); -final _testSkyEnginePackage = Directory('testing/sky_engine'); -final _testPackageWithNoReadme = Directory('testing/test_package_small'); -final _testPackageIncludeExclude = - Directory('testing/test_package_include_exclude'); -final _testPackageImportExportError = - Directory('testing/test_package_import_export_error'); -final _testPackageOptions = Directory('testing/test_package_options'); -final _testPackageOptionsImporter = - Directory('testing/test_package_options_importer'); +final _resourceProvider = pubPackageMetaProvider.resourceProvider; +final _pathContext = _resourceProvider.pathContext; + +Folder _getFolder(String p) => _resourceProvider + .getFolder(_pathContext.absolute(_pathContext.canonicalize(p))); + +final _testPackageDir = _getFolder('testing/test_package'); + +final Folder _testPackageBadDir = _getFolder('testing/test_package_bad'); +final Folder _testPackageMinimumDir = + _getFolder('testing/test_package_minimum'); +final Folder _testSkyEnginePackage = _getFolder('testing/sky_engine'); +final Folder _testPackageWithNoReadme = + _getFolder('testing/test_package_small'); +final Folder _testPackageIncludeExclude = + _getFolder('testing/test_package_include_exclude'); +final Folder _testPackageImportExportError = + _getFolder('testing/test_package_import_export_error'); +final Folder _testPackageOptions = _getFolder('testing/test_package_options'); +final Folder _testPackageOptionsImporter = + _getFolder('testing/test_package_options_importer'); final _testPackageCustomTemplates = - Directory('testing/test_package_custom_templates'); + _getFolder('testing/test_package_custom_templates'); /// Convenience factory to build a [DartdocGeneratorOptionContext] and associate /// it with a [DartdocOptionSet] based on the current working directory and/or /// the '--input' flag. Future _generatorContextFromArgv( List argv) async { - var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ - () => createDartdocOptions(pubPackageMetaProvider), - createGeneratorOptions, - ]); + var optionSet = await DartdocOptionSet.fromOptionGenerators( + 'dartdoc', + [ + createDartdocOptions, + createGeneratorOptions, + ], + pubPackageMetaProvider); optionSet.parseArguments(argv); - return DartdocGeneratorOptionContext(optionSet, null); + return DartdocGeneratorOptionContext( + optionSet, null, pubPackageMetaProvider.resourceProvider); } class DartdocLoggingOptionContext extends DartdocGeneratorOptionContext with LoggingContext { - DartdocLoggingOptionContext(DartdocOptionSet optionSet, Directory dir) - : super(optionSet, dir); + DartdocLoggingOptionContext( + DartdocOptionSet optionSet, Folder dir, ResourceProvider resourceProvider) + : super(optionSet, dir, resourceProvider); } void main() { group('dartdoc with generators', () { - Directory tempDir; + var resourceProvider = pubPackageMetaProvider.resourceProvider; + Folder tempDir; setUpAll(() async { + //resourceProvider = MemoryResourceProvider(); var optionSet = await DartdocOptionSet.fromOptionGenerators( - 'dartdoc', [createLoggingOptions]); + 'dartdoc', [createLoggingOptions], pubPackageMetaProvider); optionSet.parseArguments([]); - startLogging(DartdocLoggingOptionContext(optionSet, Directory.current)); + startLogging(DartdocLoggingOptionContext( + optionSet, + resourceProvider.getFolder(resourceProvider.pathContext.current), + resourceProvider)); }); setUp(() async { - tempDir = Directory.systemTemp.createTempSync('dartdoc.test.'); + tempDir = resourceProvider.createSystemTemp('dartdoc.test.'); }); tearDown(() async { - tempDir.deleteSync(recursive: true); + tempDir.delete(); }); Future buildDartdoc( - List argv, Directory packageRoot, Directory tempDir) async { + List argv, Folder packageRoot, Folder tempDir) async { var context = await _generatorContextFromArgv(argv ..addAll(['--input', packageRoot.path, '--output', tempDir.path])); + return await Dartdoc.fromContext( context, - PubPackageBuilder(context), + PubPackageBuilder(context, pubPackageMetaProvider), ); } @@ -85,19 +106,20 @@ void main() { Dartdoc dartdoc; DartdocResults results; PackageGraph p; - Directory tempDir; + Folder tempDir; setUpAll(() async { - tempDir = Directory.systemTemp.createTempSync('dartdoc.test.'); + tempDir = resourceProvider.createSystemTemp('dartdoc.test.'); dartdoc = await buildDartdoc([], _testPackageOptions, tempDir); results = await dartdoc.generateDocsBase(); p = results.packageGraph; }); test('generator parameters', () async { - var favicon = - File(path.joinAll([tempDir.path, 'static-assets', 'favicon.png'])); - var index = File(path.joinAll([tempDir.path, 'index.html'])); + var favicon = resourceProvider.getFile(resourceProvider.pathContext + .joinAll([tempDir.path, 'static-assets', 'favicon.png'])); + var index = resourceProvider.getFile( + resourceProvider.pathContext.joinAll([tempDir.path, 'index.html'])); expect(favicon.readAsStringSync(), contains('Not really a png, but a test file')); var indexString = index.readAsStringSync(); @@ -145,10 +167,10 @@ void main() { group('Option handling with cross-linking', () { DartdocResults results; Package testPackageOptions; - Directory tempDir; + Folder tempDir; setUpAll(() async { - tempDir = Directory.systemTemp.createTempSync('dartdoc.test.'); + tempDir = resourceProvider.createSystemTemp('dartdoc.test.'); results = await (await buildDartdoc( ['--link-to-remote'], _testPackageOptionsImporter, tempDir)) .generateDocsBase(); @@ -259,10 +281,10 @@ void main() { group('validate basic doc generation', () { Dartdoc dartdoc; DartdocResults results; - Directory tempDir; + Folder tempDir; setUpAll(() async { - tempDir = Directory.systemTemp.createTempSync('dartdoc.test.'); + tempDir = resourceProvider.createSystemTemp('dartdoc.test.'); dartdoc = await buildDartdoc([], _testPackageDir, tempDir); results = await dartdoc.generateDocs(); }); @@ -284,13 +306,15 @@ void main() { test('source code links are visible', () async { // Picked this object as this library explicitly should never contain // a library directive, so we can predict what line number it will be. - var anonymousOutput = File(path.join(tempDir.path, 'anonymous_library', - 'anonymous_library-library.html')); - expect(anonymousOutput.existsSync(), isTrue); + var anonymousOutput = resourceProvider.getFile( + resourceProvider.pathContext.join(tempDir.path, 'anonymous_library', + 'anonymous_library-library.html')); + expect(anonymousOutput.exists, isTrue); expect( anonymousOutput.readAsStringSync(), - contains( - r'description')); + contains(r'' + 'description')); }); }); @@ -397,7 +421,8 @@ void main() { expect(p.defaultPackage.name, 'test_package_custom_templates'); expect(p.localPublicLibraries, hasLength(1)); - var index = File(path.join(tempDir.path, 'index.html')); + var index = resourceProvider.getFile( + resourceProvider.pathContext.join(tempDir.path, 'index.html')); expect(index.readAsStringSync(), contains('Welcome my friends to a custom template')); }); @@ -440,14 +465,16 @@ void main() { await dartdoc.generateDocsBase(); // Verify files at different levels have correct content. - var level1 = File(path.join(tempDir.path, 'ex', 'Apple-class.html')); - expect(level1.existsSync(), isTrue); + var level1 = resourceProvider.getFile(resourceProvider.pathContext + .join(tempDir.path, 'ex', 'Apple-class.html')); + expect(level1.exists, isTrue); expect( level1.readAsStringSync(), contains( '')); - var level2 = File(path.join(tempDir.path, 'ex', 'Apple', 'm.html')); - expect(level2.existsSync(), isTrue); + var level2 = resourceProvider.getFile(resourceProvider.pathContext + .join(tempDir.path, 'ex', 'Apple', 'm.html')); + expect(level2.exists, isTrue); expect(level2.readAsStringSync(), contains('')); }); diff --git a/test/html_generator_test.dart b/test/html_generator_test.dart index 567fa3accd..0a55d1c217 100644 --- a/test/html_generator_test.dart +++ b/test/html_generator_test.dart @@ -4,14 +4,14 @@ library dartdoc.html_generator_test; -import 'dart:io' show File, FileSystemEntity, Directory; - +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/generator/generator_frontend.dart'; import 'package:dartdoc/src/generator/html_generator.dart'; import 'package:dartdoc/src/generator/html_resources.g.dart'; import 'package:dartdoc/src/generator/templates.dart'; import 'package:dartdoc/src/model/package_graph.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/warnings.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -75,54 +75,58 @@ void main() { }); group('HtmlGenerator', () { + Generator generator; + var resourceProvider = pubPackageMetaProvider.resourceProvider; + var pathContext = resourceProvider.pathContext; + Folder tempOutput; + FileWriter writer; + // TODO: Run the HtmlGenerator and validate important constraints. group('for a null package', () { - Generator generator; - Directory tempOutput; - FileWriter writer; - setUp(() async { generator = await _initGeneratorForTest(); - tempOutput = Directory.systemTemp.createTempSync('doc_test_temp'); - writer = DartdocFileWriter(tempOutput.path); + tempOutput = resourceProvider.createSystemTemp('doc_test_temp'); + writer = DartdocFileWriter(tempOutput.path, resourceProvider); return generator.generate(null, writer); }); tearDown(() { if (tempOutput != null) { - tempOutput.deleteSync(recursive: true); + tempOutput.delete(); } }); test('resources are put into the right place', () { - var output = Directory(path.join(tempOutput.path, 'static-assets')); + var output = resourceProvider + .getFolder(pathContext.join(tempOutput.path, 'static-assets')); expect(output, doesExist); for (var resource in resource_names.map((r) => path.relative(Uri.parse(r).path, from: 'dartdoc/resources'))) { - expect(File(path.join(output.path, resource)), doesExist); + expect( + resourceProvider.getFile(pathContext.join(output.path, resource)), + doesExist); } }); }); group('for a package that causes duplicate files', () { - Generator generator; PackageGraph packageGraph; - Directory tempOutput; - FileWriter writer; - var testPackageDuplicateDir = Directory('testing/test_package_duplicate'); + var testPackageDuplicateDir = resourceProvider.getFolder( + pathContext.absolute( + pathContext.canonicalize('testing/test_package_duplicate'))); setUp(() async { generator = await _initGeneratorForTest(); - packageGraph = - await utils.bootBasicPackage(testPackageDuplicateDir.path, []); - tempOutput = await Directory.systemTemp.createTemp('doc_test_temp'); - writer = DartdocFileWriter(tempOutput.path); + packageGraph = await utils.bootBasicPackage( + testPackageDuplicateDir.path, [], pubPackageMetaProvider); + tempOutput = await resourceProvider.createSystemTemp('doc_test_temp'); + writer = DartdocFileWriter(tempOutput.path, resourceProvider); }); tearDown(() { if (tempOutput != null) { - tempOutput.deleteSync(recursive: true); + tempOutput.delete(); } }); @@ -145,14 +149,13 @@ const Matcher doesExist = _DoesExist(); class _DoesExist extends Matcher { const _DoesExist(); @override - bool matches(dynamic item, Map matchState) => - (item as FileSystemEntity).existsSync(); + bool matches(dynamic item, Map matchState) => (item as Resource).exists; @override Description describe(Description description) => description.add('exists'); @override Description describeMismatch(dynamic item, Description mismatchDescription, Map matchState, bool verbose) { - if (item is! File && item is! Directory) { + if (item is! File && item is! Folder) { return mismatchDescription .addDescriptionOf(item) .add('is not a file or directory'); diff --git a/test/model_special_cases_test.dart b/test/model_special_cases_test.dart index 73b80b7a0a..3000bc24c8 100644 --- a/test/model_special_cases_test.dart +++ b/test/model_special_cases_test.dart @@ -12,7 +12,9 @@ import 'dart:io'; import 'package:async/async.dart'; import 'package:dartdoc/dartdoc.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/model/model.dart'; +import 'package:dartdoc/src/package_meta.dart'; import 'package:dartdoc/src/special_elements.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -25,7 +27,8 @@ final Version _platformVersion = Version.parse(_platformVersionString); final _testPackageGraphExperimentsMemo = AsyncMemoizer(); Future get _testPackageGraphExperiments => _testPackageGraphExperimentsMemo.runOnce(() => utils.bootBasicPackage( - 'testing/test_package_experiments', [], additionalArguments: [ + 'testing/test_package_experiments', [], pubPackageMetaProvider, + additionalArguments: [ '--enable-experiment', 'non-nullable', '--no-link-to-remote' @@ -34,11 +37,10 @@ Future get _testPackageGraphExperiments => final _testPackageGraphGinormousMemo = AsyncMemoizer(); Future get _testPackageGraphGinormous => _testPackageGraphGinormousMemo.runOnce(() => utils.bootBasicPackage( - 'testing/test_package', [ - 'css', - 'code_in_commnets', - 'excluded' - ], additionalArguments: [ + 'testing/test_package', + ['css', 'code_in_commnets', 'excluded'], + pubPackageMetaProvider, + additionalArguments: [ '--auto-include-dependencies', '--no-link-to-remote' ])); @@ -46,7 +48,7 @@ Future get _testPackageGraphGinormous => final _testPackageGraphSmallMemo = AsyncMemoizer(); Future get _testPackageGraphSmall => _testPackageGraphSmallMemo.runOnce(() => utils.bootBasicPackage( - 'testing/test_package_small', [], + 'testing/test_package_small', [], pubPackageMetaProvider, additionalArguments: ['--no-link-to-remote'])); final _testPackageGraphSdkMemo = AsyncMemoizer(); @@ -55,12 +57,16 @@ Future get _testPackageGraphSdk => Future _bootSdkPackage() async { return PubPackageBuilder( - await utils.contextFromArgv(['--input', defaultSdkDir.path])) + await utils.contextFromArgv([ + '--input', + pubPackageMetaProvider.resourceProvider.defaultSdkDir.path + ], pubPackageMetaProvider), + pubPackageMetaProvider) .buildPackageGraph(); } void main() { - var sdkDir = defaultSdkDir; + var sdkDir = pubPackageMetaProvider.resourceProvider.defaultSdkDir; if (sdkDir == null) { print('Warning: unable to locate the Dart SDK.'); @@ -256,7 +262,9 @@ void main() { setUpAll(() async { injectionPackageGraph = await utils.bootBasicPackage( - 'testing/test_package', ['css', 'code_in_comments', 'excluded'], + 'testing/test_package', + ['css', 'code_in_comments', 'excluded'], + pubPackageMetaProvider, additionalArguments: ['--inject-html']); injectionExLibrary = diff --git a/test/model_test.dart b/test/model_test.dart index 88c37b5e21..7d70c12413 100644 --- a/test/model_test.dart +++ b/test/model_test.dart @@ -8,6 +8,7 @@ import 'dart:io'; import 'package:async/async.dart'; import 'package:dartdoc/dartdoc.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/render/category_renderer.dart'; import 'package:dartdoc/src/render/enum_field_renderer.dart'; @@ -23,7 +24,9 @@ import 'src/utils.dart' as utils; final _testPackageGraphMemo = AsyncMemoizer(); Future get _testPackageGraph => _testPackageGraphMemo.runOnce(() => utils.bootBasicPackage( - 'testing/test_package', ['css', 'code_in_comments'], + 'testing/test_package', + ['css', 'code_in_comments'], + pubPackageMetaProvider, additionalArguments: ['--no-link-to-remote'])); /// For testing sort behavior. @@ -56,7 +59,7 @@ class TestLibraryContainerSdk extends TestLibraryContainer { } void main() { - var sdkDir = defaultSdkDir; + var sdkDir = pubPackageMetaProvider.resourceProvider.defaultSdkDir; if (sdkDir == null) { print('Warning: unable to locate the Dart SDK.'); diff --git a/test/package_meta_test.dart b/test/package_meta_test.dart index 4e4295a0f2..377bf198e9 100644 --- a/test/package_meta_test.dart +++ b/test/package_meta_test.dart @@ -4,18 +4,18 @@ library dartdoc.package_utils_test; -import 'dart:io'; - +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/package_meta.dart'; -import 'package:path/path.dart' as path; import 'package:test/test.dart'; void main() { + var resourceProvider = pubPackageMetaProvider.resourceProvider; + group('PackageMeta for a directory without a pubspec', () { PackageMeta p; setUp(() { - var d = Directory.systemTemp.createTempSync('test_package_not_valid'); + var d = resourceProvider.createSystemTemp('test_package_not_valid'); p = pubPackageMetaProvider.fromDir(d); }); @@ -25,17 +25,27 @@ void main() { }); group('PackageMeta for the test package', () { - var p = pubPackageMetaProvider.fromDir(Directory( - path.join(Directory.current.path, 'testing', 'test_package'))); + PackageMeta p; + + setUp(() { + p = pubPackageMetaProvider.fromDir(resourceProvider.getFolder( + resourceProvider.pathContext.join( + resourceProvider.pathContext.current, + 'testing', + 'test_package'))); + }); test('readme with corrupt UTF-8 loads without throwing', () { - expect(p.getReadmeContents().contents, + expect( + resourceProvider + .readAsMalformedAllowedStringSync(p.getReadmeContents()), contains('Here is some messed up UTF-8.\nÐf')); }); }); group('PackageMeta.fromDir for this package', () { - var p = pubPackageMetaProvider.fromDir(Directory.current); + var p = pubPackageMetaProvider.fromDir( + resourceProvider.getFolder(resourceProvider.pathContext.current)); test('has a name', () { expect(p.name, 'dartdoc'); @@ -64,25 +74,31 @@ void main() { test('has a readme', () { expect(p.getReadmeContents(), isNotNull); expect( - p.getReadmeContents().contents, + resourceProvider + .readAsMalformedAllowedStringSync(p.getReadmeContents()), contains( 'Use `dartdoc` to generate HTML documentaton for your Dart package.')); }); test('has a license', () { expect(p.getLicenseContents(), isNotNull); - expect(p.getLicenseContents().contents, + expect( + resourceProvider + .readAsMalformedAllowedStringSync(p.getLicenseContents()), contains('Copyright 2014, the Dart project authors.')); }); test('has a changelog', () { expect(p.getChangelogContents(), isNotNull); - expect(p.getChangelogContents().contents, contains('## 0.2.2')); + expect( + resourceProvider + .readAsMalformedAllowedStringSync(p.getChangelogContents()), + contains('## 0.2.2')); }); }); group('PackageMeta.fromSdk', () { - var p = pubPackageMetaProvider.fromDir(defaultSdkDir); + var p = pubPackageMetaProvider.fromDir(resourceProvider.defaultSdkDir); test('has a name', () { expect(p.name, 'Dart'); @@ -111,7 +127,10 @@ void main() { test('has a readme', () { expect(p.getReadmeContents(), isNotNull); - expect(p.getReadmeContents().contents, startsWith('Welcome')); + expect( + resourceProvider + .readAsMalformedAllowedStringSync(p.getReadmeContents()), + startsWith('Welcome')); }); test('does not have a license', () { diff --git a/test/src/utils.dart b/test/src/utils.dart index 6628fe9074..58334b29ae 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -5,10 +5,10 @@ library test_utils; import 'dart:async'; -import 'dart:io'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:dartdoc/dartdoc.dart'; -import 'package:dartdoc/src/model/model.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/package_meta.dart'; /// The number of public libraries in testing/test_package, minus 2 for @@ -16,33 +16,44 @@ import 'package:dartdoc/src/package_meta.dart'; /// and minus 1 for the tag in the 'excluded' library. const int kTestPackagePublicLibraries = 17; -final Directory testPackageToolError = - Directory('testing/test_package_tool_error'); +final _resourceProvider = pubPackageMetaProvider.resourceProvider; +final _pathContext = _resourceProvider.pathContext; + +final Folder testPackageToolError = _resourceProvider.getFolder(_pathContext + .absolute(_pathContext.normalize('testing/test_package_tool_error'))); /// Convenience factory to build a [DartdocOptionContext] and associate it with a /// [DartdocOptionSet] based on the current working directory. -Future contextFromArgv(List argv) async { - var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ - () => createDartdocOptions(pubPackageMetaProvider), - ]); +Future contextFromArgv( + List argv, PackageMetaProvider packageMetaProvider) async { + var resourceProvider = packageMetaProvider.resourceProvider; + var optionSet = await DartdocOptionSet.fromOptionGenerators( + 'dartdoc', [createDartdocOptions], packageMetaProvider); optionSet.parseArguments(argv); - return DartdocOptionContext(optionSet, Directory.current); + return DartdocOptionContext( + optionSet, + resourceProvider.getFolder(resourceProvider.pathContext.current), + pubPackageMetaProvider.resourceProvider); } -Future bootBasicPackage( - String dirPath, List excludeLibraries, +Future bootBasicPackage(String dirPath, + List excludeLibraries, PackageMetaProvider packageMetaProvider, {List additionalArguments}) async { - var dir = Directory(dirPath); + var resourceProvider = packageMetaProvider.resourceProvider; + var dir = resourceProvider.getFolder(resourceProvider.pathContext + .absolute(resourceProvider.pathContext.normalize(dirPath))); additionalArguments ??= []; - return PubPackageBuilder(await contextFromArgv([ + return PubPackageBuilder( + await contextFromArgv([ '--input', dir.path, '--sdk-dir', - defaultSdkDir.path, + resourceProvider.defaultSdkDir.path, '--exclude', excludeLibraries.join(','), '--allow-tools', - ] + - additionalArguments)) + ...additionalArguments, + ], packageMetaProvider), + packageMetaProvider) .buildPackageGraph(); } diff --git a/test/tool_runner_test.dart b/test/tool_runner_test.dart index d378acdd5e..34ac28a5d5 100644 --- a/test/tool_runner_test.dart +++ b/test/tool_runner_test.dart @@ -6,6 +6,7 @@ library dartdoc.model_test; import 'dart:io'; +import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/tool_runner.dart'; import 'package:path/path.dart' as path; @@ -36,7 +37,8 @@ void main() { '--snapshot-kind=app-jit', 'bin/drill.dart' ], - workingDirectory: _testPackageDir.absolute.path); + workingDirectory: pubPackageMetaProvider.resourceProvider.pathContext + .absolute(_testPackageDir.path)); } on ProcessException catch (exception) { stderr.writeln('Unable to make snapshot of tool: $exception'); expect(result?.exitCode, equals(0)); @@ -73,8 +75,11 @@ echo: windows: ['C:\\Windows\\System32\\cmd.exe', '/c', 'echo'] description: 'Works on everything' '''; - var pathContext = path.Context(current: _testPackageDir.absolute.path); - toolMap = ToolConfiguration.fromYamlMap(loadYaml(yamlMap), pathContext); + toolMap = ToolConfiguration.fromYamlMap( + loadYaml(yamlMap), + pubPackageMetaProvider.resourceProvider.pathContext + .absolute(_testPackageDir.path), + pubPackageMetaProvider.resourceProvider); // This shouldn't really happen, but if you didn't load the config from a // yaml map (which would fail on a missing executable), or a file is deleted // during execution,it might, so we test it. @@ -88,7 +93,7 @@ echo: tearDownAll(() { tempDir?.deleteSync(recursive: true); tracker?.dispose(); - SnapshotCache.instance.dispose(); + SnapshotCache.instance?.dispose(); setupFile = null; tempDir = null; }); diff --git a/test/unit/comment_processable_test.dart b/test/unit/comment_processable_test.dart index 7aafa2445c..15e3a4ca34 100644 --- a/test/unit/comment_processable_test.dart +++ b/test/unit/comment_processable_test.dart @@ -2,9 +2,9 @@ // 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:io' show Directory; - import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/model/model.dart'; @@ -320,10 +320,10 @@ End text.''')); /// /// End text. '''); - verify(processor.packageGraph.warnOnElement( - processor, PackageWarning.missingExampleFile, - message: - '${p.join(_projectRoot, 'abc.md')}; path listed at a.dart')) + verify(processor.packageGraph + .warnOnElement(processor, PackageWarning.missingExampleFile, + message: '${p.canonicalize(p.join(_projectRoot, 'abc.md'))}; ' + 'path listed at a.dart')) .called(1); // When the example path is invalid, the directive should be left in-place. expect(doc, equals(''' @@ -346,7 +346,8 @@ End text.''')); verify(processor.packageGraph.warnOnElement( processor, PackageWarning.missingExampleFile, message: - '${p.join(_projectRoot, 'abc', 'def', 'ghi.md')}; path listed at a.dart')) + '${p.canonicalize(p.join(_projectRoot, 'abc', 'def', 'ghi.md'))}; ' + 'path listed at a.dart')) .called(1); // When the example path is invalid, the directive should be left in-place. expect(doc, equals(''' @@ -366,10 +367,10 @@ End text.''')); /// /// End text. '''); - verify(processor.packageGraph.warnOnElement( - processor, PackageWarning.missingExampleFile, - message: - '${p.join(_projectRoot, '.', 'abc-r.md')}; path listed at a.dart')) + verify(processor.packageGraph + .warnOnElement(processor, PackageWarning.missingExampleFile, + message: '${p.canonicalize(p.join(_projectRoot, 'abc-r.md'))}; ' + 'path listed at a.dart')) .called(1); // When the example path is invalid, the directive should be left in-place. expect(doc, equals(''' @@ -564,6 +565,7 @@ class _Processor extends __Processor with CommentProcessable { .thenReturn(''); when(modelElementRenderer.renderAnimation(any, any, any, any, any)) .thenReturn(''); + when(packageGraph.resourceProvider).thenReturn(MemoryResourceProvider()); } @override @@ -573,11 +575,11 @@ class _Processor extends __Processor with CommentProcessable { message: message, referredFrom: referredFrom); } -class _FakeDirectory extends Fake implements Directory { +class _FakeFolder extends Fake implements Folder { @override final String path; - _FakeDirectory() : path = _projectRoot; + _FakeFolder() : path = _projectRoot; } class _MockModelElementRenderer extends Mock implements ModelElementRenderer {} @@ -594,9 +596,9 @@ class _FakePackage extends Fake implements Package { class _FakePackageMeta extends Fake implements PackageMeta { @override - final Directory dir; + final Folder dir; - _FakePackageMeta() : dir = _FakeDirectory(); + _FakePackageMeta() : dir = _FakeFolder(); } class _FakeElement extends Fake implements Element { diff --git a/test/warnings_test.dart b/test/warnings_test.dart index fc14061663..b4db31ee41 100644 --- a/test/warnings_test.dart +++ b/test/warnings_test.dart @@ -5,33 +5,39 @@ /// Unit tests for lib/src/warnings.dart. library dartdoc.warnings_test; -import 'dart:io'; - +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/package_meta.dart'; import 'package:dartdoc/src/warnings.dart'; -import 'package:path/path.dart' as path; import 'package:test/test.dart'; void main() { - Directory tempDir, testPackageOne, testPackageTwo, testPackageThree; + ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; + Folder tempDir, testPackageOne, testPackageTwo, testPackageThree; File pubspecYamlOne, pubspecYamlTwo, pubspecYamlThree, dartdocYamlThree; DartdocOptionSet optionSet; setUpAll(() { - tempDir = Directory.systemTemp.createTempSync('warnings_test'); - testPackageOne = Directory(path.join(tempDir.path, 'test_package_one')) - ..createSync(); - testPackageTwo = Directory(path.join(tempDir.path, 'test_package_two')) - ..createSync(); - testPackageThree = Directory(path.join(tempDir.path, 'test_package_three')) - ..createSync(); - pubspecYamlOne = File(path.join(testPackageOne.path, 'pubspec.yaml')); + tempDir = resourceProvider.createSystemTemp('warnings_test'); + testPackageOne = resourceProvider.getFolder( + resourceProvider.pathContext.join(tempDir.path, 'test_package_one')) + ..create(); + testPackageTwo = resourceProvider.getFolder( + resourceProvider.pathContext.join(tempDir.path, 'test_package_two')) + ..create(); + testPackageThree = resourceProvider.getFolder( + resourceProvider.pathContext.join(tempDir.path, 'test_package_three')) + ..create(); + pubspecYamlOne = resourceProvider.getFile( + resourceProvider.pathContext.join(testPackageOne.path, 'pubspec.yaml')); pubspecYamlOne.writeAsStringSync('name: test_package_one'); - pubspecYamlTwo = File(path.join(testPackageTwo.path, 'pubspec.yaml')); + pubspecYamlTwo = resourceProvider.getFile( + resourceProvider.pathContext.join(testPackageTwo.path, 'pubspec.yaml')); pubspecYamlTwo.writeAsStringSync('name: test_package_two'); - dartdocYamlThree = - File(path.join(testPackageThree.path, 'dartdoc_options.yaml')); + dartdocYamlThree = resourceProvider.getFile(resourceProvider.pathContext + .join(testPackageThree.path, 'dartdoc_options.yaml')); dartdocYamlThree.writeAsStringSync(''' dartdoc: warnings: @@ -42,13 +48,14 @@ dartdoc: ignore: - ambiguous-reexport '''); - pubspecYamlThree = File(path.join(testPackageThree.path, 'pubspec.yaml')); + pubspecYamlThree = resourceProvider.getFile(resourceProvider.pathContext + .join(testPackageThree.path, 'pubspec.yaml')); pubspecYamlThree.writeAsStringSync('name: test_package_three'); }); setUp(() async { optionSet = await DartdocOptionSet.fromOptionGenerators( - 'dartdoc', [() => createDartdocOptions(pubPackageMetaProvider)]); + 'dartdoc', [createDartdocOptions], pubPackageMetaProvider); }); test('Verify that options for enabling/disabling packages work', () { diff --git a/tool/grind.dart b/tool/grind.dart index bb0e98a8b2..19bd395657 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:io' hide ProcessException; +import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/package_meta.dart'; import 'package:grinder/grinder.dart'; @@ -823,7 +824,9 @@ Future _buildPubPackageDocs( var pubPackageDir = Directory.systemTemp.createTempSync(pubPackageName); await copyPath(pubPackageDirOrig.path, pubPackageDir.path); - if (packageMetaProvider.fromDir(pubPackageDir).requiresFlutter) { + if (packageMetaProvider + .fromDir(PhysicalResourceProvider.INSTANCE.getFolder(pubPackageDir.path)) + .requiresFlutter) { var flutterRepo = await FlutterRepo.fromExistingFlutterRepo(await cleanFlutterRepo); await launcher.runStreamed(flutterRepo.cachePub, ['get'], @@ -1033,7 +1036,9 @@ Future testDart2(Iterable tests) async { [...parameters, dartFile.path])); } - return CoverageSubprocessLauncher.generateCoverageToFile(File('lcov.info')); + return CoverageSubprocessLauncher.generateCoverageToFile( + PhysicalResourceProvider.INSTANCE.getFile('lcov.info'), + PhysicalResourceProvider.INSTANCE); } @Task('Generate docs for dartdoc without link-to-remote') diff --git a/tool/subprocess_launcher.dart b/tool/subprocess_launcher.dart index 31c81c2ef5..9c9ac5d64f 100644 --- a/tool/subprocess_launcher.dart +++ b/tool/subprocess_launcher.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:analyzer/file_system/file_system.dart'; import 'package:path/path.dart' as p; /// Keeps track of coverage data automatically for any processes run by this @@ -43,7 +44,8 @@ class CoverageSubprocessLauncher extends SubprocessLauncher { /// Call once all coverage runs have been generated by calling runStreamed /// on all [CoverageSubprocessLaunchers]. - static Future generateCoverageToFile(File outputFile) async { + static Future generateCoverageToFile( + File outputFile, ResourceProvider resourceProvider) async { if (!coverageEnabled) return Future.value(null); var currentCoverageResults = coverageResults; coverageResults = [];