diff --git a/pkg/pub_worker/lib/src/bin/pana_wrapper.dart b/pkg/pub_worker/lib/src/bin/pana_wrapper.dart index 4a42426717..ac81cf8491 100644 --- a/pkg/pub_worker/lib/src/bin/pana_wrapper.dart +++ b/pkg/pub_worker/lib/src/bin/pana_wrapper.dart @@ -15,7 +15,6 @@ import 'package:pana/pana.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:pub_worker/src/bin/dartdoc_wrapper.dart'; -import 'package:pub_worker/src/fetch_pubspec.dart'; import 'package:pub_worker/src/sdks.dart'; import 'package:pub_worker/src/utils.dart'; import 'package:pubspec_parse/pubspec_parse.dart' as pubspek; @@ -54,8 +53,11 @@ Future main(List args) async { final pubHostedUrl = Platform.environment['PUB_HOSTED_URL'] ?? 'https://pub.dartlang.org'; final pubCache = Platform.environment['PUB_CACHE']!; - final rawDartdocOutputFolder = - await Directory.systemTemp.createTemp('dartdoc-$package'); + final tempDir = await Directory.systemTemp.createTemp('pana-$package'); + final rawDartdocOutputFolder = Directory(p.join(tempDir.path, 'raw-dartdoc')); + await rawDartdocOutputFolder.create(recursive: true); + final pkgDownloadDir = Directory(p.join(tempDir.path, package)); + await pkgDownloadDir.create(recursive: true); // Setup logging Logger.root.level = Level.INFO; @@ -78,16 +80,24 @@ Future main(List args) async { } }); - // Fetch the pubspec so we detect which SDK to use for analysis - // TODO(https://github.com/dart-lang/pub-dev/issues/7268): Download the archive, - // extract and load the pubspec.yaml, that way we won't have to list versions. - final pubspec = await fetchPubspec( - package: package, - version: version, - pubHostedUrl: pubHostedUrl, + // Download package using the Dart SDK in the path, output will be + // `/-` + await runConstrained( + [ + 'dart', + 'pub', + 'unpack', + '$package:$version', + '--output', + pkgDownloadDir.path, + '--no-resolve', + ], + environment: { + 'PUB_HOSTED_URL': pubHostedUrl, + }, ); - - final detected = await _detectSdks(pubspec); + final pkgDir = Directory(p.join(pkgDownloadDir.path, '$package-$version')); + final detected = await _detectSdks(pkgDir.path); final toolEnv = await ToolEnvironment.create( dartSdkConfig: SdkConfig( @@ -107,11 +117,8 @@ Future main(List args) async { final resourcesOutputDir = await Directory(p.join(outputFolder, 'resources')).create(); final pana = PackageAnalyzer(toolEnv); - // TODO: add a cache purge + retry if the download would fail - // (e.g. the package version cache wasn't invalidated). - var summary = await pana.inspectPackage( - package, - version: version, + var summary = await pana.inspectDir( + pkgDir.path, options: InspectOptions( pubHostedUrl: Platform.environment['PUB_HOSTED_URL']!, dartdocTimeout: _dartdocTimeout, @@ -168,7 +175,7 @@ Future main(List args) async { docDir: rawDartdocOutputFolder.path, ); - await rawDartdocOutputFolder.delete(recursive: true); + await tempDir.delete(recursive: true); } final _workerConfigDirectory = Directory('/home/worker/config'); @@ -185,7 +192,11 @@ String? _configHomePath(String sdk, String kind) { } Future<({String configKind, String? dartSdkPath, String? flutterSdkPath})> - _detectSdks(Pubspec pubspec) async { + _detectSdks(String pkgDir) async { + // Load the pubspec so we detect which SDK to use for analysis + final pubspecFile = File(p.join(pkgDir, 'pubspec.yaml')); + final pubspec = Pubspec.parseYaml(await pubspecFile.readAsString()); + // Discover installed Dart and Flutter SDKs. // This reads sibling folders to the Dart and Flutter SDK. final dartSdks = await InstalledSdk.scanDirectory( @@ -266,6 +277,8 @@ Future<({String configKind, String? dartSdkPath, String? flutterSdkPath})> allowsMissingVersion: true, ); if (matchesInstalledSdks) { + // TODO(https://github.com/dart-lang/pub-dev/issues/7268): Also use `pub get` for better SDK selection. + return ( configKind: 'stable', dartSdkPath: installedDartSdk?.path, diff --git a/pkg/pub_worker/lib/src/fetch_pubspec.dart b/pkg/pub_worker/lib/src/fetch_pubspec.dart deleted file mode 100644 index d5a719da66..0000000000 --- a/pkg/pub_worker/lib/src/fetch_pubspec.dart +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2022, 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:async'; -import 'dart:convert' show json; -import 'dart:io' show IOException; - -import 'package:http/http.dart' as http; -import 'package:pana/pana.dart'; -import 'package:pub_semver/pub_semver.dart' show Version; -import 'package:pub_worker/src/http.dart'; -import 'package:retry/retry.dart'; - -/// Fetch pubspec for the given version -Future fetchPubspec({ - required String package, - required String version, - required String pubHostedUrl, -}) async { - final c = http.Client().withUserAgent(pubWorkerUserAgent); - try { - final result = await retry( - () async { - // TODO: Make some reusable HTTP request logic - final u = Uri.parse(_urlJoin(pubHostedUrl, 'api/packages/$package')); - final r = await c.get(u).timeout(Duration(seconds: 30)); - if (r.statusCode >= 500) { - throw _IntermittentHttpException._( - 'Failed to list versions, got ${r.statusCode} from "$u"', - ); - } - if (r.statusCode != 200) { - throw Exception( - 'Failed to list versions, got ${r.statusCode} from "$u"', - ); - } - return json.decode(r.body); - }, - retryIf: (e) => - e is _IntermittentHttpException || - e is FormatException || // should never happen assume transmission bug - e is IOException || - e is TimeoutException || - e is http.ClientException, - ); - - final versions = result['versions'] as List? ?? []; - - final v = Version.parse(version); - return versions.map((e) => Pubspec(e['pubspec'] as Map)).firstWhere( - (p) => p.version == v, - orElse: () => throw Exception('could not find $version')); - } finally { - c.close(); - } -} - -String _urlJoin(String url, String suffix) { - if (!url.endsWith('/')) { - url += '/'; - } - return url + suffix; -} - -class _IntermittentHttpException implements Exception { - final String _message; - _IntermittentHttpException._(this._message); - @override - String toString() => _message; -}