diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index 90cf481a8c..8204b8b80d 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -43,8 +43,8 @@ main(List arguments) async { exit(0); } - Directory sdkDir = getSdkDir(); - final bool sdkDocs = args['sdk-docs']; + Directory sdkDir = new Directory(args['sdk-dir']); + bool sdkDocs = args['sdk-docs']; final bool showProgress = args['show-progress']; Directory inputDir; @@ -56,6 +56,14 @@ main(List arguments) async { inputDir = args['input']; } + // If our input directory looks like the Dart SDK, then assume it is one, + // and is the one we want to document against. + PackageMeta packageMeta = new PackageMeta.fromDir(inputDir); + if (packageMeta.isSdk) { + sdkDir = inputDir; + sdkDocs = true; + } + List footerTextFilePaths = []; // If we're generating docs for the Dart SDK, we insert a copyright footer. if (sdkDocs) { @@ -142,8 +150,6 @@ main(List arguments) async { }); } - PackageMeta packageMeta = new PackageMeta.fromDir(inputDir); - if (packageMeta == null) { stderr.writeln( ' fatal error: Unable to generate documentation: no pubspec.yaml found'); @@ -249,104 +255,108 @@ main(List arguments) async { ArgParser _createArgsParser() { var parser = new ArgParser(); - parser.addFlag('help', - abbr: 'h', negatable: false, help: 'Show command help.'); - parser.addFlag('version', - help: 'Display the version for $name.', negatable: false); parser.addFlag('add-crossdart', help: 'Add Crossdart links to the source code pieces.', negatable: false, defaultsTo: false); - parser.addFlag('sdk-docs', - help: 'Generate ONLY the docs for the Dart SDK.', negatable: false); - parser.addFlag('show-warnings', - help: 'Display warnings.', negatable: false, defaultsTo: false); - parser.addFlag('show-progress', - help: 'Display progress indications to console stdout', negatable: false); - parser.addOption('sdk-readme', - help: 'Path to the SDK description file. Deprecated (ignored)'); - parser.addOption('input', help: 'Path to source directory.'); - parser.addOption('output', - help: 'Path to output directory.', defaultsTo: defaultOutDir); - parser.addMultiOption('header', - splitCommas: true, help: 'paths to header files containing HTML text.'); + parser.addOption('ambiguous-reexport-scorer-min-confidence', + help: + 'Minimum scorer confidence to suppress warning on ambiguous reexport.', + defaultsTo: '0.1', + hide: true); + parser.addFlag('auto-include-dependencies', + help: + 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', + negatable: false, + defaultsTo: false); + parser.addMultiOption('category-order', + help: + 'A list of package names to place first when grouping libraries in packages. ' + 'Unmentioned categories are sorted after these. (deprecated, replaced by package-order)', + splitCommas: true); + parser.addOption('example-path-prefix', + help: 'Prefix for @example paths.\n(defaults to the project root)'); + parser.addMultiOption('exclude', + splitCommas: true, help: 'Library names to ignore.'); + parser.addMultiOption('exclude-packages', + splitCommas: true, help: 'Package names to ignore.'); + parser.addOption('favicon', + help: 'A path to a favicon for the generated docs.'); parser.addMultiOption('footer', splitCommas: true, help: 'paths to footer files containing HTML text.'); parser.addMultiOption('footer-text', splitCommas: true, help: 'paths to footer-text files ' '(optional text next to the package name and version).'); - parser.addMultiOption('exclude', - splitCommas: true, help: 'Library names to ignore.'); - parser.addMultiOption('exclude-packages', - splitCommas: true, help: 'Package names to ignore.'); + parser.addMultiOption('header', + splitCommas: true, help: 'paths to header files containing HTML text.'); + parser.addFlag('help', + abbr: 'h', negatable: false, help: 'Show command help.'); + parser.addFlag('hide-sdk-text', + help: + 'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.', + negatable: true, + defaultsTo: false, + hide: true); + parser.addOption('hosted-url', + help: + 'URL where the docs will be hosted (used to generate the sitemap).'); parser.addMultiOption('include', splitCommas: true, help: 'Library names to generate docs for.'); parser.addMultiOption('include-external', help: 'Additional (external) dart files to include; use "dir/fileName", ' 'as in lib/material.dart.'); - parser.addOption('hosted-url', - help: - 'URL where the docs will be hosted (used to generate the sitemap).'); - parser.addOption('example-path-prefix', - help: 'Prefix for @example paths.\n(defaults to the project root)'); - parser.addOption('rel-canonical-prefix', - help: 'If provided, add a rel="canonical" prefixed with provided value. ' - 'Consider using if\nbuilding many versions of the docs for public ' - 'SEO; learn more at https://goo.gl/gktN6F.'); parser.addFlag('include-source', help: 'Show source code blocks.', negatable: true, defaultsTo: true); - parser.addOption('favicon', - help: 'A path to a favicon for the generated docs.'); - parser.addFlag('use-categories', - help: - 'Group libraries from the same package in the libraries sidebar. (deprecated, ignored)', - negatable: false, - defaultsTo: false); - parser.addMultiOption('category-order', - help: - 'A list of package names to place first when grouping libraries in packages. ' - 'Unmentioned categories are sorted after these. (deprecated, replaced by package-order)', - splitCommas: true); + parser.addOption('input', help: 'Path to source directory.'); + parser.addFlag('json', + help: 'Prints out progress JSON maps. One entry per line.', + defaultsTo: false, + negatable: true); + parser.addOption('output', + help: 'Path to output directory.', defaultsTo: defaultOutDir); parser.addMultiOption('package-order', help: 'A list of package names to place first when grouping libraries in packages. ' 'Unmentioned categories are sorted after these.', splitCommas: true); - parser.addFlag('auto-include-dependencies', - help: - 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', - negatable: false, - defaultsTo: false); parser.addFlag('pretty-index-json', help: "Generates `index.json` with indentation and newlines. The file is larger, but it's also easier to diff.", negatable: false, defaultsTo: false); - parser.addOption('ambiguous-reexport-scorer-min-confidence', - help: - 'Minimum scorer confidence to suppress warning on ambiguous reexport.', - defaultsTo: "0.1", - hide: true); - parser.addFlag('verbose-warnings', - help: 'Display extra debugging information and help with warnings.', - negatable: true, - defaultsTo: true); - parser.addFlag('hide-sdk-text', + parser.addOption('rel-canonical-prefix', + help: 'If provided, add a rel="canonical" prefixed with provided value. ' + 'Consider using if\nbuilding many versions of the docs for public ' + 'SEO; learn more at https://goo.gl/gktN6F.'); + parser.addFlag('sdk-docs', + help: 'Generate ONLY the docs for the Dart SDK.', negatable: false); + parser.addOption('sdk-readme', + help: 'Path to the SDK description file. Deprecated (ignored)'); + parser.addOption('sdk-dir', + help: 'Path to the SDK directory', + defaultsTo: defaultSdkDir.absolute.path); + parser.addFlag('show-warnings', + help: 'Display warnings.', negatable: false, defaultsTo: false); + parser.addFlag('show-progress', + help: 'Display progress indications to console stdout', negatable: false); + parser.addFlag('use-categories', help: - "Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.", - negatable: true, - defaultsTo: false, - hide: true); - parser.addFlag('json', - help: 'Prints out progress JSON maps. One entry per line.', - defaultsTo: false, - negatable: true); + 'Group libraries from the same package in the libraries sidebar. (deprecated, ignored)', + negatable: false, + defaultsTo: false); parser.addFlag('validate-links', help: 'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)', negatable: true, defaultsTo: true); + parser.addFlag('verbose-warnings', + help: 'Display extra debugging information and help with warnings.', + negatable: true, + defaultsTo: true); + parser.addFlag('version', + help: 'Display the version for $name.', negatable: false); + return parser; } diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 67ec6f3503..13e5796d9e 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -32,7 +32,6 @@ export 'src/element_type.dart'; export 'src/generator.dart'; export 'src/model.dart'; export 'src/package_meta.dart'; -export 'src/sdk.dart'; const String name = 'dartdoc'; // Update when pubspec version changes. diff --git a/lib/src/config.dart b/lib/src/config.dart index 69f99dd1b6..f32c4cade4 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -6,12 +6,9 @@ library dartdoc.config; import 'dart:io'; -import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:path/path.dart' as pathLib; -import 'model.dart'; - String _resolveTildePath(String originalPath) { if (originalPath == null || !originalPath.startsWith('~/')) { return originalPath; @@ -28,18 +25,6 @@ String _resolveTildePath(String originalPath) { return pathLib.join(homeDir, originalPath.substring(2)); } -/// Class representing values possibly local to a particular [ModelElement]. -class LocalConfig { - final Map> categoryMap; - final PackageMeta packageMeta; - - LocalConfig._(this.categoryMap, this.packageMeta); - - factory LocalConfig.fromLibrary(LibraryElement element) { - return new LocalConfig._({}, new PackageMeta.fromElement(element)); - } -} - class DartDocConfig { final bool addCrossdart; final bool autoIncludeDependencies; @@ -167,7 +152,7 @@ class DartDocConfig { prettyIndexJson, reexportMinConfidence, relCanonicalPrefix, - sdkDir ?? getSdkDir(), + sdkDir ?? defaultSdkDir, sdkVersion, showWarnings, validateLinks, diff --git a/lib/src/model.dart b/lib/src/model.dart index c67101225a..f2ce7bc009 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -2048,7 +2048,7 @@ class Library extends ModelElement with Categorization { PackageMeta _packageMeta; PackageMeta get packageMeta { if (_packageMeta == null) { - _packageMeta = new PackageMeta.fromElement(element); + _packageMeta = new PackageMeta.fromElement(element, config); } return _packageMeta; } @@ -3768,7 +3768,7 @@ class PackageGraph extends Canonicalization // Build [Library] objects, and link them to [Package]s. libraryElements.forEach((element) { - var packageMeta = new PackageMeta.fromElement(element); + var packageMeta = new PackageMeta.fromElement(element, config); var lib = new Library._( element, this, new Package.fromPackageMeta(packageMeta, this)); packageMap[packageMeta.name]._libraries.add(lib); @@ -4552,7 +4552,7 @@ class PackageGraph extends Canonicalization e.library, this, new Package.fromPackageMeta( - new PackageMeta.fromElement(e.library), packageGraph)); + new PackageMeta.fromElement(e.library, config), packageGraph)); allLibraries[e.library] = foundLibrary; } return foundLibrary; @@ -5407,7 +5407,7 @@ class PackageBuilder { if (library != null) { if (!config.isLibraryExcluded(Library.getLibraryName(library)) && !config.excludePackages - .contains(new PackageMeta.fromElement(library)?.name)) { + .contains(new PackageMeta.fromElement(library, config)?.name)) { libraries.add(library); sources.add(source); } diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index 2dbe86ad9d..e14411cb77 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -8,7 +8,6 @@ import 'dart:io'; import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/dartdoc.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:path/path.dart' as pathLib; import 'package:yaml/yaml.dart'; @@ -16,15 +15,61 @@ import 'logging.dart'; Map _packageMetaCache = {}; +Directory get defaultSdkDir { + Directory sdkDir = new File(Platform.resolvedExecutable).parent.parent; + assert(pathLib.equals(sdkDir.path, PackageMeta.sdkDirParent(sdkDir).path)); + return sdkDir; +} + class PackageMetaFailure extends DartDocFailure { PackageMetaFailure(String message) : super(message); } +/// For each list in this list, at least one of the given paths must exist +/// for this to be detected as an SDK. +final List> __sdkDirFilePathsPosix = [ + ['bin/dart.bat', 'bin/dart.exe', 'bin/dart'], + ['bin/pub.bat', 'bin/pub'], + ['lib/core/core.dart'], +]; + abstract class PackageMeta { final Directory dir; PackageMeta(this.dir); + static List> get _sdkDirFilePaths { + List> platformSdkDirFilePaths = []; + if (Platform.isWindows) { + for (List paths in __sdkDirFilePathsPosix) { + List windowsPaths = []; + for (String path in paths) { + windowsPaths.add(pathLib.joinAll( + new pathLib.Context(style: pathLib.Style.posix).split(path))); + } + platformSdkDirFilePaths.add(windowsPaths); + } + } else { + platformSdkDirFilePaths = __sdkDirFilePathsPosix; + } + return platformSdkDirFilePaths; + } + + /// 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 Directory sdkDirParent(Directory dir) { + while (dir.existsSync()) { + if (_sdkDirFilePaths.every((List l) { + return l.any((f) => new File(pathLib.join(dir.path, f)).existsSync()); + })) { + return dir; + } + if (pathLib.equals(dir.path, dir.parent.path)) break; + dir = dir.parent; + } + return null; + } + @override bool operator ==(other) { if (other is! PackageMeta) return false; @@ -35,10 +80,11 @@ abstract class PackageMeta { int get hashCode => pathLib.hash(dir.absolute.path); /// Use this instead of fromDir where possible. - factory PackageMeta.fromElement(LibraryElement libraryElement) { + factory PackageMeta.fromElement( + LibraryElement libraryElement, DartDocConfig config) { // Workaround for dart-lang/sdk#32707. Replace with isInSdk once that works. if (libraryElement.source.uri.scheme == 'dart') - return new PackageMeta.fromDir(getSdkDir()); + return new PackageMeta.fromDir(config.sdkDir); return new PackageMeta.fromDir( new File(pathLib.canonicalize(libraryElement.source.fullName)).parent); } @@ -62,10 +108,9 @@ abstract class PackageMeta { if (!_packageMetaCache.containsKey(dir.path)) { PackageMeta packageMeta; // There are pubspec.yaml files inside the SDK. Ignore them. - // TODO(jcollins-g): allow specifying alternate SDK directories (#1617) - if (pathLib.isWithin(getSdkDir().absolute.path, dir.path) || - getSdkDir().path == dir.path) { - packageMeta = new _SdkMeta(getSdkDir()); + Directory parentSdkDir = sdkDirParent(dir); + if (parentSdkDir != null) { + packageMeta = new _SdkMeta(parentSdkDir); } else { while (dir.existsSync()) { File pubspec = new File(pathLib.join(dir.path, 'pubspec.yaml')); @@ -75,7 +120,7 @@ abstract class PackageMeta { } // Allow a package to be at root (possible in a Windows setting with // drive letter mappings). - if (dir.path == dir.parent.absolute.path) break; + if (pathLib.equals(dir.path, dir.parent.path)) break; dir = dir.parent.absolute; } } @@ -259,8 +304,12 @@ class _SdkMeta extends PackageMeta { @override String get name => 'Dart'; @override - String get version => - new File(pathLib.join(dir.path, 'version')).readAsStringSync().trim(); + String get version { + File versionFile = new File(pathLib.join(dir.path, 'version')); + if (versionFile.existsSync()) return versionFile.readAsStringSync().trim(); + return 'unknown'; + } + @override String get description => 'The Dart SDK is a set of tools and libraries for the ' @@ -271,6 +320,9 @@ class _SdkMeta extends PackageMeta { @override FileContents getReadmeContents() { File f = new File(pathLib.join(dir.path, 'lib', 'api_readme.md')); + if (!f.existsSync()) { + f = new File(pathLib.join(dir.path, 'api_readme.md')); + } return f.existsSync() ? new FileContents(f) : null; } diff --git a/lib/src/sdk.dart b/lib/src/sdk.dart deleted file mode 100644 index a26d8d9899..0000000000 --- a/lib/src/sdk.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -/// Use config.sdkDir instead outside of initialization. -// TODO(jcollins-g): Avoid this function in PackageMeta, too. -Directory getSdkDir() { - File vmExecutable = new File(Platform.resolvedExecutable); - return vmExecutable.parent.parent; -} diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index f3a68ce527..2b207cf52f 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -151,5 +151,5 @@ void main() { dart_bear.allClasses.map((cls) => cls.name).contains('Bear'), isTrue); expect(p.packageMap["Dart"].publicLibraries, hasLength(3)); }); - }, timeout: new Timeout.factor(4)); + }, timeout: new Timeout.factor(8)); } diff --git a/test/model_test.dart b/test/model_test.dart index 0b53bd8628..d84e3b61f1 100644 --- a/test/model_test.dart +++ b/test/model_test.dart @@ -9,7 +9,6 @@ import 'dart:io'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/model.dart'; import 'package:dartdoc/src/warnings.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:path/path.dart' as pathLib; import 'package:test/test.dart'; @@ -39,7 +38,7 @@ class TestLibraryContainerSdk extends TestLibraryContainer { } void main() { - Directory sdkDir = getSdkDir(); + Directory sdkDir = 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 c893cb42ae..15b4d4950f 100644 --- a/test/package_meta_test.dart +++ b/test/package_meta_test.dart @@ -7,7 +7,6 @@ library dartdoc.package_utils_test; import 'dart:io'; import 'package:dartdoc/src/package_meta.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:test/test.dart'; void main() { @@ -69,7 +68,7 @@ void main() { }); group('PackageMeta.fromSdk', () { - PackageMeta p = new PackageMeta.fromDir(getSdkDir()); + PackageMeta p = new PackageMeta.fromDir(defaultSdkDir); test('has a name', () { expect(p.name, 'Dart'); diff --git a/test/src/utils.dart b/test/src/utils.dart index b381e8361c..6d00c69ee2 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -11,7 +11,6 @@ import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/config.dart'; import 'package:dartdoc/src/model.dart'; import 'package:dartdoc/src/package_meta.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:path/path.dart' as pathLib; Directory sdkDir; @@ -33,7 +32,7 @@ void delete(Directory dir) { } init() async { - sdkDir = getSdkDir(); + sdkDir = defaultSdkDir; sdkPackageMeta = new PackageMeta.fromDir(sdkDir); testPackageGraph = await bootBasicPackage(